3 Copyright (c) Microsoft Corporation. All rights reserved.
9 The file contains protocol independent API functions.
12 Wed Jul 12 10:50:31 2000, Created
21 #if (NTDDI_VERSION >= NTDDI_WIN2K)
23 #include <stdio.h> // sprintf()
24 #include <stdlib.h> // calloc(), strtoul()
25 #include <malloc.h> // calloc()
26 #include <string.h> // strlen(), strcmp(), strstr()
28 #if defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L
30 #define _WSPIAPI_STRCPY_S strcpy_s
31 #define _WSPIAPI_STRCAT_S strcat_s
32 #define _WSPIAPI_STRNCPY_S strncpy_s
33 #define _WSPIAPI_SPRINTF_S_1 sprintf_s
37 #define _WSPIAPI_STRCPY_S(_Dst, _Size, _Src) strcpy((_Dst), (_Src))
38 #define _WSPIAPI_STRCAT_S(_Dst, _Size, _Src) strcat((_Dst), (_Src))
39 #define _WSPIAPI_STRNCPY_S(_Dst, _Size, _Src, _Count) strncpy((_Dst), (_Src), (_Count)); (_Dst)[(_Size) - 1] = 0
40 #define _WSPIAPI_SPRINTF_S_1(_Dst, _Size, _Format, _Arg1) sprintf((_Dst), (_Format), (_Arg1))
42 #endif // defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L
44 #if !defined(_WSPIAPI_COUNTOF)
45 #if !defined(__cplusplus)
46 #define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
48 template <typename __CountofType, size_t _N>
49 char (&__wspiapi_countof_helper(__CountofType (&_Array)[_N]))[_N];
50 #define _WSPIAPI_COUNTOF(_Array) sizeof(__wspiapi_countof_helper(_Array))
54 #define WspiapiMalloc(tSize) calloc(1, (tSize))
55 #define WspiapiFree(p) free(p)
56 #define WspiapiSwap(a, b, c) { (c) = (a); (a) = (b); (b) = (c); }
57 #define getaddrinfo WspiapiGetAddrInfo
58 #define getnameinfo WspiapiGetNameInfo
59 #define freeaddrinfo WspiapiFreeAddrInfo
62 // These function pointers are also within the #if (NTDDI_VERSION >= WIN2K)
63 // because they are used by the other functions defined in this file available
64 // only on win2k and above.
66 typedef int (WINAPI *WSPIAPI_PGETADDRINFO) (
67 IN const char *nodename,
68 IN const char *servname,
69 IN const struct addrinfo *hints,
70 OUT struct addrinfo **res);
72 typedef int (WINAPI *WSPIAPI_PGETNAMEINFO) (
73 IN const struct sockaddr *sa,
81 typedef void (WINAPI *WSPIAPI_PFREEADDRINFO) (
82 IN struct addrinfo *ai);
90 ////////////////////////////////////////////////////////////
91 // v4 only versions of getaddrinfo and friends.
92 // NOTE: gai_strerror is inlined in ws2tcpip.h
93 ////////////////////////////////////////////////////////////
99 IN const char * pszString)
103 allocates enough storage via calloc() for a copy of the string,
104 copies the string into the new memory, and returns a pointer to it.
107 pszString string to copy into new memory
110 a pointer to the newly allocated storage with the string in it.
111 NULL if enough memory could not be allocated, or string was NULL.
121 cchMemory = strlen(pszString) + 1;
122 pszMemory = (char *) WspiapiMalloc(cchMemory);
126 _WSPIAPI_STRCPY_S(pszMemory, cchMemory, pszString);
135 WspiapiParseV4Address (
136 IN const char * pszAddress,
137 OUT PDWORD pdwAddress)
141 get the IPv4 address (in network byte order) from its string
142 representation. the syntax should be a.b.c.d.
145 pszArgument string representation of the IPv4 address
146 ptAddress pointer to the resulting IPv4 address
149 Returns FALSE if there is an error, TRUE for success.
154 const char *pcNext = NULL;
157 // ensure there are 3 '.' (periods)
158 for (pcNext = pszAddress; *pcNext != '\0'; pcNext++)
164 // return an error if dwAddress is INADDR_NONE (255.255.255.255)
165 // since this is never a valid argument to getaddrinfo.
166 dwAddress = inet_addr(pszAddress);
167 if (dwAddress == INADDR_NONE)
170 *pdwAddress = dwAddress;
187 allocate an addrinfo structure and populate fields.
188 IPv4 specific internal function, not exported.
191 iSocketType SOCK_*. can be wildcarded (zero).
192 iProtocol IPPROTO_*. can be wildcarded (zero).
193 wPort port number of service (in network order).
194 dwAddress IPv4 address (in network order).
197 returns an addrinfo struct, or NULL if out of memory.
201 struct addrinfo *ptNew;
202 struct sockaddr_in *ptAddress;
204 // allocate a new addrinfo structure.
206 (struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo));
211 (struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in));
217 ptAddress->sin_family = AF_INET;
218 ptAddress->sin_port = wPort;
219 ptAddress->sin_addr.s_addr = dwAddress;
221 // fill in the fields...
222 ptNew->ai_family = PF_INET;
223 ptNew->ai_socktype = iSocketType;
224 ptNew->ai_protocol = iProtocol;
225 ptNew->ai_addrlen = sizeof(struct sockaddr_in);
226 ptNew->ai_addr = (struct sockaddr *) ptAddress;
237 IN const char *pszNodeName,
241 OUT char pszAlias[NI_MAXHOST],
242 OUT struct addrinfo **pptResult)
246 helper routine for WspiapiLookupNode.
247 performs name resolution by querying the DNS for A records.
248 *pptResult would need to be freed if an error is returned.
251 pszNodeName name of node to resolve.
252 iSocketType SOCK_*. can be wildcarded (zero).
253 iProtocol IPPROTO_*. can be wildcarded (zero).
254 wPort port number of service (in network order).
255 pszAlias where to return the alias. must be of size NI_MAXHOST.
256 pptResult where to return the result.
259 Returns 0 on success, an EAI_* style error value otherwise.
263 struct addrinfo **pptNext = pptResult;
264 struct hostent *ptHost = NULL;
270 ptHost = gethostbyname(pszNodeName);
273 if ((ptHost->h_addrtype == AF_INET) &&
274 (ptHost->h_length == sizeof(struct in_addr)))
276 for (ppAddresses = ptHost->h_addr_list;
277 *ppAddresses != NULL;
280 // create an addrinfo structure...
281 *pptNext = WspiapiNewAddrInfo(
285 ((struct in_addr *) *ppAddresses)->s_addr);
289 pptNext = &((*pptNext)->ai_next);
293 // pick up the canonical name.
294 _WSPIAPI_STRNCPY_S(pszAlias, NI_MAXHOST, ptHost->h_name, NI_MAXHOST - 1);
299 switch (WSAGetLastError())
301 case WSAHOST_NOT_FOUND: return EAI_NONAME;
302 case WSATRY_AGAIN: return EAI_AGAIN;
303 case WSANO_RECOVERY: return EAI_FAIL;
304 case WSANO_DATA: return EAI_NODATA;
305 default: return EAI_NONAME;
315 IN const char *pszNodeName,
319 IN BOOL bAI_CANONNAME,
320 OUT struct addrinfo **pptResult)
324 resolve a nodename and return a list of addrinfo structures.
325 IPv4 specific internal function, not exported.
326 *pptResult would need to be freed if an error is returned.
328 NOTE: if bAI_CANONNAME is true, the canonical name should be
329 returned in the first addrinfo structure.
332 pszNodeName name of node to resolve.
333 iSocketType SOCK_*. can be wildcarded (zero).
334 iProtocol IPPROTO_*. can be wildcarded (zero).
335 wPort port number of service (in network order).
336 bAI_CANONNAME whether the AI_CANONNAME flag is set.
337 pptResult where to return result.
340 Returns 0 on success, an EAI_* style error value otherwise.
347 char szFQDN1[NI_MAXHOST] = "";
348 char szFQDN2[NI_MAXHOST] = "";
349 char *pszName = szFQDN1;
350 char *pszAlias = szFQDN2;
351 char *pszScratch = NULL;
352 _WSPIAPI_STRNCPY_S(pszName, NI_MAXHOST, pszNodeName, NI_MAXHOST - 1);
356 iError = WspiapiQueryDNS(pszNodeName,
365 // if we found addresses, then we are done.
369 // stop infinite loops due to DNS misconfiguration. there appears
370 // to be no particular recommended limit in RFCs 1034 and 1035.
371 if ((!strlen(pszAlias)) ||
372 (!strcmp(pszName, pszAlias)) ||
373 (++iAliasCount == 16))
379 // there was a new CNAME, look again.
380 WspiapiSwap(pszName, pszAlias, pszScratch);
383 if (!iError && bAI_CANONNAME)
385 (*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);
386 if (!(*pptResult)->ai_canonname)
400 IN struct addrinfo *ptResult)
404 clone every addrinfo structure in ptResult for the UDP service.
405 ptResult would need to be freed if an error is returned.
408 wPort port number of UDP service.
409 ptResult list of addrinfo structures, each
410 of whose node needs to be cloned.
413 Returns 0 on success, an EAI_MEMORY on allocation failure.
417 struct addrinfo *ptNext = NULL;
418 struct addrinfo *ptNew = NULL;
420 for (ptNext = ptResult; ptNext != NULL; )
422 // create an addrinfo structure...
423 ptNew = WspiapiNewAddrInfo(
427 ((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);
431 // link the cloned addrinfo
432 ptNew->ai_next = ptNext->ai_next;
433 ptNext->ai_next = ptNew;
434 ptNext = ptNew->ai_next;
448 WspiapiLegacyFreeAddrInfo (
449 IN struct addrinfo *ptHead)
453 Free an addrinfo structure (or chain of structures).
454 As specified in RFC 2553, Section 6.4.
457 ptHead structure (chain) to free
461 struct addrinfo *ptNext; // next strcture to free
463 for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead)
465 if (ptNext->ai_canonname)
466 WspiapiFree(ptNext->ai_canonname);
469 WspiapiFree(ptNext->ai_addr);
471 ptHead = ptNext->ai_next;
481 WspiapiLegacyGetAddrInfo(
482 IN const char *pszNodeName,
483 IN const char *pszServiceName,
484 IN const struct addrinfo *ptHints,
485 OUT struct addrinfo **pptResult)
489 Protocol-independent name-to-address translation.
490 As specified in RFC 2553, Section 6.4.
491 This is the hacked version that only supports IPv4.
494 pszNodeName node name to lookup.
495 pszServiceName service name to lookup.
496 ptHints hints about how to process request.
497 pptResult where to return result.
500 returns zero if successful, an EAI_* error code if not.
506 int iFamily = PF_UNSPEC;
512 struct servent *ptService = NULL;
519 // initialize pptResult with default return value.
523 ////////////////////////////////////////
524 // validate arguments...
527 // both the node name and the service name can't be NULL.
528 if ((!pszNodeName) && (!pszServiceName))
534 // all members other than ai_flags, ai_family, ai_socktype
535 // and ai_protocol must be zero or a null pointer.
536 if ((ptHints->ai_addrlen != 0) ||
537 (ptHints->ai_canonname != NULL) ||
538 (ptHints->ai_addr != NULL) ||
539 (ptHints->ai_next != NULL))
544 // the spec has the "bad flags" error code, so presumably we
545 // should check something here. insisting that there aren't
546 // any unspecified flags set would break forward compatibility,
547 // however. so we just check for non-sensical combinations.
549 // we cannot come up with a canonical name given a null node name.
550 iFlags = ptHints->ai_flags;
551 if ((iFlags & AI_CANONNAME) && !pszNodeName)
554 // we only support a limited number of protocol families.
555 iFamily = ptHints->ai_family;
556 if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
559 // we only support only these socket types.
560 iSocketType = ptHints->ai_socktype;
561 if ((iSocketType != 0) &&
562 (iSocketType != SOCK_STREAM) &&
563 (iSocketType != SOCK_DGRAM) &&
564 (iSocketType != SOCK_RAW))
567 // REVIEW: What if ai_socktype and ai_protocol are at odds?
568 iProtocol = ptHints->ai_protocol;
572 ////////////////////////////////////////
573 // do service lookup...
577 wPort = (WORD) strtoul(pszServiceName, &pc, 10);
578 if (*pc == '\0') // numeric port string
580 wPort = wTcpPort = wUdpPort = htons(wPort);
581 if (iSocketType == 0)
584 iSocketType = SOCK_STREAM;
587 else // non numeric port string
589 if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
591 ptService = getservbyname(pszServiceName, "udp");
593 wPort = wUdpPort = ptService->s_port;
596 if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
598 ptService = getservbyname(pszServiceName, "tcp");
600 wPort = wTcpPort = ptService->s_port;
603 // assumes 0 is an invalid service port...
604 if (wPort == 0) // no service exists
605 return (iSocketType ? EAI_SERVICE : EAI_NONAME);
607 if (iSocketType == 0)
609 // if both tcp and udp, process tcp now & clone udp later.
610 iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;
611 bClone = (wTcpPort && wUdpPort);
618 ////////////////////////////////////////
619 // do node name lookup...
621 // if we weren't given a node name,
622 // return the wildcard or loopback address (depending on AI_PASSIVE).
624 // if we have a numeric host address string,
625 // return the binary address.
627 if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress)))
631 dwAddress = htonl((iFlags & AI_PASSIVE)
636 // create an addrinfo structure...
638 WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
642 if (!iError && pszNodeName)
644 // implementation specific behavior: set AI_NUMERICHOST
645 // to indicate that we got a numeric host address string.
646 (*pptResult)->ai_flags |= AI_NUMERICHOST;
648 // return the numeric address string as the canonical name
649 if (iFlags & AI_CANONNAME)
651 (*pptResult)->ai_canonname =
652 WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));
653 if (!(*pptResult)->ai_canonname)
660 // if we do not have a numeric host address string and
661 // AI_NUMERICHOST flag is set, return an error!
662 else if (iFlags & AI_NUMERICHOST)
668 // since we have a non-numeric node name,
669 // we have to do a regular node name lookup.
672 iError = WspiapiLookupNode(pszNodeName,
676 (iFlags & AI_CANONNAME),
680 if (!iError && bClone)
682 iError = WspiapiClone(wUdpPort, *pptResult);
687 WspiapiLegacyFreeAddrInfo(*pptResult);
699 WspiapiLegacyGetNameInfo(
700 IN const struct sockaddr *ptSocketAddress,
701 IN socklen_t tSocketLength,
702 OUT char *pszNodeName,
703 IN size_t tNodeLength,
704 OUT char *pszServiceName,
705 IN size_t tServiceLength,
710 protocol-independent address-to-name translation.
711 as specified in RFC 2553, Section 6.5.
712 this is the hacked version that only supports IPv4.
715 ptSocketAddress socket address to translate.
716 tSocketLength length of above socket address.
717 pszNodeName where to return the node name.
718 tNodeLength size of above buffer.
719 pszServiceName where to return the service name.
720 tServiceLength size of above buffer.
721 iFlags flags of type NI_*.
724 returns zero if successful, an EAI_* error code if not.
728 struct servent *ptService;
730 char szBuffer[] = "65535";
731 char *pszService = szBuffer;
733 struct hostent *ptHost;
734 struct in_addr tAddress;
735 char *pszNode = NULL;
739 // sanity check ptSocketAddress and tSocketLength.
740 if ((!ptSocketAddress) || (tSocketLength < sizeof(struct sockaddr)))
743 if (ptSocketAddress->sa_family != AF_INET)
746 if (tSocketLength < sizeof(struct sockaddr_in))
749 if (!(pszNodeName && tNodeLength) &&
750 !(pszServiceName && tServiceLength))
755 // the draft has the "bad flags" error code, so presumably we
756 // should check something here. insisting that there aren't
757 // any unspecified flags set would break forward compatibility,
758 // however. so we just check for non-sensical combinations.
759 if ((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD))
764 // translate the port to a service name (if requested).
765 if (pszServiceName && tServiceLength)
767 wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;
769 if (iFlags & NI_NUMERICSERV)
771 // return numeric form of the address.
772 _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(szBuffer), "%u", ntohs(wPort));
776 // return service name corresponding to port.
777 ptService = getservbyport(wPort,
778 (iFlags & NI_DGRAM) ? "udp" : NULL);
779 if (ptService && ptService->s_name)
781 // lookup successful.
782 pszService = ptService->s_name;
786 // DRAFT: return numeric form of the port!
787 _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(szBuffer), "%u", ntohs(wPort));
792 if (tServiceLength > strlen(pszService))
793 _WSPIAPI_STRCPY_S(pszServiceName, tServiceLength, pszService);
799 // translate the address to a node name (if requested).
800 if (pszNodeName && tNodeLength)
802 // this is the IPv4-only version, so we have an IPv4 address.
803 tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;
805 if (iFlags & NI_NUMERICHOST)
807 // return numeric form of the address.
808 pszNode = inet_ntoa(tAddress);
812 // return node name corresponding to address.
813 ptHost = gethostbyaddr((char *) &tAddress,
814 sizeof(struct in_addr),
816 if (ptHost && ptHost->h_name)
818 // DNS lookup successful.
819 // stop copying at a "." if NI_NOFQDN is specified.
820 pszNode = ptHost->h_name;
821 if ((iFlags & NI_NOFQDN) &&
822 ((pc = strchr(pszNode, '.')) != NULL))
827 // DNS lookup failed. return numeric form of the address.
828 if (iFlags & NI_NAMEREQD)
830 switch (WSAGetLastError())
832 case WSAHOST_NOT_FOUND: return EAI_NONAME;
833 case WSATRY_AGAIN: return EAI_AGAIN;
834 case WSANO_RECOVERY: return EAI_FAIL;
835 default: return EAI_NONAME;
839 pszNode = inet_ntoa(tAddress);
843 if (tNodeLength > strlen(pszNode))
844 _WSPIAPI_STRCPY_S(pszNodeName, tNodeLength, pszNode);
860 #define WSPIAPI_FUNCTION_ARRAY \
862 "getaddrinfo", (FARPROC) WspiapiLegacyGetAddrInfo, \
863 "getnameinfo", (FARPROC) WspiapiLegacyGetNameInfo, \
864 "freeaddrinfo", (FARPROC) WspiapiLegacyFreeAddrInfo, \
877 try to locate the address family independent name resolution routines
878 (i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).
881 this function call is not synchronized. hence the library containing
882 the routines might be loaded multiple times. another option is to
883 synchronize through a spin lock using a static local variable and the
884 InterlockedExchange operation.
888 wFunction ordinal # of the function to get the pointer to
894 address of the library/legacy routine
898 HMODULE hLibrary = NULL;
900 // these static variables store state across calls, across threads.
901 static BOOL bInitialized = FALSE;
902 static WSPIAPI_FUNCTION rgtGlobal[] = WSPIAPI_FUNCTION_ARRAY;
903 static const int iNumGlobal = (sizeof(rgtGlobal) /
904 sizeof(WSPIAPI_FUNCTION));
906 // we overwrite rgtGlobal only if all routines exist in library.
907 WSPIAPI_FUNCTION rgtLocal[] = WSPIAPI_FUNCTION_ARRAY;
908 FARPROC fScratch = NULL;
912 if (bInitialized) // WspiapiLoad has already been called once
913 return (rgtGlobal[wFunction].pfAddress);
915 for (;;) // breakout loop
917 CHAR SystemDir[MAX_PATH + 1];
918 CHAR Path[MAX_PATH + 8];
920 if (GetSystemDirectoryA(SystemDir, MAX_PATH) == 0)
925 // in Whistler and beyond...
926 // the routines are present in the WinSock 2 library (ws2_32.dll).
927 // printf("Looking in ws2_32 for getaddrinfo...\n");
928 _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir);
929 _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\ws2_32");
930 hLibrary = LoadLibraryA(Path);
931 if (hLibrary != NULL)
933 fScratch = GetProcAddress(hLibrary, "getaddrinfo");
934 if (fScratch == NULL)
936 FreeLibrary(hLibrary);
940 if (hLibrary != NULL)
944 // in the IPv6 Technology Preview...
945 // the routines are present in the IPv6 WinSock library (wship6.dll).
946 // printf("Looking in wship6 for getaddrinfo...\n");
947 _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir);
948 _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\wship6");
949 hLibrary = LoadLibraryA(Path);
950 if (hLibrary != NULL)
952 fScratch = GetProcAddress(hLibrary, "getaddrinfo");
953 if (fScratch == NULL)
955 FreeLibrary(hLibrary);
964 if (hLibrary != NULL)
966 // use routines from this library...
967 // since getaddrinfo is here, we expect all routines to be here,
968 // but will fall back to IPv4-only if any of them is missing.
969 for (i = 0; i < iNumGlobal; i++)
971 rgtLocal[i].pfAddress
972 = GetProcAddress(hLibrary, rgtLocal[i].pszName);
973 if (rgtLocal[i].pfAddress == NULL)
975 FreeLibrary(hLibrary);
981 if (hLibrary != NULL)
983 // printf("found!\n");
984 for (i = 0; i < iNumGlobal; i++)
985 rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;
990 return (rgtGlobal[wFunction].pfAddress);
999 IN const char *nodename,
1000 IN const char *servname,
1001 IN const struct addrinfo *hints,
1002 OUT struct addrinfo **res)
1005 static WSPIAPI_PGETADDRINFO pfGetAddrInfo = NULL;
1008 pfGetAddrInfo = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);
1010 iError = (*pfGetAddrInfo)(nodename, servname, hints, res);
1011 WSASetLastError(iError);
1020 WspiapiGetNameInfo (
1021 IN const struct sockaddr *sa,
1030 static WSPIAPI_PGETNAMEINFO pfGetNameInfo = NULL;
1033 pfGetNameInfo = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);
1035 iError = (*pfGetNameInfo)(sa, salen, host, hostlen, serv, servlen, flags);
1036 WSASetLastError(iError);
1045 WspiapiFreeAddrInfo (
1046 IN struct addrinfo *ai)
1048 static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo = NULL;
1050 if (!pfFreeAddrInfo)
1051 pfFreeAddrInfo = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);
1052 (*pfFreeAddrInfo)(ai);
1059 #endif // if (NTDDI_VERSION >= WIN2K)
1060 #endif // _WSPIAPI_H_