3 Copyright (c) 2000, Microsoft Corporation
9 The file contains protocol independent API functions.
12 Wed Jul 12 10:50:31 2000, Created
19 #include <stdio.h> // sprintf()
20 #include <stdlib.h> // calloc(), strtoul()
21 #include <malloc.h> // calloc()
22 #include <string.h> // strlen(), strcmp(), strstr()
24 #define WspiapiMalloc(tSize) calloc(1, (tSize))
25 #define WspiapiFree(p) free(p)
26 #define WspiapiSwap(a, b, c) { (c) = (a); (a) = (b); (b) = (c); }
27 #define getaddrinfo WspiapiGetAddrInfo
28 #define getnameinfo WspiapiGetNameInfo
29 #define freeaddrinfo WspiapiFreeAddrInfo
31 typedef int (WINAPI
*WSPIAPI_PGETADDRINFO
) (
32 IN
const char *nodename
,
33 IN
const char *servname
,
34 IN
const struct addrinfo
*hints
,
35 OUT
struct addrinfo
**res
);
37 typedef int (WINAPI
*WSPIAPI_PGETNAMEINFO
) (
38 IN
const struct sockaddr
*sa
,
46 typedef void (WINAPI
*WSPIAPI_PFREEADDRINFO
) (
47 IN
struct addrinfo
*ai
);
55 ////////////////////////////////////////////////////////////
56 // v4 only versions of getaddrinfo and friends.
57 // NOTE: gai_strerror is inlined in ws2tcpip.h
58 ////////////////////////////////////////////////////////////
64 IN
const char * pszString
)
68 allocates enough storage via calloc() for a copy of the string,
69 copies the string into the new memory, and returns a pointer to it.
72 pszString string to copy into new memory
75 a pointer to the newly allocated storage with the string in it.
76 NULL if enough memory could not be allocated, or string was NULL.
85 pszMemory
= (char *) WspiapiMalloc(strlen(pszString
) + 1);
89 return(strcpy(pszMemory
, pszString
));
97 WspiapiParseV4Address (
98 IN
const char * pszAddress
,
99 OUT PDWORD pdwAddress
)
103 get the IPv4 address (in network byte order) from its string
104 representation. the syntax should be a.b.c.d.
107 pszArgument string representation of the IPv4 address
108 ptAddress pointer to the resulting IPv4 address
111 Returns FALSE if there is an error, TRUE for success.
116 const char *pcNext
= NULL
;
119 // ensure there are 3 '.' (periods)
120 for (pcNext
= pszAddress
; *pcNext
!= '\0'; pcNext
++)
126 // return an error if dwAddress is INADDR_NONE (255.255.255.255)
127 // since this is never a valid argument to getaddrinfo.
128 dwAddress
= inet_addr(pszAddress
);
129 if (dwAddress
== INADDR_NONE
)
132 *pdwAddress
= dwAddress
;
149 allocate an addrinfo structure and populate fields.
150 IPv4 specific internal function, not exported.
153 iSocketType SOCK_*. can be wildcarded (zero).
154 iProtocol IPPROTO_*. can be wildcarded (zero).
155 wPort port number of service (in network order).
156 dwAddress IPv4 address (in network order).
159 returns an addrinfo struct, or NULL if out of memory.
163 struct addrinfo
*ptNew
;
164 struct sockaddr_in
*ptAddress
;
166 // allocate a new addrinfo structure.
168 (struct addrinfo
*) WspiapiMalloc(sizeof(struct addrinfo
));
173 (struct sockaddr_in
*) WspiapiMalloc(sizeof(struct sockaddr_in
));
179 ptAddress
->sin_family
= AF_INET
;
180 ptAddress
->sin_port
= wPort
;
181 ptAddress
->sin_addr
.s_addr
= dwAddress
;
183 // fill in the fields...
184 ptNew
->ai_family
= PF_INET
;
185 ptNew
->ai_socktype
= iSocketType
;
186 ptNew
->ai_protocol
= iProtocol
;
187 ptNew
->ai_addrlen
= sizeof(struct sockaddr_in
);
188 ptNew
->ai_addr
= (struct sockaddr
*) ptAddress
;
199 IN
const char *pszNodeName
,
204 OUT
struct addrinfo
**pptResult
)
208 helper routine for WspiapiLookupNode.
209 performs name resolution by querying the DNS for A records.
210 *pptResult would need to be freed if an error is returned.
213 pszNodeName name of node to resolve.
214 iSocketType SOCK_*. can be wildcarded (zero).
215 iProtocol IPPROTO_*. can be wildcarded (zero).
216 wPort port number of service (in network order).
217 pszAlias where to return the alias.
218 pptResult where to return the result.
221 Returns 0 on success, an EAI_* style error value otherwise.
225 struct addrinfo
**pptNext
= pptResult
;
226 struct hostent
*ptHost
= NULL
;
232 ptHost
= gethostbyname(pszNodeName
);
235 if ((ptHost
->h_addrtype
== AF_INET
) &&
236 (ptHost
->h_length
== sizeof(struct in_addr
)))
238 for (ppAddresses
= ptHost
->h_addr_list
;
239 *ppAddresses
!= NULL
;
242 // create an addrinfo structure...
243 *pptNext
= WspiapiNewAddrInfo(
247 ((struct in_addr
*) *ppAddresses
)->s_addr
);
251 pptNext
= &((*pptNext
)->ai_next
);
255 // pick up the canonical name.
256 strcpy(pszAlias
, ptHost
->h_name
);
260 switch (WSAGetLastError())
262 case WSAHOST_NOT_FOUND
: return EAI_NONAME
;
263 case WSATRY_AGAIN
: return EAI_AGAIN
;
264 case WSANO_RECOVERY
: return EAI_FAIL
;
265 case WSANO_DATA
: return EAI_NODATA
;
266 default: return EAI_NONAME
;
276 IN
const char *pszNodeName
,
280 IN BOOL bAI_CANONNAME
,
281 OUT
struct addrinfo
**pptResult
)
285 resolve a nodename and return a list of addrinfo structures.
286 IPv4 specific internal function, not exported.
287 *pptResult would need to be freed if an error is returned.
289 NOTE: if bAI_CANONNAME is true, the canonical name should be
290 returned in the first addrinfo structure.
293 pszNodeName name of node to resolve.
294 iSocketType SOCK_*. can be wildcarded (zero).
295 iProtocol IPPROTO_*. can be wildcarded (zero).
296 wPort port number of service (in network order).
297 bAI_CANONNAME whether the AI_CANONNAME flag is set.
298 pptResult where to return result.
301 Returns 0 on success, an EAI_* style error value otherwise.
308 char szFQDN1
[NI_MAXHOST
] = "";
309 char szFQDN2
[NI_MAXHOST
] = "";
310 char *pszName
= szFQDN1
;
311 char *pszAlias
= szFQDN2
;
312 char *pszScratch
= NULL
;
313 strcpy(pszName
, pszNodeName
);
317 iError
= WspiapiQueryDNS(pszNodeName
,
326 // if we found addresses, then we are done.
330 // stop infinite loops due to DNS misconfiguration. there appears
331 // to be no particular recommended limit in RFCs 1034 and 1035.
332 if ((!strlen(pszAlias
)) ||
333 (!strcmp(pszName
, pszAlias
)) ||
334 (++iAliasCount
== 16))
340 // there was a new CNAME, look again.
341 WspiapiSwap(pszName
, pszAlias
, pszScratch
);
344 if (!iError
&& bAI_CANONNAME
)
346 (*pptResult
)->ai_canonname
= WspiapiStrdup(pszAlias
);
347 if (!(*pptResult
)->ai_canonname
)
361 IN
struct addrinfo
*ptResult
)
365 clone every addrinfo structure in ptResult for the UDP service.
366 ptResult would need to be freed if an error is returned.
369 wPort port number of UDP service.
370 ptResult list of addrinfo structures, each
371 of whose node needs to be cloned.
374 Returns 0 on success, an EAI_MEMORY on allocation failure.
378 struct addrinfo
*ptNext
= NULL
;
379 struct addrinfo
*ptNew
= NULL
;
381 for (ptNext
= ptResult
; ptNext
!= NULL
; )
383 // create an addrinfo structure...
384 ptNew
= WspiapiNewAddrInfo(
388 ((struct sockaddr_in
*) ptNext
->ai_addr
)->sin_addr
.s_addr
);
392 // link the cloned addrinfo
393 ptNew
->ai_next
= ptNext
->ai_next
;
394 ptNext
->ai_next
= ptNew
;
395 ptNext
= ptNew
->ai_next
;
409 WspiapiLegacyFreeAddrInfo (
410 IN
struct addrinfo
*ptHead
)
414 Free an addrinfo structure (or chain of structures).
415 As specified in RFC 2553, Section 6.4.
418 ptHead structure (chain) to free
422 struct addrinfo
*ptNext
; // next strcture to free
424 for (ptNext
= ptHead
; ptNext
!= NULL
; ptNext
= ptHead
)
426 if (ptNext
->ai_canonname
)
427 WspiapiFree(ptNext
->ai_canonname
);
430 WspiapiFree(ptNext
->ai_addr
);
432 ptHead
= ptNext
->ai_next
;
442 WspiapiLegacyGetAddrInfo(
443 IN
const char *pszNodeName
,
444 IN
const char *pszServiceName
,
445 IN
const struct addrinfo
*ptHints
,
446 OUT
struct addrinfo
**pptResult
)
450 Protocol-independent name-to-address translation.
451 As specified in RFC 2553, Section 6.4.
452 This is the hacked version that only supports IPv4.
455 pszNodeName node name to lookup.
456 pszServiceName service name to lookup.
457 ptHints hints about how to process request.
458 pptResult where to return result.
461 returns zero if successful, an EAI_* error code if not.
467 int iFamily
= PF_UNSPEC
;
473 struct servent
*ptService
= NULL
;
480 // initialize pptResult with default return value.
484 ////////////////////////////////////////
485 // validate arguments...
488 // both the node name and the service name can't be NULL.
489 if ((!pszNodeName
) && (!pszServiceName
))
495 // all members other than ai_flags, ai_family, ai_socktype
496 // and ai_protocol must be zero or a null pointer.
497 if ((ptHints
->ai_addrlen
!= 0) ||
498 (ptHints
->ai_canonname
!= NULL
) ||
499 (ptHints
->ai_addr
!= NULL
) ||
500 (ptHints
->ai_next
!= NULL
))
505 // the spec has the "bad flags" error code, so presumably we
506 // should check something here. insisting that there aren't
507 // any unspecified flags set would break forward compatibility,
508 // however. so we just check for non-sensical combinations.
510 // we cannot come up with a canonical name given a null node name.
511 iFlags
= ptHints
->ai_flags
;
512 if ((iFlags
& AI_CANONNAME
) && !pszNodeName
)
515 // we only support a limited number of protocol families.
516 iFamily
= ptHints
->ai_family
;
517 if ((iFamily
!= PF_UNSPEC
) && (iFamily
!= PF_INET
))
520 // we only support only these socket types.
521 iSocketType
= ptHints
->ai_socktype
;
522 if ((iSocketType
!= 0) &&
523 (iSocketType
!= SOCK_STREAM
) &&
524 (iSocketType
!= SOCK_DGRAM
) &&
525 (iSocketType
!= SOCK_RAW
))
528 // REVIEW: What if ai_socktype and ai_protocol are at odds?
529 iProtocol
= ptHints
->ai_protocol
;
533 ////////////////////////////////////////
534 // do service lookup...
538 wPort
= (WORD
) strtoul(pszServiceName
, &pc
, 10);
539 if (*pc
== '\0') // numeric port string
541 wPort
= wTcpPort
= wUdpPort
= htons(wPort
);
542 if (iSocketType
== 0)
545 iSocketType
= SOCK_STREAM
;
548 else // non numeric port string
550 if ((iSocketType
== 0) || (iSocketType
== SOCK_DGRAM
))
552 ptService
= getservbyname(pszServiceName
, "udp");
554 wPort
= wUdpPort
= ptService
->s_port
;
557 if ((iSocketType
== 0) || (iSocketType
== SOCK_STREAM
))
559 ptService
= getservbyname(pszServiceName
, "tcp");
561 wPort
= wTcpPort
= ptService
->s_port
;
564 // assumes 0 is an invalid service port...
565 if (wPort
== 0) // no service exists
566 return (iSocketType
? EAI_SERVICE
: EAI_NONAME
);
568 if (iSocketType
== 0)
570 // if both tcp and udp, process tcp now & clone udp later.
571 iSocketType
= (wTcpPort
) ? SOCK_STREAM
: SOCK_DGRAM
;
572 bClone
= (wTcpPort
&& wUdpPort
);
579 ////////////////////////////////////////
580 // do node name lookup...
582 // if we weren't given a node name,
583 // return the wildcard or loopback address (depending on AI_PASSIVE).
585 // if we have a numeric host address string,
586 // return the binary address.
588 if ((!pszNodeName
) || (WspiapiParseV4Address(pszNodeName
, &dwAddress
)))
592 dwAddress
= htonl((iFlags
& AI_PASSIVE
)
597 // create an addrinfo structure...
599 WspiapiNewAddrInfo(iSocketType
, iProtocol
, wPort
, dwAddress
);
603 if (!iError
&& pszNodeName
)
605 // implementation specific behavior: set AI_NUMERICHOST
606 // to indicate that we got a numeric host address string.
607 (*pptResult
)->ai_flags
|= AI_NUMERICHOST
;
609 // return the numeric address string as the canonical name
610 if (iFlags
& AI_CANONNAME
)
612 (*pptResult
)->ai_canonname
=
613 WspiapiStrdup(inet_ntoa(*((struct in_addr
*) &dwAddress
)));
614 if (!(*pptResult
)->ai_canonname
)
621 // if we do not have a numeric host address string and
622 // AI_NUMERICHOST flag is set, return an error!
623 else if (iFlags
& AI_NUMERICHOST
)
629 // since we have a non-numeric node name,
630 // we have to do a regular node name lookup.
633 iError
= WspiapiLookupNode(pszNodeName
,
637 (iFlags
& AI_CANONNAME
),
641 if (!iError
&& bClone
)
643 iError
= WspiapiClone(wUdpPort
, *pptResult
);
648 WspiapiLegacyFreeAddrInfo(*pptResult
);
660 WspiapiLegacyGetNameInfo(
661 IN
const struct sockaddr
*ptSocketAddress
,
662 IN socklen_t tSocketLength
,
663 OUT
char *pszNodeName
,
664 IN
size_t tNodeLength
,
665 OUT
char *pszServiceName
,
666 IN
size_t tServiceLength
,
671 protocol-independent address-to-name translation.
672 as specified in RFC 2553, Section 6.5.
673 this is the hacked version that only supports IPv4.
676 ptSocketAddress socket address to translate.
677 tSocketLength length of above socket address.
678 pszNodeName where to return the node name.
679 tNodeLength size of above buffer.
680 pszServiceName where to return the service name.
681 tServiceLength size of above buffer.
682 iFlags flags of type NI_*.
685 returns zero if successful, an EAI_* error code if not.
689 struct servent
*ptService
;
691 char szBuffer
[] = "65535";
692 char *pszService
= szBuffer
;
694 struct hostent
*ptHost
;
695 struct in_addr tAddress
;
696 char *pszNode
= NULL
;
700 // sanity check ptSocketAddress and tSocketLength.
701 if (!ptSocketAddress
)
704 if ((ptSocketAddress
->sa_family
!= AF_INET
) ||
705 (tSocketLength
!= sizeof(struct sockaddr_in
)))
710 if (!(pszNodeName
&& tNodeLength
) &&
711 !(pszServiceName
&& tServiceLength
))
716 // the draft has the "bad flags" error code, so presumably we
717 // should check something here. insisting that there aren't
718 // any unspecified flags set would break forward compatibility,
719 // however. so we just check for non-sensical combinations.
720 if ((iFlags
& NI_NUMERICHOST
) && (iFlags
& NI_NAMEREQD
))
725 // translate the port to a service name (if requested).
726 if (pszServiceName
&& tServiceLength
)
728 wPort
= ((struct sockaddr_in
*) ptSocketAddress
)->sin_port
;
730 if (iFlags
& NI_NUMERICSERV
)
732 // return numeric form of the address.
733 sprintf(szBuffer
, "%u", ntohs(wPort
));
737 // return service name corresponding to port.
738 ptService
= getservbyport(wPort
,
739 (iFlags
& NI_DGRAM
) ? "udp" : NULL
);
740 if (ptService
&& ptService
->s_name
)
742 // lookup successful.
743 pszService
= ptService
->s_name
;
747 // DRAFT: return numeric form of the port!
748 sprintf(szBuffer
, "%u", ntohs(wPort
));
753 if (tServiceLength
> strlen(pszService
))
754 strcpy(pszServiceName
, pszService
);
760 // translate the address to a node name (if requested).
761 if (pszNodeName
&& tNodeLength
)
763 // this is the IPv4-only version, so we have an IPv4 address.
764 tAddress
= ((struct sockaddr_in
*) ptSocketAddress
)->sin_addr
;
766 if (iFlags
& NI_NUMERICHOST
)
768 // return numeric form of the address.
769 pszNode
= inet_ntoa(tAddress
);
773 // return node name corresponding to address.
774 ptHost
= gethostbyaddr((char *) &tAddress
,
775 sizeof(struct in_addr
),
777 if (ptHost
&& ptHost
->h_name
)
779 // DNS lookup successful.
780 // stop copying at a "." if NI_NOFQDN is specified.
781 pszNode
= ptHost
->h_name
;
782 if ((iFlags
& NI_NOFQDN
) && (pc
= strchr(pszNode
, '.')))
787 // DNS lookup failed. return numeric form of the address.
788 if (iFlags
& NI_NAMEREQD
)
790 switch (WSAGetLastError())
792 case WSAHOST_NOT_FOUND
: return EAI_NONAME
;
793 case WSATRY_AGAIN
: return EAI_AGAIN
;
794 case WSANO_RECOVERY
: return EAI_FAIL
;
795 default: return EAI_NONAME
;
799 pszNode
= inet_ntoa(tAddress
);
803 if (tNodeLength
> strlen(pszNode
))
804 strcpy(pszNodeName
, pszNode
);
820 #define WSPIAPI_FUNCTION_ARRAY \
822 "getaddrinfo", (FARPROC) WspiapiLegacyGetAddrInfo, \
823 "getnameinfo", (FARPROC) WspiapiLegacyGetNameInfo, \
824 "freeaddrinfo", (FARPROC) WspiapiLegacyFreeAddrInfo, \
837 try to locate the address family independent name resolution routines
838 (i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).
841 this function call is not synchronized. hence the library containing
842 the routines might be loaded multiple times. another option is to
843 synchronize through a spin lock using a static local variable and the
844 InterlockedExchange operation.
848 wFunction ordinal # of the function to get the pointer to
854 address of the library/legacy routine
858 HMODULE hLibrary
= NULL
;
860 // these static variables store state across calls, across threads.
861 static BOOL bInitialized
= FALSE
;
862 static WSPIAPI_FUNCTION rgtGlobal
[] = WSPIAPI_FUNCTION_ARRAY
;
863 static const int iNumGlobal
= (sizeof(rgtGlobal
) /
864 sizeof(WSPIAPI_FUNCTION
));
866 // we overwrite rgtGlobal only if all routines exist in library.
867 WSPIAPI_FUNCTION rgtLocal
[] = WSPIAPI_FUNCTION_ARRAY
;
868 FARPROC fScratch
= NULL
;
872 if (bInitialized
) // WspiapiLoad has already been called once
873 return (rgtGlobal
[wFunction
].pfAddress
);
877 // in Whistler and beyond...
878 // the routines are present in the WinSock 2 library (ws2_32.dll).
879 // printf("Looking in ws2_32 for getaddrinfo...\n");
880 hLibrary
= LoadLibraryA("ws2_32");
881 if (hLibrary
!= NULL
)
883 fScratch
= GetProcAddress(hLibrary
, "getaddrinfo");
884 if (fScratch
== NULL
)
886 FreeLibrary(hLibrary
);
890 if (hLibrary
!= NULL
)
894 // in the IPv6 Technology Preview...
895 // the routines are present in the IPv6 WinSock library (wship6.dll).
896 // printf("Looking in wship6 for getaddrinfo...\n");
897 hLibrary
= LoadLibraryA("wship6");
898 if (hLibrary
!= NULL
)
900 fScratch
= GetProcAddress(hLibrary
, "getaddrinfo");
901 if (fScratch
== NULL
)
903 FreeLibrary(hLibrary
);
910 if (hLibrary
!= NULL
)
912 // use routines from this library...
913 // since getaddrinfo is here, we expect all routines to be here,
914 // but will fall back to IPv4-only if any of them is missing.
915 for (i
= 0; i
< iNumGlobal
; i
++)
917 rgtLocal
[i
].pfAddress
918 = GetProcAddress(hLibrary
, rgtLocal
[i
].pszName
);
919 if (rgtLocal
[i
].pfAddress
== NULL
)
921 FreeLibrary(hLibrary
);
927 if (hLibrary
!= NULL
)
929 // printf("found!\n");
930 for (i
= 0; i
< iNumGlobal
; i
++)
931 rgtGlobal
[i
].pfAddress
= rgtLocal
[i
].pfAddress
;
936 return (rgtGlobal
[wFunction
].pfAddress
);
945 IN
const char *nodename
,
946 IN
const char *servname
,
947 IN
const struct addrinfo
*hints
,
948 OUT
struct addrinfo
**res
)
950 static WSPIAPI_PGETADDRINFO pfGetAddrInfo
= NULL
;
953 pfGetAddrInfo
= (WSPIAPI_PGETADDRINFO
) WspiapiLoad(0);
954 return ((*pfGetAddrInfo
)
955 (nodename
, servname
, hints
, res
));
964 IN
const struct sockaddr
*sa
,
972 static WSPIAPI_PGETNAMEINFO pfGetNameInfo
= NULL
;
975 pfGetNameInfo
= (WSPIAPI_PGETNAMEINFO
) WspiapiLoad(1);
976 return ((*pfGetNameInfo
)
977 (sa
, salen
, host
, hostlen
, serv
, servlen
, flags
));
985 WspiapiFreeAddrInfo (
986 IN
struct addrinfo
*ai
)
988 static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo
= NULL
;
991 pfFreeAddrInfo
= (WSPIAPI_PFREEADDRINFO
) WspiapiLoad(2);
992 (*pfFreeAddrInfo
)(ai
);
999 #endif // _WSPIAPI_H_