WSPiApi.h
上传用户:dzyhzl
上传日期:2019-04-29
资源大小:56270k
文件大小:30k
源码类别:

模拟服务器

开发平台:

C/C++

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