-/*++\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
+/*++
+
+Copyright (c) Microsoft Corporation. All rights reserved.
+
+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_
+
+#pragma once
+
+#if (NTDDI_VERSION >= NTDDI_WIN2K)
+
+#include <stdio.h> // sprintf()
+#include <stdlib.h> // calloc(), strtoul()
+#include <malloc.h> // calloc()
+#include <string.h> // strlen(), strcmp(), strstr()
+
+#if defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L
+
+#define _WSPIAPI_STRCPY_S strcpy_s
+#define _WSPIAPI_STRCAT_S strcat_s
+#define _WSPIAPI_STRNCPY_S strncpy_s
+#define _WSPIAPI_SPRINTF_S_1 sprintf_s
+
+#else
+
+#define _WSPIAPI_STRCPY_S(_Dst, _Size, _Src) strcpy((_Dst), (_Src))
+#define _WSPIAPI_STRCAT_S(_Dst, _Size, _Src) strcat((_Dst), (_Src))
+#define _WSPIAPI_STRNCPY_S(_Dst, _Size, _Src, _Count) strncpy((_Dst), (_Src), (_Count)); (_Dst)[(_Size) - 1] = 0
+#define _WSPIAPI_SPRINTF_S_1(_Dst, _Size, _Format, _Arg1) sprintf((_Dst), (_Format), (_Arg1))
+
+#endif // defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L
+
+#if !defined(_WSPIAPI_COUNTOF)
+#if !defined(__cplusplus)
+#define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))
+#else
+template <typename __CountofType, size_t _N>
+char (&__wspiapi_countof_helper(__CountofType (&_Array)[_N]))[_N];
+#define _WSPIAPI_COUNTOF(_Array) sizeof(__wspiapi_countof_helper(_Array))
+#endif
+#endif
+
+#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
+
+//
+// These function pointers are also within the #if (NTDDI_VERSION >= WIN2K)
+// because they are used by the other functions defined in this file available
+// only on win2k and above.
+//
+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;
+ size_t cchMemory;
+
+ if (!pszString)
+ return(NULL);
+
+ cchMemory = strlen(pszString) + 1;
+ pszMemory = (char *) WspiapiMalloc(cchMemory);
+ if (!pszMemory)
+ return(NULL);
+
+ _WSPIAPI_STRCPY_S(pszMemory, cchMemory, pszString);
+ return pszMemory;
+}
+
+
+
+__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[NI_MAXHOST],
+ 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. must be of size NI_MAXHOST.
+ 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.
+ _WSPIAPI_STRNCPY_S(pszAlias, NI_MAXHOST, ptHost->h_name, NI_MAXHOST - 1);
+
+ 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;
+ _WSPIAPI_STRNCPY_S(pszName, NI_MAXHOST, pszNodeName, NI_MAXHOST - 1);
+
+ 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) || (tSocketLength < sizeof(struct sockaddr)))
+ return EAI_FAIL;
+
+ if (ptSocketAddress->sa_family != AF_INET)
+ return EAI_FAMILY;
+
+ if (tSocketLength < sizeof(struct sockaddr_in))
+ return EAI_FAIL;
+
+ 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.
+ _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(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!
+ _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(szBuffer), "%u", ntohs(wPort));
+ }
+ }
+
+
+ if (tServiceLength > strlen(pszService))
+ _WSPIAPI_STRCPY_S(pszServiceName, tServiceLength, 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, '.')) != NULL))
+ *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))
+ _WSPIAPI_STRCPY_S(pszNodeName, tNodeLength, 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);
+
+ for (;;) // breakout loop
+ {
+ CHAR SystemDir[MAX_PATH + 1];
+ CHAR Path[MAX_PATH + 8];
+
+ if (GetSystemDirectoryA(SystemDir, MAX_PATH) == 0)
+ {
+ break;
+ }
+
+ // in Whistler and beyond...
+ // the routines are present in the WinSock 2 library (ws2_32.dll).
+ // printf("Looking in ws2_32 for getaddrinfo...\n");
+ _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir);
+ _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\ws2_32");
+ hLibrary = LoadLibraryA(Path);
+ 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");
+ _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir);
+ _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\wship6");
+ hLibrary = LoadLibraryA(Path);
+ if (hLibrary != NULL)
+ {
+ fScratch = GetProcAddress(hLibrary, "getaddrinfo");
+ if (fScratch == NULL)
+ {
+ FreeLibrary(hLibrary);
+ hLibrary = NULL;
+ }
+ }
+
+ break;
+ }
+
+
+ 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)
+{
+ int iError;
+ static WSPIAPI_PGETADDRINFO pfGetAddrInfo = NULL;
+
+ if (!pfGetAddrInfo)
+ pfGetAddrInfo = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);
+
+ iError = (*pfGetAddrInfo)(nodename, servname, hints, res);
+ WSASetLastError(iError);
+ return iError;
+}
+
+
+
+__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)
+{
+ int iError;
+ static WSPIAPI_PGETNAMEINFO pfGetNameInfo = NULL;
+
+ if (!pfGetNameInfo)
+ pfGetNameInfo = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);
+
+ iError = (*pfGetNameInfo)(sa, salen, host, hostlen, serv, servlen, flags);
+ WSASetLastError(iError);
+ return iError;
+}
+
+
+
+__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 // if (NTDDI_VERSION >= WIN2K)
+#endif // _WSPIAPI_H_
+