--- /dev/null
+/*++
+
+Copyright (c) 2000, Microsoft Corporation
+
+Module Name:
+ wspiapi.h
+
+Abstract:
+ The file contains protocol independent API functions.
+
+Revision History:
+ Wed Jul 12 10:50:31 2000, Created
+
+--*/
+
+#ifndef _WSPIAPI_H_
+#define _WSPIAPI_H_
+
+#include <stdio.h> // sprintf()
+#include <stdlib.h> // calloc(), strtoul()
+#include <malloc.h> // calloc()
+#include <string.h> // strlen(), strcmp(), strstr()
+
+#define WspiapiMalloc(tSize) calloc(1, (tSize))
+#define WspiapiFree(p) free(p)
+#define WspiapiSwap(a, b, c) { (c) = (a); (a) = (b); (b) = (c); }
+#define getaddrinfo WspiapiGetAddrInfo
+#define getnameinfo WspiapiGetNameInfo
+#define freeaddrinfo WspiapiFreeAddrInfo
+
+typedef int (WINAPI *WSPIAPI_PGETADDRINFO) (
+ IN const char *nodename,
+ IN const char *servname,
+ IN const struct addrinfo *hints,
+ OUT struct addrinfo **res);
+
+typedef int (WINAPI *WSPIAPI_PGETNAMEINFO) (
+ IN const struct sockaddr *sa,
+ IN socklen_t salen,
+ OUT char *host,
+ IN size_t hostlen,
+ OUT char *serv,
+ IN size_t servlen,
+ IN int flags);
+
+typedef void (WINAPI *WSPIAPI_PFREEADDRINFO) (
+ IN struct addrinfo *ai);
+
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+////////////////////////////////////////////////////////////
+// v4 only versions of getaddrinfo and friends.
+// NOTE: gai_strerror is inlined in ws2tcpip.h
+////////////////////////////////////////////////////////////
+
+__inline
+char *
+WINAPI
+WspiapiStrdup (
+ IN const char * pszString)
+/*++
+
+Routine Description
+ allocates enough storage via calloc() for a copy of the string,
+ copies the string into the new memory, and returns a pointer to it.
+
+Arguments
+ pszString string to copy into new memory
+
+Return Value
+ a pointer to the newly allocated storage with the string in it.
+ NULL if enough memory could not be allocated, or string was NULL.
+
+--*/
+{
+ char *pszMemory;
+
+ if (!pszString)
+ return(NULL);
+
+ pszMemory = (char *) WspiapiMalloc(strlen(pszString) + 1);
+ if (!pszMemory)
+ return(NULL);
+
+ return(strcpy(pszMemory, pszString));
+}
+
+
+
+__inline
+BOOL
+WINAPI
+WspiapiParseV4Address (
+ IN const char * pszAddress,
+ OUT PDWORD pdwAddress)
+/*++
+
+Routine Description
+ get the IPv4 address (in network byte order) from its string
+ representation. the syntax should be a.b.c.d.
+
+Arguments
+ pszArgument string representation of the IPv4 address
+ ptAddress pointer to the resulting IPv4 address
+
+Return Value
+ Returns FALSE if there is an error, TRUE for success.
+
+--*/
+{
+ DWORD dwAddress = 0;
+ const char *pcNext = NULL;
+ int iCount = 0;
+
+ // ensure there are 3 '.' (periods)
+ for (pcNext = pszAddress; *pcNext != '\0'; pcNext++)
+ if (*pcNext == '.')
+ iCount++;
+ if (iCount != 3)
+ return FALSE;
+
+ // return an error if dwAddress is INADDR_NONE (255.255.255.255)
+ // since this is never a valid argument to getaddrinfo.
+ dwAddress = inet_addr(pszAddress);
+ if (dwAddress == INADDR_NONE)
+ return FALSE;
+
+ *pdwAddress = dwAddress;
+ return TRUE;
+}
+
+
+
+__inline
+struct addrinfo *
+WINAPI
+WspiapiNewAddrInfo (
+ IN int iSocketType,
+ IN int iProtocol,
+ IN WORD wPort,
+ IN DWORD dwAddress)
+/*++
+
+Routine Description
+ allocate an addrinfo structure and populate fields.
+ IPv4 specific internal function, not exported.
+
+Arguments
+ iSocketType SOCK_*. can be wildcarded (zero).
+ iProtocol IPPROTO_*. can be wildcarded (zero).
+ wPort port number of service (in network order).
+ dwAddress IPv4 address (in network order).
+
+Return Value
+ returns an addrinfo struct, or NULL if out of memory.
+
+--*/
+{
+ struct addrinfo *ptNew;
+ struct sockaddr_in *ptAddress;
+
+ // allocate a new addrinfo structure.
+ ptNew =
+ (struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo));
+ if (!ptNew)
+ return NULL;
+
+ ptAddress =
+ (struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in));
+ if (!ptAddress)
+ {
+ WspiapiFree(ptNew);
+ return NULL;
+ }
+ ptAddress->sin_family = AF_INET;
+ ptAddress->sin_port = wPort;
+ ptAddress->sin_addr.s_addr = dwAddress;
+
+ // fill in the fields...
+ ptNew->ai_family = PF_INET;
+ ptNew->ai_socktype = iSocketType;
+ ptNew->ai_protocol = iProtocol;
+ ptNew->ai_addrlen = sizeof(struct sockaddr_in);
+ ptNew->ai_addr = (struct sockaddr *) ptAddress;
+
+ return ptNew;
+}
+
+
+
+__inline
+int
+WINAPI
+WspiapiQueryDNS(
+ IN const char *pszNodeName,
+ IN int iSocketType,
+ IN int iProtocol,
+ IN WORD wPort,
+ OUT char *pszAlias,
+ OUT struct addrinfo **pptResult)
+/*++
+
+Routine Description
+ helper routine for WspiapiLookupNode.
+ performs name resolution by querying the DNS for A records.
+ *pptResult would need to be freed if an error is returned.
+
+Arguments
+ pszNodeName name of node to resolve.
+ iSocketType SOCK_*. can be wildcarded (zero).
+ iProtocol IPPROTO_*. can be wildcarded (zero).
+ wPort port number of service (in network order).
+ pszAlias where to return the alias.
+ pptResult where to return the result.
+
+Return Value
+ Returns 0 on success, an EAI_* style error value otherwise.
+
+--*/
+{
+ struct addrinfo **pptNext = pptResult;
+ struct hostent *ptHost = NULL;
+ char **ppAddresses;
+
+ *pptNext = NULL;
+ pszAlias[0] = '\0';
+
+ ptHost = gethostbyname(pszNodeName);
+ if (ptHost)
+ {
+ if ((ptHost->h_addrtype == AF_INET) &&
+ (ptHost->h_length == sizeof(struct in_addr)))
+ {
+ for (ppAddresses = ptHost->h_addr_list;
+ *ppAddresses != NULL;
+ ppAddresses++)
+ {
+ // create an addrinfo structure...
+ *pptNext = WspiapiNewAddrInfo(
+ iSocketType,
+ iProtocol,
+ wPort,
+ ((struct in_addr *) *ppAddresses)->s_addr);
+ if (!*pptNext)
+ return EAI_MEMORY;
+
+ pptNext = &((*pptNext)->ai_next);
+ }
+ }
+
+ // pick up the canonical name.
+ strcpy(pszAlias, ptHost->h_name);
+ return 0;
+ }
+
+ switch (WSAGetLastError())
+ {
+ case WSAHOST_NOT_FOUND: return EAI_NONAME;
+ case WSATRY_AGAIN: return EAI_AGAIN;
+ case WSANO_RECOVERY: return EAI_FAIL;
+ case WSANO_DATA: return EAI_NODATA;
+ default: return EAI_NONAME;
+ }
+}
+
+
+
+__inline
+int
+WINAPI
+WspiapiLookupNode(
+ IN const char *pszNodeName,
+ IN int iSocketType,
+ IN int iProtocol,
+ IN WORD wPort,
+ IN BOOL bAI_CANONNAME,
+ OUT struct addrinfo **pptResult)
+/*++
+
+Routine Description
+ resolve a nodename and return a list of addrinfo structures.
+ IPv4 specific internal function, not exported.
+ *pptResult would need to be freed if an error is returned.
+
+ NOTE: if bAI_CANONNAME is true, the canonical name should be
+ returned in the first addrinfo structure.
+
+Arguments
+ pszNodeName name of node to resolve.
+ iSocketType SOCK_*. can be wildcarded (zero).
+ iProtocol IPPROTO_*. can be wildcarded (zero).
+ wPort port number of service (in network order).
+ bAI_CANONNAME whether the AI_CANONNAME flag is set.
+ pptResult where to return result.
+
+Return Value
+ Returns 0 on success, an EAI_* style error value otherwise.
+
+--*/
+{
+ int iError = 0;
+ int iAliasCount = 0;
+
+ char szFQDN1[NI_MAXHOST] = "";
+ char szFQDN2[NI_MAXHOST] = "";
+ char *pszName = szFQDN1;
+ char *pszAlias = szFQDN2;
+ char *pszScratch = NULL;
+ strcpy(pszName, pszNodeName);
+
+ for (;;)
+ {
+ iError = WspiapiQueryDNS(pszNodeName,
+ iSocketType,
+ iProtocol,
+ wPort,
+ pszAlias,
+ pptResult);
+ if (iError)
+ break;
+
+ // if we found addresses, then we are done.
+ if (*pptResult)
+ break;
+
+ // stop infinite loops due to DNS misconfiguration. there appears
+ // to be no particular recommended limit in RFCs 1034 and 1035.
+ if ((!strlen(pszAlias)) ||
+ (!strcmp(pszName, pszAlias)) ||
+ (++iAliasCount == 16))
+ {
+ iError = EAI_FAIL;
+ break;
+ }
+
+ // there was a new CNAME, look again.
+ WspiapiSwap(pszName, pszAlias, pszScratch);
+ }
+
+ if (!iError && bAI_CANONNAME)
+ {
+ (*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);
+ if (!(*pptResult)->ai_canonname)
+ iError = EAI_MEMORY;
+ }
+
+ return iError;
+}
+
+
+
+__inline
+int
+WINAPI
+WspiapiClone (
+ IN WORD wPort,
+ IN struct addrinfo *ptResult)
+/*++
+
+Routine Description
+ clone every addrinfo structure in ptResult for the UDP service.
+ ptResult would need to be freed if an error is returned.
+
+Arguments
+ wPort port number of UDP service.
+ ptResult list of addrinfo structures, each
+ of whose node needs to be cloned.
+
+Return Value
+ Returns 0 on success, an EAI_MEMORY on allocation failure.
+
+--*/
+{
+ struct addrinfo *ptNext = NULL;
+ struct addrinfo *ptNew = NULL;
+
+ for (ptNext = ptResult; ptNext != NULL; )
+ {
+ // create an addrinfo structure...
+ ptNew = WspiapiNewAddrInfo(
+ SOCK_DGRAM,
+ ptNext->ai_protocol,
+ wPort,
+ ((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);
+ if (!ptNew)
+ break;
+
+ // link the cloned addrinfo
+ ptNew->ai_next = ptNext->ai_next;
+ ptNext->ai_next = ptNew;
+ ptNext = ptNew->ai_next;
+ }
+
+ if (ptNext != NULL)
+ return EAI_MEMORY;
+
+ return 0;
+}
+
+
+
+__inline
+void
+WINAPI
+WspiapiLegacyFreeAddrInfo (
+ IN struct addrinfo *ptHead)
+/*++
+
+Routine Description
+ Free an addrinfo structure (or chain of structures).
+ As specified in RFC 2553, Section 6.4.
+
+Arguments
+ ptHead structure (chain) to free
+
+--*/
+{
+ struct addrinfo *ptNext; // next strcture to free
+
+ for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead)
+ {
+ if (ptNext->ai_canonname)
+ WspiapiFree(ptNext->ai_canonname);
+
+ if (ptNext->ai_addr)
+ WspiapiFree(ptNext->ai_addr);
+
+ ptHead = ptNext->ai_next;
+ WspiapiFree(ptNext);
+ }
+}
+
+
+
+__inline
+int
+WINAPI
+WspiapiLegacyGetAddrInfo(
+ IN const char *pszNodeName,
+ IN const char *pszServiceName,
+ IN const struct addrinfo *ptHints,
+ OUT struct addrinfo **pptResult)
+/*++
+
+Routine Description
+ Protocol-independent name-to-address translation.
+ As specified in RFC 2553, Section 6.4.
+ This is the hacked version that only supports IPv4.
+
+Arguments
+ pszNodeName node name to lookup.
+ pszServiceName service name to lookup.
+ ptHints hints about how to process request.
+ pptResult where to return result.
+
+Return Value
+ returns zero if successful, an EAI_* error code if not.
+
+--*/
+{
+ int iError = 0;
+ int iFlags = 0;
+ int iFamily = PF_UNSPEC;
+ int iSocketType = 0;
+ int iProtocol = 0;
+ WORD wPort = 0;
+ DWORD dwAddress = 0;
+
+ struct servent *ptService = NULL;
+ char *pc = NULL;
+ BOOL bClone = FALSE;
+ WORD wTcpPort = 0;
+ WORD wUdpPort = 0;
+
+
+ // initialize pptResult with default return value.
+ *pptResult = NULL;
+
+
+ ////////////////////////////////////////
+ // validate arguments...
+ //
+
+ // both the node name and the service name can't be NULL.
+ if ((!pszNodeName) && (!pszServiceName))
+ return EAI_NONAME;
+
+ // validate hints.
+ if (ptHints)
+ {
+ // all members other than ai_flags, ai_family, ai_socktype
+ // and ai_protocol must be zero or a null pointer.
+ if ((ptHints->ai_addrlen != 0) ||
+ (ptHints->ai_canonname != NULL) ||
+ (ptHints->ai_addr != NULL) ||
+ (ptHints->ai_next != NULL))
+ {
+ return EAI_FAIL;
+ }
+
+ // the spec has the "bad flags" error code, so presumably we
+ // should check something here. insisting that there aren't
+ // any unspecified flags set would break forward compatibility,
+ // however. so we just check for non-sensical combinations.
+ //
+ // we cannot come up with a canonical name given a null node name.
+ iFlags = ptHints->ai_flags;
+ if ((iFlags & AI_CANONNAME) && !pszNodeName)
+ return EAI_BADFLAGS;
+
+ // we only support a limited number of protocol families.
+ iFamily = ptHints->ai_family;
+ if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
+ return EAI_FAMILY;
+
+ // we only support only these socket types.
+ iSocketType = ptHints->ai_socktype;
+ if ((iSocketType != 0) &&
+ (iSocketType != SOCK_STREAM) &&
+ (iSocketType != SOCK_DGRAM) &&
+ (iSocketType != SOCK_RAW))
+ return EAI_SOCKTYPE;
+
+ // REVIEW: What if ai_socktype and ai_protocol are at odds?
+ iProtocol = ptHints->ai_protocol;
+ }
+
+
+ ////////////////////////////////////////
+ // do service lookup...
+
+ if (pszServiceName)
+ {
+ wPort = (WORD) strtoul(pszServiceName, &pc, 10);
+ if (*pc == '\0') // numeric port string
+ {
+ wPort = wTcpPort = wUdpPort = htons(wPort);
+ if (iSocketType == 0)
+ {
+ bClone = TRUE;
+ iSocketType = SOCK_STREAM;
+ }
+ }
+ else // non numeric port string
+ {
+ if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
+ {
+ ptService = getservbyname(pszServiceName, "udp");
+ if (ptService)
+ wPort = wUdpPort = ptService->s_port;
+ }
+
+ if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
+ {
+ ptService = getservbyname(pszServiceName, "tcp");
+ if (ptService)
+ wPort = wTcpPort = ptService->s_port;
+ }
+
+ // assumes 0 is an invalid service port...
+ if (wPort == 0) // no service exists
+ return (iSocketType ? EAI_SERVICE : EAI_NONAME);
+
+ if (iSocketType == 0)
+ {
+ // if both tcp and udp, process tcp now & clone udp later.
+ iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;
+ bClone = (wTcpPort && wUdpPort);
+ }
+ }
+ }
+
+
+
+ ////////////////////////////////////////
+ // do node name lookup...
+
+ // if we weren't given a node name,
+ // return the wildcard or loopback address (depending on AI_PASSIVE).
+ //
+ // if we have a numeric host address string,
+ // return the binary address.
+ //
+ if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress)))
+ {
+ if (!pszNodeName)
+ {
+ dwAddress = htonl((iFlags & AI_PASSIVE)
+ ? INADDR_ANY
+ : INADDR_LOOPBACK);
+ }
+
+ // create an addrinfo structure...
+ *pptResult =
+ WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
+ if (!(*pptResult))
+ iError = EAI_MEMORY;
+
+ if (!iError && pszNodeName)
+ {
+ // implementation specific behavior: set AI_NUMERICHOST
+ // to indicate that we got a numeric host address string.
+ (*pptResult)->ai_flags |= AI_NUMERICHOST;
+
+ // return the numeric address string as the canonical name
+ if (iFlags & AI_CANONNAME)
+ {
+ (*pptResult)->ai_canonname =
+ WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));
+ if (!(*pptResult)->ai_canonname)
+ iError = EAI_MEMORY;
+ }
+ }
+ }
+
+
+ // if we do not have a numeric host address string and
+ // AI_NUMERICHOST flag is set, return an error!
+ else if (iFlags & AI_NUMERICHOST)
+ {
+ iError = EAI_NONAME;
+ }
+
+
+ // since we have a non-numeric node name,
+ // we have to do a regular node name lookup.
+ else
+ {
+ iError = WspiapiLookupNode(pszNodeName,
+ iSocketType,
+ iProtocol,
+ wPort,
+ (iFlags & AI_CANONNAME),
+ pptResult);
+ }
+
+ if (!iError && bClone)
+ {
+ iError = WspiapiClone(wUdpPort, *pptResult);
+ }
+
+ if (iError)
+ {
+ WspiapiLegacyFreeAddrInfo(*pptResult);
+ *pptResult = NULL;
+ }
+
+ return (iError);
+}
+
+
+
+__inline
+int
+WINAPI
+WspiapiLegacyGetNameInfo(
+ IN const struct sockaddr *ptSocketAddress,
+ IN socklen_t tSocketLength,
+ OUT char *pszNodeName,
+ IN size_t tNodeLength,
+ OUT char *pszServiceName,
+ IN size_t tServiceLength,
+ IN int iFlags)
+/*++
+
+Routine Description
+ protocol-independent address-to-name translation.
+ as specified in RFC 2553, Section 6.5.
+ this is the hacked version that only supports IPv4.
+
+Arguments
+ ptSocketAddress socket address to translate.
+ tSocketLength length of above socket address.
+ pszNodeName where to return the node name.
+ tNodeLength size of above buffer.
+ pszServiceName where to return the service name.
+ tServiceLength size of above buffer.
+ iFlags flags of type NI_*.
+
+Return Value
+ returns zero if successful, an EAI_* error code if not.
+
+--*/
+{
+ struct servent *ptService;
+ WORD wPort;
+ char szBuffer[] = "65535";
+ char *pszService = szBuffer;
+
+ struct hostent *ptHost;
+ struct in_addr tAddress;
+ char *pszNode = NULL;
+ char *pc = NULL;
+
+
+ // sanity check ptSocketAddress and tSocketLength.
+ if (!ptSocketAddress)
+ return EAI_FAIL;
+
+ if ((ptSocketAddress->sa_family != AF_INET) ||
+ (tSocketLength != sizeof(struct sockaddr_in)))
+ {
+ return EAI_FAMILY;
+ }
+
+ if (!(pszNodeName && tNodeLength) &&
+ !(pszServiceName && tServiceLength))
+ {
+ return EAI_NONAME;
+ }
+
+ // the draft has the "bad flags" error code, so presumably we
+ // should check something here. insisting that there aren't
+ // any unspecified flags set would break forward compatibility,
+ // however. so we just check for non-sensical combinations.
+ if ((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD))
+ {
+ return EAI_BADFLAGS;
+ }
+
+ // translate the port to a service name (if requested).
+ if (pszServiceName && tServiceLength)
+ {
+ wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;
+
+ if (iFlags & NI_NUMERICSERV)
+ {
+ // return numeric form of the address.
+ sprintf(szBuffer, "%u", ntohs(wPort));
+ }
+ else
+ {
+ // return service name corresponding to port.
+ ptService = getservbyport(wPort,
+ (iFlags & NI_DGRAM) ? "udp" : NULL);
+ if (ptService && ptService->s_name)
+ {
+ // lookup successful.
+ pszService = ptService->s_name;
+ }
+ else
+ {
+ // DRAFT: return numeric form of the port!
+ sprintf(szBuffer, "%u", ntohs(wPort));
+ }
+ }
+
+
+ if (tServiceLength > strlen(pszService))
+ strcpy(pszServiceName, pszService);
+ else
+ return EAI_FAIL;
+ }
+
+
+ // translate the address to a node name (if requested).
+ if (pszNodeName && tNodeLength)
+ {
+ // this is the IPv4-only version, so we have an IPv4 address.
+ tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;
+
+ if (iFlags & NI_NUMERICHOST)
+ {
+ // return numeric form of the address.
+ pszNode = inet_ntoa(tAddress);
+ }
+ else
+ {
+ // return node name corresponding to address.
+ ptHost = gethostbyaddr((char *) &tAddress,
+ sizeof(struct in_addr),
+ AF_INET);
+ if (ptHost && ptHost->h_name)
+ {
+ // DNS lookup successful.
+ // stop copying at a "." if NI_NOFQDN is specified.
+ pszNode = ptHost->h_name;
+ if ((iFlags & NI_NOFQDN) && (pc = strchr(pszNode, '.')))
+ *pc = '\0';
+ }
+ else
+ {
+ // DNS lookup failed. return numeric form of the address.
+ if (iFlags & NI_NAMEREQD)
+ {
+ switch (WSAGetLastError())
+ {
+ case WSAHOST_NOT_FOUND: return EAI_NONAME;
+ case WSATRY_AGAIN: return EAI_AGAIN;
+ case WSANO_RECOVERY: return EAI_FAIL;
+ default: return EAI_NONAME;
+ }
+ }
+ else
+ pszNode = inet_ntoa(tAddress);
+ }
+ }
+
+ if (tNodeLength > strlen(pszNode))
+ strcpy(pszNodeName, pszNode);
+ else
+ return EAI_FAIL;
+ }
+
+ return 0;
+}
+
+
+
+typedef struct
+{
+ char const *pszName;
+ FARPROC pfAddress;
+} WSPIAPI_FUNCTION;
+
+#define WSPIAPI_FUNCTION_ARRAY \
+{ \
+ "getaddrinfo", (FARPROC) WspiapiLegacyGetAddrInfo, \
+ "getnameinfo", (FARPROC) WspiapiLegacyGetNameInfo, \
+ "freeaddrinfo", (FARPROC) WspiapiLegacyFreeAddrInfo, \
+}
+
+
+
+__inline
+FARPROC
+WINAPI
+WspiapiLoad(
+ IN WORD wFunction)
+/*++
+
+Routine Description
+ try to locate the address family independent name resolution routines
+ (i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).
+
+Locks
+ this function call is not synchronized. hence the library containing
+ the routines might be loaded multiple times. another option is to
+ synchronize through a spin lock using a static local variable and the
+ InterlockedExchange operation.
+
+
+Arguments
+ wFunction ordinal # of the function to get the pointer to
+ 0 getaddrinfo
+ 1 getnameinfo
+ 2 freeaddrinfo
+
+Return Value
+ address of the library/legacy routine
+
+--*/
+{
+ HMODULE hLibrary = NULL;
+
+ // these static variables store state across calls, across threads.
+ static BOOL bInitialized = FALSE;
+ static WSPIAPI_FUNCTION rgtGlobal[] = WSPIAPI_FUNCTION_ARRAY;
+ static const int iNumGlobal = (sizeof(rgtGlobal) /
+ sizeof(WSPIAPI_FUNCTION));
+
+ // we overwrite rgtGlobal only if all routines exist in library.
+ WSPIAPI_FUNCTION rgtLocal[] = WSPIAPI_FUNCTION_ARRAY;
+ FARPROC fScratch = NULL;
+ int i = 0;
+
+
+ if (bInitialized) // WspiapiLoad has already been called once
+ return (rgtGlobal[wFunction].pfAddress);
+
+ do // breakout loop
+ {
+ // in Whistler and beyond...
+ // the routines are present in the WinSock 2 library (ws2_32.dll).
+ // printf("Looking in ws2_32 for getaddrinfo...\n");
+ hLibrary = LoadLibraryA("ws2_32");
+ if (hLibrary != NULL)
+ {
+ fScratch = GetProcAddress(hLibrary, "getaddrinfo");
+ if (fScratch == NULL)
+ {
+ FreeLibrary(hLibrary);
+ hLibrary = NULL;
+ }
+ }
+ if (hLibrary != NULL)
+ break;
+
+
+ // in the IPv6 Technology Preview...
+ // the routines are present in the IPv6 WinSock library (wship6.dll).
+ // printf("Looking in wship6 for getaddrinfo...\n");
+ hLibrary = LoadLibraryA("wship6");
+ if (hLibrary != NULL)
+ {
+ fScratch = GetProcAddress(hLibrary, "getaddrinfo");
+ if (fScratch == NULL)
+ {
+ FreeLibrary(hLibrary);
+ hLibrary = NULL;
+ }
+ }
+ } while (FALSE);
+
+
+ if (hLibrary != NULL)
+ {
+ // use routines from this library...
+ // since getaddrinfo is here, we expect all routines to be here,
+ // but will fall back to IPv4-only if any of them is missing.
+ for (i = 0; i < iNumGlobal; i++)
+ {
+ rgtLocal[i].pfAddress
+ = GetProcAddress(hLibrary, rgtLocal[i].pszName);
+ if (rgtLocal[i].pfAddress == NULL)
+ {
+ FreeLibrary(hLibrary);
+ hLibrary = NULL;
+ break;
+ }
+ }
+
+ if (hLibrary != NULL)
+ {
+ // printf("found!\n");
+ for (i = 0; i < iNumGlobal; i++)
+ rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;
+ }
+ }
+
+ bInitialized = TRUE;
+ return (rgtGlobal[wFunction].pfAddress);
+}
+
+
+
+__inline
+int
+WINAPI
+WspiapiGetAddrInfo(
+ IN const char *nodename,
+ IN const char *servname,
+ IN const struct addrinfo *hints,
+ OUT struct addrinfo **res)
+{
+ static WSPIAPI_PGETADDRINFO pfGetAddrInfo = NULL;
+
+ if (!pfGetAddrInfo)
+ pfGetAddrInfo = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);
+ return ((*pfGetAddrInfo)
+ (nodename, servname, hints, res));
+}
+
+
+
+__inline
+int
+WINAPI
+WspiapiGetNameInfo (
+ IN const struct sockaddr *sa,
+ IN socklen_t salen,
+ OUT char *host,
+ IN size_t hostlen,
+ OUT char *serv,
+ IN size_t servlen,
+ IN int flags)
+{
+ static WSPIAPI_PGETNAMEINFO pfGetNameInfo = NULL;
+
+ if (!pfGetNameInfo)
+ pfGetNameInfo = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);
+ return ((*pfGetNameInfo)
+ (sa, salen, host, hostlen, serv, servlen, flags));
+}
+
+
+
+__inline
+void
+WINAPI
+WspiapiFreeAddrInfo (
+ IN struct addrinfo *ai)
+{
+ static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo = NULL;
+
+ if (!pfFreeAddrInfo)
+ pfFreeAddrInfo = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);
+ (*pfFreeAddrInfo)(ai);
+}
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif // _WSPIAPI_H_