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)
9 /* INCLUDES ******************************************************************/
18 /* DEFINES *******************************************************************/
20 #define Swap(a, b, c) { (c) = (a); (a) = (b); (b) = (c); }
21 #define FreeAddrInfoW(a) freeaddrinfo((LPADDRINFO)a)
23 /* FUNCTIONS *****************************************************************/
25 /* FIXME: put into dnslib */
28 Dns_Ip4AddressToReverseName_W(IN LPWSTR AddressBuffer
,
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
);
41 Dns_SplitHostFromDomainNameW(IN LPWSTR DomainName
)
49 ConvertAddrinfoFromUnicodeToAnsi(IN PADDRINFOW Addrinfo
)
54 /* Make sure we have a valid pointer */
60 UnicodeName
= &Addrinfo
->ai_canonname
;
62 /* Check if it exists */
66 AnsiName
= AnsiDupFromUnicode(*UnicodeName
);
69 /* Free the old one */
70 HeapFree(WsSockHeap
, 0, *UnicodeName
);
73 *UnicodeName
= (LPWSTR
)AnsiName
;
77 return GetLastError();
80 } while ((Addrinfo
= Addrinfo
->ai_next
));
90 ParseV4Address(IN PCWSTR AddressString
,
98 Status
= RtlIpv4StringToAddressW(AddressString
, FALSE
, &Terminator
, &Address
);
100 if (!NT_SUCCESS(Status
))
103 *pAddress
= Address
.S_un
.S_addr
;
110 NewAddrInfo(IN INT SocketType
,
116 PSOCKADDR_IN SockAddress
;
118 /* Allocate a structure */
119 AddrInfo
= HeapAlloc(WsSockHeap
, 0, sizeof(ADDRINFOW
));
120 if (!AddrInfo
) return NULL
;
122 /* Allocate a sockaddr */
123 SockAddress
= HeapAlloc(WsSockHeap
, 0, sizeof(SOCKADDR_IN
));
126 /* Free the addrinfo and fail */
127 HeapFree(WsSockHeap
, 0, AddrInfo
);
131 /* Write data for socket address */
132 SockAddress
->sin_family
= AF_INET
;
133 SockAddress
->sin_port
= Port
;
134 SockAddress
->sin_addr
.s_addr
= Address
;
135 ZeroMemory(SockAddress
->sin_zero
, sizeof(SockAddress
->sin_zero
));
137 /* Fill out the addrinfo */
138 AddrInfo
->ai_family
= PF_INET
;
139 AddrInfo
->ai_socktype
= SocketType
;
140 AddrInfo
->ai_protocol
= Protocol
;
141 AddrInfo
->ai_flags
= 0;
142 AddrInfo
->ai_next
= 0;
143 AddrInfo
->ai_canonname
= NULL
;
144 AddrInfo
->ai_addrlen
= sizeof(SOCKADDR_IN
);
145 AddrInfo
->ai_addr
= (PSOCKADDR
)SockAddress
;
154 CloneAddrInfo(IN WORD Port
,
155 IN PADDRINFOW ptResult
)
157 PADDRINFOW Next
= NULL
;
158 PADDRINFOW New
= NULL
;
161 for (Next
= ptResult
; Next
;)
163 /* Create a new structure */
164 New
= NewAddrInfo(SOCK_DGRAM
,
167 ((PSOCKADDR_IN
)Next
->ai_addr
)->sin_addr
.s_addr
);
171 New
->ai_next
= Next
->ai_next
;
176 /* Check if we ran out of memory */
177 if (Next
) return EAI_MEMORY
;
186 QueryDNS(IN LPCSTR NodeName
,
190 OUT CHAR Alias
[NI_MAXHOST
],
191 OUT PADDRINFOW
*pptResult
)
193 PADDRINFOW
*Next
= pptResult
;
194 PHOSTENT Hostent
= NULL
;
197 /* Assume nothing found */
201 /* Get the hostent */
202 Hostent
= gethostbyname(NodeName
);
205 /* Check for valid addresses */
206 if ((Hostent
->h_addrtype
== AF_INET
) &&
207 (Hostent
->h_length
== sizeof(IN_ADDR
)))
209 /* Loop every address in it */
210 for (Addresses
= Hostent
->h_addr_list
; *Addresses
; Addresses
++)
212 /* Create an addrinfo structure for it*/
213 *Next
= NewAddrInfo(SocketType
,
216 ((PIN_ADDR
)*Addresses
)->s_addr
);
217 if (!*Next
) return EAI_MEMORY
;
219 /* Move to the next entry */
220 Next
= &((*Next
)->ai_next
);
224 /* Copy the canonical name */
225 strcpy(Alias
, Hostent
->h_name
);
231 /* Find out what the error was */
232 switch (GetLastError())
234 /* Convert the Winsock Error to an EAI error */
235 case WSAHOST_NOT_FOUND
: return EAI_NONAME
;
236 case WSATRY_AGAIN
: return EAI_AGAIN
;
237 case WSANO_RECOVERY
: return EAI_FAIL
;
238 case WSANO_DATA
: return EAI_NODATA
;
239 default: return EAI_NONAME
;
246 LookupNodeByAddr(IN LPWSTR pNodeBuffer
,
247 IN DWORD NodeBufferSize
,
248 IN BOOLEAN OnlyNodeName
,
251 IN INT AddressFamily
)
253 GUID LookupGuid
= SVCID_DNS_TYPE_PTR
;
254 PIN_ADDR Ip4Addr
= Addr
;
255 WCHAR ReverseBuffer
[76];
256 WSAQUERYSETW Restrictions
, Reply
;
261 /* Validate the address */
262 if (!Addr
) return WSAEFAULT
;
264 /* Make sure the family and address size match */
265 if (AddressFamily
== AF_INET6
)
267 /* Check the address size for this type */
268 if (AddrSize
!= sizeof(IN6_ADDR
)) return WSAEFAULT
;
269 Ip4Addr
= (PIN_ADDR
)&((PIN6_ADDR
)Addr
)->u
.Byte
[12];
271 else if (AddressFamily
== AF_INET
)
273 /* Check the address size for this type */
274 if (AddrSize
!= sizeof(IN_ADDR
)) return WSAEFAULT
;
278 /* Address family not supported */
279 return WSAEAFNOSUPPORT
;
282 /* Check if this is a mapped V4 IPv6 or pure IPv4 */
283 if (((AddressFamily
== AF_INET6
) && (IN6_IS_ADDR_V4MAPPED(Addr
))) ||
284 (AddressFamily
== AF_INET
))
286 /* Get the reverse name */
287 Dns_Ip4AddressToReverseName_W(ReverseBuffer
, *Ip4Addr
);
289 /* FIXME: Not implemented for now
292 /* By this point we have the Reverse Name, so prepare for lookup */
293 RtlZeroMemory(&Restrictions
, sizeof(Restrictions
));
294 Restrictions
.dwSize
= sizeof(Restrictions
);
295 Restrictions
.lpszServiceInstanceName
= ReverseBuffer
;
296 Restrictions
.lpServiceClassId
= &LookupGuid
;
297 Restrictions
.dwNameSpace
= NS_DNS
;
299 /* Now do the lookup */
300 ErrorCode
= WSALookupServiceBeginW(&Restrictions
,
303 if (ErrorCode
== ERROR_SUCCESS
)
305 /* Lookup succesfull, now get the data */
306 BufferLength
= (NI_MAXHOST
- 1) * sizeof(WCHAR
) + sizeof(Restrictions
);
307 ErrorCode
= WSALookupServiceNextW(LookupHandle
,
311 if (ErrorCode
== ERROR_SUCCESS
)
313 /* Now check if we have a name back */
314 Reply
= Restrictions
;
315 if (!Reply
.lpszServiceInstanceName
)
318 ErrorCode
= WSAHOST_NOT_FOUND
;
322 /* Check if the caller only wants the node name */
325 /* Split it and get only the partial host name */
326 Dns_SplitHostFromDomainNameW(Reply
.lpszServiceInstanceName
);
329 /* Check the length and see if it's within our limit */
330 if (wcslen(Reply
.lpszServiceInstanceName
) + 1 >
333 /* It's not, so fail */
334 ErrorCode
= WSAEFAULT
;
338 /* It will fit, let's copy it*/
339 wcscpy(pNodeBuffer
, Reply
.lpszServiceInstanceName
);
344 else if (ErrorCode
== WSASERVICE_NOT_FOUND
)
346 /* Normalize the error code */
347 ErrorCode
= WSAHOST_NOT_FOUND
;
350 /* Finish the lookup if one was in progress */
351 if (LookupHandle
) WSALookupServiceEnd(LookupHandle
);
353 /* Return the error code */
360 GetServiceNameForPort(IN LPWSTR pServiceBuffer
,
361 IN DWORD ServiceBufferSize
,
365 return ERROR_SUCCESS
;
371 LookupAddressForName(IN LPCSTR NodeName
,
375 IN BOOL bAI_CANONNAME
,
376 OUT PADDRINFOW
*pptResult
)
380 CHAR szFQDN1
[NI_MAXHOST
] = "";
381 CHAR szFQDN2
[NI_MAXHOST
] = "";
382 PCHAR Name
= szFQDN1
;
383 PCHAR Alias
= szFQDN2
;
384 PCHAR Scratch
= NULL
;
386 /* Make a copy of the name */
387 strcpy(Name
, NodeName
);
392 /* Do a DNS Query for the name */
393 iError
= QueryDNS(NodeName
,
401 /* Exit if we have a result */
402 if (*pptResult
) break;
404 /* Don't loop continously if this is a DNS misconfiguration */
405 if ((!strlen(Alias
)) || (!strcmp(Name
, Alias
)) || (++AliasCount
== 16))
407 /* Exit the loop with a failure */
412 /* Restart loopup if we got a CNAME */
413 Swap(Name
, Alias
, Scratch
);
416 /* Check if we suceeded and the canonical name is requested */
417 if (!iError
&& bAI_CANONNAME
)
419 /* Allocate memory for a copy */
420 (*pptResult
)->ai_canonname
= HeapAlloc(WsSockHeap
, 0, 512);
422 /* Check if we had enough memory */
423 if (!(*pptResult
)->ai_canonname
)
425 /* Set failure code */
430 /* Convert the alias to UNICODE */
431 MultiByteToWideChar(CP_ACP
,
435 (*pptResult
)->ai_canonname
,
440 /* Return to caller */
449 GetAddrInfoW(IN PCWSTR pszNodeName
,
450 IN PCWSTR pszServiceName
,
451 IN
const ADDRINFOW
*ptHints
,
452 OUT PADDRINFOW
*pptResult
)
456 INT iFamily
= PF_UNSPEC
;
461 PSERVENT ptService
= NULL
;
466 WCHAR CanonicalName
[0x42];
467 CHAR AnsiServiceName
[256];
468 CHAR AnsiNodeName
[256];
469 DPRINT("GetAddrInfoW: %S, %S, %p, %p\n", pszNodeName
, pszServiceName
, ptHints
, pptResult
);
474 /* We must have at least one name to work with */
475 if (!(pszNodeName
) && !(pszServiceName
))
478 SetLastError(EAI_NONAME
);
482 /* Check if we got hints */
485 /* Make sure these are empty */
486 if ((ptHints
->ai_addrlen
) ||
487 (ptHints
->ai_canonname
) ||
488 (ptHints
->ai_addr
) ||
491 /* Fail if they aren't */
492 SetLastError(EAI_FAIL
);
496 /* Save the flags and validate them */
497 iFlags
= ptHints
->ai_flags
;
498 if ((iFlags
& AI_CANONNAME
) && !pszNodeName
)
503 /* Save family and validate it */
504 iFamily
= ptHints
->ai_family
;
505 if ((iFamily
!= PF_UNSPEC
) && (iFamily
!= PF_INET
))
510 /* Save socket type and validate it */
511 iSocketType
= ptHints
->ai_socktype
;
512 if ((iSocketType
!= 0) &&
513 (iSocketType
!= SOCK_STREAM
) &&
514 (iSocketType
!= SOCK_DGRAM
) &&
515 (iSocketType
!= SOCK_RAW
))
520 /* Save the protocol */
521 iProtocol
= ptHints
->ai_protocol
;
524 /* Check if we have a service name */
527 /* We need to convert it to ANSI */
528 WideCharToMultiByte(CP_ACP
,
538 wPort
= (WORD
)strtoul(AnsiServiceName
, &pc
, 10);
540 /* Check if the port string is numeric */
543 /* Get the port directly */
544 wPort
= wTcpPort
= wUdpPort
= htons(wPort
);
546 /* Check if this is both TCP and UDP */
547 if (iSocketType
== 0)
549 /* Set it to TCP for now, but remember to clone */
551 iSocketType
= SOCK_STREAM
;
556 /* The port name was a string. Check if this is a UDP socket */
557 if ((iSocketType
== 0) || (iSocketType
== SOCK_DGRAM
))
559 /* It's UDP, do a getservbyname */
560 ptService
= getservbyname(AnsiServiceName
, "udp");
562 /* If we got a servent, return the port from it */
563 if (ptService
) wPort
= wUdpPort
= ptService
->s_port
;
566 /* Check if this is a TCP socket */
567 if ((iSocketType
== 0) || (iSocketType
== SOCK_STREAM
))
569 /* It's TCP, do a getserbyname */
570 ptService
= getservbyname(AnsiServiceName
, "tcp");
572 /* Return the port from the servent */
573 if (ptService
) wPort
= wTcpPort
= ptService
->s_port
;
576 /* If we got 0, then fail */
579 return iSocketType
? EAI_SERVICE
: EAI_NONAME
;
582 /* Check if this was for both */
583 if (iSocketType
== 0)
585 /* Do the TCP case right now */
586 iSocketType
= (wTcpPort
) ? SOCK_STREAM
: SOCK_DGRAM
;
587 bClone
= (wTcpPort
&& wUdpPort
);
592 /* Check if no node was given or if this is is a valid IPv4 address */
593 if ((!pszNodeName
) || (ParseV4Address(pszNodeName
, &dwAddress
)))
595 /* Check if we don't have a node name */
598 /* Make one up based on the flags */
599 dwAddress
= htonl((iFlags
& AI_PASSIVE
) ?
600 INADDR_ANY
: INADDR_LOOPBACK
);
603 /* Create the Addr Info */
604 *pptResult
= NewAddrInfo(iSocketType
, iProtocol
, wPort
, dwAddress
);
606 /* If we didn't get one back, assume out of memory */
607 if (!(*pptResult
)) iError
= EAI_MEMORY
;
609 /* Check if we have success and a nodename */
610 if (!iError
&& pszNodeName
)
612 /* Set AI_NUMERICHOST since this is a numeric string */
613 (*pptResult
)->ai_flags
|= AI_NUMERICHOST
;
615 /* Check if the canonical name was requestd */
616 if (iFlags
& AI_CANONNAME
)
618 /* Get the canonical name */
619 GetNameInfoW((*pptResult
)->ai_addr
,
620 (socklen_t
)(*pptResult
)->ai_addrlen
,
627 /* Allocate memory for a copy */
628 (*pptResult
)->ai_canonname
= HeapAlloc(WsSockHeap
,
630 wcslen(CanonicalName
));
632 if (!(*pptResult
)->ai_canonname
)
634 /* No memory for the copy */
639 /* Duplicate the string */
640 RtlMoveMemory((*pptResult
)->ai_canonname
,
642 wcslen(CanonicalName
));
647 else if (iFlags
& AI_NUMERICHOST
)
649 /* No name for this request (we have a non-numeric name) */
654 /* We need to convert it to ANSI */
655 WideCharToMultiByte(CP_ACP
,
664 /* Non-numeric name, do DNS lookup */
665 iError
= LookupAddressForName(AnsiNodeName
,
669 (iFlags
& AI_CANONNAME
),
673 /* If all was good and the caller requested UDP and TCP */
674 if (!iError
&& bClone
)
676 /* Process UDP now, we already did TCP */
677 iError
= CloneAddrInfo(wUdpPort
, *pptResult
);
680 /* If we've hit an error till here */
683 /* Free the address info and return nothing */
684 FreeAddrInfoW(*pptResult
);
688 /* Return to caller */
698 freeaddrinfo(PADDRINFOA AddrInfo
)
702 /* Loop the chain of structures */
703 for (NextInfo
= AddrInfo
; NextInfo
; NextInfo
= AddrInfo
)
705 /* Check if there is a canonical name */
706 if (NextInfo
->ai_canonname
)
709 HeapFree(WsSockHeap
, 0, NextInfo
->ai_canonname
);
712 /* Check if there is an address */
713 if (NextInfo
->ai_addr
)
716 HeapFree(WsSockHeap
, 0, NextInfo
->ai_addr
);
719 /* Move to the next entry */
720 AddrInfo
= NextInfo
->ai_next
;
722 /* Free this entry */
723 HeapFree(WsSockHeap
, 0, NextInfo
);
733 getaddrinfo(const char FAR
*nodename
,
734 const char FAR
*servname
,
735 const struct addrinfo FAR
*hints
,
736 struct addrinfo FAR
* FAR
*res
)
739 LPWSTR UnicodeNodeName
;
740 LPWSTR UnicodeServName
= NULL
;
741 DPRINT("getaddrinfo: %s, %s, %p, %p\n", nodename
, servname
, hints
, res
);
743 /* Check for WSAStartup */
744 if ((ErrorCode
= WsQuickProlog()) != ERROR_SUCCESS
) return ErrorCode
;
749 /* Convert the node name */
750 UnicodeNodeName
= UnicodeDupFromAnsi((LPSTR
)nodename
);
751 if (!UnicodeNodeName
)
753 /* Prepare to fail */
754 ErrorCode
= GetLastError();
758 /* Convert the servname too, if we have one */
761 UnicodeServName
= UnicodeDupFromAnsi((LPSTR
)servname
);
762 if (!UnicodeServName
)
764 /* Prepare to fail */
765 ErrorCode
= GetLastError();
770 /* Now call the unicode function */
771 ErrorCode
= GetAddrInfoW(UnicodeNodeName
,
776 /* Convert it to ANSI if we suceeded */
777 if (ErrorCode
== ERROR_SUCCESS
) ConvertAddrinfoFromUnicodeToAnsi((PADDRINFOW
)*res
);
780 /* Check if we have a unicode node name and serv name */
781 if (UnicodeNodeName
) HeapFree(WsSockHeap
, 0, UnicodeNodeName
);
782 if (UnicodeServName
) HeapFree(WsSockHeap
, 0, UnicodeServName
);
784 /* Check if we are in error */
785 if (ErrorCode
!= ERROR_SUCCESS
)
787 /* Free the structure and return nothing */
792 /* Set the last error and return */
793 SetLastError(ErrorCode
);
802 GetNameInfoW(IN CONST SOCKADDR
*pSockaddr
,
803 IN socklen_t SockaddrLength
,
804 OUT PWCHAR pNodeBuffer
,
805 IN DWORD NodeBufferSize
,
806 OUT PWCHAR pServiceBuffer
,
807 IN DWORD ServiceBufferSize
,
810 DWORD AddressLength
, AddrSize
;
813 INT ErrorCode
= ERROR_SUCCESS
;
815 /* Check for valid socket */
816 if (!pSockaddr
) return EAI_FAIL
;
818 /* Check which family this is */
819 if (pSockaddr
->sa_family
== AF_INET
)
822 AddressLength
= sizeof(SOCKADDR_IN
);
823 Addr
= &((PSOCKADDR_IN
)pSockaddr
)->sin_addr
;
824 AddrSize
= sizeof(IN_ADDR
);
826 else if (pSockaddr
->sa_family
== AF_INET6
)
829 AddressLength
= sizeof(SOCKADDR_IN6
);
830 Addr
= &((PSOCKADDR_IN6
)pSockaddr
)->sin6_addr
;
831 AddrSize
= sizeof(IN6_ADDR
);
835 /* Unsupported family */
839 /* Check for valid socket adress length */
840 if ((DWORD
)SockaddrLength
< AddressLength
) return EAI_FAIL
;
842 /* Check if we have a node name */
845 /* Check if only the numeric host is wanted */
846 if (!(Flags
& NI_NUMERICHOST
))
848 /* Do the lookup by addr */
849 ErrorCode
= LookupNodeByAddr(pNodeBuffer
,
854 pSockaddr
->sa_family
);
855 /* Check if we failed */
856 if (ErrorCode
!= ERROR_SUCCESS
)
858 /* Fail if the caller REALLY wants the NAME itself? */
859 if (Flags
& NI_NAMEREQD
) goto quickie
;
863 /* We suceeded, no need to get the numeric address */
868 /* Copy the address */
869 RtlMoveMemory(&Address
, pSockaddr
, AddressLength
);
871 /* Get the numeric address */
872 Address
.sin_port
= 0;
873 ErrorCode
= WSAAddressToStringW((LPSOCKADDR
)&Address
,
878 if (ErrorCode
== SOCKET_ERROR
)
880 /* Get the error code and exit with it */
881 ErrorCode
= GetLastError();
887 /* Check if we got a service name */
890 /* Handle this request */
891 ErrorCode
= GetServiceNameForPort(pServiceBuffer
,
893 ((PSOCKADDR_IN
)pSockaddr
)->sin_port
,
897 /* Set the error and return it (or success) */
899 SetLastError(ErrorCode
);
909 getnameinfo(const struct sockaddr FAR
*sa
,
919 WCHAR ServiceBuffer
[17];
920 DWORD HostLength
= 0, ServLength
= 0;
921 PWCHAR ServiceString
= NULL
, HostString
= NULL
;
922 DPRINT("getnameinfo: %p, %p, %p, %lx\n", host
, serv
, sa
, salen
);
924 /* Check for WSAStartup */
925 if ((ErrorCode
= WsQuickProlog()) != ERROR_SUCCESS
) return ErrorCode
;
927 /* Check if we have a host pointer */
930 /* Setup the data for it */
932 HostLength
= sizeof(Buffer
) / sizeof(WCHAR
);
935 /* Check if we have a service pointer */
938 /* Setup the data for it */
939 ServiceString
= ServiceBuffer
;
940 ServLength
= sizeof(ServiceBuffer
) - 1;
943 /* Now call the unicode function */
944 ErrorCode
= GetNameInfoW(sa
,
952 /* Check for success */
953 if (ErrorCode
== ERROR_SUCCESS
)
955 /* Check if we had a host pointer */
958 /* Convert it back to ANSI */
959 ErrorCode
= WideCharToMultiByte(CP_ACP
,
967 if (!ErrorCode
) goto Quickie
;
970 /* Check if we have a service pointer */
973 /* Convert it back to ANSI */
974 ErrorCode
= WideCharToMultiByte(CP_ACP
,
982 if (!ErrorCode
) goto Quickie
;
986 return ERROR_SUCCESS
;
989 /* Set the last error and return */
991 SetLastError(ErrorCode
);