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