1 #pragma once 2 3 #ifdef __cplusplus 4 extern "C" { 5 #endif 6 7 #if (NTDDI_VERSION >= NTDDI_WIN2K) 8 9 #include <stdio.h> 10 #include <stdlib.h> 11 #include <malloc.h> 12 #include <string.h> 13 14 #if defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L 15 16 #define _WSPIAPI_STRCPY_S strcpy_s 17 #define _WSPIAPI_STRCAT_S strcat_s 18 19 #else 20 21 #define _WSPIAPI_STRCPY_S(_Dst, _Size, _Src) strcpy((_Dst), (_Src)) 22 #define _WSPIAPI_STRCAT_S(_Dst, _Size, _Src) strcat((_Dst), (_Src)) 23 24 #endif /* defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L */ 25 26 #define _WSPIAPI_STRNCPY_S(_Dst, _Size, _Src, _Count) strncpy((_Dst), (_Src), (_Count)); (_Dst)[(_Size) - 1] = 0 //FIXME 27 #define _WSPIAPI_SPRINTF_S_1(_Dst, _Size, _Format, _Arg1) sprintf((_Dst), (_Format), (_Arg1)) //FIXME 28 29 #if !defined(_WSPIAPI_COUNTOF) 30 31 #if !defined(__cplusplus) 32 #define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0])) 33 #else 34 template <typename __CountofType, size_t _N> 35 char (&__wspiapi_countof_helper(__CountofType (&_Array)[_N]))[_N]; 36 #define _WSPIAPI_COUNTOF(_Array) sizeof(__wspiapi_countof_helper(_Array)) 37 #endif 38 39 #endif /* !defined(_WSPIAPI_COUNTOF) */ 40 41 #define WspiapiMalloc(tSize) calloc(1, (tSize)) 42 #define WspiapiFree(p) free(p) 43 #define WspiapiSwap(a, b, c) {(c) = (a); (a) = (b); (b) = (c);} 44 #define getaddrinfo WspiapiGetAddrInfo 45 #define getnameinfo WspiapiGetNameInfo 46 #define freeaddrinfo WspiapiFreeAddrInfo 47 48 #if _MSC_VER 49 #define WSPIAPI_INLINE __inline 50 #else 51 #define WSPIAPI_INLINE static inline 52 #endif 53 54 typedef int 55 (WINAPI *WSPIAPI_PGETADDRINFO)( 56 IN const char *nodename, 57 IN const char *servname, 58 IN const struct addrinfo *hints, 59 OUT struct addrinfo **res); 60 61 typedef int 62 (WINAPI *WSPIAPI_PGETNAMEINFO)( 63 IN const struct sockaddr *sa, 64 IN socklen_t salen, 65 OUT char *host, 66 IN size_t hostlen, 67 OUT char *serv, 68 IN size_t servlen, 69 IN int flags); 70 71 typedef void 72 (WINAPI *WSPIAPI_PFREEADDRINFO)( 73 IN struct addrinfo *ai); 74 75 FORCEINLINE 76 char * 77 WINAPI 78 WspiapiStrdup( 79 IN const char *pszString) 80 { 81 char *pszMemory; 82 size_t cchMemory; 83 84 if (!pszString) return(NULL); 85 cchMemory = strlen(pszString) + 1; 86 pszMemory = (char *) WspiapiMalloc(cchMemory); 87 if (!pszMemory) return(NULL); 88 _WSPIAPI_STRCPY_S(pszMemory, cchMemory, pszString); 89 return pszMemory; 90 } 91 92 FORCEINLINE 93 BOOL 94 WINAPI 95 WspiapiParseV4Address( 96 IN const char *pszAddress, 97 OUT PDWORD pdwAddress) 98 { 99 DWORD dwAddress = 0; 100 const char *pcNext = NULL; 101 int iCount = 0; 102 103 for (pcNext = pszAddress; *pcNext != '\0'; pcNext++) 104 if (*pcNext == '.') iCount++; 105 if (iCount != 3) return FALSE; 106 dwAddress = inet_addr(pszAddress); 107 if (dwAddress == INADDR_NONE) return FALSE; 108 *pdwAddress = dwAddress; 109 return TRUE; 110 } 111 112 FORCEINLINE 113 struct addrinfo * 114 WINAPI 115 WspiapiNewAddrInfo( 116 IN int iSocketType, 117 IN int iProtocol, 118 IN WORD wPort, 119 IN DWORD dwAddress) 120 { 121 struct addrinfo *ptNew; 122 struct sockaddr_in *ptAddress; 123 124 ptNew = (struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo)); 125 if (!ptNew) return NULL; 126 ptAddress = (struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in)); 127 if (!ptAddress) { 128 WspiapiFree(ptNew); 129 return NULL; 130 } 131 ptAddress->sin_family = AF_INET; 132 ptAddress->sin_port = wPort; 133 ptAddress->sin_addr.s_addr = dwAddress; 134 ptNew->ai_family = PF_INET; 135 ptNew->ai_socktype = iSocketType; 136 ptNew->ai_protocol = iProtocol; 137 ptNew->ai_addrlen = sizeof(struct sockaddr_in); 138 ptNew->ai_addr = (struct sockaddr *) ptAddress; 139 140 return ptNew; 141 } 142 143 FORCEINLINE 144 int 145 WINAPI 146 WspiapiQueryDNS( 147 IN const char *pszNodeName, 148 IN int iSocketType, 149 IN int iProtocol, 150 IN WORD wPort, 151 OUT char pszAlias[NI_MAXHOST], 152 OUT struct addrinfo **pptResult) 153 { 154 struct addrinfo **pptNext = pptResult; 155 struct hostent *ptHost = NULL; 156 char **ppAddresses; 157 158 *pptNext = NULL; 159 pszAlias[0] = '\0'; 160 161 ptHost = gethostbyname(pszNodeName); 162 if (ptHost) { 163 if ((ptHost->h_addrtype == AF_INET) && (ptHost->h_length == sizeof(struct in_addr))) { 164 for (ppAddresses = ptHost->h_addr_list; *ppAddresses != NULL; ppAddresses++) { 165 *pptNext = WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, ((struct in_addr *) *ppAddresses)->s_addr); 166 if (!*pptNext) return EAI_MEMORY; 167 pptNext = &((*pptNext)->ai_next); 168 } 169 } 170 _WSPIAPI_STRNCPY_S(pszAlias, NI_MAXHOST, ptHost->h_name, NI_MAXHOST - 1); 171 return 0; 172 } 173 switch (WSAGetLastError()) { 174 case WSAHOST_NOT_FOUND: return EAI_NONAME; 175 case WSATRY_AGAIN: return EAI_AGAIN; 176 case WSANO_RECOVERY: return EAI_FAIL; 177 case WSANO_DATA: return EAI_NODATA; 178 default: return EAI_NONAME; 179 } 180 } 181 182 FORCEINLINE 183 int 184 WINAPI 185 WspiapiLookupNode( 186 IN const char *pszNodeName, 187 IN int iSocketType, 188 IN int iProtocol, 189 IN WORD wPort, 190 IN BOOL bAI_CANONNAME, 191 OUT struct addrinfo **pptResult) 192 { 193 int iError = 0; 194 int iAliasCount = 0; 195 char szFQDN1[NI_MAXHOST] = ""; 196 char szFQDN2[NI_MAXHOST] = ""; 197 char *pszName = szFQDN1; 198 char *pszAlias = szFQDN2; 199 char *pszScratch = NULL; 200 201 _WSPIAPI_STRNCPY_S(pszName, NI_MAXHOST, pszNodeName, NI_MAXHOST - 1); 202 for (;;) { 203 iError = WspiapiQueryDNS(pszNodeName, iSocketType, iProtocol, wPort, pszAlias, pptResult); 204 if (iError) break; 205 if (*pptResult) break; 206 if ((!strlen(pszAlias)) || (!strcmp(pszName, pszAlias)) || (++iAliasCount == 16)) { 207 iError = EAI_FAIL; 208 break; 209 } 210 WspiapiSwap(pszName, pszAlias, pszScratch); 211 } 212 if (!iError && bAI_CANONNAME) { 213 (*pptResult)->ai_canonname = WspiapiStrdup(pszAlias); 214 if (!(*pptResult)->ai_canonname) iError = EAI_MEMORY; 215 } 216 217 return iError; 218 } 219 220 221 222 FORCEINLINE 223 int 224 WINAPI 225 WspiapiClone( 226 IN WORD wPort, 227 IN struct addrinfo *ptResult) 228 { 229 struct addrinfo *ptNext = NULL; 230 struct addrinfo *ptNew = NULL; 231 232 for (ptNext = ptResult; ptNext != NULL; ) { 233 ptNew = WspiapiNewAddrInfo(SOCK_DGRAM, ptNext->ai_protocol, wPort, 234 ((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr); 235 if (!ptNew) break; 236 ptNew->ai_next = ptNext->ai_next; 237 ptNext->ai_next = ptNew; 238 ptNext = ptNew->ai_next; 239 } 240 if (ptNext != NULL) return EAI_MEMORY; 241 242 return 0; 243 } 244 245 static __inline 246 void 247 WINAPI 248 WspiapiLegacyFreeAddrInfo( 249 IN struct addrinfo *ptHead) 250 { 251 struct addrinfo *ptNext; 252 253 for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead) { 254 if (ptNext->ai_canonname) WspiapiFree(ptNext->ai_canonname); 255 if (ptNext->ai_addr) WspiapiFree(ptNext->ai_addr); 256 ptHead = ptNext->ai_next; 257 WspiapiFree(ptNext); 258 } 259 } 260 261 static __inline 262 int 263 WINAPI 264 WspiapiLegacyGetAddrInfo( 265 IN const char *pszNodeName, 266 IN const char *pszServiceName, 267 IN const struct addrinfo *ptHints, 268 OUT struct addrinfo **pptResult) 269 { 270 int iError = 0; 271 int iFlags = 0; 272 int iFamily = PF_UNSPEC; 273 int iSocketType = 0; 274 int iProtocol = 0; 275 WORD wPort = 0; 276 DWORD dwAddress = 0; 277 struct servent *ptService = NULL; 278 char *pc = NULL; 279 BOOL bClone = FALSE; 280 WORD wTcpPort = 0; 281 WORD wUdpPort = 0; 282 *pptResult = NULL; 283 284 if ((!pszNodeName) && (!pszServiceName)) return EAI_NONAME; 285 if (ptHints) { 286 if ((ptHints->ai_addrlen != 0) || 287 (ptHints->ai_canonname != NULL) || 288 (ptHints->ai_addr != NULL) || 289 (ptHints->ai_next != NULL)) { 290 return EAI_FAIL; 291 } 292 iFlags = ptHints->ai_flags; 293 if ((iFlags & AI_CANONNAME) && !pszNodeName) return EAI_BADFLAGS; 294 iFamily = ptHints->ai_family; 295 if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET)) return EAI_FAMILY; 296 iSocketType = ptHints->ai_socktype; 297 if ((iSocketType != 0) && 298 (iSocketType != SOCK_STREAM) && 299 (iSocketType != SOCK_DGRAM) && 300 (iSocketType != SOCK_RAW)) 301 return EAI_SOCKTYPE; 302 iProtocol = ptHints->ai_protocol; 303 } 304 if (pszServiceName) { 305 wPort = (WORD) strtoul(pszServiceName, &pc, 10); 306 if (*pc == '\0') { 307 wPort = wTcpPort = wUdpPort = htons(wPort); 308 if (iSocketType == 0) { 309 bClone = TRUE; 310 iSocketType = SOCK_STREAM; 311 } 312 } 313 else { 314 if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM)) { 315 ptService = getservbyname(pszServiceName, "udp"); 316 if (ptService) wPort = wUdpPort = ptService->s_port; 317 } 318 if ((iSocketType == 0) || (iSocketType == SOCK_STREAM)) { 319 ptService = getservbyname(pszServiceName, "tcp"); 320 if (ptService) wPort = wTcpPort = ptService->s_port; 321 } 322 if (wPort == 0) return (iSocketType ? EAI_SERVICE : EAI_NONAME); 323 if (iSocketType == 0) { 324 iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM; 325 bClone = (wTcpPort && wUdpPort); 326 } 327 } 328 } 329 if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress))) { 330 if (!pszNodeName) dwAddress = htonl((iFlags & AI_PASSIVE) ? INADDR_ANY : INADDR_LOOPBACK); 331 *pptResult = WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress); 332 if (!(*pptResult)) iError = EAI_MEMORY; 333 if (!iError && pszNodeName) { 334 (*pptResult)->ai_flags |= AI_NUMERICHOST; 335 if (iFlags & AI_CANONNAME) { 336 (*pptResult)->ai_canonname = WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress))); 337 if (!(*pptResult)->ai_canonname) iError = EAI_MEMORY; 338 } 339 } 340 } 341 else if (iFlags & AI_NUMERICHOST) { 342 iError = EAI_NONAME; 343 } 344 else { 345 iError = WspiapiLookupNode(pszNodeName, iSocketType, 346 iProtocol, wPort, 347 (iFlags & AI_CANONNAME), 348 pptResult); 349 } 350 if (!iError && bClone) { 351 iError = WspiapiClone(wUdpPort, *pptResult); 352 } 353 if (iError) { 354 WspiapiLegacyFreeAddrInfo(*pptResult); 355 *pptResult = NULL; 356 } 357 358 return (iError); 359 } 360 361 static __inline 362 int 363 WINAPI 364 WspiapiLegacyGetNameInfo( 365 IN const struct sockaddr *ptSocketAddress, 366 IN socklen_t tSocketLength, 367 OUT char *pszNodeName, 368 IN size_t tNodeLength, 369 OUT char *pszServiceName, 370 IN size_t tServiceLength, 371 IN int iFlags) 372 { 373 struct servent *ptService; 374 WORD wPort; 375 char szBuffer[] = "65535"; 376 char *pszService = szBuffer; 377 struct hostent *ptHost; 378 struct in_addr tAddress; 379 char *pszNode = NULL; 380 char *pc = NULL; 381 382 if ((!ptSocketAddress) || (tSocketLength < sizeof(struct sockaddr))) return EAI_FAIL; 383 if (ptSocketAddress->sa_family != AF_INET) return EAI_FAMILY; 384 if (tSocketLength < sizeof(struct sockaddr_in)) return EAI_FAIL; 385 if (!(pszNodeName && tNodeLength) && !(pszServiceName && tServiceLength)) { 386 return EAI_NONAME; 387 } 388 if ((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD)) { 389 return EAI_BADFLAGS; 390 } 391 if (pszServiceName && tServiceLength) { 392 wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port; 393 if (iFlags & NI_NUMERICSERV) { 394 _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(szBuffer), "%u", ntohs(wPort)); 395 } 396 else { 397 ptService = getservbyport(wPort, (iFlags & NI_DGRAM) ? "udp" : NULL); 398 if (ptService && ptService->s_name) { 399 pszService = ptService->s_name; 400 } 401 else { 402 _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(szBuffer), "%u", ntohs(wPort)); 403 } 404 } 405 if (tServiceLength > strlen(pszService)) 406 _WSPIAPI_STRCPY_S(pszServiceName, tServiceLength, pszService); 407 else return EAI_FAIL; 408 } 409 if (pszNodeName && tNodeLength) { 410 tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr; 411 if (iFlags & NI_NUMERICHOST) { 412 pszNode = inet_ntoa(tAddress); 413 } 414 else { 415 ptHost = gethostbyaddr((char *) &tAddress, sizeof(struct in_addr), AF_INET); 416 if (ptHost && ptHost->h_name) { 417 pszNode = ptHost->h_name; 418 if ((iFlags & NI_NOFQDN) && ((pc = strchr(pszNode, '.')) != NULL)) *pc = '\0'; 419 } 420 else { 421 if (iFlags & NI_NAMEREQD) { 422 switch (WSAGetLastError()) { 423 case WSAHOST_NOT_FOUND: return EAI_NONAME; 424 case WSATRY_AGAIN: return EAI_AGAIN; 425 case WSANO_RECOVERY: return EAI_FAIL; 426 default: return EAI_NONAME; 427 } 428 } 429 else pszNode = inet_ntoa(tAddress); 430 } 431 } 432 if (tNodeLength > strlen(pszNode)) _WSPIAPI_STRCPY_S(pszNodeName, tNodeLength, pszNode); 433 else return EAI_FAIL; 434 } 435 436 return 0; 437 } 438 439 typedef struct { 440 char const *pszName; 441 FARPROC pfAddress; 442 } WSPIAPI_FUNCTION; 443 444 #define WSPIAPI_FUNCTION_ARRAY { \ 445 {"getaddrinfo", (FARPROC) WspiapiLegacyGetAddrInfo}, \ 446 {"getnameinfo", (FARPROC) WspiapiLegacyGetNameInfo}, \ 447 {"freeaddrinfo", (FARPROC) WspiapiLegacyFreeAddrInfo} \ 448 } 449 450 WSPIAPI_INLINE 451 FARPROC 452 WINAPI 453 WspiapiLoad( 454 IN WORD wFunction) 455 { 456 HMODULE hLibrary = NULL; 457 458 static BOOL bInitialized = FALSE; 459 static WSPIAPI_FUNCTION rgtGlobal[] = WSPIAPI_FUNCTION_ARRAY; 460 static const int iNumGlobal = (sizeof(rgtGlobal) / sizeof(WSPIAPI_FUNCTION)); 461 WSPIAPI_FUNCTION rgtLocal[] = WSPIAPI_FUNCTION_ARRAY; 462 FARPROC fScratch = NULL; 463 int i = 0; 464 465 if (bInitialized) return (rgtGlobal[wFunction].pfAddress); 466 for (;;) { 467 CHAR SystemDir[MAX_PATH + 1]; 468 CHAR Path[MAX_PATH + 8]; 469 if (GetSystemDirectoryA(SystemDir, MAX_PATH) == 0) break; 470 _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir); 471 _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\ws2_32"); 472 hLibrary = LoadLibraryA(Path); 473 if (hLibrary != NULL) { 474 fScratch = GetProcAddress(hLibrary, "getaddrinfo"); 475 if (fScratch == NULL) { 476 FreeLibrary(hLibrary); 477 hLibrary = NULL; 478 } 479 } 480 if (hLibrary != NULL) break; 481 _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir); 482 _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\wship6"); 483 hLibrary = LoadLibraryA(Path); 484 if (hLibrary != NULL) { 485 fScratch = GetProcAddress(hLibrary, "getaddrinfo"); 486 if (fScratch == NULL) { 487 FreeLibrary(hLibrary); 488 hLibrary = NULL; 489 } 490 } 491 break; 492 } 493 if (hLibrary != NULL) { 494 for (i = 0; i < iNumGlobal; i++) { 495 rgtLocal[i].pfAddress = GetProcAddress(hLibrary, rgtLocal[i].pszName); 496 if (rgtLocal[i].pfAddress == NULL) { 497 FreeLibrary(hLibrary); 498 hLibrary = NULL; 499 break; 500 } 501 } 502 if (hLibrary != NULL) { 503 for (i = 0; i < iNumGlobal; i++) 504 rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress; 505 } 506 } 507 bInitialized = TRUE; 508 509 return (rgtGlobal[wFunction].pfAddress); 510 } 511 512 WSPIAPI_INLINE 513 int 514 WINAPI 515 WspiapiGetAddrInfo( 516 IN const char *nodename OPTIONAL, 517 IN const char *servname OPTIONAL, 518 IN const struct addrinfo *hints OPTIONAL, 519 OUT struct addrinfo **res) 520 { 521 int iError; 522 static WSPIAPI_PGETADDRINFO pfGetAddrInfo = NULL; 523 524 if (!pfGetAddrInfo) pfGetAddrInfo = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0); 525 iError = (*pfGetAddrInfo)(nodename, servname, hints, res); 526 WSASetLastError(iError); 527 528 return iError; 529 } 530 531 WSPIAPI_INLINE 532 int 533 WINAPI 534 WspiapiGetNameInfo( 535 IN const struct sockaddr *sa, 536 IN socklen_t salen, 537 OUT char *host, 538 IN size_t hostlen, 539 OUT char *serv, 540 IN size_t servlen, 541 IN int flags) 542 { 543 int iError; 544 static WSPIAPI_PGETNAMEINFO pfGetNameInfo = NULL; 545 546 if (!pfGetNameInfo) pfGetNameInfo = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1); 547 iError = (*pfGetNameInfo)(sa, salen, host, hostlen, serv, servlen, flags); 548 WSASetLastError(iError); 549 550 return iError; 551 } 552 553 WSPIAPI_INLINE 554 void 555 WINAPI 556 WspiapiFreeAddrInfo( 557 IN struct addrinfo *ai) 558 { 559 static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo = NULL; 560 561 if (!pfFreeAddrInfo) pfFreeAddrInfo = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2); 562 (*pfFreeAddrInfo)(ai); 563 } 564 565 #endif /* (NTDDI_VERSION >= NTDDI_WIN2K) */ 566 567 #ifdef __cplusplus 568 } 569 #endif 570