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