include/wspiapi.h

00001 /*++
00002 
00003 Copyright (c) 2000, Microsoft Corporation
00004 
00005 Module Name:
00006     wspiapi.h
00007 
00008 Abstract:
00009     The file contains protocol independent API functions.
00010 
00011 Revision History:
00012     Wed Jul 12 10:50:31 2000, Created
00013 
00014 --*/
00015 
00016 #ifndef _WSPIAPI_H_
00017 #define _WSPIAPI_H_
00018 
00019 #include <stdio.h>              // sprintf()
00020 #include <stdlib.h>             // calloc(), strtoul()
00021 #include <malloc.h>             // calloc()
00022 #include <string.h>             // strlen(), strcmp(), strstr()
00023 
00024 #define WspiapiMalloc(tSize)    calloc(1, (tSize))
00025 #define WspiapiFree(p)          free(p)
00026 #define WspiapiSwap(a, b, c)    { (c) = (a); (a) = (b); (b) = (c); }
00027 #define getaddrinfo             WspiapiGetAddrInfo
00028 #define getnameinfo             WspiapiGetNameInfo
00029 #define freeaddrinfo            WspiapiFreeAddrInfo
00030 
00031 typedef int (WINAPI *WSPIAPI_PGETADDRINFO) (
00032     IN  const char                      *nodename,
00033     IN  const char                      *servname,
00034     IN  const struct addrinfo           *hints,
00035     OUT struct addrinfo                 **res);
00036 
00037 typedef int (WINAPI *WSPIAPI_PGETNAMEINFO) (
00038     IN  const struct sockaddr           *sa,
00039     IN  socklen_t                       salen,
00040     OUT char                            *host,
00041     IN  size_t                          hostlen,
00042     OUT char                            *serv,
00043     IN  size_t                          servlen,
00044     IN  int                             flags);
00045 
00046 typedef void (WINAPI *WSPIAPI_PFREEADDRINFO) (
00047     IN  struct addrinfo                 *ai);
00048 
00049 
00050 
00051 #ifdef __cplusplus
00052 extern "C" {
00053 #endif
00054 
00056 // v4 only versions of getaddrinfo and friends.
00057 // NOTE: gai_strerror is inlined in ws2tcpip.h
00059 
00060 __inline
00061 char *
00062 WINAPI
00063 WspiapiStrdup (
00064         IN  const char *                    pszString)
00065 /*++
00066 
00067 Routine Description
00068     allocates enough storage via calloc() for a copy of the string,
00069     copies the string into the new memory, and returns a pointer to it.
00070 
00071 Arguments
00072     pszString       string to copy into new memory
00073 
00074 Return Value
00075     a pointer to the newly allocated storage with the string in it.
00076     NULL if enough memory could not be allocated, or string was NULL.
00077 
00078 --*/
00079 {
00080     char    *pszMemory;
00081 
00082     if (!pszString)
00083         return(NULL);
00084 
00085     pszMemory = (char *) WspiapiMalloc(strlen(pszString) + 1);
00086     if (!pszMemory)
00087         return(NULL);
00088 
00089     return(strcpy(pszMemory, pszString));
00090 }
00091 
00092 
00093 
00094 __inline
00095 BOOL
00096 WINAPI
00097 WspiapiParseV4Address (
00098     IN  const char *                    pszAddress,
00099     OUT PDWORD                          pdwAddress)
00100 /*++
00101 
00102 Routine Description
00103     get the IPv4 address (in network byte order) from its string
00104     representation.  the syntax should be a.b.c.d.
00105 
00106 Arguments
00107     pszArgument         string representation of the IPv4 address
00108     ptAddress           pointer to the resulting IPv4 address
00109 
00110 Return Value
00111     Returns FALSE if there is an error, TRUE for success.
00112 
00113 --*/
00114 {
00115     DWORD       dwAddress   = 0;
00116     const char  *pcNext     = NULL;
00117     int         iCount      = 0;
00118 
00119     // ensure there are 3 '.' (periods)
00120     for (pcNext = pszAddress; *pcNext != '\0'; pcNext++)
00121         if (*pcNext == '.')
00122             iCount++;
00123     if (iCount != 3)
00124         return FALSE;
00125 
00126     // return an error if dwAddress is INADDR_NONE (255.255.255.255)
00127     // since this is never a valid argument to getaddrinfo.
00128     dwAddress = inet_addr(pszAddress);
00129     if (dwAddress == INADDR_NONE)
00130         return FALSE;
00131 
00132     *pdwAddress = dwAddress;
00133     return TRUE;
00134 }
00135 
00136 
00137 
00138 __inline
00139 struct addrinfo *
00140 WINAPI
00141 WspiapiNewAddrInfo (
00142     IN  int                             iSocketType,
00143     IN  int                             iProtocol,
00144     IN  WORD                            wPort,
00145     IN  DWORD                           dwAddress)
00146 /*++
00147 
00148 Routine Description
00149     allocate an addrinfo structure and populate fields.
00150     IPv4 specific internal function, not exported.
00151 
00152 Arguments
00153     iSocketType         SOCK_*.  can be wildcarded (zero).
00154     iProtocol           IPPROTO_*.  can be wildcarded (zero).
00155     wPort               port number of service (in network order).
00156     dwAddress           IPv4 address (in network order).
00157 
00158 Return Value
00159     returns an addrinfo struct, or NULL if out of memory.
00160 
00161 --*/
00162 {
00163     struct addrinfo     *ptNew;
00164     struct sockaddr_in  *ptAddress;
00165 
00166     // allocate a new addrinfo structure.
00167     ptNew       =
00168         (struct addrinfo *) WspiapiMalloc(sizeof(struct addrinfo));
00169     if (!ptNew)
00170         return NULL;
00171 
00172     ptAddress   =
00173         (struct sockaddr_in *) WspiapiMalloc(sizeof(struct sockaddr_in));
00174     if (!ptAddress)
00175     {
00176         WspiapiFree(ptNew);
00177         return NULL;
00178     }
00179     ptAddress->sin_family       = AF_INET;
00180     ptAddress->sin_port         = wPort;
00181     ptAddress->sin_addr.s_addr  = dwAddress;
00182 
00183     // fill in the fields...
00184     ptNew->ai_family            = PF_INET;
00185     ptNew->ai_socktype          = iSocketType;
00186     ptNew->ai_protocol          = iProtocol;
00187     ptNew->ai_addrlen           = sizeof(struct sockaddr_in);
00188     ptNew->ai_addr              = (struct sockaddr *) ptAddress;
00189 
00190     return ptNew;
00191 }
00192 
00193 
00194 
00195 __inline
00196 int
00197 WINAPI
00198 WspiapiQueryDNS(
00199     IN  const char                      *pszNodeName,
00200     IN  int                             iSocketType,
00201     IN  int                             iProtocol,
00202     IN  WORD                            wPort,
00203     OUT char                            *pszAlias,
00204     OUT struct addrinfo                 **pptResult)
00205 /*++
00206 
00207 Routine Description
00208     helper routine for WspiapiLookupNode.
00209     performs name resolution by querying the DNS for A records.
00210     *pptResult would need to be freed if an error is returned.
00211 
00212 Arguments
00213     pszNodeName         name of node to resolve.
00214     iSocketType         SOCK_*.  can be wildcarded (zero).
00215     iProtocol           IPPROTO_*.  can be wildcarded (zero).
00216     wPort               port number of service (in network order).
00217     pszAlias            where to return the alias.
00218     pptResult           where to return the result.
00219 
00220 Return Value
00221     Returns 0 on success, an EAI_* style error value otherwise.
00222 
00223 --*/
00224 {
00225     struct addrinfo **pptNext   = pptResult;
00226     struct hostent  *ptHost     = NULL;
00227     char            **ppAddresses;
00228 
00229     *pptNext    = NULL;
00230     pszAlias[0] = '\0';
00231 
00232     ptHost = gethostbyname(pszNodeName);
00233     if (ptHost)
00234     {
00235         if ((ptHost->h_addrtype == AF_INET)     &&
00236             (ptHost->h_length   == sizeof(struct in_addr)))
00237         {
00238             for (ppAddresses    = ptHost->h_addr_list;
00239                  *ppAddresses   != NULL;
00240                  ppAddresses++)
00241             {
00242                 // create an addrinfo structure...
00243                 *pptNext = WspiapiNewAddrInfo(
00244                     iSocketType,
00245                     iProtocol,
00246                     wPort,
00247                     ((struct in_addr *) *ppAddresses)->s_addr);
00248                 if (!*pptNext)
00249                     return EAI_MEMORY;
00250 
00251                 pptNext = &((*pptNext)->ai_next);
00252             }
00253         }
00254 
00255         // pick up the canonical name.
00256         strcpy(pszAlias, ptHost->h_name);
00257         return 0;
00258     }
00259 
00260     switch (WSAGetLastError())
00261     {
00262         case WSAHOST_NOT_FOUND: return EAI_NONAME;
00263         case WSATRY_AGAIN:      return EAI_AGAIN;
00264         case WSANO_RECOVERY:    return EAI_FAIL;
00265         case WSANO_DATA:        return EAI_NODATA;
00266         default:                return EAI_NONAME;
00267     }
00268 }
00269 
00270 
00271 
00272 __inline
00273 int
00274 WINAPI
00275 WspiapiLookupNode(
00276     IN  const char                      *pszNodeName,
00277     IN  int                             iSocketType,
00278     IN  int                             iProtocol,
00279     IN  WORD                            wPort,
00280     IN  BOOL                            bAI_CANONNAME,
00281     OUT struct addrinfo                 **pptResult)
00282 /*++
00283 
00284 Routine Description
00285     resolve a nodename and return a list of addrinfo structures.
00286     IPv4 specific internal function, not exported.
00287     *pptResult would need to be freed if an error is returned.
00288 
00289     NOTE: if bAI_CANONNAME is true, the canonical name should be
00290           returned in the first addrinfo structure.
00291 
00292 Arguments
00293     pszNodeName         name of node to resolve.
00294     iSocketType         SOCK_*.  can be wildcarded (zero).
00295     iProtocol           IPPROTO_*.  can be wildcarded (zero).
00296     wPort               port number of service (in network order).
00297     bAI_CANONNAME       whether the AI_CANONNAME flag is set.
00298     pptResult           where to return result.
00299 
00300 Return Value
00301     Returns 0 on success, an EAI_* style error value otherwise.
00302 
00303 --*/
00304 {
00305     int     iError              = 0;
00306     int     iAliasCount         = 0;
00307 
00308     char    szFQDN1[NI_MAXHOST] = "";
00309     char    szFQDN2[NI_MAXHOST] = "";
00310     char    *pszName            = szFQDN1;
00311     char    *pszAlias           = szFQDN2;
00312     char    *pszScratch         = NULL;
00313     strcpy(pszName, pszNodeName);
00314 
00315     for (;;)
00316     {
00317         iError = WspiapiQueryDNS(pszNodeName,
00318                                  iSocketType,
00319                                  iProtocol,
00320                                  wPort,
00321                                  pszAlias,
00322                                  pptResult);
00323         if (iError)
00324             break;
00325 
00326         // if we found addresses, then we are done.
00327         if (*pptResult)
00328             break;
00329 
00330         // stop infinite loops due to DNS misconfiguration.  there appears
00331         // to be no particular recommended limit in RFCs 1034 and 1035.
00332         if ((!strlen(pszAlias))             ||
00333             (!strcmp(pszName, pszAlias))    ||
00334             (++iAliasCount == 16))
00335         {
00336             iError = EAI_FAIL;
00337             break;
00338         }
00339 
00340         // there was a new CNAME, look again.
00341         WspiapiSwap(pszName, pszAlias, pszScratch);
00342     }
00343 
00344     if (!iError && bAI_CANONNAME)
00345     {
00346         (*pptResult)->ai_canonname = WspiapiStrdup(pszAlias);
00347         if (!(*pptResult)->ai_canonname)
00348             iError = EAI_MEMORY;
00349     }
00350 
00351     return iError;
00352 }
00353 
00354 
00355 
00356 __inline
00357 int
00358 WINAPI
00359 WspiapiClone (
00360     IN  WORD                            wPort,
00361     IN  struct addrinfo                 *ptResult)
00362 /*++
00363 
00364 Routine Description
00365     clone every addrinfo structure in ptResult for the UDP service.
00366     ptResult would need to be freed if an error is returned.
00367 
00368 Arguments
00369     wPort               port number of UDP service.
00370     ptResult            list of addrinfo structures, each
00371                         of whose node needs to be cloned.
00372 
00373 Return Value
00374     Returns 0 on success, an EAI_MEMORY on allocation failure.
00375 
00376 --*/
00377 {
00378     struct addrinfo *ptNext = NULL;
00379     struct addrinfo *ptNew  = NULL;
00380 
00381     for (ptNext = ptResult; ptNext != NULL; )
00382     {
00383         // create an addrinfo structure...
00384         ptNew = WspiapiNewAddrInfo(
00385             SOCK_DGRAM,
00386             ptNext->ai_protocol,
00387             wPort,
00388             ((struct sockaddr_in *) ptNext->ai_addr)->sin_addr.s_addr);
00389         if (!ptNew)
00390             break;
00391 
00392         // link the cloned addrinfo
00393         ptNew->ai_next  = ptNext->ai_next;
00394         ptNext->ai_next = ptNew;
00395         ptNext          = ptNew->ai_next;
00396     }
00397 
00398     if (ptNext != NULL)
00399         return EAI_MEMORY;
00400 
00401     return 0;
00402 }
00403 
00404 
00405 
00406 __inline
00407 void
00408 WINAPI
00409 WspiapiLegacyFreeAddrInfo (
00410     IN  struct addrinfo                 *ptHead)
00411 /*++
00412 
00413 Routine Description
00414     Free an addrinfo structure (or chain of structures).
00415     As specified in RFC 2553, Section 6.4.
00416 
00417 Arguments
00418     ptHead              structure (chain) to free
00419 
00420 --*/
00421 {
00422     struct addrinfo *ptNext;    // next strcture to free
00423 
00424     for (ptNext = ptHead; ptNext != NULL; ptNext = ptHead)
00425     {
00426         if (ptNext->ai_canonname)
00427             WspiapiFree(ptNext->ai_canonname);
00428 
00429         if (ptNext->ai_addr)
00430             WspiapiFree(ptNext->ai_addr);
00431 
00432         ptHead = ptNext->ai_next;
00433         WspiapiFree(ptNext);
00434     }
00435 }
00436 
00437 
00438 
00439 __inline
00440 int
00441 WINAPI
00442 WspiapiLegacyGetAddrInfo(
00443     IN const char                       *pszNodeName,
00444     IN const char                       *pszServiceName,
00445     IN const struct addrinfo            *ptHints,
00446     OUT struct addrinfo                 **pptResult)
00447 /*++
00448 
00449 Routine Description
00450     Protocol-independent name-to-address translation.
00451     As specified in RFC 2553, Section 6.4.
00452     This is the hacked version that only supports IPv4.
00453 
00454 Arguments
00455     pszNodeName         node name to lookup.
00456     pszServiceName      service name to lookup.
00457     ptHints             hints about how to process request.
00458     pptResult           where to return result.
00459 
00460 Return Value
00461     returns zero if successful, an EAI_* error code if not.
00462 
00463 --*/
00464 {
00465     int                 iError      = 0;
00466     int                 iFlags      = 0;
00467     int                 iFamily     = PF_UNSPEC;
00468     int                 iSocketType = 0;
00469     int                 iProtocol   = 0;
00470     WORD                wPort       = 0;
00471     DWORD               dwAddress   = 0;
00472 
00473     struct servent      *ptService  = NULL;
00474     char                *pc         = NULL;
00475     BOOL                bClone      = FALSE;
00476     WORD                wTcpPort    = 0;
00477     WORD                wUdpPort    = 0;
00478 
00479 
00480     // initialize pptResult with default return value.
00481     *pptResult  = NULL;
00482 
00483 
00485     // validate arguments...
00486     //
00487 
00488     // both the node name and the service name can't be NULL.
00489     if ((!pszNodeName) && (!pszServiceName))
00490         return EAI_NONAME;
00491 
00492     // validate hints.
00493     if (ptHints)
00494     {
00495         // all members other than ai_flags, ai_family, ai_socktype
00496         // and ai_protocol must be zero or a null pointer.
00497         if ((ptHints->ai_addrlen    != 0)       ||
00498             (ptHints->ai_canonname  != NULL)    ||
00499             (ptHints->ai_addr       != NULL)    ||
00500             (ptHints->ai_next       != NULL))
00501         {
00502             return EAI_FAIL;
00503         }
00504 
00505         // the spec has the "bad flags" error code, so presumably we
00506         // should check something here.  insisting that there aren't
00507         // any unspecified flags set would break forward compatibility,
00508         // however.  so we just check for non-sensical combinations.
00509         //
00510         // we cannot come up with a canonical name given a null node name.
00511         iFlags      = ptHints->ai_flags;
00512         if ((iFlags & AI_CANONNAME) && !pszNodeName)
00513             return EAI_BADFLAGS;
00514 
00515         // we only support a limited number of protocol families.
00516         iFamily     = ptHints->ai_family;
00517         if ((iFamily != PF_UNSPEC) && (iFamily != PF_INET))
00518             return EAI_FAMILY;
00519 
00520         // we only support only these socket types.
00521         iSocketType = ptHints->ai_socktype;
00522         if ((iSocketType != 0)                  &&
00523             (iSocketType != SOCK_STREAM)        &&
00524             (iSocketType != SOCK_DGRAM)         &&
00525             (iSocketType != SOCK_RAW))
00526             return EAI_SOCKTYPE;
00527 
00528         // REVIEW: What if ai_socktype and ai_protocol are at odds?
00529         iProtocol   = ptHints->ai_protocol;
00530     }
00531 
00532 
00534     // do service lookup...
00535 
00536     if (pszServiceName)
00537     {
00538         wPort = (WORD) strtoul(pszServiceName, &pc, 10);
00539         if (*pc == '\0')        // numeric port string
00540         {
00541             wPort = wTcpPort = wUdpPort = htons(wPort);
00542             if (iSocketType == 0)
00543             {
00544                 bClone      = TRUE;
00545                 iSocketType = SOCK_STREAM;
00546             }
00547         }
00548         else                    // non numeric port string
00549         {
00550             if ((iSocketType == 0) || (iSocketType == SOCK_DGRAM))
00551             {
00552                 ptService = getservbyname(pszServiceName, "udp");
00553                 if (ptService)
00554                     wPort = wUdpPort = ptService->s_port;
00555             }
00556 
00557             if ((iSocketType == 0) || (iSocketType == SOCK_STREAM))
00558             {
00559                 ptService = getservbyname(pszServiceName, "tcp");
00560                 if (ptService)
00561                     wPort = wTcpPort = ptService->s_port;
00562             }
00563 
00564             // assumes 0 is an invalid service port...
00565             if (wPort == 0)     // no service exists
00566                 return (iSocketType ? EAI_SERVICE : EAI_NONAME);
00567 
00568             if (iSocketType == 0)
00569             {
00570                 // if both tcp and udp, process tcp now & clone udp later.
00571                 iSocketType = (wTcpPort) ? SOCK_STREAM : SOCK_DGRAM;
00572                 bClone      = (wTcpPort && wUdpPort);
00573             }
00574         }
00575     }
00576 
00577 
00578 
00580     // do node name lookup...
00581 
00582     // if we weren't given a node name,
00583     // return the wildcard or loopback address (depending on AI_PASSIVE).
00584     //
00585     // if we have a numeric host address string,
00586     // return the binary address.
00587     //
00588     if ((!pszNodeName) || (WspiapiParseV4Address(pszNodeName, &dwAddress)))
00589     {
00590         if (!pszNodeName)
00591         {
00592             dwAddress = htonl((iFlags & AI_PASSIVE)
00593                               ? INADDR_ANY
00594                               : INADDR_LOOPBACK);
00595         }
00596 
00597         // create an addrinfo structure...
00598         *pptResult =
00599             WspiapiNewAddrInfo(iSocketType, iProtocol, wPort, dwAddress);
00600         if (!(*pptResult))
00601             iError = EAI_MEMORY;
00602 
00603         if (!iError && pszNodeName)
00604         {
00605             // implementation specific behavior: set AI_NUMERICHOST
00606             // to indicate that we got a numeric host address string.
00607             (*pptResult)->ai_flags |= AI_NUMERICHOST;
00608 
00609             // return the numeric address string as the canonical name
00610             if (iFlags & AI_CANONNAME)
00611             {
00612                 (*pptResult)->ai_canonname =
00613                     WspiapiStrdup(inet_ntoa(*((struct in_addr *) &dwAddress)));
00614                 if (!(*pptResult)->ai_canonname)
00615                     iError = EAI_MEMORY;
00616             }
00617         }
00618     }
00619 
00620 
00621     // if we do not have a numeric host address string and
00622     // AI_NUMERICHOST flag is set, return an error!
00623     else if (iFlags & AI_NUMERICHOST)
00624     {
00625         iError = EAI_NONAME;
00626     }
00627 
00628 
00629     // since we have a non-numeric node name,
00630     // we have to do a regular node name lookup.
00631     else
00632     {
00633         iError = WspiapiLookupNode(pszNodeName,
00634                                    iSocketType,
00635                                    iProtocol,
00636                                    wPort,
00637                                    (iFlags & AI_CANONNAME),
00638                                    pptResult);
00639     }
00640 
00641     if (!iError && bClone)
00642     {
00643         iError = WspiapiClone(wUdpPort, *pptResult);
00644     }
00645 
00646     if (iError)
00647     {
00648         WspiapiLegacyFreeAddrInfo(*pptResult);
00649         *pptResult  = NULL;
00650     }
00651 
00652     return (iError);
00653 }
00654 
00655 
00656 
00657 __inline
00658 int
00659 WINAPI
00660 WspiapiLegacyGetNameInfo(
00661     IN  const struct sockaddr           *ptSocketAddress,
00662     IN  socklen_t                       tSocketLength,
00663     OUT char                            *pszNodeName,
00664     IN  size_t                          tNodeLength,
00665     OUT char                            *pszServiceName,
00666     IN  size_t                          tServiceLength,
00667     IN  int                             iFlags)
00668 /*++
00669 
00670 Routine Description
00671     protocol-independent address-to-name translation.
00672     as specified in RFC 2553, Section 6.5.
00673     this is the hacked version that only supports IPv4.
00674 
00675 Arguments
00676     ptSocketAddress     socket address to translate.
00677     tSocketLength       length of above socket address.
00678     pszNodeName         where to return the node name.
00679     tNodeLength         size of above buffer.
00680     pszServiceName      where to return the service name.
00681     tServiceLength      size of above buffer.
00682     iFlags              flags of type NI_*.
00683 
00684 Return Value
00685     returns zero if successful, an EAI_* error code if not.
00686 
00687 --*/
00688 {
00689     struct servent  *ptService;
00690     WORD            wPort;
00691     char            szBuffer[]  = "65535";
00692     char            *pszService = szBuffer;
00693 
00694     struct hostent  *ptHost;
00695     struct in_addr  tAddress;
00696     char            *pszNode    = NULL;
00697     char            *pc         = NULL;
00698 
00699 
00700     // sanity check ptSocketAddress and tSocketLength.
00701     if (!ptSocketAddress)
00702         return EAI_FAIL;
00703 
00704     if ((ptSocketAddress->sa_family != AF_INET)     ||
00705         (tSocketLength != sizeof(struct sockaddr_in)))
00706     {
00707         return EAI_FAMILY;
00708     }
00709 
00710     if (!(pszNodeName && tNodeLength) &&
00711         !(pszServiceName && tServiceLength))
00712     {
00713         return EAI_NONAME;
00714     }
00715 
00716     // the draft has the "bad flags" error code, so presumably we
00717     // should check something here.  insisting that there aren't
00718     // any unspecified flags set would break forward compatibility,
00719     // however.  so we just check for non-sensical combinations.
00720     if ((iFlags & NI_NUMERICHOST) && (iFlags & NI_NAMEREQD))
00721     {
00722         return EAI_BADFLAGS;
00723     }
00724 
00725     // translate the port to a service name (if requested).
00726     if (pszServiceName && tServiceLength)
00727     {
00728         wPort = ((struct sockaddr_in *) ptSocketAddress)->sin_port;
00729 
00730         if (iFlags & NI_NUMERICSERV)
00731         {
00732             // return numeric form of the address.
00733             sprintf(szBuffer, "%u", ntohs(wPort));
00734         }
00735         else
00736         {
00737             // return service name corresponding to port.
00738             ptService = getservbyport(wPort,
00739                                       (iFlags & NI_DGRAM) ? "udp" : NULL);
00740             if (ptService && ptService->s_name)
00741             {
00742                 // lookup successful.
00743                 pszService = ptService->s_name;
00744             }
00745             else
00746             {
00747                 // DRAFT: return numeric form of the port!
00748                 sprintf(szBuffer, "%u", ntohs(wPort));
00749             }
00750         }
00751 
00752 
00753         if (tServiceLength > strlen(pszService))
00754             strcpy(pszServiceName, pszService);
00755         else
00756             return EAI_FAIL;
00757     }
00758 
00759 
00760     // translate the address to a node name (if requested).
00761     if (pszNodeName && tNodeLength)
00762     {
00763         // this is the IPv4-only version, so we have an IPv4 address.
00764         tAddress = ((struct sockaddr_in *) ptSocketAddress)->sin_addr;
00765 
00766         if (iFlags & NI_NUMERICHOST)
00767         {
00768             // return numeric form of the address.
00769             pszNode  = inet_ntoa(tAddress);
00770         }
00771         else
00772         {
00773             // return node name corresponding to address.
00774             ptHost = gethostbyaddr((char *) &tAddress,
00775                                    sizeof(struct in_addr),
00776                                    AF_INET);
00777             if (ptHost && ptHost->h_name)
00778             {
00779                 // DNS lookup successful.
00780                 // stop copying at a "." if NI_NOFQDN is specified.
00781                 pszNode = ptHost->h_name;
00782                 if ((iFlags & NI_NOFQDN) && (pc = strchr(pszNode, '.')))
00783                     *pc = '\0';
00784             }
00785             else
00786             {
00787                 // DNS lookup failed.  return numeric form of the address.
00788                 if (iFlags & NI_NAMEREQD)
00789                 {
00790                     switch (WSAGetLastError())
00791                     {
00792                         case WSAHOST_NOT_FOUND: return EAI_NONAME;
00793                         case WSATRY_AGAIN:      return EAI_AGAIN;
00794                         case WSANO_RECOVERY:    return EAI_FAIL;
00795                         default:                return EAI_NONAME;
00796                     }
00797                 }
00798                 else
00799                     pszNode  = inet_ntoa(tAddress);
00800             }
00801         }
00802 
00803         if (tNodeLength > strlen(pszNode))
00804             strcpy(pszNodeName, pszNode);
00805         else
00806             return EAI_FAIL;
00807     }
00808 
00809     return 0;
00810 }
00811 
00812 
00813 
00814 typedef struct
00815 {
00816     char const          *pszName;
00817     FARPROC             pfAddress;
00818 } WSPIAPI_FUNCTION;
00819 
00820 #define WSPIAPI_FUNCTION_ARRAY                                  \
00821 {                                                               \
00822     "getaddrinfo",      (FARPROC) WspiapiLegacyGetAddrInfo,     \
00823     "getnameinfo",      (FARPROC) WspiapiLegacyGetNameInfo,     \
00824     "freeaddrinfo",     (FARPROC) WspiapiLegacyFreeAddrInfo,    \
00825 }
00826 
00827 
00828 
00829 __inline
00830 FARPROC
00831 WINAPI
00832 WspiapiLoad(
00833     IN  WORD                            wFunction)
00834 /*++
00835 
00836 Routine Description
00837     try to locate the address family independent name resolution routines
00838     (i.e. getaddrinfo, getnameinfo, freeaddrinfo, gai_strerror).
00839 
00840 Locks
00841     this function call is not synchronized.  hence the library containing
00842     the routines might be loaded multiple times.  another option is to
00843     synchronize through a spin lock using a static local variable and the
00844     InterlockedExchange operation.
00845 
00846 
00847 Arguments
00848     wFunction           ordinal # of the function to get the pointer to
00849                         0   getaddrinfo
00850                         1   getnameinfo
00851                         2   freeaddrinfo
00852 
00853 Return Value
00854     address of the library/legacy routine
00855 
00856 --*/
00857 {
00858     HMODULE                 hLibrary        = NULL;
00859 
00860     // these static variables store state across calls, across threads.
00861     static BOOL             bInitialized    = FALSE;
00862     static WSPIAPI_FUNCTION rgtGlobal[]     = WSPIAPI_FUNCTION_ARRAY;
00863     static const int        iNumGlobal      = (sizeof(rgtGlobal) /
00864                                                sizeof(WSPIAPI_FUNCTION));
00865 
00866     // we overwrite rgtGlobal only if all routines exist in library.
00867     WSPIAPI_FUNCTION        rgtLocal[]      = WSPIAPI_FUNCTION_ARRAY;
00868     FARPROC                 fScratch        = NULL;
00869     int                     i               = 0;
00870 
00871 
00872     if (bInitialized)           // WspiapiLoad has already been called once
00873         return (rgtGlobal[wFunction].pfAddress);
00874 
00875     do                          // breakout loop
00876     {
00877         // in Whistler and beyond...
00878         // the routines are present in the WinSock 2 library (ws2_32.dll).
00879         // printf("Looking in ws2_32 for getaddrinfo...\n");
00880         hLibrary = LoadLibraryA("ws2_32");
00881         if (hLibrary != NULL)
00882         {
00883             fScratch = GetProcAddress(hLibrary, "getaddrinfo");
00884             if (fScratch == NULL)
00885             {
00886                 FreeLibrary(hLibrary);
00887                 hLibrary = NULL;
00888             }
00889         }
00890         if (hLibrary != NULL)
00891             break;
00892 
00893 
00894         // in the IPv6 Technology Preview...
00895         // the routines are present in the IPv6 WinSock library (wship6.dll).
00896         // printf("Looking in wship6 for getaddrinfo...\n");
00897         hLibrary = LoadLibraryA("wship6");
00898         if (hLibrary != NULL)
00899         {
00900             fScratch = GetProcAddress(hLibrary, "getaddrinfo");
00901             if (fScratch == NULL)
00902             {
00903                 FreeLibrary(hLibrary);
00904                 hLibrary = NULL;
00905             }
00906         }
00907     } while (FALSE);
00908 
00909 
00910     if (hLibrary != NULL)
00911     {
00912         // use routines from this library...
00913         // since getaddrinfo is here, we expect all routines to be here,
00914         // but will fall back to IPv4-only if any of them is missing.
00915         for (i = 0; i < iNumGlobal; i++)
00916         {
00917             rgtLocal[i].pfAddress
00918                 = GetProcAddress(hLibrary, rgtLocal[i].pszName);
00919             if (rgtLocal[i].pfAddress == NULL)
00920             {
00921                 FreeLibrary(hLibrary);
00922                 hLibrary = NULL;
00923                 break;
00924             }
00925         }
00926 
00927         if (hLibrary != NULL)
00928         {
00929             // printf("found!\n");
00930             for (i = 0; i < iNumGlobal; i++)
00931                 rgtGlobal[i].pfAddress = rgtLocal[i].pfAddress;
00932         }
00933     }
00934 
00935     bInitialized = TRUE;
00936     return (rgtGlobal[wFunction].pfAddress);
00937 }
00938 
00939 
00940 
00941 __inline
00942 int
00943 WINAPI
00944 WspiapiGetAddrInfo(
00945     IN const char                       *nodename,
00946     IN const char                       *servname,
00947     IN const struct addrinfo            *hints,
00948     OUT struct addrinfo                 **res)
00949 {
00950     static WSPIAPI_PGETADDRINFO     pfGetAddrInfo   = NULL;
00951 
00952     if (!pfGetAddrInfo)
00953         pfGetAddrInfo   = (WSPIAPI_PGETADDRINFO) WspiapiLoad(0);
00954     return ((*pfGetAddrInfo)
00955             (nodename, servname, hints, res));
00956 }
00957 
00958 
00959 
00960 __inline
00961 int
00962 WINAPI
00963 WspiapiGetNameInfo (
00964     IN  const struct sockaddr           *sa,
00965     IN  socklen_t                       salen,
00966     OUT char                            *host,
00967     IN  size_t                          hostlen,
00968     OUT char                            *serv,
00969     IN  size_t                          servlen,
00970     IN  int                             flags)
00971 {
00972     static WSPIAPI_PGETNAMEINFO     pfGetNameInfo   = NULL;
00973 
00974     if (!pfGetNameInfo)
00975         pfGetNameInfo   = (WSPIAPI_PGETNAMEINFO) WspiapiLoad(1);
00976     return ((*pfGetNameInfo)
00977             (sa, salen, host, hostlen, serv, servlen, flags));
00978 }
00979 
00980 
00981 
00982 __inline
00983 void
00984 WINAPI
00985 WspiapiFreeAddrInfo (
00986     IN  struct addrinfo                 *ai)
00987 {
00988     static WSPIAPI_PFREEADDRINFO    pfFreeAddrInfo   = NULL;
00989 
00990     if (!pfFreeAddrInfo)
00991         pfFreeAddrInfo  = (WSPIAPI_PFREEADDRINFO) WspiapiLoad(2);
00992     (*pfFreeAddrInfo)(ai);
00993 }
00994 
00995 #ifdef  __cplusplus
00996 }
00997 #endif
00998 
00999 #endif // _WSPIAPI_H_

Generated on Sun Aug 23 08:55:35 2009 for libssh by  doxygen 1.4.7