add DX3 headers
[xonotic/xonotic.git] / misc / builddeps / dp.win32 / include / wspiapi.h
1 /*++\r
2 \r
3 Copyright (c) Microsoft Corporation. All rights reserved.\r
4 \r
5 Module Name:\r
6     wspiapi.h\r
7 \r
8 Abstract:\r
9     The file contains protocol independent API functions.\r
10 \r
11 Revision History:\r
12     Wed Jul 12 10:50:31 2000, Created\r
13 \r
14 --*/\r
15 \r
16 #ifndef _WSPIAPI_H_\r
17 #define _WSPIAPI_H_\r
18 \r
19 #pragma once\r
20 \r
21 #if (NTDDI_VERSION >= NTDDI_WIN2K)\r
22 \r
23 #include <stdio.h>              // sprintf()\r
24 #include <stdlib.h>             // calloc(), strtoul()\r
25 #include <malloc.h>             // calloc()\r
26 #include <string.h>             // strlen(), strcmp(), strstr()\r
27 \r
28 #if defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L\r
29 \r
30 #define _WSPIAPI_STRCPY_S strcpy_s\r
31 #define _WSPIAPI_STRCAT_S strcat_s\r
32 #define _WSPIAPI_STRNCPY_S strncpy_s\r
33 #define _WSPIAPI_SPRINTF_S_1 sprintf_s\r
34 \r
35 #else\r
36 \r
37 #define _WSPIAPI_STRCPY_S(_Dst, _Size, _Src) strcpy((_Dst), (_Src))\r
38 #define _WSPIAPI_STRCAT_S(_Dst, _Size, _Src) strcat((_Dst), (_Src))\r
39 #define _WSPIAPI_STRNCPY_S(_Dst, _Size, _Src, _Count) strncpy((_Dst), (_Src), (_Count)); (_Dst)[(_Size) - 1] = 0\r
40 #define _WSPIAPI_SPRINTF_S_1(_Dst, _Size, _Format, _Arg1) sprintf((_Dst), (_Format), (_Arg1))\r
41 \r
42 #endif // defined(__GOT_SECURE_LIB__) && __GOT_SECURE_LIB__ >= 200402L\r
43 \r
44 #if !defined(_WSPIAPI_COUNTOF)\r
45 #if !defined(__cplusplus)\r
46 #define _WSPIAPI_COUNTOF(_Array) (sizeof(_Array) / sizeof(_Array[0]))\r
47 #else\r
48 template <typename __CountofType, size_t _N>\r
49 char (&__wspiapi_countof_helper(__CountofType (&_Array)[_N]))[_N];\r
50 #define _WSPIAPI_COUNTOF(_Array) sizeof(__wspiapi_countof_helper(_Array))\r
51 #endif\r
52 #endif\r
53 \r
54 #define WspiapiMalloc(tSize)    calloc(1, (tSize))\r
55 #define WspiapiFree(p)          free(p)\r
56 #define WspiapiSwap(a, b, c)    { (c) = (a); (a) = (b); (b) = (c); }\r
57 #define getaddrinfo             WspiapiGetAddrInfo\r
58 #define getnameinfo             WspiapiGetNameInfo\r
59 #define freeaddrinfo            WspiapiFreeAddrInfo\r
60 \r
61 //\r
62 // These function pointers are also within the #if (NTDDI_VERSION >= WIN2K)\r
63 // because they are used by the other functions defined in this file available\r
64 // only on win2k and above.\r
65 //\r
66 typedef int (WINAPI *WSPIAPI_PGETADDRINFO) (\r
67     IN  const char                      *nodename,\r
68     IN  const char                      *servname,\r
69     IN  const struct addrinfo           *hints,\r
70     OUT struct addrinfo                 **res);\r
71 \r
72 typedef int (WINAPI *WSPIAPI_PGETNAMEINFO) (\r
73     IN  const struct sockaddr           *sa,\r
74     IN  socklen_t                       salen,\r
75     OUT char                            *host,\r
76     IN  size_t                          hostlen,\r
77     OUT char                            *serv,\r
78     IN  size_t                          servlen,\r
79     IN  int                             flags);\r
80 \r
81 typedef void (WINAPI *WSPIAPI_PFREEADDRINFO) (\r
82     IN  struct addrinfo                 *ai);\r
83 \r
84 \r
85 \r
86 #ifdef __cplusplus\r
87 extern "C" {\r
88 #endif\r
89     \r
90 ////////////////////////////////////////////////////////////\r
91 // v4 only versions of getaddrinfo and friends.\r
92 // NOTE: gai_strerror is inlined in ws2tcpip.h\r
93 ////////////////////////////////////////////////////////////\r
94 \r
95 __inline    \r
96 char *\r
97 WINAPI\r
98 WspiapiStrdup (\r
99         IN  const char *                    pszString)\r
100 /*++\r
101 \r
102 Routine Description\r
103     allocates enough storage via calloc() for a copy of the string,\r
104     copies the string into the new memory, and returns a pointer to it.\r
105 \r
106 Arguments\r
107     pszString       string to copy into new memory\r
108 \r
109 Return Value\r
110     a pointer to the newly allocated storage with the string in it.\r
111     NULL if enough memory could not be allocated, or string was NULL.\r
112 \r
113 --*/    \r
114 {\r
115     char    *pszMemory;\r
116     size_t  cchMemory;\r
117 \r
118     if (!pszString)\r
119         return(NULL);\r
120 \r
121     cchMemory = strlen(pszString) + 1;\r
122     pszMemory = (char *) WspiapiMalloc(cchMemory);\r
123     if (!pszMemory)\r
124         return(NULL);\r
125 \r
126     _WSPIAPI_STRCPY_S(pszMemory, cchMemory, pszString);\r
127     return pszMemory;\r
128 }\r
129 \r
130     \r
131     \r
132 __inline\r
133 BOOL\r
134 WINAPI\r
135 WspiapiParseV4Address (\r
136     IN  const char *                    pszAddress,\r
137     OUT PDWORD                          pdwAddress)\r
138 /*++\r
139 \r
140 Routine Description\r
141     get the IPv4 address (in network byte order) from its string\r
142     representation.  the syntax should be a.b.c.d.\r
143     \r
144 Arguments\r
145     pszArgument         string representation of the IPv4 address\r
146     ptAddress           pointer to the resulting IPv4 address\r
147 \r
148 Return Value\r
149     Returns FALSE if there is an error, TRUE for success.\r
150     \r
151 --*/\r
152 {\r
153     DWORD       dwAddress   = 0;\r
154     const char  *pcNext     = NULL;\r
155     int         iCount      = 0;\r
156 \r
157     // ensure there are 3 '.' (periods)\r
158     for (pcNext = pszAddress; *pcNext != '\0'; pcNext++)\r
159         if (*pcNext == '.')\r
160             iCount++;\r
161     if (iCount != 3)\r
162         return FALSE;\r
163 \r
164     // return an error if dwAddress is INADDR_NONE (255.255.255.255)\r
165     // since this is never a valid argument to getaddrinfo.\r
166     dwAddress = inet_addr(pszAddress);\r
167     if (dwAddress == INADDR_NONE)\r
168         return FALSE;\r
169 \r
170     *pdwAddress = dwAddress;\r
171     return TRUE;\r
172 }\r
173 \r
174 \r
175 \r
176 __inline\r
177 struct addrinfo *\r
178 WINAPI\r
179 WspiapiNewAddrInfo (\r
180     IN  int                             iSocketType,\r
181     IN  int                             iProtocol,\r
182     IN  WORD                            wPort,\r
183     IN  DWORD                           dwAddress)\r
184 /*++\r
185 \r
186 Routine Description\r
187     allocate an addrinfo structure and populate fields.\r
188     IPv4 specific internal function, not exported.\r
189     \r
190 Arguments\r
191     iSocketType         SOCK_*.  can be wildcarded (zero).\r
192     iProtocol           IPPROTO_*.  can be wildcarded (zero).\r
193     wPort               port number of service (in network order).\r
194     dwAddress           IPv4 address (in network order).\r
195     \r
196 Return Value\r
197     returns an addrinfo struct, or NULL if out of memory.\r
198 \r
199 --*/    \r
200 {\r
201     struct addrinfo     *ptNew;\r
202     struct sockaddr_in  *ptAddress;\r
203 \r
204     // allocate a new addrinfo structure.\r
205     ptNew       =\r
206         (struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo));\r
207     if (!ptNew)\r
208         return NULL;\r
209 \r
210     ptAddress   =\r
211         (struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in));\r
212     if (!ptAddress)\r
213     {\r
214         WspiapiFree(ptNew);\r
215         return NULL;\r
216     }\r
217     ptAddress->sin_family       = AF_INET;\r
218     ptAddress->sin_port         = wPort;\r
219     ptAddress->sin_addr.s_addr  = dwAddress;\r
220     \r
221     // fill in the fields...\r
222     ptNew->ai_family            = PF_INET;\r
223     ptNew->ai_socktype          = iSocketType;\r
224     ptNew->ai_protocol          = iProtocol;\r
225     ptNew->ai_addrlen           = sizeof(struct sockaddr_in);\r
226     ptNew->ai_addr              = (struct sockaddr *) ptAddress;\r
227 \r
228     return ptNew;\r
229 }\r
230 \r
231 \r
232 \r
233 __inline\r
234 int\r
235 WINAPI\r
236 WspiapiQueryDNS(\r
237     IN  const char                      *pszNodeName,\r
238     IN  int                             iSocketType,\r
239     IN  int                             iProtocol,  \r
240     IN  WORD                            wPort,      \r
241     OUT char                            pszAlias[NI_MAXHOST],\r
242     OUT struct addrinfo                 **pptResult)\r
243 /*++\r
244 \r
245 Routine Description\r
246     helper routine for WspiapiLookupNode.\r
247     performs name resolution by querying the DNS for A records.\r
248     *pptResult would need to be freed if an error is returned.\r
249     \r
250 Arguments\r
251     pszNodeName         name of node to resolve.\r
252     iSocketType         SOCK_*.  can be wildcarded (zero).\r
253     iProtocol           IPPROTO_*.  can be wildcarded (zero).\r
254     wPort               port number of service (in network order).\r
255     pszAlias            where to return the alias.  must be of size NI_MAXHOST.\r
256     pptResult           where to return the result.\r
257     \r
258 Return Value\r
259     Returns 0 on success, an EAI_* style error value otherwise.\r
260 \r
261 --*/    \r
262 {\r
263     struct addrinfo **pptNext   = pptResult;\r
264     struct hostent  *ptHost     = NULL;\r
265     char            **ppAddresses;\r
266 \r
267     *pptNext    = NULL;\r
268     pszAlias[0] = '\0';\r
269 \r
270     ptHost = gethostbyname(pszNodeName);\r
271     if (ptHost)\r
272     {\r
273         if ((ptHost->h_addrtype == AF_INET)     &&\r
274             (ptHost->h_length   == sizeof(struct in_addr)))\r
275         {\r
276             for (ppAddresses    = ptHost->h_addr_list;\r
277                  *ppAddresses   != NULL;\r
278                  ppAddresses++)\r
279             {\r
280                 // create an addrinfo structure...\r
281                 *pptNext = WspiapiNewAddrInfo(\r
282                     iSocketType,\r
283                     iProtocol,\r
284                     wPort,\r
285                     ((struct in_addr *) *ppAddresses)->s_addr);\r
286                 if (!*pptNext)\r
287                     return EAI_MEMORY;\r
288 \r
289                 pptNext = &((*pptNext)->ai_next);\r
290             }\r
291         }\r
292 \r
293         // pick up the canonical name.\r
294         _WSPIAPI_STRNCPY_S(pszAlias, NI_MAXHOST, ptHost->h_name, NI_MAXHOST - 1);\r
295         \r
296         return 0;\r
297     }\r
298     \r
299     switch (WSAGetLastError())\r
300     {\r
301         case WSAHOST_NOT_FOUND: return EAI_NONAME;\r
302         case WSATRY_AGAIN:      return EAI_AGAIN;\r
303         case WSANO_RECOVERY:    return EAI_FAIL;\r
304         case WSANO_DATA:        return EAI_NODATA;\r
305         default:                return EAI_NONAME;\r
306     }\r
307 }\r
308 \r
309 \r
310 \r
311 __inline\r
312 int\r
313 WINAPI\r
314 WspiapiLookupNode(\r
315     IN  const char                      *pszNodeName,\r
316     IN  int                             iSocketType,\r
317     IN  int                             iProtocol,  \r
318     IN  WORD                            wPort,      \r
319     IN  BOOL                            bAI_CANONNAME,\r
320     OUT struct addrinfo                 **pptResult)\r
321 /*++\r
322 \r
323 Routine Description\r
324     resolve a nodename and return a list of addrinfo structures.\r
325     IPv4 specific internal function, not exported.\r
326     *pptResult would need to be freed if an error is returned.\r
327     \r
328     NOTE: if bAI_CANONNAME is true, the canonical name should be\r
329           returned in the first addrinfo structure.\r
330     \r
331 Arguments\r
332     pszNodeName         name of node to resolve.\r
333     iSocketType         SOCK_*.  can be wildcarded (zero).\r
334     iProtocol           IPPROTO_*.  can be wildcarded (zero).\r
335     wPort               port number of service (in network order).\r
336     bAI_CANONNAME       whether the AI_CANONNAME flag is set.\r
337     pptResult           where to return result.\r
338     \r
339 Return Value\r
340     Returns 0 on success, an EAI_* style error value otherwise.\r
341 \r
342 --*/\r
343 {\r
344     int     iError              = 0;\r
345     int     iAliasCount         = 0;\r
346 \r
347     char    szFQDN1[NI_MAXHOST] = "";\r
348     char    szFQDN2[NI_MAXHOST] = "";\r
349     char    *pszName            = szFQDN1;\r
350     char    *pszAlias           = szFQDN2;\r
351     char    *pszScratch         = NULL;\r
352     _WSPIAPI_STRNCPY_S(pszName, NI_MAXHOST, pszNodeName, NI_MAXHOST - 1);\r
353     \r
354     for (;;)\r
355     {\r
356         iError = WspiapiQueryDNS(pszNodeName,\r
357                                  iSocketType,\r
358                                  iProtocol,\r
359                                  wPort,\r
360                                  pszAlias,\r
361                                  pptResult);\r
362         if (iError)\r
363             break;\r
364 \r
365         // if we found addresses, then we are done.\r
366         if (*pptResult)\r
367             break;\r
368 \r
369         // stop infinite loops due to DNS misconfiguration.  there appears\r
370         // to be no particular recommended limit in RFCs 1034 and 1035.\r
371         if ((!strlen(pszAlias))             ||\r
372             (!strcmp(pszName, pszAlias))    ||\r
373             (++iAliasCount == 16))\r
374         {\r
375             iError = EAI_FAIL;\r
376             break;\r
377         }\r
378 \r
379         // there was a new CNAME, look again.\r
380         WspiapiSwap(pszName, pszAlias, pszScratch);\r
381     }\r
382 \r
383     if (!iError && bAI_CANONNAME)\r
384     {\r
385         (*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);\r
386         if (!(*pptResult)->ai_canonname)\r
387             iError = EAI_MEMORY;\r
388     }\r
389 \r
390     return iError;\r
391 }\r
392 \r
393 \r
394 \r
395 __inline\r
396 int\r
397 WINAPI\r
398 WspiapiClone (\r
399     IN  WORD                            wPort,      \r
400     IN  struct addrinfo                 *ptResult)\r
401 /*++\r
402 \r
403 Routine Description\r
404     clone every addrinfo structure in ptResult for the UDP service.\r
405     ptResult would need to be freed if an error is returned.\r
406     \r
407 Arguments\r
408     wPort               port number of UDP service.\r
409     ptResult            list of addrinfo structures, each\r
410                         of whose node needs to be cloned.\r
411 \r
412 Return Value\r
413     Returns 0 on success, an EAI_MEMORY on allocation failure.\r
414 \r
415 --*/\r
416 {\r
417     struct addrinfo *ptNext = NULL;\r
418     struct addrinfo *ptNew  = NULL;\r
419 \r
420     for (ptNext = ptResult; ptNext != NULL; )\r
421     {\r
422         // create an addrinfo structure...\r
423         ptNew = WspiapiNewAddrInfo(\r
424             SOCK_DGRAM,\r
425             ptNext->ai_protocol,\r
426             wPort,\r
427             ((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);\r
428         if (!ptNew)\r
429             break;\r
430 \r
431         // link the cloned addrinfo\r
432         ptNew->ai_next  = ptNext->ai_next;\r
433         ptNext->ai_next = ptNew;\r
434         ptNext          = ptNew->ai_next;\r
435     }\r
436 \r
437     if (ptNext != NULL)\r
438         return EAI_MEMORY;\r
439     \r
440     return 0;\r
441 }\r
442 \r
443 \r
444 \r
445 __inline\r
446 void\r
447 WINAPI\r
448 WspiapiLegacyFreeAddrInfo (\r
449     IN  struct addrinfo                 *ptHead)\r
450 /*++\r
451 \r
452 Routine Description\r
453     Free an addrinfo structure (or chain of structures).\r
454     As specified in RFC 2553, Section 6.4.\r
455     \r
456 Arguments\r
457     ptHead              structure (chain) to free\r
458     \r
459 --*/    \r
460 {\r
461     struct addrinfo *ptNext;    // next strcture to free\r
462 \r
463     for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead)\r
464     {\r
465         if (ptNext->ai_canonname)\r
466             WspiapiFree(ptNext->ai_canonname);\r
467         \r
468         if (ptNext->ai_addr)\r
469             WspiapiFree(ptNext->ai_addr);\r
470 \r
471         ptHead = ptNext->ai_next;\r
472         WspiapiFree(ptNext);\r
473     }\r
474 }\r
475 \r
476 \r
477 \r
478 __inline\r
479 int\r
480 WINAPI\r
481 WspiapiLegacyGetAddrInfo(\r
482     IN const char                       *pszNodeName,\r
483     IN const char                       *pszServiceName,\r
484     IN const struct addrinfo            *ptHints,\r
485     OUT struct addrinfo                 **pptResult)\r
486 /*++\r
487 \r
488 Routine Description\r
489     Protocol-independent name-to-address translation.\r
490     As specified in RFC 2553, Section 6.4.\r
491     This is the hacked version that only supports IPv4.\r
492     \r
493 Arguments\r
494     pszNodeName         node name to lookup.\r
495     pszServiceName      service name to lookup.\r
496     ptHints             hints about how to process request.\r
497     pptResult           where to return result.\r
498     \r
499 Return Value\r
500     returns zero if successful, an EAI_* error code if not.\r
501 \r
502 --*/    \r
503 {\r
504     int                 iError      = 0;\r
505     int                 iFlags      = 0;\r
506     int                 iFamily     = PF_UNSPEC;\r
507     int                 iSocketType = 0;\r
508     int                 iProtocol   = 0;\r
509     WORD                wPort       = 0;\r
510     DWORD               dwAddress   = 0;\r
511 \r
512     struct servent      *ptService  = NULL;\r
513     char                *pc         = NULL;\r
514     BOOL                bClone      = FALSE;\r
515     WORD                wTcpPort    = 0;\r
516     WORD                wUdpPort    = 0;\r
517     \r
518     \r
519     // initialize pptResult with default return value.\r
520     *pptResult  = NULL;\r
521 \r
522 \r
523     ////////////////////////////////////////\r
524     // validate arguments...\r
525     //\r
526     \r
527     // both the node name and the service name can't be NULL.\r
528     if ((!pszNodeName) && (!pszServiceName))\r
529         return EAI_NONAME;\r
530 \r
531     // validate hints.\r
532     if (ptHints)\r
533     {\r
534         // all members other than ai_flags, ai_family, ai_socktype\r
535         // and ai_protocol must be zero or a null pointer.\r
536         if ((ptHints->ai_addrlen    != 0)       ||\r
537             (ptHints->ai_canonname  != NULL)    ||\r
538             (ptHints->ai_addr       != NULL)    ||\r
539             (ptHints->ai_next       != NULL))\r
540         {\r
541             return EAI_FAIL;\r
542         }\r
543         \r
544         // the spec has the "bad flags" error code, so presumably we\r
545         // should check something here.  insisting that there aren't\r
546         // any unspecified flags set would break forward compatibility,\r
547         // however.  so we just check for non-sensical combinations.\r
548         //\r
549         // we cannot come up with a canonical name given a null node name.\r
550         iFlags      = ptHints->ai_flags;\r
551         if ((iFlags & AI_CANONNAME) && !pszNodeName)\r
552             return EAI_BADFLAGS;\r
553 \r
554         // we only support a limited number of protocol families.\r
555         iFamily     = ptHints->ai_family;\r
556         if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))\r
557             return EAI_FAMILY;\r
558 \r
559         // we only support only these socket types.\r
560         iSocketType = ptHints->ai_socktype;\r
561         if ((iSocketType != 0)                  &&\r
562             (iSocketType != SOCK_STREAM)        &&\r
563             (iSocketType != SOCK_DGRAM)         &&\r
564             (iSocketType != SOCK_RAW))\r
565             return EAI_SOCKTYPE;\r
566 \r
567         // REVIEW: What if ai_socktype and ai_protocol are at odds?\r
568         iProtocol   = ptHints->ai_protocol;\r
569     }\r
570 \r
571 \r
572     ////////////////////////////////////////\r
573     // do service lookup...\r
574 \r
575     if (pszServiceName)\r
576     {\r
577         wPort = (WORD) strtoul(pszServiceName, &pc, 10);\r
578         if (*pc == '\0')        // numeric port string\r
579         {\r
580             wPort = wTcpPort = wUdpPort = htons(wPort);\r
581             if (iSocketType == 0)\r
582             {\r
583                 bClone      = TRUE;\r
584                 iSocketType = SOCK_STREAM;\r
585             }\r
586         }\r
587         else                    // non numeric port string\r
588         {\r
589             if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))\r
590             {\r
591                 ptService = getservbyname(pszServiceName, "udp");\r
592                 if (ptService)\r
593                     wPort = wUdpPort = ptService->s_port;\r
594             }\r
595 \r
596             if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))\r
597             {\r
598                 ptService = getservbyname(pszServiceName, "tcp");\r
599                 if (ptService)\r
600                     wPort = wTcpPort = ptService->s_port;\r
601             }\r
602             \r
603             // assumes 0 is an invalid service port...\r
604             if (wPort == 0)     // no service exists\r
605                 return (iSocketType ? EAI_SERVICE : EAI_NONAME);\r
606 \r
607             if (iSocketType == 0)\r
608             {\r
609                 // if both tcp and udp, process tcp now & clone udp later.\r
610                 iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;\r
611                 bClone      = (wTcpPort && wUdpPort); \r
612             }\r
613         }\r
614     }\r
615     \r
616 \r
617 \r
618     ////////////////////////////////////////\r
619     // do node name lookup...\r
620 \r
621     // if we weren't given a node name,\r
622     // return the wildcard or loopback address (depending on AI_PASSIVE).\r
623     //\r
624     // if we have a numeric host address string,\r
625     // return the binary address.\r
626     //\r
627     if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress)))\r
628     {\r
629         if (!pszNodeName)\r
630         {\r
631             dwAddress = htonl((iFlags & AI_PASSIVE)\r
632                               ? INADDR_ANY\r
633                               : INADDR_LOOPBACK);\r
634         }\r
635         \r
636         // create an addrinfo structure...\r
637         *pptResult =\r
638             WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);\r
639         if (!(*pptResult))\r
640             iError = EAI_MEMORY;\r
641         \r
642         if (!iError && pszNodeName)\r
643         {\r
644             // implementation specific behavior: set AI_NUMERICHOST\r
645             // to indicate that we got a numeric host address string.\r
646             (*pptResult)->ai_flags |= AI_NUMERICHOST;\r
647             \r
648             // return the numeric address string as the canonical name\r
649             if (iFlags & AI_CANONNAME)\r
650             {\r
651                 (*pptResult)->ai_canonname =\r
652                     WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));\r
653                 if (!(*pptResult)->ai_canonname)        \r
654                     iError = EAI_MEMORY;\r
655             }\r
656         }\r
657     }\r
658 \r
659 \r
660     // if we do not have a numeric host address string and\r
661     // AI_NUMERICHOST flag is set, return an error!\r
662     else if (iFlags & AI_NUMERICHOST)\r
663     {\r
664         iError = EAI_NONAME;\r
665     }\r
666     \r
667 \r
668     // since we have a non-numeric node name,\r
669     // we have to do a regular node name lookup.\r
670     else\r
671     {\r
672         iError = WspiapiLookupNode(pszNodeName,\r
673                                    iSocketType,\r
674                                    iProtocol,\r
675                                    wPort,\r
676                                    (iFlags & AI_CANONNAME),\r
677                                    pptResult);\r
678     }\r
679 \r
680     if (!iError && bClone)\r
681     {\r
682         iError = WspiapiClone(wUdpPort, *pptResult);\r
683     }\r
684 \r
685     if (iError)\r
686     {\r
687         WspiapiLegacyFreeAddrInfo(*pptResult);\r
688         *pptResult  = NULL;        \r
689     }\r
690 \r
691     return (iError);\r
692 }\r
693 \r
694 \r
695 \r
696 __inline\r
697 int\r
698 WINAPI\r
699 WspiapiLegacyGetNameInfo(\r
700     IN  const struct sockaddr           *ptSocketAddress,\r
701     IN  socklen_t                       tSocketLength,\r
702     OUT char                            *pszNodeName,\r
703     IN  size_t                          tNodeLength,\r
704     OUT char                            *pszServiceName,\r
705     IN  size_t                          tServiceLength,\r
706     IN  int                             iFlags)\r
707 /*++\r
708 \r
709 Routine Description\r
710     protocol-independent address-to-name translation.\r
711     as specified in RFC 2553, Section 6.5.\r
712     this is the hacked version that only supports IPv4.\r
713     \r
714 Arguments\r
715     ptSocketAddress     socket address to translate.\r
716     tSocketLength       length of above socket address.\r
717     pszNodeName         where to return the node name.\r
718     tNodeLength         size of above buffer.\r
719     pszServiceName      where to return the service name.\r
720     tServiceLength      size of above buffer.\r
721     iFlags              flags of type NI_*.\r
722     \r
723 Return Value\r
724     returns zero if successful, an EAI_* error code if not.\r
725 \r
726 --*/    \r
727 {\r
728     struct servent  *ptService;\r
729     WORD            wPort;    \r
730     char            szBuffer[]  = "65535";\r
731     char            *pszService = szBuffer;\r
732 \r
733     struct hostent  *ptHost;\r
734     struct in_addr  tAddress;\r
735     char            *pszNode    = NULL;\r
736     char            *pc         = NULL;\r
737     \r
738 \r
739     // sanity check ptSocketAddress and tSocketLength.\r
740     if ((!ptSocketAddress) || (tSocketLength < sizeof(struct sockaddr)))\r
741         return EAI_FAIL;\r
742     \r
743     if (ptSocketAddress->sa_family != AF_INET)\r
744         return EAI_FAMILY;\r
745 \r
746     if (tSocketLength < sizeof(struct sockaddr_in))\r
747         return EAI_FAIL;\r
748     \r
749     if (!(pszNodeName && tNodeLength) &&\r
750         !(pszServiceName && tServiceLength))\r
751     {\r
752         return EAI_NONAME;    \r
753     }\r
754 \r
755     // the draft has the "bad flags" error code, so presumably we\r
756     // should check something here.  insisting that there aren't\r
757     // any unspecified flags set would break forward compatibility,\r
758     // however.  so we just check for non-sensical combinations.\r
759     if ((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD))\r
760     {                                                                       \r
761         return EAI_BADFLAGS;\r
762     }\r
763         \r
764     // translate the port to a service name (if requested).\r
765     if (pszServiceName && tServiceLength)\r
766     {\r
767         wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;\r
768         \r
769         if (iFlags & NI_NUMERICSERV)\r
770         {\r
771             // return numeric form of the address.\r
772             _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(szBuffer), "%u", ntohs(wPort));\r
773         }\r
774         else\r
775         {\r
776             // return service name corresponding to port.\r
777             ptService = getservbyport(wPort,\r
778                                       (iFlags & NI_DGRAM) ? "udp" : NULL);\r
779             if (ptService && ptService->s_name)\r
780             {\r
781                 // lookup successful.\r
782                 pszService = ptService->s_name;\r
783             }\r
784             else\r
785             {\r
786                 // DRAFT: return numeric form of the port!\r
787                 _WSPIAPI_SPRINTF_S_1(szBuffer, _WSPIAPI_COUNTOF(szBuffer), "%u", ntohs(wPort));\r
788             }\r
789         }\r
790         \r
791         \r
792         if (tServiceLength > strlen(pszService))\r
793             _WSPIAPI_STRCPY_S(pszServiceName, tServiceLength, pszService);\r
794         else\r
795             return EAI_FAIL;\r
796     }\r
797 \r
798     \r
799     // translate the address to a node name (if requested).\r
800     if (pszNodeName && tNodeLength)\r
801     {    \r
802         // this is the IPv4-only version, so we have an IPv4 address.\r
803         tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;\r
804 \r
805         if (iFlags & NI_NUMERICHOST)\r
806         {\r
807             // return numeric form of the address.\r
808             pszNode  = inet_ntoa(tAddress);\r
809         }\r
810         else\r
811         {\r
812             // return node name corresponding to address.\r
813             ptHost = gethostbyaddr((char *) &tAddress,\r
814                                    sizeof(struct in_addr),\r
815                                    AF_INET);\r
816             if (ptHost && ptHost->h_name)\r
817             {\r
818                 // DNS lookup successful.\r
819                 // stop copying at a "." if NI_NOFQDN is specified.\r
820                 pszNode = ptHost->h_name;\r
821                 if ((iFlags & NI_NOFQDN) &&\r
822                     ((pc = strchr(pszNode, '.')) != NULL))\r
823                     *pc = '\0';\r
824             }\r
825             else\r
826             {\r
827                 // DNS lookup failed.  return numeric form of the address.\r
828                 if (iFlags & NI_NAMEREQD)\r
829                 {\r
830                     switch (WSAGetLastError())\r
831                     {\r
832                         case WSAHOST_NOT_FOUND: return EAI_NONAME;\r
833                         case WSATRY_AGAIN:      return EAI_AGAIN;\r
834                         case WSANO_RECOVERY:    return EAI_FAIL;\r
835                         default:                return EAI_NONAME;\r
836                     }\r
837                 }\r
838                 else\r
839                     pszNode  = inet_ntoa(tAddress);\r
840             }\r
841         }\r
842 \r
843         if (tNodeLength > strlen(pszNode))\r
844             _WSPIAPI_STRCPY_S(pszNodeName, tNodeLength, pszNode);\r
845         else\r
846             return EAI_FAIL;\r
847     }\r
848 \r
849     return 0;\r
850 }\r
851 \r
852 \r
853 \r
854 typedef struct \r
855 {\r
856     char const          *pszName;\r
857     FARPROC             pfAddress;\r
858 } WSPIAPI_FUNCTION;\r
859 \r
860 #define WSPIAPI_FUNCTION_ARRAY                                  \\r
861 {                                                               \\r
862     "getaddrinfo",      (FARPROC) WspiapiLegacyGetAddrInfo,     \\r
863     "getnameinfo",      (FARPROC) WspiapiLegacyGetNameInfo,     \\r
864     "freeaddrinfo",     (FARPROC) WspiapiLegacyFreeAddrInfo,    \\r
865 }\r
866 \r
867 \r
868 \r
869 __inline\r
870 FARPROC\r
871 WINAPI\r
872 WspiapiLoad(\r
873     IN  WORD                            wFunction)\r
874 /*++\r
875 \r
876 Routine Description\r
877     try to locate the address family independent name resolution routines\r
878     (i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).\r
879     \r
880 Locks\r
881     this function call is not synchronized.  hence the library containing\r
882     the routines might be loaded multiple times.  another option is to\r
883     synchronize through a spin lock using a static local variable and the\r
884     InterlockedExchange operation.  \r
885 \r
886     \r
887 Arguments\r
888     wFunction           ordinal # of the function to get the pointer to\r
889                         0   getaddrinfo\r
890                         1   getnameinfo\r
891                         2   freeaddrinfo\r
892     \r
893 Return Value\r
894     address of the library/legacy routine\r
895 \r
896 --*/\r
897 {\r
898     HMODULE                 hLibrary        = NULL;\r
899 \r
900     // these static variables store state across calls, across threads.\r
901     static BOOL             bInitialized    = FALSE;\r
902     static WSPIAPI_FUNCTION rgtGlobal[]     = WSPIAPI_FUNCTION_ARRAY;\r
903     static const int        iNumGlobal      = (sizeof(rgtGlobal) /\r
904                                                sizeof(WSPIAPI_FUNCTION));\r
905     \r
906     // we overwrite rgtGlobal only if all routines exist in library.\r
907     WSPIAPI_FUNCTION        rgtLocal[]      = WSPIAPI_FUNCTION_ARRAY;\r
908     FARPROC                 fScratch        = NULL;\r
909     int                     i               = 0;\r
910     \r
911     \r
912     if (bInitialized)           // WspiapiLoad has already been called once\r
913         return (rgtGlobal[wFunction].pfAddress);\r
914 \r
915     for (;;)                    // breakout loop\r
916     {\r
917         CHAR SystemDir[MAX_PATH + 1];\r
918         CHAR Path[MAX_PATH + 8];\r
919 \r
920         if (GetSystemDirectoryA(SystemDir, MAX_PATH) == 0) \r
921         {\r
922             break;\r
923         }\r
924 \r
925         // in Whistler and beyond...\r
926         // the routines are present in the WinSock 2 library (ws2_32.dll).\r
927         // printf("Looking in ws2_32 for getaddrinfo...\n");\r
928         _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir);\r
929         _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\ws2_32");\r
930         hLibrary = LoadLibraryA(Path);\r
931         if (hLibrary != NULL)\r
932         {\r
933             fScratch = GetProcAddress(hLibrary, "getaddrinfo");\r
934             if (fScratch == NULL)\r
935             {\r
936                 FreeLibrary(hLibrary);\r
937                 hLibrary = NULL;\r
938             }\r
939         }\r
940         if (hLibrary != NULL)\r
941             break;\r
942         \r
943 \r
944         // in the IPv6 Technology Preview...        \r
945         // the routines are present in the IPv6 WinSock library (wship6.dll).\r
946         // printf("Looking in wship6 for getaddrinfo...\n");\r
947         _WSPIAPI_STRCPY_S(Path, _WSPIAPI_COUNTOF(Path), SystemDir);\r
948         _WSPIAPI_STRCAT_S(Path, _WSPIAPI_COUNTOF(Path), "\\wship6");\r
949         hLibrary = LoadLibraryA(Path);\r
950         if (hLibrary != NULL)\r
951         {\r
952             fScratch = GetProcAddress(hLibrary, "getaddrinfo");\r
953             if (fScratch == NULL)\r
954             {\r
955                 FreeLibrary(hLibrary);\r
956                 hLibrary = NULL;\r
957             }\r
958         }\r
959 \r
960         break;\r
961     }\r
962 \r
963 \r
964     if (hLibrary != NULL)\r
965     {\r
966         // use routines from this library...\r
967         // since getaddrinfo is here, we expect all routines to be here,\r
968         // but will fall back to IPv4-only if any of them is missing.\r
969         for (i = 0; i < iNumGlobal; i++)\r
970         {\r
971             rgtLocal[i].pfAddress\r
972                 = GetProcAddress(hLibrary, rgtLocal[i].pszName);\r
973             if (rgtLocal[i].pfAddress == NULL)\r
974             {\r
975                 FreeLibrary(hLibrary);\r
976                 hLibrary = NULL;\r
977                 break;\r
978             }\r
979         }\r
980 \r
981         if (hLibrary != NULL)\r
982         {\r
983             // printf("found!\n");\r
984             for (i = 0; i < iNumGlobal; i++)\r
985                 rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;\r
986         }\r
987     }\r
988     \r
989     bInitialized = TRUE;\r
990     return (rgtGlobal[wFunction].pfAddress);\r
991 }\r
992 \r
993 \r
994 \r
995 __inline\r
996 int\r
997 WINAPI\r
998 WspiapiGetAddrInfo(\r
999     IN const char                       *nodename,\r
1000     IN const char                       *servname,\r
1001     IN const struct addrinfo            *hints,\r
1002     OUT struct addrinfo                 **res)\r
1003 {\r
1004     int                             iError;\r
1005     static WSPIAPI_PGETADDRINFO     pfGetAddrInfo   = NULL;\r
1006     \r
1007     if (!pfGetAddrInfo)\r
1008         pfGetAddrInfo   = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);\r
1009 \r
1010     iError = (*pfGetAddrInfo)(nodename, servname, hints, res);\r
1011     WSASetLastError(iError);\r
1012     return iError;\r
1013 }\r
1014 \r
1015 \r
1016 \r
1017 __inline\r
1018 int\r
1019 WINAPI\r
1020 WspiapiGetNameInfo (\r
1021     IN  const struct sockaddr           *sa,\r
1022     IN  socklen_t                       salen,\r
1023     OUT char                            *host,\r
1024     IN  size_t                          hostlen,\r
1025     OUT char                            *serv,\r
1026     IN  size_t                          servlen,\r
1027     IN  int                             flags)\r
1028 {\r
1029     int                             iError;\r
1030     static WSPIAPI_PGETNAMEINFO     pfGetNameInfo   = NULL;\r
1031     \r
1032     if (!pfGetNameInfo)\r
1033         pfGetNameInfo   = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);\r
1034 \r
1035     iError = (*pfGetNameInfo)(sa, salen, host, hostlen, serv, servlen, flags);\r
1036     WSASetLastError(iError);\r
1037     return iError;\r
1038 }\r
1039 \r
1040 \r
1041 \r
1042 __inline\r
1043 void\r
1044 WINAPI\r
1045 WspiapiFreeAddrInfo (\r
1046     IN  struct addrinfo                 *ai)\r
1047 {\r
1048     static WSPIAPI_PFREEADDRINFO    pfFreeAddrInfo   = NULL;\r
1049 \r
1050     if (!pfFreeAddrInfo)\r
1051         pfFreeAddrInfo  = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);\r
1052     (*pfFreeAddrInfo)(ai);\r
1053 }\r
1054 \r
1055 #ifdef  __cplusplus\r
1056 }\r
1057 #endif\r
1058 \r
1059 #endif // if (NTDDI_VERSION >= WIN2K)\r
1060 #endif // _WSPIAPI_H_\r
1061 \r