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