Main Page | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members

wspiapi.h

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

Generated on Sun Aug 7 22:47:16 2005 for Dibbler - a portable DHCPv6 by  doxygen 1.3.9.1