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