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