xref: /reactos/dll/win32/ws2_32/src/addrconv.c (revision 454de56c)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 API
4  * FILE:        dll/win32/ws2_32/src/addrconv.c
5  * PURPOSE:     Address and Port Conversion Support
6  * PROGRAMMER:  Alex Ionescu (alex@relsoft.net)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ws2_32.h>
12 
13 #define NDEBUG
14 #include <debug.h>
15 
16 /* DEFINES *******************************************************************/
17 
18 #ifndef BE
19 
20 /* DWORD network to host byte order conversion for little endian machines */
21 #define DN2H(dw) \
22   ((((dw) & 0xFF000000L) >> 24) | \
23    (((dw) & 0x00FF0000L) >> 8) | \
24      (((dw) & 0x0000FF00L) << 8) | \
25      (((dw) & 0x000000FFL) << 24))
26 
27 /* DWORD host to network byte order conversion for little endian machines */
28 #define DH2N(dw) \
29     ((((dw) & 0xFF000000L) >> 24) | \
30      (((dw) & 0x00FF0000L) >> 8) | \
31      (((dw) & 0x0000FF00L) << 8) | \
32      (((dw) & 0x000000FFL) << 24))
33 
34 /* WORD network to host order conversion for little endian machines */
35 #define WN2H(w) \
36     ((((w) & 0xFF00) >> 8) | \
37      (((w) & 0x00FF) << 8))
38 
39 /* WORD host to network byte order conversion for little endian machines */
40 #define WH2N(w) \
41     ((((w) & 0xFF00) >> 8) | \
42      (((w) & 0x00FF) << 8))
43 
44 #else /* BE */
45 
46 /* DWORD network to host byte order conversion for big endian machines */
47 #define DN2H(dw) \
48     (dw)
49 
50 /* DWORD host to network byte order conversion big endian machines */
51 #define DH2N(dw) \
52     (dw)
53 
54 /* WORD network to host order conversion for big endian machines */
55 #define WN2H(w) \
56     (w)
57 
58 /* WORD host to network byte order conversion for big endian machines */
59 #define WH2N(w) \
60     (w)
61 
62 #endif /* BE */
63 
64 /* FUNCTIONS *****************************************************************/
65 
66 /*
67  * @implemented
68  */
69 ULONG
70 WSAAPI
inet_addr(IN CONST CHAR FAR * cp)71 inet_addr(IN  CONST CHAR FAR* cp)
72 {
73     register u_long val, base, n;
74     register unsigned char c;
75     u_long parts[4], *pp = parts;
76     if (!cp) return INADDR_ANY;
77     if (!isdigit(*cp)) return INADDR_NONE;
78 
79 again:
80     /*
81      * Collect number up to ``.''.
82      * Values are specified as for C:
83      * 0x=hex, 0=octal, other=decimal.
84      */
85     val = 0; base = 10;
86     if (*cp == '0') {
87         if (*++cp == 'x' || *cp == 'X')
88             base = 16, cp++;
89         else
90             base = 8;
91     }
92     while ((c = *cp)) {
93         if (isdigit(c)) {
94             val = (val * base) + (c - '0');
95             cp++;
96             continue;
97         }
98         if (base == 16 && isxdigit(c)) {
99             val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
100             cp++;
101             continue;
102         }
103         break;
104     }
105     if (*cp == '.') {
106         /*
107          * Internet format:
108          *    a.b.c.d
109          *    a.b.c    (with c treated as 16-bits)
110          *    a.b    (with b treated as 24 bits)
111          */
112         if (pp >= parts + 4) return (INADDR_NONE);
113         *pp++ = val;
114         cp++;
115         goto again;
116     }
117     /*
118      * Check for trailing characters.
119      */
120     if (*cp && !isspace((UCHAR)*cp)) return (INADDR_NONE);
121 
122     *pp++ = val;
123     /*
124      * Concoct the address according to
125      * the number of parts specified.
126      */
127     n = (u_long)(pp - parts);
128     switch (n) {
129 
130     case 1:                /* a -- 32 bits */
131         val = parts[0];
132         break;
133 
134     case 2:                /* a.b -- 8.24 bits */
135         val = (parts[0] << 24) | (parts[1] & 0xffffff);
136         break;
137 
138     case 3:                /* a.b.c -- 8.8.16 bits */
139         val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
140             (parts[2] & 0xffff);
141         break;
142 
143     case 4:                /* a.b.c.d -- 8.8.8.8 bits */
144         val = (parts[0] << 24) | ((parts[1] & 0xff) << 16) |
145               ((parts[2] & 0xff) << 8) | (parts[3] & 0xff);
146         break;
147 
148     default:
149         return (INADDR_NONE);
150     }
151     val = htonl(val);
152     return (val);
153 }
154 
155 /*
156  * @implemented
157  */
158 CHAR FAR*
159 WSAAPI
inet_ntoa(IN IN_ADDR in)160 inet_ntoa(IN IN_ADDR in)
161 {
162     PWSPROCESS Process;
163     PWSTHREAD Thread;
164     INT ErrorCode;
165     WSADATA WsaData;
166     BOOL ManualLoad = FALSE;
167     CHAR b[10];
168     PCHAR p;
169     DPRINT("inet_ntoa: %lx\n", in);
170 
171     /* Enter prolog */
172     if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
173     {
174         DPRINT("MANUAL LOAD\n");
175 
176         /* Only fail if the error wasn't related to a missing WSAStartup */
177         if (ErrorCode != WSANOTINITIALISED)
178         {
179             /* Fail */
180             SetLastError(ErrorCode);
181             return NULL;
182         }
183 
184         /* Apps aren't expected to call WSAStartup for this API, so we will */
185         if ((ErrorCode = WSAStartup(MAKEWORD(2,2), &WsaData)) != ERROR_SUCCESS)
186         {
187             /* We failed */
188             SetLastError(ErrorCode);
189             return NULL;
190         }
191 
192         /* Try the prolog again */
193         ManualLoad = TRUE;
194         if ((ErrorCode = WsApiProlog(&Process, &Thread)) != ERROR_SUCCESS)
195         {
196             /* Failed again... */
197             WSACleanup();
198             SetLastError(ErrorCode);
199             return NULL;
200         }
201     }
202 
203     p = Thread->Buffer;
204     _itoa(in.S_un.S_addr & 0xFF, b, 10);
205     strcpy(p, b);
206     _itoa((in.S_un.S_addr >> 8) & 0xFF, b, 10);
207     strcat(p, ".");
208     strcat(p, b);
209     _itoa((in.S_un.S_addr >> 16) & 0xFF, b, 10);
210     strcat(p, ".");
211     strcat(p, b);
212     _itoa((in.S_un.S_addr >> 24) & 0xFF, b, 10);
213     strcat(p, ".");
214     strcat(p, b);
215 
216     /* Cleanup the manual load */
217     if (ManualLoad) WSACleanup();
218 
219     /* Return the buffer */
220     return p;
221 }
222 
223 /*
224  * @implemented
225  */
226 ULONG
227 WSAAPI
htonl(IN ULONG hostlong)228 htonl(IN ULONG hostlong)
229 {
230     return DH2N(hostlong);
231 }
232 
233 /*
234  * @implemented
235  */
236 USHORT
237 WSAAPI
htons(IN USHORT hostshort)238 htons(IN USHORT hostshort)
239 {
240     return WH2N(hostshort);
241 }
242 
243 /*
244  * @implemented
245  */
246 ULONG
247 WSAAPI
ntohl(IN ULONG netlong)248 ntohl(IN ULONG netlong)
249 {
250     return DN2H(netlong);
251 }
252 
253 /*
254  * @implemented
255  */
256 USHORT
257 WSAAPI
ntohs(IN USHORT netshort)258 ntohs(IN USHORT netshort)
259 {
260     return WN2H(netshort);
261 }
262 
263 /*
264  * @implemented
265  */
266 INT
267 WSAAPI
WSAHtonl(IN SOCKET s,IN ULONG hostlong,OUT ULONG FAR * lpnetlong)268 WSAHtonl(IN SOCKET s,
269          IN ULONG hostlong,
270          OUT ULONG FAR* lpnetlong)
271 {
272     INT ErrorCode;
273     PWSSOCKET Socket;
274     DPRINT("WSAHtonl: %p, %lx, %p\n", s, hostlong, lpnetlong);
275 
276     /* Check for WSAStartup */
277     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
278     {
279         /* Make sure we got a parameter */
280         if (!lpnetlong)
281         {
282             /* Fail */
283             SetLastError(WSAEFAULT);
284             return SOCKET_ERROR;
285         }
286 
287         /* Get the Socket Context */
288         if ((Socket = WsSockGetSocket(s)))
289         {
290             /* Check which byte order to use */
291             if (Socket->CatalogEntry->ProtocolInfo.iNetworkByteOrder ==
292                 LITTLEENDIAN)
293             {
294                 /* No conversion needed */
295                 *lpnetlong = hostlong;
296             }
297             else
298             {
299                 /* Use a swap */
300                 *lpnetlong = DN2H(hostlong);
301             }
302 
303             /* Dereference the socket */
304             WsSockDereference(Socket);
305 
306             /* Return success */
307             return ERROR_SUCCESS;
308         }
309         else
310         {
311             /* Set the error code */
312             ErrorCode = WSAENOTSOCK;
313         }
314     }
315 
316     /* Return with error */
317     SetLastError(ErrorCode);
318     return SOCKET_ERROR;
319 }
320 
321 /*
322  * @implemented
323  */
324 INT
325 WSAAPI
WSAHtons(IN SOCKET s,IN USHORT hostshort,OUT USHORT FAR * lpnetshort)326 WSAHtons(IN SOCKET s,
327          IN USHORT hostshort,
328          OUT USHORT FAR* lpnetshort)
329 {
330     INT ErrorCode;
331     PWSSOCKET Socket;
332     DPRINT("WSAHtons: %p, %lx, %p\n", s, hostshort, lpnetshort);
333 
334     /* Check for WSAStartup */
335     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
336     {
337         /* Make sure we got a parameter */
338         if (!lpnetshort)
339         {
340             /* Fail */
341             SetLastError(WSAEFAULT);
342             return SOCKET_ERROR;
343         }
344 
345         /* Get the Socket Context */
346         if ((Socket = WsSockGetSocket(s)))
347         {
348             /* Check which byte order to use */
349             if (Socket->CatalogEntry->ProtocolInfo.iNetworkByteOrder ==
350                 LITTLEENDIAN)
351             {
352                 /* No conversion needed */
353                 *lpnetshort = hostshort;
354             }
355             else
356             {
357                 /* Use a swap */
358                 *lpnetshort = WN2H(hostshort);
359             }
360 
361             /* Dereference the socket */
362             WsSockDereference(Socket);
363 
364             /* Return success */
365             return ERROR_SUCCESS;
366         }
367         else
368         {
369             /* Set the error code */
370             ErrorCode = WSAENOTSOCK;
371         }
372     }
373 
374     /* Return with error */
375     SetLastError(ErrorCode);
376     return SOCKET_ERROR;
377 }
378 
379 /*
380  * @implemented
381  */
382 INT
383 WSAAPI
WSANtohl(IN SOCKET s,IN ULONG netlong,OUT ULONG FAR * lphostlong)384 WSANtohl(IN SOCKET s,
385          IN ULONG netlong,
386          OUT ULONG FAR* lphostlong)
387 {
388     INT ErrorCode;
389     PWSSOCKET Socket;
390     DPRINT("WSANtohl: %p, %lx, %p\n", s, netlong, lphostlong);
391 
392     /* Check for WSAStartup */
393     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
394     {
395         /* Make sure we got a parameter */
396         if (!lphostlong)
397         {
398             /* Fail */
399             SetLastError(WSAEFAULT);
400             return SOCKET_ERROR;
401         }
402 
403         /* Get the Socket Context */
404         if ((Socket = WsSockGetSocket(s)))
405         {
406             /* Check which byte order to use */
407             if (Socket->CatalogEntry->ProtocolInfo.iNetworkByteOrder ==
408                 LITTLEENDIAN)
409             {
410                 /* No conversion needed */
411                 *lphostlong = netlong;
412             }
413             else
414             {
415                 /* Use a swap */
416                 *lphostlong = DN2H(netlong);
417             }
418 
419             /* Dereference the socket */
420             WsSockDereference(Socket);
421 
422             /* Return success */
423             return ERROR_SUCCESS;
424         }
425         else
426         {
427             /* Set the error code */
428             ErrorCode = WSAENOTSOCK;
429         }
430     }
431 
432     /* Return with error */
433     SetLastError(ErrorCode);
434     return SOCKET_ERROR;
435 }
436 
437 /*
438  * @implemented
439  */
440 INT
441 WSAAPI
WSANtohs(IN SOCKET s,IN USHORT netshort,OUT USHORT FAR * lphostshort)442 WSANtohs(IN SOCKET s,
443          IN USHORT netshort,
444          OUT USHORT FAR* lphostshort)
445 {
446     INT ErrorCode;
447     PWSSOCKET Socket;
448     DPRINT("WSANtohs: %p, %lx, %p\n", s, netshort, lphostshort);
449 
450     /* Check for WSAStartup */
451     if ((ErrorCode = WsQuickProlog()) == ERROR_SUCCESS)
452     {
453         /* Make sure we got a parameter */
454         if (!lphostshort)
455         {
456             /* Fail */
457             SetLastError(WSAEFAULT);
458             return SOCKET_ERROR;
459         }
460 
461         /* Get the Socket Context */
462         if ((Socket = WsSockGetSocket(s)))
463         {
464             /* Check which byte order to use */
465             if (Socket->CatalogEntry->ProtocolInfo.iNetworkByteOrder ==
466                 LITTLEENDIAN)
467             {
468                 /* No conversion needed */
469                 *lphostshort = netshort;
470             }
471             else
472             {
473                 /* Use a swap */
474                 *lphostshort = WN2H(netshort);
475             }
476 
477             /* Dereference the socket */
478             WsSockDereference(Socket);
479 
480             /* Return success */
481             return ERROR_SUCCESS;
482         }
483         else
484         {
485             /* Set the error code */
486             ErrorCode = WSAENOTSOCK;
487         }
488     }
489 
490     /* Return with error */
491     SetLastError(ErrorCode);
492     return SOCKET_ERROR;
493 }
494 
495 PCSTR
496 WSAAPI
inet_ntop(_In_ INT Family,_In_ const VOID * pAddr,_Out_writes_ (StringBufSize)PSTR pStringBuf,_In_ size_t StringBufSize)497 inet_ntop(
498     _In_ INT Family,
499     _In_ const VOID *pAddr,
500     _Out_writes_(StringBufSize) PSTR pStringBuf,
501     _In_ size_t StringBufSize)
502 {
503     NTSTATUS Status;
504     ULONG BufSize = StringBufSize;
505 
506     switch (Family)
507     {
508         case AF_INET:
509             Status = RtlIpv4AddressToStringExA(pAddr, 0, pStringBuf, &BufSize);
510             break;
511         case AF_INET6:
512             Status = RtlIpv6AddressToStringExA(pAddr, 0, 0, pStringBuf, &BufSize);
513             break;
514         default:
515             SetLastError(WSAEAFNOSUPPORT);
516             return NULL;
517     }
518 
519     if (!NT_SUCCESS(Status))
520     {
521         SetLastError(WSAEINVAL);
522         return NULL;
523     }
524 
525     return pStringBuf;
526 }
527 
528 PCWSTR
529 WSAAPI
InetNtopW(_In_ INT Family,_In_ const VOID * pAddr,_Out_writes_ (StringBufSize)PWSTR pStringBuf,_In_ size_t StringBufSize)530 InetNtopW(
531     _In_ INT Family,
532     _In_ const VOID *pAddr,
533     _Out_writes_(StringBufSize) PWSTR pStringBuf,
534     _In_ size_t StringBufSize)
535 {
536     NTSTATUS Status;
537     ULONG BufSize = StringBufSize;
538 
539     switch (Family)
540     {
541         case AF_INET:
542             Status = RtlIpv4AddressToStringExW(pAddr, 0, pStringBuf, &BufSize);
543             break;
544         case AF_INET6:
545             Status = RtlIpv6AddressToStringExW(pAddr, 0, 0, pStringBuf, &BufSize);
546             break;
547         default:
548             SetLastError(WSAEAFNOSUPPORT);
549             return NULL;
550     }
551 
552     if (!NT_SUCCESS(Status))
553     {
554         SetLastError(WSAEINVAL);
555         return NULL;
556     }
557 
558     return pStringBuf;
559 }
560 
561 INT
562 WSAAPI
inet_pton(_In_ INT Family,_In_ PCSTR pszAddrString,_Out_writes_bytes_ (sizeof (IN_ADDR6))PVOID pAddrBuf)563 inet_pton(
564     _In_ INT Family,
565     _In_ PCSTR pszAddrString,
566     _Out_writes_bytes_(sizeof(IN_ADDR6)) PVOID pAddrBuf)
567 {
568     NTSTATUS Status;
569     PCSTR ch;
570 
571     if (!pszAddrString || !pAddrBuf)
572     {
573         SetLastError(WSAEFAULT);
574         return -1;
575     }
576 
577     switch (Family)
578     {
579         case AF_INET:
580             Status = RtlIpv4StringToAddressA(pszAddrString, TRUE, &ch, pAddrBuf);
581             break;
582         case AF_INET6:
583             Status = RtlIpv6StringToAddressA(pszAddrString, &ch, pAddrBuf);
584             break;
585         default:
586             SetLastError(WSAEAFNOSUPPORT);
587             return -1;
588     }
589 
590     if (!NT_SUCCESS(Status) || (*ch != 0))
591     {
592         return 0;
593     }
594 
595     return 1;
596 }
597 
598 INT
599 WSAAPI
InetPtonW(_In_ INT Family,_In_ PCWSTR pszAddrString,_Out_writes_bytes_ (sizeof (IN_ADDR6))PVOID pAddrBuf)600 InetPtonW(
601     _In_ INT Family,
602     _In_ PCWSTR pszAddrString,
603     _Out_writes_bytes_(sizeof(IN_ADDR6)) PVOID pAddrBuf)
604 {
605     NTSTATUS Status;
606     PCWSTR ch;
607 
608     if (!pszAddrString || !pAddrBuf)
609     {
610         SetLastError(WSAEFAULT);
611         return -1;
612     }
613 
614     switch (Family)
615     {
616         case AF_INET:
617             Status = RtlIpv4StringToAddressW(pszAddrString, TRUE, &ch, pAddrBuf);
618             break;
619         case AF_INET6:
620             Status = RtlIpv6StringToAddressW(pszAddrString, &ch, pAddrBuf);
621             break;
622         default:
623             SetLastError(WSAEAFNOSUPPORT);
624             return -1;
625     }
626 
627     if (!NT_SUCCESS(Status) || (*ch != 0))
628     {
629         SetLastError(WSAEINVAL); /* Only unicode version sets this error */
630         return 0;
631     }
632 
633     return 1;
634 }
635