3
Copyright (c) 2000, Microsoft Corporation
9
The file contains protocol independent API functions.
12
Wed Jul 12 10:50:31 2000, Created
19
#include <stdio.h> // sprintf()
20
#include <stdlib.h> // calloc(), strtoul()
21
#include <malloc.h> // calloc()
22
#include <string.h> // strlen(), strcmp(), strstr()
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
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);
37
typedef int (WINAPI *WSPIAPI_PGETNAMEINFO) (
38
IN const struct sockaddr *sa,
46
typedef void (WINAPI *WSPIAPI_PFREEADDRINFO) (
47
IN struct addrinfo *ai);
55
////////////////////////////////////////////////////////////
56
// v4 only versions of getaddrinfo and friends.
57
// NOTE: gai_strerror is inlined in ws2tcpip.h
58
////////////////////////////////////////////////////////////
64
IN const char * pszString)
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.
72
pszString string to copy into new memory
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.
85
pszMemory = (char *) WspiapiMalloc(strlen(pszString) + 1);
89
return(strcpy(pszMemory, pszString));
97
WspiapiParseV4Address (
98
IN const char * pszAddress,
99
OUT PDWORD pdwAddress)
103
get the IPv4 address (in network byte order) from its string
104
representation. the syntax should be a.b.c.d.
107
pszArgument string representation of the IPv4 address
108
ptAddress pointer to the resulting IPv4 address
111
Returns FALSE if there is an error, TRUE for success.
116
const char *pcNext = NULL;
119
// ensure there are 3 '.' (periods)
120
for (pcNext = pszAddress; *pcNext != '\0'; pcNext++)
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)
132
*pdwAddress = dwAddress;
149
allocate an addrinfo structure and populate fields.
150
IPv4 specific internal function, not exported.
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).
159
returns an addrinfo struct, or NULL if out of memory.
163
struct addrinfo *ptNew;
164
struct sockaddr_in *ptAddress;
166
// allocate a new addrinfo structure.
168
(struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo));
173
(struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in));
179
ptAddress->sin_family = AF_INET;
180
ptAddress->sin_port = wPort;
181
ptAddress->sin_addr.s_addr = dwAddress;
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;
199
IN const char *pszNodeName,
204
OUT struct addrinfo **pptResult)
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.
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.
221
Returns 0 on success, an EAI_* style error value otherwise.
225
struct addrinfo **pptNext = pptResult;
226
struct hostent *ptHost = NULL;
232
ptHost = gethostbyname(pszNodeName);
235
if ((ptHost->h_addrtype == AF_INET) &&
236
(ptHost->h_length == sizeof(struct in_addr)))
238
for (ppAddresses = ptHost->h_addr_list;
239
*ppAddresses != NULL;
242
// create an addrinfo structure...
243
*pptNext = WspiapiNewAddrInfo(
247
((struct in_addr *) *ppAddresses)->s_addr);
251
pptNext = &((*pptNext)->ai_next);
255
// pick up the canonical name.
256
strcpy(pszAlias, ptHost->h_name);
260
switch (WSAGetLastError())
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;
276
IN const char *pszNodeName,
280
IN BOOL bAI_CANONNAME,
281
OUT struct addrinfo **pptResult)
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.
289
NOTE: if bAI_CANONNAME is true, the canonical name should be
290
returned in the first addrinfo structure.
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.
301
Returns 0 on success, an EAI_* style error value otherwise.
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);
317
iError = WspiapiQueryDNS(pszNodeName,
326
// if we found addresses, then we are done.
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))
340
// there was a new CNAME, look again.
341
WspiapiSwap(pszName, pszAlias, pszScratch);
344
if (!iError && bAI_CANONNAME)
346
(*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);
347
if (!(*pptResult)->ai_canonname)
361
IN struct addrinfo *ptResult)
365
clone every addrinfo structure in ptResult for the UDP service.
366
ptResult would need to be freed if an error is returned.
369
wPort port number of UDP service.
370
ptResult list of addrinfo structures, each
371
of whose node needs to be cloned.
374
Returns 0 on success, an EAI_MEMORY on allocation failure.
378
struct addrinfo *ptNext = NULL;
379
struct addrinfo *ptNew = NULL;
381
for (ptNext = ptResult; ptNext != NULL; )
383
// create an addrinfo structure...
384
ptNew = WspiapiNewAddrInfo(
388
((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);
392
// link the cloned addrinfo
393
ptNew->ai_next = ptNext->ai_next;
394
ptNext->ai_next = ptNew;
395
ptNext = ptNew->ai_next;
409
WspiapiLegacyFreeAddrInfo (
410
IN struct addrinfo *ptHead)
414
Free an addrinfo structure (or chain of structures).
415
As specified in RFC 2553, Section 6.4.
418
ptHead structure (chain) to free
422
struct addrinfo *ptNext; // next strcture to free
424
for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead)
426
if (ptNext->ai_canonname)
427
WspiapiFree(ptNext->ai_canonname);
430
WspiapiFree(ptNext->ai_addr);
432
ptHead = ptNext->ai_next;
442
WspiapiLegacyGetAddrInfo(
443
IN const char *pszNodeName,
444
IN const char *pszServiceName,
445
IN const struct addrinfo *ptHints,
446
OUT struct addrinfo **pptResult)
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.
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.
461
returns zero if successful, an EAI_* error code if not.
467
int iFamily = PF_UNSPEC;
473
struct servent *ptService = NULL;
480
// initialize pptResult with default return value.
484
////////////////////////////////////////
485
// validate arguments...
488
// both the node name and the service name can't be NULL.
489
if ((!pszNodeName) && (!pszServiceName))
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))
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.
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)
515
// we only support a limited number of protocol families.
516
iFamily = ptHints->ai_family;
517
if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
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))
528
// REVIEW: What if ai_socktype and ai_protocol are at odds?
529
iProtocol = ptHints->ai_protocol;
533
////////////////////////////////////////
534
// do service lookup...
538
wPort = (WORD) strtoul(pszServiceName, &pc, 10);
539
if (*pc == '\0') // numeric port string
541
wPort = wTcpPort = wUdpPort = htons(wPort);
542
if (iSocketType == 0)
545
iSocketType = SOCK_STREAM;
548
else // non numeric port string
550
if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
552
ptService = getservbyname(pszServiceName, "udp");
554
wPort = wUdpPort = ptService->s_port;
557
if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
559
ptService = getservbyname(pszServiceName, "tcp");
561
wPort = wTcpPort = ptService->s_port;
564
// assumes 0 is an invalid service port...
565
if (wPort == 0) // no service exists
566
return (iSocketType ? EAI_SERVICE : EAI_NONAME);
568
if (iSocketType == 0)
570
// if both tcp and udp, process tcp now & clone udp later.
571
iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;
572
bClone = (wTcpPort && wUdpPort);
579
////////////////////////////////////////
580
// do node name lookup...
582
// if we weren't given a node name,
583
// return the wildcard or loopback address (depending on AI_PASSIVE).
585
// if we have a numeric host address string,
586
// return the binary address.
588
if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress)))
592
dwAddress = htonl((iFlags & AI_PASSIVE)
597
// create an addrinfo structure...
599
WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
603
if (!iError && pszNodeName)
605
// implementation specific behavior: set AI_NUMERICHOST
606
// to indicate that we got a numeric host address string.
607
(*pptResult)->ai_flags |= AI_NUMERICHOST;
609
// return the numeric address string as the canonical name
610
if (iFlags & AI_CANONNAME)
612
(*pptResult)->ai_canonname =
613
WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));
614
if (!(*pptResult)->ai_canonname)
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)
629
// since we have a non-numeric node name,
630
// we have to do a regular node name lookup.
633
iError = WspiapiLookupNode(pszNodeName,
637
(iFlags & AI_CANONNAME),
641
if (!iError && bClone)
643
iError = WspiapiClone(wUdpPort, *pptResult);
648
WspiapiLegacyFreeAddrInfo(*pptResult);
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,
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.
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_*.
685
returns zero if successful, an EAI_* error code if not.
689
struct servent *ptService;
691
char szBuffer[] = "65535";
692
char *pszService = szBuffer;
694
struct hostent *ptHost;
695
struct in_addr tAddress;
696
char *pszNode = NULL;
700
// sanity check ptSocketAddress and tSocketLength.
701
if (!ptSocketAddress)
704
if ((ptSocketAddress->sa_family != AF_INET) ||
705
(tSocketLength != sizeof(struct sockaddr_in)))
710
if (!(pszNodeName && tNodeLength) &&
711
!(pszServiceName && tServiceLength))
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))
725
// translate the port to a service name (if requested).
726
if (pszServiceName && tServiceLength)
728
wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;
730
if (iFlags & NI_NUMERICSERV)
732
// return numeric form of the address.
733
sprintf(szBuffer, "%u", ntohs(wPort));
737
// return service name corresponding to port.
738
ptService = getservbyport(wPort,
739
(iFlags & NI_DGRAM) ? "udp" : NULL);
740
if (ptService && ptService->s_name)
742
// lookup successful.
743
pszService = ptService->s_name;
747
// DRAFT: return numeric form of the port!
748
sprintf(szBuffer, "%u", ntohs(wPort));
753
if (tServiceLength > strlen(pszService))
754
strcpy(pszServiceName, pszService);
760
// translate the address to a node name (if requested).
761
if (pszNodeName && tNodeLength)
763
// this is the IPv4-only version, so we have an IPv4 address.
764
tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;
766
if (iFlags & NI_NUMERICHOST)
768
// return numeric form of the address.
769
pszNode = inet_ntoa(tAddress);
773
// return node name corresponding to address.
774
ptHost = gethostbyaddr((char *) &tAddress,
775
sizeof(struct in_addr),
777
if (ptHost && ptHost->h_name)
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, '.')))
787
// DNS lookup failed. return numeric form of the address.
788
if (iFlags & NI_NAMEREQD)
790
switch (WSAGetLastError())
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;
799
pszNode = inet_ntoa(tAddress);
803
if (tNodeLength > strlen(pszNode))
804
strcpy(pszNodeName, pszNode);
820
#define WSPIAPI_FUNCTION_ARRAY \
822
"getaddrinfo", (FARPROC) WspiapiLegacyGetAddrInfo, \
823
"getnameinfo", (FARPROC) WspiapiLegacyGetNameInfo, \
824
"freeaddrinfo", (FARPROC) WspiapiLegacyFreeAddrInfo, \
837
try to locate the address family independent name resolution routines
838
(i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).
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.
848
wFunction ordinal # of the function to get the pointer to
854
address of the library/legacy routine
858
HMODULE hLibrary = NULL;
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));
866
// we overwrite rgtGlobal only if all routines exist in library.
867
WSPIAPI_FUNCTION rgtLocal[] = WSPIAPI_FUNCTION_ARRAY;
868
FARPROC fScratch = NULL;
872
if (bInitialized) // WspiapiLoad has already been called once
873
return (rgtGlobal[wFunction].pfAddress);
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)
883
fScratch = GetProcAddress(hLibrary, "getaddrinfo");
884
if (fScratch == NULL)
886
FreeLibrary(hLibrary);
890
if (hLibrary != NULL)
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)
900
fScratch = GetProcAddress(hLibrary, "getaddrinfo");
901
if (fScratch == NULL)
903
FreeLibrary(hLibrary);
910
if (hLibrary != NULL)
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++)
917
rgtLocal[i].pfAddress
918
= GetProcAddress(hLibrary, rgtLocal[i].pszName);
919
if (rgtLocal[i].pfAddress == NULL)
921
FreeLibrary(hLibrary);
927
if (hLibrary != NULL)
929
// printf("found!\n");
930
for (i = 0; i < iNumGlobal; i++)
931
rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;
936
return (rgtGlobal[wFunction].pfAddress);
945
IN const char *nodename,
946
IN const char *servname,
947
IN const struct addrinfo *hints,
948
OUT struct addrinfo **res)
950
static WSPIAPI_PGETADDRINFO pfGetAddrInfo = NULL;
953
pfGetAddrInfo = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);
954
return ((*pfGetAddrInfo)
955
(nodename, servname, hints, res));
964
IN const struct sockaddr *sa,
972
static WSPIAPI_PGETNAMEINFO pfGetNameInfo = NULL;
975
pfGetNameInfo = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);
976
return ((*pfGetNameInfo)
977
(sa, salen, host, hostlen, serv, servlen, flags));
985
WspiapiFreeAddrInfo (
986
IN struct addrinfo *ai)
988
static WSPIAPI_PFREEADDRINFO pfFreeAddrInfo = NULL;
991
pfFreeAddrInfo = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);
992
(*pfFreeAddrInfo)(ai);
999
#endif // _WSPIAPI_H_