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