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