blob: fab5e8cfc11cdff8de2db1f160a111fa680b9eb4 [file] [log] [blame]
/**
* This file has no copyright assigned and is placed in the Public Domain.
* This file is part of the w64 mingw-runtime package.
* No warranty is given; refer to the file DISCLAIMER within this package.
*/
#ifndef _WSPIAPI_H_
#define _WSPIAPI_H_
#include <stdio.h>
#include <stdlib.h>
#include <malloc.h>
#include <string.h>
#include <ws2tcpip.h>
#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))
#ifndef _WSPIAPI_COUNTOF
#ifndef __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
typedef int (WINAPI *WSPIAPI_PGETADDRINFO)(const char *nodename,const char *servname,const struct addrinfo *hints,struct addrinfo **res);
typedef int (WINAPI *WSPIAPI_PGETNAMEINFO)(const struct sockaddr *sa,socklen_t salen,char *host,size_t hostlen,char *serv,size_t servlen,int flags);
typedef void (WINAPI *WSPIAPI_PFREEADDRINFO)(struct addrinfo *ai);
#ifdef __cplusplus
extern "C" {
#endif
__CRT_INLINE char *WINAPI WspiapiStrdup (const char *pszString) {
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;
}
__CRT_INLINE WINBOOL WINAPI WspiapiParseV4Address (const char *pszAddress,PDWORD pdwAddress) {
DWORD dwAddress = 0;
const char *pcNext = NULL;
int iCount = 0;
for(pcNext = pszAddress;*pcNext!='\0';pcNext++)
if(*pcNext=='.') iCount++;
if(iCount!=3) return FALSE;
dwAddress = inet_addr(pszAddress);
if(dwAddress==INADDR_NONE) return FALSE;
*pdwAddress = dwAddress;
return TRUE;
}
__CRT_INLINE struct addrinfo *WINAPI WspiapiNewAddrInfo (int iSocketType,int iProtocol,WORD wPort,DWORD dwAddress) {
struct addrinfo *ptNew;
struct sockaddr_in *ptAddress;
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;
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;
}
__CRT_INLINE int WINAPI WspiapiQueryDNS(const char *pszNodeName,int iSocketType,int iProtocol,WORD wPort,char pszAlias[NI_MAXHOST],struct addrinfo **pptResult) {
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++) {
*pptNext = WspiapiNewAddrInfo(iSocketType,iProtocol,wPort,((struct in_addr *) *ppAddresses)->s_addr);
if(!*pptNext) return EAI_MEMORY;
pptNext = &((*pptNext)->ai_next);
}
}
_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;
}
}
__CRT_INLINE int WINAPI WspiapiLookupNode(const char *pszNodeName,int iSocketType,int iProtocol,WORD wPort,WINBOOL bAI_CANONNAME,struct addrinfo **pptResult) {
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(*pptResult) break;
if((!strlen(pszAlias)) || (!strcmp(pszName,pszAlias)) || (++iAliasCount==16)) {
iError = EAI_FAIL;
break;
}
WspiapiSwap(pszName,pszAlias,pszScratch);
}
if(!iError && bAI_CANONNAME) {
(*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);
if(!(*pptResult)->ai_canonname) iError = EAI_MEMORY;
}
return iError;
}
__CRT_INLINE int WINAPI WspiapiClone (WORD wPort,struct addrinfo *ptResult) {
struct addrinfo *ptNext = NULL;
struct addrinfo *ptNew = NULL;
for(ptNext = ptResult; ptNext!=NULL;) {
ptNew = WspiapiNewAddrInfo(SOCK_DGRAM,ptNext->ai_protocol,wPort,((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);
if(!ptNew) break;
ptNew->ai_next = ptNext->ai_next;
ptNext->ai_next = ptNew;
ptNext = ptNew->ai_next;
}
if(ptNext!=NULL) return EAI_MEMORY;
return 0;
}
__CRT_INLINE void WINAPI WspiapiLegacyFreeAddrInfo (struct addrinfo *ptHead) {
struct addrinfo *ptNext;
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);
}
}
__CRT_INLINE int WINAPI WspiapiLegacyGetAddrInfo(const char *pszNodeName,const char *pszServiceName,const struct addrinfo *ptHints,struct addrinfo **pptResult) {
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;
WINBOOL bClone = FALSE;
WORD wTcpPort = 0;
WORD wUdpPort = 0;
*pptResult = NULL;
if((!pszNodeName) && (!pszServiceName)) return EAI_NONAME;
if(ptHints) {
if((ptHints->ai_addrlen!=0) || (ptHints->ai_canonname!=NULL) || (ptHints->ai_addr!=NULL) || (ptHints->ai_next!=NULL)) return EAI_FAIL;
iFlags = ptHints->ai_flags;
if((iFlags & AI_CANONNAME) && !pszNodeName) return EAI_BADFLAGS;
iFamily = ptHints->ai_family;
if((iFamily!=PF_UNSPEC) && (iFamily!=PF_INET)) return EAI_FAMILY;
iSocketType = ptHints->ai_socktype;
if((iSocketType!=0) && (iSocketType!=SOCK_STREAM) && (iSocketType!=SOCK_DGRAM) && (iSocketType!=SOCK_RAW)) return EAI_SOCKTYPE;
iProtocol = ptHints->ai_protocol;
}
if(pszServiceName) {
wPort = (WORD) strtoul(pszServiceName,&pc,10);
if(*pc=='\0') {
wPort = wTcpPort = wUdpPort = htons(wPort);
if(iSocketType==0) {
bClone = TRUE;
iSocketType = SOCK_STREAM;
}
} else {
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;
}
if(wPort==0) return (iSocketType ? EAI_SERVICE : EAI_NONAME);
if(iSocketType==0) {
iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;
bClone = (wTcpPort && wUdpPort);
}
}
}
if((!pszNodeName) || (WspiapiParseV4Address(pszNodeName,&dwAddress))) {
if(!pszNodeName) {
dwAddress = htonl((iFlags & AI_PASSIVE) ? INADDR_ANY : INADDR_LOOPBACK);
}
*pptResult = WspiapiNewAddrInfo(iSocketType,iProtocol,wPort,dwAddress);
if(!(*pptResult)) iError = EAI_MEMORY;
if(!iError && pszNodeName) {
(*pptResult)->ai_flags |= AI_NUMERICHOST;
if(iFlags & AI_CANONNAME) {
(*pptResult)->ai_canonname =
WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));
if(!(*pptResult)->ai_canonname) iError = EAI_MEMORY;
}
}
} else if(iFlags & AI_NUMERICHOST) iError = EAI_NONAME;
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);
}
__CRT_INLINE int WINAPI WspiapiLegacyGetNameInfo(const struct sockaddr *ptSocketAddress,socklen_t tSocketLength,char *pszNodeName,size_t tNodeLength,char *pszServiceName,size_t tServiceLength,int iFlags) {
struct servent *ptService;
WORD wPort;
char szBuffer[] = "65535";
char *pszService = szBuffer;
struct hostent *ptHost;
struct in_addr tAddress;
char *pszNode = NULL;
char *pc = NULL;
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;
if((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD)) return EAI_BADFLAGS;
if(pszServiceName && tServiceLength) {
wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;
if(iFlags & NI_NUMERICSERV) {
_WSPIAPI_SPRINTF_S_1(szBuffer,_WSPIAPI_COUNTOF(szBuffer),"%u",ntohs(wPort));
} else {
ptService = getservbyport(wPort,(iFlags & NI_DGRAM) ? "udp" : NULL);
if(ptService && ptService->s_name) {
pszService = ptService->s_name;
} else {
_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;
}
if(pszNodeName && tNodeLength) {
tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;
if(iFlags & NI_NUMERICHOST) {
pszNode = inet_ntoa(tAddress);
} else {
ptHost = gethostbyaddr((char *) &tAddress,sizeof(struct in_addr),AF_INET);
if(ptHost && ptHost->h_name) {
pszNode = ptHost->h_name;
if((iFlags & NI_NOFQDN) && ((pc = strchr(pszNode,'.'))!=NULL)) *pc = '\0';
} else {
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,}
__CRT_INLINE FARPROC WINAPI WspiapiLoad(WORD wFunction) {
HMODULE hLibrary = NULL;
static WINBOOL bInitialized = FALSE;
static WSPIAPI_FUNCTION rgtGlobal[] = WSPIAPI_FUNCTION_ARRAY;
static const int iNumGlobal = (sizeof(rgtGlobal) / sizeof(WSPIAPI_FUNCTION));
WSPIAPI_FUNCTION rgtLocal[] = WSPIAPI_FUNCTION_ARRAY;
FARPROC fScratch = NULL;
int i = 0;
if(bInitialized) return (rgtGlobal[wFunction].pfAddress);
for(;;) {
CHAR SystemDir[MAX_PATH + 1];
CHAR Path[MAX_PATH + 8];
if(GetSystemDirectoryA(SystemDir,MAX_PATH)==0) break;
_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) {
FreeLibrary(hLibrary);
hLibrary = NULL;
}
}
if(hLibrary!=NULL) break;
_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) {
FreeLibrary(hLibrary);
hLibrary = NULL;
}
}
break;
}
if(hLibrary!=NULL) {
for(i = 0;i < iNumGlobal;i++) {
rgtLocal[i].pfAddress = GetProcAddress(hLibrary,rgtLocal[i].pszName);
if(!(rgtLocal[i].pfAddress)) {
FreeLibrary(hLibrary);
hLibrary = NULL;
break;
}
}
if(hLibrary!=NULL) {
for(i = 0;i < iNumGlobal;i++)
rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;
}
}
bInitialized = TRUE;
return (rgtGlobal[wFunction].pfAddress);
}
__CRT_INLINE int WINAPI WspiapiGetAddrInfo(const char *nodename,const char *servname,const struct addrinfo *hints,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;
}
__CRT_INLINE int WINAPI WspiapiGetNameInfo (const struct sockaddr *sa,socklen_t salen,char *host,size_t hostlen,char *serv,size_t servlen,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;
}
__CRT_INLINE void WINAPI WspiapiFreeAddrInfo (struct addrinfo *ai) {
static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo = NULL;
if(!pfFreeAddrInfo) pfFreeAddrInfo = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);
(*pfFreeAddrInfo)(ai);
}
#ifdef __cplusplus
}
#endif
#endif