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