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