Pythorian

[CPP] WSALookup

Oct 4th, 2012
167
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 16.47 KB | None | 0 0
  1. #define WIN32_LEAN_AND_MEAN
  2.  
  3. #include <windows.h>
  4. #include <winsock2.h>
  5. #include <Ws2tcpip.h>
  6. #include <windns.h>
  7. #include <svcguid.h>
  8. #include <stdio.h>
  9.  
  10. // Link with ws2_32.lib
  11. #pragma comment(lib, "Ws2_32.lib")
  12.  
  13. #undef WINSOCK_API_LINKAGE
  14.  
  15. #define WINSOCK_API_LINKAGE __control_entrypoint(DllExport)
  16.  
  17. /*++
  18.     xbyrnr.cpp
  19.  
  20.    
  21.     GetXbyY emulation via new WinSock2 RNR. This source module shows
  22.     code that is built into the WinSock2 DLL (ws2_32.dll). It
  23.     demonstrates how the older GetXByY functions are mapped to the new
  24.     WSALookupServiceBegin, WSALookupServiceNext, WSALookupServiceEnd
  25.     functions.
  26.  
  27.     This module is not guaranteed to compile. It is provided as source
  28.     code for RNR namespace service providers to understand what will
  29.     be coming down to their code in response to the traditional
  30.     GetXbyY calls.
  31.  
  32.     At this time, only
  33.         gethostname
  34.         gethostbyname
  35.         gethostbyaddr
  36.         getservbyname
  37.         getservbyport
  38.     are implemented in this manner.
  39.  
  40.    
  41.     Warning: This is not provided as a template for either RNR
  42.     applications or namespace providers. This code is only intended
  43.     to illustrate what happens in the WinSock2 DLL to map the GetXbyY
  44.     calls to the new RNR APIs.
  45. --*/
  46.  
  47. // The initial buffer size passed by getxbyy functions
  48. // to WSALookupServiceNext. If it is insuffucient for the query,
  49. // the amount specified by the provider is allocated and call is
  50. // repeated.
  51.  
  52. // The initial buffer is allocated from stack, so we try to keep it
  53. // relatively small, but still for performance reasons we want to be able
  54. // to satisfy most of the calls with just this amount
  55.  
  56. #define RNR_BUFFER_SIZE (sizeof(WSAQUERYSET) + 256)
  57.  
  58. //
  59. //  Forward declares
  60. //
  61.  
  62. LPBLOB getxyDataEnt(
  63.     PCHAR  *pResults,
  64.     DWORD  dwSize,
  65.     LPSTR  lpszName,
  66.     LPGUID lpType,
  67.     LPSTR *lppName
  68.     );
  69.  
  70.  
  71. VOID FixList(PCHAR ** List, PCHAR Base);
  72.  
  73. VOID UnpackHostEnt(struct hostent * hostent);
  74.  
  75. VOID UnpackServEnt(struct servent * servent);
  76.  
  77. GUID HostAddrByNameGuid = SVCID_INET_HOSTADDRBYNAME;
  78. GUID HostNameGuid = SVCID_HOSTNAME;
  79. GUID AddressGuid =  SVCID_INET_HOSTADDRBYINETSTRING;
  80. GUID IANAGuid    =  SVCID_INET_SERVICEBYNAME;
  81.  
  82. //
  83. // Utility to turn a list of offsets into a list of addresses. Used
  84. // to convert structures returned as BLOBs.
  85. //
  86.  
  87. VOID FixList(PCHAR ** List, PCHAR Base)
  88. {
  89.     if(*List)
  90.     {
  91.         PCHAR * Addr;
  92.  
  93.         Addr = *List = (PCHAR *)( ((DWORD)*List + Base) );
  94.         while(*Addr)
  95.         {
  96.             *Addr = (PCHAR)(((DWORD)*Addr + Base));
  97.             Addr++;
  98.         }
  99.     }
  100. }
  101.  
  102.  
  103. //
  104. // Routine to convert a hostent returned in a BLOB to one with
  105. // usable pointers. The structure is converted in-place.
  106. //
  107. VOID UnpackHostEnt(struct hostent * hostent)
  108. {
  109.      PCHAR pch;
  110.  
  111.      pch = (PCHAR)hostent;
  112.  
  113.      if(hostent->h_name)
  114.      {
  115.          hostent->h_name = (PCHAR)((DWORD)hostent->h_name + pch);
  116.      }
  117.      FixList(&hostent->h_aliases, pch);
  118.      FixList(&hostent->h_addr_list, pch);
  119. }
  120.  
  121. //
  122. // Routine to unpack a servent returned in a BLOB to one with
  123. // usable pointers. The structure is converted in-place
  124. //
  125.  
  126. VOID UnpackServEnt(struct servent * servent)
  127. {
  128.     PCHAR pch;
  129.  
  130.     pch = (PCHAR)servent;
  131.  
  132.     FixList(&servent->s_aliases, pch);
  133.     servent->s_name = (PCHAR)(DWORD(servent->s_name) + pch);
  134.     servent->s_proto = (PCHAR)(DWORD(servent->s_proto) + pch);
  135. }
  136.  
  137. WINSOCK_API_LINKAGE
  138. struct hostent FAR *
  139. WSAAPI
  140. gethostbyaddr(
  141.     IN const char *addr,
  142.     IN int len,
  143.     IN int type
  144.     )
  145. /*++
  146. Routine Description:
  147.  
  148.     Get host information corresponding to an address.
  149.  
  150. Arguments:
  151.  
  152.     addr - A pointer to an address in network byte order.
  153.  
  154.     len - The length of the address, which must be 4 for PF_INET
  155.     addresses.
  156.  
  157.     type - The type of the address, which must be PF_INET.
  158.  
  159. Returns:
  160.  
  161.     If no error occurs, gethostbyaddr() returns a pointer to the
  162.     hostent structure described above. Otherwise it returns a NULL
  163.     pointer and a specific error code is stored with SetErrorCode().
  164. --*/
  165. {
  166.     CHAR qbuf[DNS_MAX_NAME_BUFFER_LENGTH];
  167.     struct hostent *ph;
  168.     LPBLOB pBlob;
  169.     PCHAR pResults;
  170.     CHAR localResults[RNR_BUFFER_SIZE];
  171.     INT ErrorCode;
  172.     PTHREAD Thread;
  173.  
  174.     ErrorCode = PROLOG(&Thread);
  175.     if(ErrorCode != NO_ERROR)
  176.     {
  177.         SetLastError(ErrorCode);
  178.         return(NULL);
  179.     }
  180.  
  181.     if ( !addr )
  182.     {
  183.         SetLastError(WSAEINVAL);
  184.         return(NULL);
  185.     }
  186.  
  187.     pResults = localResults;
  188.  
  189.     //
  190.     // NOTICE. Only handles current inet address forms.
  191.     //
  192.     (void)sprintf_s(qbuf, sizeof(qbuf); "%u.%u.%u.%u",
  193.             ((unsigned)addr[0] & 0xff),
  194.             ((unsigned)addr[1] & 0xff),
  195.             ((unsigned)addr[2] & 0xff),
  196.             ((unsigned)addr[3] & 0xff));
  197.  
  198.  
  199.     pBlob = getxyDataEnt(pResults,
  200.                          RNR_BUFFER_SIZE,
  201.                          qbuf,
  202.                          &AddressGuid,
  203.                          0);
  204.     if(pBlob)
  205.     {
  206.         ph = (struct hostent *)Thread->CopyHostEnt(pBlob);
  207.         if(ph)
  208.         {
  209.             UnpackHostEnt(ph);
  210.         }
  211.     }
  212.     else
  213.     {
  214.         ph = 0;
  215.         if(GetLastError() == WSASERVICE_NOT_FOUND)
  216.         {
  217.             SetLastError(WSANO_ADDRESS);
  218.         }
  219.     }
  220.     if (pResults != localResults)
  221.         delete pResults;
  222.  
  223.     return(ph);
  224. }  // gethostbyaddr
  225.  
  226.  
  227. WINSOCK_API_LINKAGE
  228. struct hostent* FAR WSAAPI
  229. gethostbyname(
  230.     IN const char FAR * name
  231.     )
  232. /*++
  233. Routine Description:
  234.  
  235.     Get host information corresponding to a hostname.
  236.  
  237. Arguments:
  238.  
  239.     name - A pointer to the null-terminated name of the host.
  240.  
  241. Returns:
  242.  
  243.     If no error occurs, gethostbyname() returns a pointer to the
  244.     hostent structure described above. Otherwise it returns a null
  245.     pointer and a specific errorr code is stored with SetErrorCode().
  246. --*/
  247. {
  248.     struct hostent * hent;
  249.     LPBLOB pBlob;
  250.     PCHAR pResults;
  251.     CHAR localResults[RNR_BUFFER_SIZE];
  252.     INT ErrorCode;
  253.     CHAR  szLocalName[200];   // for storing the local name. This
  254.                               // is simply a big number assumed
  255.                               // to be large enough. This is used
  256.                               // only when the caller chooses not to
  257.                               // provide a name.
  258.     PCHAR pszName;
  259.  
  260.     PDTHREAD Thread;
  261.  
  262.     ErrorCode = PROLOG(&Thread);
  263.     if(ErrorCode != NO_ERROR)
  264.     {
  265.         SetLastError(ErrorCode);
  266.         return(NULL);
  267.     }
  268.  
  269.     //
  270.     // A NULL input name means look for the local name. So,
  271.     // get it.
  272.     //
  273.     if(!name || !*name)
  274.     {
  275.         if(gethostname(szLocalName, 200) != NO_ERROR)
  276.         {
  277.             return(NULL);
  278.         }
  279.         pszName = szLocalName;
  280.     }
  281.     else
  282.     {
  283.         pszName = (PCHAR)name;
  284.     }
  285.  
  286.     pResults = localResults;
  287.  
  288.     pBlob = getxyDataEnt( &pResults,
  289.                           RNR_BUFFER_SIZE,
  290.                           pszName,
  291.                           &HostAddrByNameGuid,
  292.                           0);
  293.     if(pBlob &&
  294.          ( !name || !*name ) )
  295.     {
  296.         pBlob = getxyDataEnt( &pResults,
  297.                               RNR_BUFFER_SIZE,
  298.                               NULL,
  299.                               &HostAddrByNameGuid,
  300.                               0);
  301.     }
  302.          
  303.     if(pBlob )    {
  304.         hent = (struct hostent *)Thread->CopyHostEnt(pBlob);
  305.         if(hent)
  306.         {
  307.             UnpackHostEnt(hent);
  308.         }
  309.     }
  310.     else
  311.     {
  312.         hent = 0;
  313.         if(GetLastError() == WSASERVICE_NOT_FOUND)
  314.         {
  315.             SetLastError(WSAHOST_NOT_FOUND);
  316.         }
  317.     }
  318.  
  319.     if (pResults!=localResults)
  320.         delete pResults;
  321.  
  322.     return(hent);
  323. }  // gethostbyname
  324.  
  325. WINSOCK_API_LINKAGE
  326. int WSAAPI
  327. gethostname(
  328.     OUT char FAR * name,
  329.     IN int namelen
  330.     )
  331. /*++
  332. Routine Description:
  333.  
  334.     Return the standard host name for the local computer.
  335.  
  336. Arguments:
  337.  
  338.     name    - A pointer to a buffer that will receive the host name.
  339.  
  340.     namelen - The length of the buffer.
  341.  
  342. Returns:
  343.  
  344.     Zero on success else SOCKET_ERROR. The error code is stored with
  345.     SetErrorCode().
  346. --*/
  347. {
  348.     PCHAR lpName;
  349.     PCHAR pResults;
  350.     CHAR localResults[RNR_BUFFER_SIZE];
  351.     INT ErrorCode;
  352.     PDTHREAD Thread;
  353.  
  354.     ErrorCode = PROLOG(&Thread);
  355.     if(ErrorCode != NO_ERROR)
  356.     {
  357.         gSetLastError(ErrorCode);
  358.         return(NULL);
  359.     }
  360.  
  361.     pResults = localResults;
  362.  
  363.     if(getxyDataEnt(pResults,
  364.                     RNR_BUFFER_SIZE,
  365.                     NULL,
  366.                     &HostNameGuid,
  367.                     &lpName
  368.                     ))
  369.     {
  370.         INT iSize = strlen(lpName) + 1;
  371.  
  372.         if(iSize <= namelen)
  373.         {
  374.             memcpy(name, lpName, iSize);
  375.         }
  376.         else
  377.         {
  378.             SetLastError(WSAEFAULT);
  379.             ErrorCode = SOCKET_ERROR;
  380.         }
  381.     }
  382.     else
  383.     {
  384.         ErrorCode = SOCKET_ERROR;   // assume LastError has been set
  385.     }
  386.  
  387.     if (pResults!=localResults)
  388.         delete pResults;
  389.  
  390.     return(ErrorCode);
  391. }  // gethostname
  392.  
  393.  
  394. WINSOCK_API_LINKAGE
  395. struct servent FAR * WSAAPI
  396. getservbyport(
  397.     IN int port,
  398.     IN const char FAR * proto
  399.     )
  400. /*++
  401. Routine Description:
  402.  
  403.     Get service information corresponding to a port and protocol.
  404.  
  405. Arguments:
  406.  
  407.     port  - The port for a service, in network byte order.
  408.  
  409.     proto - An optional pointer to a protocol name. If this is NULL,
  410.             getservbyport() returns the first service entry for which
  411.             the port matches the s_port. Otherwise getservbyport()
  412.             matches both the port and the proto.
  413.  
  414. Returns:
  415.  
  416.     If no error occurs, getservbyport() returns a pointer to the
  417.     servent structure described above. Otherwise it returns a NULL
  418.     pointer and a specific error code is stored with SetErrorCode().
  419. --*/
  420. {
  421.     PCHAR pszTemp;
  422.     struct servent * sent;
  423.     LPBLOB pBlob;
  424.     PCHAR pResults;
  425.     CHAR localResults[RNR_BUFFER_SIZE];
  426.     INT ErrorCode;
  427.     PDTHREAD Thread;
  428.  
  429.     ErrorCode = PROLOG(&Thread);
  430.     if(ErrorCode != NO_ERROR)
  431.     {
  432.         SetLastError(ErrorCode);
  433.         return(NULL);
  434.     }
  435.  
  436.     pResults = localResults;
  437.  
  438.     if(!proto)
  439.     {
  440.         proto = "";
  441.     }
  442.  
  443.     //
  444.     // the 5 is the max number of digits in a port
  445.     //
  446.     pszTemp = new CHAR[strlen(proto) + 1 + 1 + 5];
  447.     sprintf_s(pszTemp, strlen(proto)+1+1+5, "%d/%s", (port & 0xffff), proto);
  448.     pBlob =  getxyDataEnt(pResults,
  449.                           RNR_BUFFER_SIZE,
  450.                           pszTemp,
  451.                           &IANAGuid,
  452.                           0
  453.                           );
  454.     delete pszTemp;
  455.     if(!pBlob)
  456.     {
  457.         sent = 0;
  458.         if(GetLastError() == WSATYPE_NOT_FOUND)
  459.         {
  460.             SetLastError(WSANO_DATA);
  461.         }
  462.     }
  463.     else
  464.     {
  465.         sent = (struct servent *)Thread->CopyServEnt(pBlob);
  466.         if(sent)
  467.         {
  468.             UnpackServEnt(sent);
  469.         }
  470.     }
  471.  
  472.     if (pResults!=localResults)
  473.         delete pResults;
  474.  
  475.     return(sent);
  476. }  // getservbyport
  477.  
  478. WINSOCK_API_LINKAGE
  479. struct servent FAR * WSAAPI
  480. getservbyname(
  481.     IN const char FAR * name,
  482.     IN const char FAR * proto
  483.     )
  484. /*++
  485. Routine Description:
  486.  
  487.     Get service information corresponding to a service name and
  488.     protocol.
  489.  
  490. Arguments:
  491.  
  492.      name  - A pointer to a null-terminated service name.
  493.  
  494.     proto - An optional pointer to a null-terminated protocol name. If
  495.             this pointer is NULL, getservbyname() returns the first
  496.             service entry for which the name matches the s_name or one
  497.             of the s_aliases. Otherwise getservbyname() matches both
  498.             the name and the proto.
  499.  
  500. Returns:
  501.  
  502.     If no error occurs, getservbyname() returns a pointer to the servent
  503.     structure described above. Otherwise it returns a NULL pointer and a
  504.     specific error code is stored with SetErrorCode().
  505.  
  506. --*/
  507. {
  508.     PCHAR pszTemp;
  509.     struct servent * sent;
  510.     LPBLOB pBlob;
  511.     PCHAR pResults;
  512.     CHAR localResults[RNR_BUFFER_SIZE];
  513.     INT ErrorCode;
  514.     PDTHREAD Thread;
  515.  
  516.     ErrorCode = PROLOG(&Thread);
  517.     if(ErrorCode != NO_ERROR)
  518.     {
  519.         SetLastError(ErrorCode);
  520.         return(NULL);
  521.     }
  522.  
  523.     pResults = localResults;
  524.  
  525.     if(!proto)
  526.     {
  527.         proto = "";
  528.     }
  529.     pszTemp = new CHAR[strlen(name) + strlen(proto) + 1 + 1];
  530.     sprintf_s(pszTemp, strlen(name)+strlen(proto)+1+1, "%s/%s", name, proto);
  531.     pBlob = getxyDataEnt(pResults,
  532.                         RNR_BUFFER_SIZE,
  533.                         pszTemp,
  534.                         &IANAGuid,
  535.                         0
  536.                         );
  537.     delete pszTemp;
  538.     if(!pBlob)
  539.     {
  540.         sent = 0;
  541.         if(GetLastError() == WSATYPE_NOT_FOUND)
  542.         {
  543.             SetLastError(WSANO_DATA);
  544.         }
  545.     }
  546.     else
  547.     {
  548.         sent = (struct servent *)Thread->CopyServEnt(pBlob);
  549.         if(sent)
  550.         {
  551.             UnpackServEnt(sent);
  552.         }
  553.     }
  554.  
  555.     if (pResults!=localResults)
  556.         delete pResults;
  557.  
  558.     return(sent);
  559. }  // getservbyname
  560.  
  561. //
  562. // Common routine for obtaining a xxxent buffer. Input is used to
  563. // execute the WSALookup series of APIs.
  564. //
  565. // Args:
  566. //   pResults -- a buffer supplied by the caller to be used in
  567. //               the WASLookup calls. This should be as large as
  568. //               the caller can afford to offer.
  569. //   dwLength -- number of bytes in pResults
  570. //   lpszName -- pointer to the service name. May by NULL
  571. //   lpType   -- pointer to the service type . This should be one of
  572. //               the SVCID_INET_xxxxx types. It may be anything
  573. //               that produces a BLOB.
  574. //   lppName  -- pointer to pointer where the resulting name pointer
  575. //               is stored. May be NULL if the name is not needed.
  576. //
  577. // Returns:
  578. //   0  --   No BLOB data was returned. In general, this means the
  579. //           operation failed. Evev if the WSALookupNext succeeded
  580. //           and returned a name, the name will not be returned.
  581. //   else -- a pointer to the BLOB.
  582. //
  583. //
  584. //
  585. // The protocol restrictions list for all emulation operations. This
  586. // should limit the invoked providers to the set that know about
  587. // hostents and servents. If not, then the special SVCID_INET GUIDs
  588. // should take care of the remainder.
  589. //
  590. AFPROTOCOLS afp[2] = {
  591.                       {AF_INET, IPPROTO_UDP},
  592.                       {AF_INET, IPPROTO_TCP}
  593.                      };
  594.  
  595. LPBLOB
  596. getxyDataEnt(
  597.     PCHAR *pResults,
  598.     DWORD dwLength,
  599.     LPSTR lpszName,
  600.     LPGUID lpType,
  601.     LPSTR *lppName)
  602. {
  603.  
  604.     PWSAQUERYSETA pwsaq = (PWSAQUERYSETA)pResults;
  605.     int err;
  606.     HANDLE hRnR;
  607.     LPBLOB pvRet = 0;
  608.     INT Err = 0;
  609.  
  610.     //
  611.     // create the query
  612.     //
  613.     memset(pwsaq, 0, sizeof(*pwsaq));
  614.     pwsaq->dwSize = sizeof(*pwsaq);
  615.     pwsaq->lpszServiceInstanceName = lpszName;
  616.     pwsaq->lpServiceClassId = lpType;
  617.     pwsaq->dwNameSpace = NS_ALL;
  618.     pwsaq->dwNumberOfProtocols = 2;
  619.     pwsaq->lpafpProtocols = &afp[0];
  620.  
  621.     err = WSALookupServiceBeginA(pwsaq,
  622.                                  LUP_RETURN_BLOB | LUP_RETURN_NAME,
  623.                                  &hRnR);
  624.  
  625.     if(err == NO_ERROR)
  626.     {
  627.         //
  628.         // The query was accepted, so execute it via the Next call.
  629.         //
  630.         err = WSALookupServiceNextA(
  631.                                 hRnR,
  632.                                 0,
  633.                                 &dwLength,
  634.                                 pwsaq);
  635.         //
  636.         // if NO_ERROR was returned and a BLOB is present, this
  637.         // worked, just return the requested information. Otherwise,
  638.         // invent an error or capture the transmitted one.
  639.         //
  640.  
  641.         if(err == NO_ERROR)
  642.         {
  643.             if(pvRet = pwsaq->lpBlob)
  644.             {
  645.                 if(lppName)
  646.                 {
  647.                     *lppName = pwsaq->lpszServiceInstanceName;
  648.                 }
  649.             }
  650.             else
  651.             {
  652.                 err = WSANO_DATA;
  653.             }
  654.         }
  655.         else
  656.         {
  657.             //
  658.             // WSALookupServiceEnd clobbers LastError so save
  659.             // it before closing the handle.
  660.             //
  661.  
  662.             err = GetLastError();
  663.         }
  664.         WSALookupServiceEnd(hRnR);
  665.  
  666.         //
  667.         // if an error happened, stash the value in LastError
  668.         //
  669.  
  670.         if(err != NO_ERROR)
  671.         {
  672.             SetLastError(err);
  673.         }
  674.     }
  675.     return(pvRet);
  676. }
Advertisement
Add Comment
Please, Sign In to add comment