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