xref: /reactos/dll/win32/ws2_32/src/addrinfo.c (revision 3476cdae)
1 /*
2  * COPYRIGHT:   See COPYING in the top level directory
3  * PROJECT:     ReactOS WinSock 2 API
4  * FILE:        dll/win32/ws2_32/src/addrinfo.c
5  * PURPOSE:     Protocol-Independent Address Resolution
6  * PROGRAMMER:  Alex Ionescu (alex@relsoft.net)
7  */
8 
9 /* INCLUDES ******************************************************************/
10 
11 #include <ws2_32.h>
12 
13 #include <ws2tcpip.h>
14 
15 #define NDEBUG
16 #include <debug.h>
17 
18 /* DEFINES *******************************************************************/
19 
20 #define Swap(a, b, c)       { (c) = (a); (a) = (b); (b) = (c); }
21 #define FreeAddrInfoW(a)    freeaddrinfo((LPADDRINFO)a)
22 
23 /* FUNCTIONS *****************************************************************/
24 
25 /* FIXME: put into dnslib */
26 VOID
27 WSAAPI
28 Dns_Ip4AddressToReverseName_W(IN LPWSTR AddressBuffer,
29                               IN IN_ADDR Address)
30 {
31     /* Convert the address into IPv4 format */
32     wsprintfW(AddressBuffer, L"%u.%u.%u.%u.in-addr.arpa.",
33               Address.S_un.S_un_b.s_b4,
34               Address.S_un.S_un_b.s_b3,
35               Address.S_un.S_un_b.s_b2,
36               Address.S_un.S_un_b.s_b1);
37 }
38 
39 VOID
40 WINAPI
41 Dns_SplitHostFromDomainNameW(IN LPWSTR DomainName)
42 {
43     /* FIXME */
44 }
45 
46 static
47 INT
48 WINAPI
49 ConvertAddrinfoFromUnicodeToAnsi(IN PADDRINFOW Addrinfo)
50 {
51     LPSTR AnsiName;
52     LPWSTR *UnicodeName;
53 
54     /* Make sure we have a valid pointer */
55     if (Addrinfo)
56     {
57         do
58         {
59             /* Get the name */
60             UnicodeName = &Addrinfo->ai_canonname;
61 
62             /* Check if it exists */
63             if (*UnicodeName)
64             {
65                 /* Convert it */
66                 AnsiName = AnsiDupFromUnicode(*UnicodeName);
67                 if (AnsiName)
68                 {
69                     /* Free the old one */
70                     HeapFree(WsSockHeap, 0, *UnicodeName);
71 
72                     /* Set the new one */
73                     *UnicodeName = (LPWSTR)AnsiName;
74                 }
75                 else
76                 {
77                     return GetLastError();
78                 }
79             }
80         } while ((Addrinfo = Addrinfo->ai_next));
81     }
82 
83     /* All done */
84     return ERROR_SUCCESS;
85 }
86 
87 static
88 BOOL
89 WINAPI
90 ParseV4Address(IN PCWSTR AddressString,
91                OUT PDWORD pAddress)
92 {
93     CHAR AnsiAddressString[MAX_HOSTNAME_LEN];
94     CHAR * cp = AnsiAddressString;
95     DWORD val, base;
96     unsigned char c;
97     DWORD parts[4], *pp = parts;
98     if (!AddressString)
99         return FALSE;
100     WideCharToMultiByte(CP_ACP,
101                         0,
102                         AddressString,
103                         -1,
104                         AnsiAddressString,
105                         sizeof(AnsiAddressString),
106                         NULL,
107                         0);
108     if (!isdigit(*cp)) return FALSE;
109 
110 again:
111     /*
112     * Collect number up to ``.''.
113     * Values are specified as for C:
114     * 0x=hex, 0=octal, other=decimal.
115     */
116     val = 0; base = 10;
117     if (*cp == '0') {
118         if (*++cp == 'x' || *cp == 'X')
119             base = 16, cp++;
120         else
121             base = 8;
122     }
123     while ((c = *cp)) {
124         if (isdigit(c)) {
125             val = (val * base) + (c - '0');
126             cp++;
127             continue;
128         }
129         if (base == 16 && isxdigit(c)) {
130             val = (val << 4) + (c + 10 - (islower(c) ? 'a' : 'A'));
131             cp++;
132             continue;
133         }
134         break;
135     }
136     if (*cp == '.') {
137         /*
138         * Internet format:
139         *    a.b.c.d
140         */
141         if (pp >= parts + 4) return FALSE;
142         *pp++ = val;
143         cp++;
144         goto again;
145     }
146     /*
147     * Check for trailing characters.
148     */
149     if (*cp) return FALSE;
150 
151     if (pp >= parts + 4) return FALSE;
152     *pp++ = val;
153     /*
154     * Concoct the address according to
155     * the number of parts specified.
156     */
157     if ((DWORD)(pp - parts) != 4) return FALSE;
158     if (parts[0] > 0xff || parts[1] > 0xff || parts[2] > 0xff || parts[3] > 0xff) return FALSE;
159     val = (parts[0] << 24) | (parts[1] << 16) | (parts[2] << 8) | parts[3];
160 
161     if (pAddress)
162         *pAddress = htonl(val);
163 
164     return TRUE;
165 }
166 
167 static
168 PADDRINFOW
169 WINAPI
170 NewAddrInfo(IN INT SocketType,
171             IN INT Protocol,
172             IN WORD Port,
173             IN DWORD Address)
174 {
175     PADDRINFOW AddrInfo;
176     PSOCKADDR_IN SockAddress;
177 
178     /* Allocate a structure */
179     AddrInfo = HeapAlloc(WsSockHeap, 0, sizeof(ADDRINFOW));
180     if (!AddrInfo) return NULL;
181 
182     /* Allocate a sockaddr */
183     SockAddress = HeapAlloc(WsSockHeap, 0, sizeof(SOCKADDR_IN));
184     if (!SockAddress)
185     {
186         /* Free the addrinfo and fail */
187         HeapFree(WsSockHeap, 0, AddrInfo);
188         return NULL;
189     }
190 
191     /* Write data for socket address */
192     SockAddress->sin_family = AF_INET;
193     SockAddress->sin_port = Port;
194     SockAddress->sin_addr.s_addr = Address;
195     ZeroMemory(SockAddress->sin_zero, sizeof(SockAddress->sin_zero));
196 
197     /* Fill out the addrinfo */
198     AddrInfo->ai_family = PF_INET;
199     AddrInfo->ai_socktype = SocketType;
200     AddrInfo->ai_protocol = Protocol;
201     AddrInfo->ai_flags = 0;
202     AddrInfo->ai_next = 0;
203     AddrInfo->ai_canonname = NULL;
204     AddrInfo->ai_addrlen = sizeof(SOCKADDR_IN);
205     AddrInfo->ai_addr = (PSOCKADDR)SockAddress;
206 
207     /* Return it */
208     return AddrInfo;
209 }
210 
211 static
212 INT
213 WINAPI
214 CloneAddrInfo(IN WORD Port,
215               IN PADDRINFOW ptResult)
216 {
217     PADDRINFOW Next = NULL;
218     PADDRINFOW New  = NULL;
219 
220     /* Loop the chain */
221     for (Next = ptResult; Next;)
222     {
223         /* Create a new structure */
224         New = NewAddrInfo(SOCK_DGRAM,
225                           Next->ai_protocol,
226                           Port,
227                           ((PSOCKADDR_IN)Next->ai_addr)->sin_addr.s_addr);
228         if (!New) break;
229 
230         /* Link them */
231         New->ai_next = Next->ai_next;
232         Next->ai_next = New;
233         Next = New->ai_next;
234     }
235 
236     /* Check if we ran out of memory */
237     if (Next) return EAI_MEMORY;
238 
239     /* Return success */
240     return 0;
241 }
242 
243 static
244 INT
245 WINAPI
246 QueryDNS(IN LPCSTR NodeName,
247          IN INT SocketType,
248          IN INT Protocol,
249          IN WORD Port,
250          OUT CHAR Alias[NI_MAXHOST],
251          OUT PADDRINFOW *pptResult)
252 {
253     PADDRINFOW *Next = pptResult;
254     PHOSTENT Hostent = NULL;
255     PCHAR *Addresses;
256 
257     /* Assume nothing found */
258     *Next = NULL;
259     Alias[0] = '\0';
260 
261     /* Get the hostent */
262     Hostent = gethostbyname(NodeName);
263     if (Hostent)
264     {
265         /* Check for valid addresses */
266         if ((Hostent->h_addrtype == AF_INET) &&
267             (Hostent->h_length == sizeof(IN_ADDR)))
268         {
269             /* Loop every address in it */
270             for (Addresses = Hostent->h_addr_list; *Addresses; Addresses++)
271             {
272                 /* Create an addrinfo structure for it*/
273                 *Next = NewAddrInfo(SocketType,
274                                     Protocol,
275                                     Port,
276                                     ((PIN_ADDR)*Addresses)->s_addr);
277                 if (!*Next) return EAI_MEMORY;
278 
279                 /* Move to the next entry */
280                 Next = &((*Next)->ai_next);
281             }
282         }
283 
284         /* Copy the canonical name */
285         strcpy(Alias, Hostent->h_name);
286 
287         /* Return success */
288         return 0;
289     }
290 
291     /* Find out what the error was */
292     switch (GetLastError())
293     {
294         /* Convert the Winsock Error to an EAI error */
295         case WSAHOST_NOT_FOUND: return EAI_NONAME;
296         case WSATRY_AGAIN: return EAI_AGAIN;
297         case WSANO_RECOVERY: return EAI_FAIL;
298         case WSANO_DATA: return EAI_NODATA;
299         default: return EAI_NONAME;
300     }
301 }
302 
303 static
304 INT
305 WINAPI
306 LookupNodeByAddr(IN LPWSTR pNodeBuffer,
307                  IN DWORD NodeBufferSize,
308                  IN BOOLEAN OnlyNodeName,
309                  IN PVOID Addr,
310                  IN DWORD AddrSize,
311                  IN INT AddressFamily)
312 {
313     GUID LookupGuid = SVCID_DNS_TYPE_PTR;
314     PIN_ADDR Ip4Addr = Addr;
315     WCHAR ReverseBuffer[76];
316     WSAQUERYSETW Restrictions, Reply;
317     DWORD BufferLength;
318     INT ErrorCode;
319     HANDLE LookupHandle;
320 
321     /* Validate the address */
322     if (!Addr) return WSAEFAULT;
323 
324     /* Make sure the family and address size match */
325     if (AddressFamily == AF_INET6)
326     {
327         /* Check the address size for this type */
328         if (AddrSize != sizeof(IN6_ADDR)) return WSAEFAULT;
329         Ip4Addr = (PIN_ADDR)&((PIN6_ADDR)Addr)->u.Byte[12];
330     }
331     else if (AddressFamily == AF_INET)
332     {
333         /* Check the address size for this type */
334         if (AddrSize != sizeof(IN_ADDR)) return WSAEFAULT;
335     }
336     else
337     {
338         /* Address family not supported */
339         return WSAEAFNOSUPPORT;
340     }
341 
342     /* Check if this is a mapped V4 IPv6 or pure IPv4 */
343     if (((AddressFamily == AF_INET6) && (IN6_IS_ADDR_V4MAPPED(Addr))) ||
344         (AddressFamily == AF_INET))
345     {
346         /* Get the reverse name */
347         Dns_Ip4AddressToReverseName_W(ReverseBuffer, *Ip4Addr);
348     }
349     /* FIXME: Not implemented for now
350     else if ( */
351 
352     /* By this point we have the Reverse Name, so prepare for lookup */
353     RtlZeroMemory(&Restrictions, sizeof(Restrictions));
354     Restrictions.dwSize = sizeof(Restrictions);
355     Restrictions.lpszServiceInstanceName = ReverseBuffer;
356     Restrictions.lpServiceClassId = &LookupGuid;
357     Restrictions.dwNameSpace = NS_DNS;
358 
359     /* Now do the lookup */
360     ErrorCode = WSALookupServiceBeginW(&Restrictions,
361                                        LUP_RETURN_NAME,
362                                        &LookupHandle);
363     if (ErrorCode == ERROR_SUCCESS)
364     {
365         /* Lookup successful, now get the data */
366         BufferLength = (NI_MAXHOST - 1) * sizeof(WCHAR) + sizeof(Restrictions);
367         ErrorCode = WSALookupServiceNextW(LookupHandle,
368                                           0,
369                                           &BufferLength,
370                                           &Restrictions);
371         if (ErrorCode == ERROR_SUCCESS)
372         {
373             /* Now check if we have a name back */
374             Reply = Restrictions;
375             if (!Reply.lpszServiceInstanceName)
376             {
377                 /* Fail */
378                 ErrorCode = WSAHOST_NOT_FOUND;
379             }
380             else
381             {
382                 /* Check if the caller only wants the node name */
383                 if (OnlyNodeName)
384                 {
385                     /* Split it and get only the partial host name */
386                     Dns_SplitHostFromDomainNameW(Reply.lpszServiceInstanceName);
387                 }
388 
389                 /* Check the length and see if it's within our limit */
390                 if (wcslen(Reply.lpszServiceInstanceName) + 1 >
391                     NodeBufferSize)
392                 {
393                     /* It's not, so fail */
394                     ErrorCode = WSAEFAULT;
395                 }
396                 else
397                 {
398                     /* It will fit, let's copy it*/
399                     wcscpy(pNodeBuffer, Reply.lpszServiceInstanceName);
400                 }
401             }
402         }
403     }
404     else if (ErrorCode == WSASERVICE_NOT_FOUND)
405     {
406         /* Normalize the error code */
407         ErrorCode = WSAHOST_NOT_FOUND;
408     }
409 
410     /* Finish the lookup if one was in progress */
411     if (LookupHandle) WSALookupServiceEnd(LookupHandle);
412 
413     /* Return the error code */
414     return ErrorCode;
415 }
416 
417 static
418 INT
419 WINAPI
420 GetServiceNameForPort(IN LPWSTR pServiceBuffer,
421                       IN DWORD ServiceBufferSize,
422                       IN WORD Port,
423                       IN DWORD Flags)
424 {
425     return ERROR_SUCCESS;
426 }
427 
428 static
429 INT
430 WINAPI
431 LookupAddressForName(IN LPCSTR NodeName,
432                      IN INT SocketType,
433                      IN INT Protocol,
434                      IN WORD Port,
435                      IN BOOL bAI_CANONNAME,
436                      OUT PADDRINFOW *pptResult)
437 {
438     INT iError = 0;
439     INT AliasCount = 0;
440     CHAR szFQDN1[NI_MAXHOST] = "";
441     CHAR szFQDN2[NI_MAXHOST] = "";
442     PCHAR Name = szFQDN1;
443     PCHAR Alias = szFQDN2;
444     PCHAR Scratch = NULL;
445 
446     /* Make a copy of the name */
447     strcpy(Name, NodeName);
448 
449     /* Loop */
450     while (TRUE)
451     {
452         /* Do a DNS Query for the name */
453         iError = QueryDNS(NodeName,
454                           SocketType,
455                           Protocol,
456                           Port,
457                           Alias,
458                           pptResult);
459         if (iError) break;
460 
461         /* Exit if we have a result */
462         if (*pptResult) break;
463 
464         /* Don't loop continuously if this is a DNS misconfiguration */
465         if ((!strlen(Alias)) || (!strcmp(Name, Alias)) || (++AliasCount == 16))
466         {
467             /* Exit the loop with a failure */
468             iError = EAI_FAIL;
469             break;
470         }
471 
472         /* Restart loopup if we got a CNAME */
473         Swap(Name, Alias, Scratch);
474     }
475 
476     /* Check if we succeeded and the canonical name is requested */
477     if (!iError && bAI_CANONNAME)
478     {
479         /* Allocate memory for a copy */
480         (*pptResult)->ai_canonname = HeapAlloc(WsSockHeap, 0, 512);
481 
482         /* Check if we had enough memory */
483         if (!(*pptResult)->ai_canonname)
484         {
485             /* Set failure code */
486             iError = EAI_MEMORY;
487         }
488         else
489         {
490             /* Convert the alias to UNICODE */
491             MultiByteToWideChar(CP_ACP,
492                                 0,
493                                 Alias,
494                                 -1,
495                                 (*pptResult)->ai_canonname,
496                                 256);
497         }
498     }
499 
500     /* Return to caller */
501     return iError;
502 }
503 
504 /*
505  * @implemented
506  */
507 INT
508 WSAAPI
509 GetAddrInfoW(IN PCWSTR pszNodeName,
510              IN PCWSTR pszServiceName,
511              IN const ADDRINFOW *ptHints,
512              OUT PADDRINFOW *pptResult)
513 {
514     INT iError = 0;
515     INT iFlags = 0;
516     INT iFamily = PF_UNSPEC;
517     INT iSocketType = 0;
518     INT iProtocol = 0;
519     WORD wPort = 0;
520     DWORD dwAddress = 0;
521     PSERVENT ptService = NULL;
522     PCHAR pc = NULL;
523     BOOL bClone = FALSE;
524     WORD wTcpPort = 0;
525     WORD wUdpPort = 0;
526     WCHAR CanonicalName[0x42];
527     CHAR AnsiServiceName[256];
528     CHAR AnsiNodeName[256];
529     DPRINT("GetAddrInfoW: %S, %S, %p, %p\n", pszNodeName, pszServiceName, ptHints, pptResult);
530 
531     /* Assume error */
532     *pptResult  = NULL;
533 
534     /* We must have at least one name to work with */
535     if (!(pszNodeName) && !(pszServiceName))
536     {
537         /* Fail */
538         SetLastError(EAI_NONAME);
539         return EAI_NONAME;
540     }
541 
542     /* Check if we got hints */
543     if (ptHints)
544     {
545         /* Make sure these are empty */
546         if ((ptHints->ai_addrlen) ||
547             (ptHints->ai_canonname) ||
548             (ptHints->ai_addr) ||
549             (ptHints->ai_next))
550         {
551             /* Fail if they aren't */
552             SetLastError(EAI_FAIL);
553             return EAI_FAIL;
554         }
555 
556         /* Save the flags and validate them */
557         iFlags = ptHints->ai_flags;
558         if ((iFlags & AI_CANONNAME) && !pszNodeName)
559         {
560             SetLastError(EAI_BADFLAGS);
561             return EAI_BADFLAGS;
562         }
563 
564         /* Save family and validate it */
565         iFamily = ptHints->ai_family;
566         if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
567         {
568             SetLastError(EAI_FAMILY);
569             return EAI_FAMILY;
570         }
571 
572         /* Save socket type and validate it */
573         iSocketType = ptHints->ai_socktype;
574         if ((iSocketType != 0) &&
575             (iSocketType != SOCK_STREAM) &&
576             (iSocketType != SOCK_DGRAM) &&
577             (iSocketType != SOCK_RAW))
578         {
579             SetLastError(EAI_SOCKTYPE);
580             return EAI_SOCKTYPE;
581         }
582 
583         /* Save the protocol */
584         iProtocol = ptHints->ai_protocol;
585     }
586 
587     /* Check if we have a service name */
588     if (pszServiceName)
589     {
590         /* We need to convert it to ANSI */
591         WideCharToMultiByte(CP_ACP,
592                             0,
593                             pszServiceName,
594                             -1,
595                             AnsiServiceName,
596                             sizeof(AnsiServiceName),
597                             NULL,
598                             0);
599 
600         /* Get the port */
601         wPort = (WORD)strtoul(AnsiServiceName, &pc, 10);
602 
603         /* Check if the port string is numeric */
604         if (*pc == '\0')
605         {
606             /* Get the port directly */
607             wPort = wTcpPort = wUdpPort = htons(wPort);
608 
609 #if 0
610             /* Check if this is both TCP and UDP */
611             if (iSocketType == 0)
612             {
613                 /* Set it to TCP for now, but remember to clone */
614                 bClone = TRUE;
615                 iSocketType = SOCK_STREAM;
616             }
617 #endif
618         }
619         else
620         {
621             wPort = 0;
622             /* The port name was a string. Check if this is a UDP socket */
623             if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
624             {
625                 /* It's UDP, do a getservbyname */
626                 ptService = getservbyname(AnsiServiceName, "udp");
627 
628                 /* If we got a servent, return the port from it */
629                 if (ptService) wPort = wUdpPort = ptService->s_port;
630             }
631 
632             /* Check if this is a TCP socket */
633             if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
634             {
635                 /* It's TCP, do a getserbyname */
636                 ptService = getservbyname(AnsiServiceName, "tcp");
637 
638                 /* Return the port from the servent */
639                 if (ptService) wPort = wTcpPort = ptService->s_port;
640             }
641 
642             /* If we got 0, then fail */
643             if (wPort == 0)
644             {
645                 SetLastError(EAI_SERVICE);
646                 return EAI_SERVICE;
647             }
648 
649             /* Check if this was for both */
650             if (iSocketType == 0)
651             {
652                 /* Do the TCP case right now */
653                 if (wTcpPort && !wUdpPort)
654                     iSocketType = SOCK_STREAM;
655                 if (!wTcpPort && wUdpPort)
656                     iSocketType = SOCK_DGRAM;
657                 //bClone = (wTcpPort && wUdpPort);
658             }
659         }
660     }
661 
662     /* Check if no node was given or if this is is a valid IPv4 address */
663     if ((!pszNodeName) || (ParseV4Address(pszNodeName, &dwAddress)))
664     {
665         /* Check if we don't have a node name */
666         if (!pszNodeName)
667         {
668             /* Make one up based on the flags */
669             dwAddress = htonl((iFlags & AI_PASSIVE) ?
670                               INADDR_ANY : INADDR_LOOPBACK);
671         }
672 
673         /* Create the Addr Info */
674         *pptResult = NewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
675 
676         /* If we didn't get one back, assume out of memory */
677         if (!(*pptResult)) iError = EAI_MEMORY;
678 
679         /* Check if we have success and a nodename */
680         if (!iError && pszNodeName)
681         {
682             /* Set AI_NUMERICHOST since this is a numeric string */
683             (*pptResult)->ai_flags |= AI_NUMERICHOST;
684 
685             /* Check if the canonical name was requested */
686             if (iFlags & AI_CANONNAME)
687             {
688                 /* Get the canonical name */
689                 GetNameInfoW((*pptResult)->ai_addr,
690                              (socklen_t)(*pptResult)->ai_addrlen,
691                              CanonicalName,
692                              0x41,
693                              NULL,
694                              0,
695                              2);
696 
697                 /* Allocate memory for a copy */
698                 (*pptResult)->ai_canonname = HeapAlloc(WsSockHeap,
699                                                        0,
700                                                        wcslen(CanonicalName));
701 
702                 if (!(*pptResult)->ai_canonname)
703                 {
704                     /* No memory for the copy */
705                     iError = EAI_MEMORY;
706                 }
707                 else
708                 {
709                     /* Duplicate the string */
710                     RtlMoveMemory((*pptResult)->ai_canonname,
711                                   CanonicalName,
712                                   wcslen(CanonicalName));
713                 }
714             }
715         }
716     }
717     else if (iFlags & AI_NUMERICHOST)
718     {
719         /* No name for this request (we have a non-numeric name) */
720         iError = EAI_NONAME;
721     }
722     else
723     {
724         /* We need to convert it to ANSI */
725         WideCharToMultiByte(CP_ACP,
726                             0,
727                             pszNodeName,
728                             -1,
729                             AnsiNodeName,
730                             sizeof(AnsiNodeName),
731                             NULL,
732                             0);
733 
734         /* Non-numeric name, do DNS lookup */
735         iError = LookupAddressForName(AnsiNodeName,
736                                       iSocketType,
737                                       iProtocol,
738                                       wPort,
739                                       (iFlags & AI_CANONNAME),
740                                       pptResult);
741     }
742 
743     /* If all was good and the caller requested UDP and TCP */
744     if (!iError && bClone)
745     {
746         /* Process UDP now, we already did TCP */
747         iError = CloneAddrInfo(wUdpPort, *pptResult);
748     }
749 
750     /* If we've hit an error till here */
751     if (iError)
752     {
753         /* Free the address info and return nothing */
754         FreeAddrInfoW(*pptResult);
755         *pptResult = NULL;
756     }
757 
758     /* Return to caller */
759     SetLastError(iError);
760     return iError;
761 }
762 
763 #undef freeaddrinfo
764 /*
765  * @implemented
766  */
767 VOID
768 WINAPI
769 freeaddrinfo(PADDRINFOA AddrInfo)
770 {
771     PADDRINFOA NextInfo;
772 
773     /* Loop the chain of structures */
774     for (NextInfo = AddrInfo; NextInfo; NextInfo = AddrInfo)
775     {
776         /* Check if there is a canonical name */
777         if (NextInfo->ai_canonname)
778         {
779             /* Free it */
780             HeapFree(WsSockHeap, 0, NextInfo->ai_canonname);
781         }
782 
783         /* Check if there is an address */
784         if (NextInfo->ai_addr)
785         {
786             /* Free it */
787             HeapFree(WsSockHeap, 0, NextInfo->ai_addr);
788         }
789 
790         /* Move to the next entry */
791         AddrInfo = NextInfo->ai_next;
792 
793         /* Free this entry */
794         HeapFree(WsSockHeap, 0, NextInfo);
795     }
796 }
797 
798 #undef getaddrinfo
799 /*
800  * @implemented
801  */
802 INT
803 WINAPI
804 getaddrinfo(const char FAR *nodename,
805             const char FAR *servname,
806             const struct addrinfo FAR *hints,
807             struct addrinfo FAR * FAR *res)
808 {
809     INT ErrorCode;
810     LPWSTR UnicodeNodeName = NULL;
811     LPWSTR UnicodeServName = NULL;
812     DPRINT("getaddrinfo: %s, %s, %p, %p\n", nodename, servname, hints, res);
813 
814     /* Check for WSAStartup */
815     if ((ErrorCode = WsQuickProlog()) != ERROR_SUCCESS) return ErrorCode;
816 
817     /* Convert the node name */
818     if (nodename)
819     {
820         UnicodeNodeName = UnicodeDupFromAnsi(nodename);
821         if (!UnicodeNodeName)
822         {
823             /* Prepare to fail */
824             ErrorCode = GetLastError();
825             goto Quickie;
826         }
827     }
828 
829     /* Convert the servname too, if we have one */
830     if (servname)
831     {
832         UnicodeServName = UnicodeDupFromAnsi(servname);
833         if (!UnicodeServName)
834         {
835             /* Prepare to fail */
836             ErrorCode = GetLastError();
837             goto Quickie;
838         }
839     }
840 
841     /* Now call the unicode function */
842     ErrorCode = GetAddrInfoW(UnicodeNodeName,
843                              UnicodeServName,
844                              (PADDRINFOW)hints,
845                              (PADDRINFOW*)res);
846 
847     /* Convert it to ANSI if we succeeded */
848     if (ErrorCode == ERROR_SUCCESS) ConvertAddrinfoFromUnicodeToAnsi((PADDRINFOW)*res);
849 
850 Quickie:
851     /* Check if we have a unicode node name and serv name */
852     if (UnicodeNodeName) HeapFree(WsSockHeap, 0, UnicodeNodeName);
853     if (UnicodeServName) HeapFree(WsSockHeap, 0, UnicodeServName);
854 
855     /* Check if we are in error */
856     if (ErrorCode != ERROR_SUCCESS)
857     {
858         /* Free the structure and return nothing */
859         freeaddrinfo(*res);
860         *res = NULL;
861     }
862 
863     /* Set the last error and return */
864     SetLastError(ErrorCode);
865     return ErrorCode;
866 }
867 
868 /*
869  * @implemented
870  */
871 INT
872 WSAAPI
873 GetNameInfoW(IN CONST SOCKADDR *pSockaddr,
874              IN socklen_t SockaddrLength,
875              OUT PWCHAR pNodeBuffer,
876              IN DWORD NodeBufferSize,
877              OUT PWCHAR pServiceBuffer,
878              IN DWORD ServiceBufferSize,
879              IN INT Flags)
880 {
881     DWORD AddressLength, AddrSize;
882     PVOID Addr;
883     SOCKADDR_IN6 Address;
884     INT ErrorCode = ERROR_SUCCESS;
885 
886     DPRINT("GetNameInfoW: %p, %d, %p, %ld, %p, %ld, %d\n",
887            pSockaddr,
888            SockaddrLength,
889            pNodeBuffer,
890            NodeBufferSize,
891            pServiceBuffer,
892            ServiceBufferSize,
893            Flags);
894 
895     /* Check for valid socket */
896     if (!pSockaddr)
897         return WSAEFAULT;
898 
899     /* Check which family this is */
900     if (pSockaddr->sa_family == AF_INET)
901     {
902         /* IPv4 */
903         AddressLength = sizeof(SOCKADDR_IN);
904         Addr = &((PSOCKADDR_IN)pSockaddr)->sin_addr;
905         AddrSize = sizeof(IN_ADDR);
906     }
907     else if (pSockaddr->sa_family == AF_INET6)
908     {
909         /* IPv6 */
910         AddressLength = sizeof(SOCKADDR_IN6);
911         Addr = &((PSOCKADDR_IN6)pSockaddr)->sin6_addr;
912         AddrSize = sizeof(IN6_ADDR);
913     }
914     else
915     {
916         /* Unsupported family */
917         SetLastError(EAI_FAMILY);
918         return EAI_FAMILY;
919     }
920 
921     /* Check for valid socket address length */
922     if ((DWORD)SockaddrLength < AddressLength)
923         return WSAEFAULT;
924 
925     /* Check if we have a node name */
926     if (pNodeBuffer)
927     {
928         /* Check if only the numeric host is wanted */
929         if (!(Flags & NI_NUMERICHOST))
930         {
931             /* Do the lookup by addr */
932             ErrorCode = LookupNodeByAddr(pNodeBuffer,
933                                          NodeBufferSize,
934                                          Flags & NI_NOFQDN,
935                                          Addr,
936                                          AddrSize,
937                                          pSockaddr->sa_family);
938             /* Check if we failed */
939             if (ErrorCode != ERROR_SUCCESS)
940             {
941                 /* Fail if the caller REALLY wants the NAME itself? */
942                 if (Flags & NI_NAMEREQD) goto quickie;
943             }
944             else
945             {
946                 /* We succeeded, no need to get the numeric address */
947                 goto SkipNumeric;
948             }
949         }
950 
951         /* Copy the address */
952         RtlMoveMemory(&Address, pSockaddr, AddressLength);
953 
954         /* Get the numeric address */
955         if (pSockaddr->sa_family == AF_INET)
956         {
957             /* IPv4 */
958             ((PSOCKADDR_IN)&Address)->sin_port = 0;
959         }
960         else if (pSockaddr->sa_family == AF_INET6)
961         {
962             /* IPv6 */
963             ((PSOCKADDR_IN6)&Address)->sin6_port = 0;
964         }
965         ErrorCode = WSAAddressToStringW((LPSOCKADDR)&Address,
966                                         AddressLength,
967                                         NULL,
968                                         pNodeBuffer,
969                                         &NodeBufferSize);
970         if (ErrorCode == SOCKET_ERROR)
971         {
972             /* Get the error code and exit with it */
973             ErrorCode = GetLastError();
974             goto quickie;
975         }
976     }
977 
978 SkipNumeric:
979     /* Check if we got a service name */
980     if (pServiceBuffer)
981     {
982         /* Handle this request */
983         ErrorCode = GetServiceNameForPort(pServiceBuffer,
984                                           ServiceBufferSize,
985                                           ((PSOCKADDR_IN)pSockaddr)->sin_port,
986                                           Flags);
987     }
988 
989     /* Set the error and return it (or success) */
990 quickie:
991     SetLastError(ErrorCode);
992     return ErrorCode;
993 }
994 
995 #undef getnameinfo
996 /*
997  * @implemented
998  */
999 INT
1000 WINAPI
1001 getnameinfo(const struct sockaddr FAR *sa,
1002             socklen_t salen,
1003             char FAR *host,
1004             DWORD hostlen,
1005             char FAR *serv,
1006             DWORD servlen,
1007             INT flags)
1008 {
1009     INT ErrorCode;
1010     WCHAR Buffer[256];
1011     WCHAR ServiceBuffer[17];
1012     DWORD HostLength = 0, ServLength = 0;
1013     PWCHAR ServiceString = NULL, HostString = NULL;
1014     DPRINT("getnameinfo: %p, %p, %p, %lx\n", host, serv, sa, salen);
1015 
1016     /* Check for WSAStartup */
1017     if ((ErrorCode = WsQuickProlog()) != ERROR_SUCCESS) return ErrorCode;
1018 
1019     /* Check if we have a host pointer */
1020     if (host)
1021     {
1022         /* Setup the data for it */
1023         HostString = Buffer;
1024         HostLength = sizeof(Buffer) / sizeof(WCHAR);
1025     }
1026 
1027     /* Check if we have a service pointer */
1028     if (serv)
1029     {
1030         /* Setup the data for it */
1031         ServiceString = ServiceBuffer;
1032         ServLength = sizeof(ServiceBuffer) / sizeof(WCHAR);
1033     }
1034 
1035     /* Now call the unicode function */
1036     ErrorCode = GetNameInfoW(sa,
1037                              salen,
1038                              HostString,
1039                              HostLength,
1040                              ServiceString,
1041                              ServLength,
1042                              flags);
1043 
1044     /* Check for success */
1045     if (ErrorCode == ERROR_SUCCESS)
1046     {
1047         /* Check if we had a host pointer */
1048         if (HostString)
1049         {
1050             /* Convert it back to ANSI */
1051             ErrorCode = WideCharToMultiByte(CP_ACP,
1052                                             0,
1053                                             HostString,
1054                                             -1,
1055                                             host,
1056                                             hostlen,
1057                                             NULL,
1058                                             NULL);
1059             if (!ErrorCode) goto Quickie;
1060         }
1061 
1062         /* Check if we have a service pointer */
1063         if (ServiceString)
1064         {
1065             /* Convert it back to ANSI */
1066             ErrorCode = WideCharToMultiByte(CP_ACP,
1067                                             0,
1068                                             ServiceString,
1069                                             -1,
1070                                             serv,
1071                                             servlen,
1072                                             NULL,
1073                                             NULL);
1074             if (!ErrorCode) goto Quickie;
1075         }
1076 
1077         /* Return success */
1078         return ERROR_SUCCESS;
1079     }
1080 
1081     /* Set the last error and return */
1082 Quickie:
1083     SetLastError(ErrorCode);
1084     return ErrorCode;
1085 }
1086