xref: /reactos/sdk/include/psdk/wspiapi.h (revision 9393fc32)
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