19f492dde2bdd3d24a55f7f99c625a3f54017d46
[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 successful, 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 continuously 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 succeeded 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 SetLastError(EAI_BADFLAGS);
560 return EAI_BADFLAGS;
561 }
562
563 /* Save family and validate it */
564 iFamily = ptHints->ai_family;
565 if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
566 {
567 SetLastError(EAI_FAMILY);
568 return EAI_FAMILY;
569 }
570
571 /* Save socket type and validate it */
572 iSocketType = ptHints->ai_socktype;
573 if ((iSocketType != 0) &&
574 (iSocketType != SOCK_STREAM) &&
575 (iSocketType != SOCK_DGRAM) &&
576 (iSocketType != SOCK_RAW))
577 {
578 SetLastError(EAI_SOCKTYPE);
579 return EAI_SOCKTYPE;
580 }
581
582 /* Save the protocol */
583 iProtocol = ptHints->ai_protocol;
584 }
585
586 /* Check if we have a service name */
587 if (pszServiceName)
588 {
589 /* We need to convert it to ANSI */
590 WideCharToMultiByte(CP_ACP,
591 0,
592 pszServiceName,
593 -1,
594 AnsiServiceName,
595 sizeof(AnsiServiceName),
596 NULL,
597 0);
598
599 /* Get the port */
600 wPort = (WORD)strtoul(AnsiServiceName, &pc, 10);
601
602 /* Check if the port string is numeric */
603 if (*pc == '\0')
604 {
605 /* Get the port directly */
606 wPort = wTcpPort = wUdpPort = htons(wPort);
607
608 #if 0
609 /* Check if this is both TCP and UDP */
610 if (iSocketType == 0)
611 {
612 /* Set it to TCP for now, but remember to clone */
613 bClone = TRUE;
614 iSocketType = SOCK_STREAM;
615 }
616 #endif
617 }
618 else
619 {
620 wPort = 0;
621 /* The port name was a string. Check if this is a UDP socket */
622 if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
623 {
624 /* It's UDP, do a getservbyname */
625 ptService = getservbyname(AnsiServiceName, "udp");
626
627 /* If we got a servent, return the port from it */
628 if (ptService) wPort = wUdpPort = ptService->s_port;
629 }
630
631 /* Check if this is a TCP socket */
632 if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
633 {
634 /* It's TCP, do a getserbyname */
635 ptService = getservbyname(AnsiServiceName, "tcp");
636
637 /* Return the port from the servent */
638 if (ptService) wPort = wTcpPort = ptService->s_port;
639 }
640
641 /* If we got 0, then fail */
642 if (wPort == 0)
643 {
644 SetLastError(EAI_SERVICE);
645 return EAI_SERVICE;
646 }
647
648 /* Check if this was for both */
649 if (iSocketType == 0)
650 {
651 /* Do the TCP case right now */
652 if (wTcpPort && !wUdpPort)
653 iSocketType = SOCK_STREAM;
654 if (!wTcpPort && wUdpPort)
655 iSocketType = SOCK_DGRAM;
656 //bClone = (wTcpPort && wUdpPort);
657 }
658 }
659 }
660
661 /* Check if no node was given or if this is is a valid IPv4 address */
662 if ((!pszNodeName) || (ParseV4Address(pszNodeName, &dwAddress)))
663 {
664 /* Check if we don't have a node name */
665 if (!pszNodeName)
666 {
667 /* Make one up based on the flags */
668 dwAddress = htonl((iFlags & AI_PASSIVE) ?
669 INADDR_ANY : INADDR_LOOPBACK);
670 }
671
672 /* Create the Addr Info */
673 *pptResult = NewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
674
675 /* If we didn't get one back, assume out of memory */
676 if (!(*pptResult)) iError = EAI_MEMORY;
677
678 /* Check if we have success and a nodename */
679 if (!iError && pszNodeName)
680 {
681 /* Set AI_NUMERICHOST since this is a numeric string */
682 (*pptResult)->ai_flags |= AI_NUMERICHOST;
683
684 /* Check if the canonical name was requested */
685 if (iFlags & AI_CANONNAME)
686 {
687 /* Get the canonical name */
688 GetNameInfoW((*pptResult)->ai_addr,
689 (socklen_t)(*pptResult)->ai_addrlen,
690 CanonicalName,
691 0x41,
692 NULL,
693 0,
694 2);
695
696 /* Allocate memory for a copy */
697 (*pptResult)->ai_canonname = HeapAlloc(WsSockHeap,
698 0,
699 wcslen(CanonicalName));
700
701 if (!(*pptResult)->ai_canonname)
702 {
703 /* No memory for the copy */
704 iError = EAI_MEMORY;
705 }
706 else
707 {
708 /* Duplicate the string */
709 RtlMoveMemory((*pptResult)->ai_canonname,
710 CanonicalName,
711 wcslen(CanonicalName));
712 }
713 }
714 }
715 }
716 else if (iFlags & AI_NUMERICHOST)
717 {
718 /* No name for this request (we have a non-numeric name) */
719 iError = EAI_NONAME;
720 }
721 else
722 {
723 /* We need to convert it to ANSI */
724 WideCharToMultiByte(CP_ACP,
725 0,
726 pszNodeName,
727 -1,
728 AnsiNodeName,
729 sizeof(AnsiNodeName),
730 NULL,
731 0);
732
733 /* Non-numeric name, do DNS lookup */
734 iError = LookupAddressForName(AnsiNodeName,
735 iSocketType,
736 iProtocol,
737 wPort,
738 (iFlags & AI_CANONNAME),
739 pptResult);
740 }
741
742 /* If all was good and the caller requested UDP and TCP */
743 if (!iError && bClone)
744 {
745 /* Process UDP now, we already did TCP */
746 iError = CloneAddrInfo(wUdpPort, *pptResult);
747 }
748
749 /* If we've hit an error till here */
750 if (iError)
751 {
752 /* Free the address info and return nothing */
753 FreeAddrInfoW(*pptResult);
754 *pptResult = NULL;
755 }
756
757 /* Return to caller */
758 SetLastError(iError);
759 return iError;
760 }
761
762 #undef freeaddrinfo
763 /*
764 * @implemented
765 */
766 VOID
767 WINAPI
768 freeaddrinfo(PADDRINFOA AddrInfo)
769 {
770 PADDRINFOA NextInfo;
771
772 /* Loop the chain of structures */
773 for (NextInfo = AddrInfo; NextInfo; NextInfo = AddrInfo)
774 {
775 /* Check if there is a canonical name */
776 if (NextInfo->ai_canonname)
777 {
778 /* Free it */
779 HeapFree(WsSockHeap, 0, NextInfo->ai_canonname);
780 }
781
782 /* Check if there is an address */
783 if (NextInfo->ai_addr)
784 {
785 /* Free it */
786 HeapFree(WsSockHeap, 0, NextInfo->ai_addr);
787 }
788
789 /* Move to the next entry */
790 AddrInfo = NextInfo->ai_next;
791
792 /* Free this entry */
793 HeapFree(WsSockHeap, 0, NextInfo);
794 }
795 }
796
797 #undef getaddrinfo
798 /*
799 * @implemented
800 */
801 INT
802 WINAPI
803 getaddrinfo(const char FAR *nodename,
804 const char FAR *servname,
805 const struct addrinfo FAR *hints,
806 struct addrinfo FAR * FAR *res)
807 {
808 INT ErrorCode;
809 LPWSTR UnicodeNodeName = NULL;
810 LPWSTR UnicodeServName = NULL;
811 DPRINT("getaddrinfo: %s, %s, %p, %p\n", nodename, servname, hints, res);
812
813 /* Check for WSAStartup */
814 if ((ErrorCode = WsQuickProlog()) != ERROR_SUCCESS) return ErrorCode;
815
816 /* Convert the node name */
817 if (nodename)
818 {
819 UnicodeNodeName = UnicodeDupFromAnsi(nodename);
820 if (!UnicodeNodeName)
821 {
822 /* Prepare to fail */
823 ErrorCode = GetLastError();
824 goto Quickie;
825 }
826 }
827
828 /* Convert the servname too, if we have one */
829 if (servname)
830 {
831 UnicodeServName = UnicodeDupFromAnsi(servname);
832 if (!UnicodeServName)
833 {
834 /* Prepare to fail */
835 ErrorCode = GetLastError();
836 goto Quickie;
837 }
838 }
839
840 /* Now call the unicode function */
841 ErrorCode = GetAddrInfoW(UnicodeNodeName,
842 UnicodeServName,
843 (PADDRINFOW)hints,
844 (PADDRINFOW*)res);
845
846 /* Convert it to ANSI if we succeeded */
847 if (ErrorCode == ERROR_SUCCESS) ConvertAddrinfoFromUnicodeToAnsi((PADDRINFOW)*res);
848
849 Quickie:
850 /* Check if we have a unicode node name and serv name */
851 if (UnicodeNodeName) HeapFree(WsSockHeap, 0, UnicodeNodeName);
852 if (UnicodeServName) HeapFree(WsSockHeap, 0, UnicodeServName);
853
854 /* Check if we are in error */
855 if (ErrorCode != ERROR_SUCCESS)
856 {
857 /* Free the structure and return nothing */
858 freeaddrinfo(*res);
859 *res = NULL;
860 }
861
862 /* Set the last error and return */
863 SetLastError(ErrorCode);
864 return ErrorCode;
865 }
866
867 /*
868 * @implemented
869 */
870 INT
871 WSAAPI
872 GetNameInfoW(IN CONST SOCKADDR *pSockaddr,
873 IN socklen_t SockaddrLength,
874 OUT PWCHAR pNodeBuffer,
875 IN DWORD NodeBufferSize,
876 OUT PWCHAR pServiceBuffer,
877 IN DWORD ServiceBufferSize,
878 IN INT Flags)
879 {
880 DWORD AddressLength, AddrSize;
881 PVOID Addr;
882 SOCKADDR_IN6 Address;
883 INT ErrorCode = ERROR_SUCCESS;
884
885 DPRINT("GetNameInfoW: %p, %d, %p, %ld, %p, %ld, %d\n",
886 pSockaddr,
887 SockaddrLength,
888 pNodeBuffer,
889 NodeBufferSize,
890 pServiceBuffer,
891 ServiceBufferSize,
892 Flags);
893
894 /* Check for valid socket */
895 if (!pSockaddr)
896 return WSAEFAULT;
897
898 /* Check which family this is */
899 if (pSockaddr->sa_family == AF_INET)
900 {
901 /* IPv4 */
902 AddressLength = sizeof(SOCKADDR_IN);
903 Addr = &((PSOCKADDR_IN)pSockaddr)->sin_addr;
904 AddrSize = sizeof(IN_ADDR);
905 }
906 else if (pSockaddr->sa_family == AF_INET6)
907 {
908 /* IPv6 */
909 AddressLength = sizeof(SOCKADDR_IN6);
910 Addr = &((PSOCKADDR_IN6)pSockaddr)->sin6_addr;
911 AddrSize = sizeof(IN6_ADDR);
912 }
913 else
914 {
915 /* Unsupported family */
916 SetLastError(EAI_FAMILY);
917 return EAI_FAMILY;
918 }
919
920 /* Check for valid socket address length */
921 if ((DWORD)SockaddrLength < AddressLength)
922 return WSAEFAULT;
923
924 /* Check if we have a node name */
925 if (pNodeBuffer)
926 {
927 /* Check if only the numeric host is wanted */
928 if (!(Flags & NI_NUMERICHOST))
929 {
930 /* Do the lookup by addr */
931 ErrorCode = LookupNodeByAddr(pNodeBuffer,
932 NodeBufferSize,
933 Flags & NI_NOFQDN,
934 Addr,
935 AddrSize,
936 pSockaddr->sa_family);
937 /* Check if we failed */
938 if (ErrorCode != ERROR_SUCCESS)
939 {
940 /* Fail if the caller REALLY wants the NAME itself? */
941 if (Flags & NI_NAMEREQD) goto quickie;
942 }
943 else
944 {
945 /* We succeeded, no need to get the numeric address */
946 goto SkipNumeric;
947 }
948 }
949
950 /* Copy the address */
951 RtlMoveMemory(&Address, pSockaddr, AddressLength);
952
953 /* Get the numeric address */
954 if (pSockaddr->sa_family == AF_INET)
955 {
956 /* IPv4 */
957 ((PSOCKADDR_IN)&Address)->sin_port = 0;
958 }
959 else if (pSockaddr->sa_family == AF_INET6)
960 {
961 /* IPv6 */
962 ((PSOCKADDR_IN6)&Address)->sin6_port = 0;
963 }
964 ErrorCode = WSAAddressToStringW((LPSOCKADDR)&Address,
965 AddressLength,
966 NULL,
967 pNodeBuffer,
968 &NodeBufferSize);
969 if (ErrorCode == SOCKET_ERROR)
970 {
971 /* Get the error code and exit with it */
972 ErrorCode = GetLastError();
973 goto quickie;
974 }
975 }
976
977 SkipNumeric:
978 /* Check if we got a service name */
979 if (pServiceBuffer)
980 {
981 /* Handle this request */
982 ErrorCode = GetServiceNameForPort(pServiceBuffer,
983 ServiceBufferSize,
984 ((PSOCKADDR_IN)pSockaddr)->sin_port,
985 Flags);
986 }
987
988 /* Set the error and return it (or success) */
989 quickie:
990 SetLastError(ErrorCode);
991 return ErrorCode;
992 }
993
994 #undef getnameinfo
995 /*
996 * @implemented
997 */
998 INT
999 WINAPI
1000 getnameinfo(const struct sockaddr FAR *sa,
1001 socklen_t salen,
1002 char FAR *host,
1003 DWORD hostlen,
1004 char FAR *serv,
1005 DWORD servlen,
1006 INT flags)
1007 {
1008 INT ErrorCode;
1009 WCHAR Buffer[256];
1010 WCHAR ServiceBuffer[17];
1011 DWORD HostLength = 0, ServLength = 0;
1012 PWCHAR ServiceString = NULL, HostString = NULL;
1013 DPRINT("getnameinfo: %p, %p, %p, %lx\n", host, serv, sa, salen);
1014
1015 /* Check for WSAStartup */
1016 if ((ErrorCode = WsQuickProlog()) != ERROR_SUCCESS) return ErrorCode;
1017
1018 /* Check if we have a host pointer */
1019 if (host)
1020 {
1021 /* Setup the data for it */
1022 HostString = Buffer;
1023 HostLength = sizeof(Buffer) / sizeof(WCHAR);
1024 }
1025
1026 /* Check if we have a service pointer */
1027 if (serv)
1028 {
1029 /* Setup the data for it */
1030 ServiceString = ServiceBuffer;
1031 ServLength = sizeof(ServiceBuffer) / sizeof(WCHAR);
1032 }
1033
1034 /* Now call the unicode function */
1035 ErrorCode = GetNameInfoW(sa,
1036 salen,
1037 HostString,
1038 HostLength,
1039 ServiceString,
1040 ServLength,
1041 flags);
1042
1043 /* Check for success */
1044 if (ErrorCode == ERROR_SUCCESS)
1045 {
1046 /* Check if we had a host pointer */
1047 if (HostString)
1048 {
1049 /* Convert it back to ANSI */
1050 ErrorCode = WideCharToMultiByte(CP_ACP,
1051 0,
1052 HostString,
1053 -1,
1054 host,
1055 hostlen,
1056 NULL,
1057 NULL);
1058 if (!ErrorCode) goto Quickie;
1059 }
1060
1061 /* Check if we have a service pointer */
1062 if (ServiceString)
1063 {
1064 /* Convert it back to ANSI */
1065 ErrorCode = WideCharToMultiByte(CP_ACP,
1066 0,
1067 ServiceString,
1068 -1,
1069 serv,
1070 servlen,
1071 NULL,
1072 NULL);
1073 if (!ErrorCode) goto Quickie;
1074 }
1075
1076 /* Return success */
1077 return ERROR_SUCCESS;
1078 }
1079
1080 /* Set the last error and return */
1081 Quickie:
1082 SetLastError(ErrorCode);
1083 return ErrorCode;
1084 }