home *** CD-ROM | disk | FTP | other *** search
/ Tricks of the Windows Gam…ming Gurus (2nd Edition) / Disc2.iso / msdn_vcb / samples / vc98 / sdk / netds / winsock / rnr / rnrclnt / rnrclnt.c < prev    next >
C/C++ Source or Header  |  1997-09-18  |  24KB  |  817 lines

  1. /*++
  2.  
  3. Copyright (c) 1992 Microsoft Corporation
  4.  
  5. Module Name:
  6.  
  7.     RnrClnt.c
  8.  
  9. Abstract:
  10.  
  11.     Test and demonstration client for the RNR (service Registration and
  12.     Name Resolution) APIs.  This is a simple client application designed
  13.     to show the basic principles involved in using the RNR APIs to _write
  14.     a protocol-independent Windows Sockets client application.
  15.  
  16.     This client works by examining the protocols loaded on the machine,
  17.     looking for protocols which are reliable and stream-oriented.  Then
  18.     it attempts to locate and connect to the service on these protocols.
  19.     When is has successfully connected to the service, it sends
  20.     exchanges several messages with the service and then terminates the
  21.     connection.
  22.  
  23.     The OpenConnection() routine implemented herein is intended to be a
  24.     demonstration of RNR functionality commonly used in
  25.     protocol-independent clients.  Application writers are encouraged to
  26.     leverage this code to assist them in writing protocol-independent
  27.     applications on top of the Windows Sockets API.
  28.  
  29.  
  30. --*/
  31.  
  32. #include <stdio.h>
  33. #include <stdlib.h>
  34. #include <windows.h>
  35. #include <winsock2.h>
  36. #include <nspapi.h>
  37.  
  38. #define DEFAULT_TRANSFER_SIZE    512
  39. #define DEFAULT_TRANSFER_COUNT   0x10
  40. #define DEFAULT_CONNECTION_COUNT 1
  41. #define DEFAULT_DELAY            0
  42.  
  43. #define DEFAULT_RECEIVE_BUFFER_SIZE 4096
  44. #define DEFAULT_SEND_BUFFER_SIZE    4096
  45.  
  46. #define MAX_PROTOCOLS  10
  47. #define MAX_HOST_NAMES 16
  48.  
  49. WSADATA WsaData;
  50. DWORD TransferSize = DEFAULT_TRANSFER_SIZE;
  51. DWORD TransferCount = DEFAULT_TRANSFER_COUNT;
  52. PCHAR IoBuffer;
  53. DWORD RepeatCount = 1;
  54. INT ReceiveBufferSize = DEFAULT_RECEIVE_BUFFER_SIZE;
  55. INT SendBufferSize = DEFAULT_SEND_BUFFER_SIZE;
  56.  
  57. PCHAR RemoteName = "localhost";
  58. PCHAR ServiceTypeName = "EchoExample";
  59.  
  60. VOID
  61. DoEcho(
  62.     IN SOCKET s );
  63.  
  64. SOCKET
  65. OpenConnection(
  66.     IN  PTSTR  ServiceName,
  67.     IN  LPGUID ServiceType,
  68.     IN  BOOL   Reliable,
  69.     IN  BOOL   MessageOriented,
  70.     IN  BOOL   StreamOriented,
  71.     IN  BOOL   Connectionless,
  72.     OUT PINT   ProtocolUsed );
  73.  
  74. INT
  75. Rnr20_GetAddressByName(
  76.     IN     PTSTR         ServiceName,
  77.     IN     LPGUID        ServiceType,
  78.     IN     DWORD         dwNameSpace,
  79.     IN     DWORD         dwNumberOfProtocols,
  80.     IN     LPAFPROTOCOLS lpAfpProtocols,
  81.     IN OUT LPVOID        lpCSAddrInfo,
  82.     IN OUT LPDWORD       lpdwBufferLength );
  83.  
  84. void _CRTAPI1
  85. main(
  86.     int argc,
  87.     char *argv[] )
  88. {
  89.     INT err;
  90.     DWORD i;
  91.     DWORD protocol[2];
  92.     SOCKET s;
  93.     BYTE buffer[1024];
  94.     BYTE buffer2[1024];
  95.     DWORD bytesRequired;
  96.     PPROTOCOL_INFO protocolInfo;
  97.     GUID serviceType;
  98.  
  99.     //
  100.     // Initialize the Windows Sockets DLL.
  101.     //
  102.  
  103.     err = WSAStartup( 0x0202, &WsaData );
  104.     if ( err == SOCKET_ERROR )
  105.     {
  106.         printf( "WSAStartup() failed: %ld\n", GetLastError( ) );
  107.         return;
  108.     }
  109.  
  110.     //
  111.     // Parse command-line arguments.
  112.     //
  113.  
  114.     for ( i = 1; i < (ULONG)argc != 0; i++ )
  115.     {
  116.         if ( _strnicmp( argv[i], "/name:", 6 ) == 0 )
  117.         {
  118.             RemoteName = argv[i] + 6;
  119.         }
  120.         else if ( _strnicmp( argv[i], "/type:", 6 ) == 0 )
  121.         {
  122.             ServiceTypeName = argv[i] + 6;
  123.         }
  124.         else if ( _strnicmp( argv[i], "/size:", 6 ) == 0 )
  125.         {
  126.             TransferSize = atoi( argv[i] + 6 );
  127.         }
  128.         else if ( _strnicmp( argv[i], "/count:", 7 ) == 0 )
  129.         {
  130.             TransferCount = atoi( argv[i] + 7 );
  131.         }
  132.         else if ( _strnicmp( argv[i], "/rcvbuf:", 8 ) == 0 )
  133.         {
  134.             ReceiveBufferSize = atoi( argv[i] + 8 );
  135.         }
  136.         else if ( _strnicmp( argv[i], "/sndbuf:", 8 ) == 0 )
  137.         {
  138.             SendBufferSize = atoi( argv[i] + 8 );
  139.         }
  140.         else
  141.         {
  142.             printf( "Usage: rnrclnt [/name:SVCNAME] [/type:TYPENAME] [/size:N]\n" );
  143.             printf( "               [/count:N] [/rcvbuf:N] [/sndbuf:N]\n" );
  144.             exit( 0 );
  145.         }
  146.     }
  147.  
  148.     //
  149.     // Allocate memory to hold the network I/O buffer.
  150.     //
  151.  
  152.     IoBuffer = malloc( TransferSize + 1 );
  153.     if ( IoBuffer == NULL )
  154.     {
  155.         printf( "Failed to allocate I/O buffer.\n" );
  156.         exit( 0 );
  157.     }
  158.  
  159.     //
  160.     // Determine the type (GUID) of the service we are interested in
  161.     // connecting to.
  162.     //
  163.  
  164.     err = GetTypeByName( ServiceTypeName, &serviceType );
  165.     if ( err == SOCKET_ERROR )
  166.     {
  167.         printf( "GetTypeByName for \"%s\" failed: %ld\n",
  168.                     ServiceTypeName, GetLastError( ) );
  169.         exit( 0 );
  170.     }
  171.  
  172.     //
  173.     // Open a connected socket to the service.
  174.     //
  175.  
  176.     s = OpenConnection(
  177.             RemoteName,
  178.             &serviceType,
  179.             TRUE,
  180.             FALSE,
  181.             FALSE,
  182.             FALSE,
  183.             &protocol[0]
  184.             );
  185.  
  186.     if ( s == INVALID_SOCKET )
  187.     {
  188.         printf( "Failed to open connection to name \"%s\" type \"%s\"\n",
  189.                     RemoteName, ServiceTypeName );
  190.         exit( 0 );
  191.     }
  192.  
  193.     //
  194.     // The connection succeeded.  Display some information on the
  195.     // protocol which was used.
  196.     //
  197.  
  198.     bytesRequired = sizeof(buffer);
  199.     protocol[1] = 0;
  200.  
  201.     err = EnumProtocols( protocol, buffer, &bytesRequired );
  202.  
  203.     if ( err < 1 )
  204.     {
  205.         printf( "EnumProtocols failed for protocol %ld: %ld\n",
  206.                 protocol[0], GetLastError( ) );
  207.         exit( 0 );
  208.     }
  209.  
  210.     err = GetNameByType( &serviceType, buffer2, sizeof(buffer2) );
  211.  
  212.     if ( err != NO_ERROR )
  213.     {
  214.         printf( "GetNameByType failed: %ld\n", GetLastError( ) );
  215.         exit ( 0 );
  216.     }
  217.  
  218.     protocolInfo = (PPROTOCOL_INFO)buffer;
  219.     printf( "Connected to %s/%s with protocol \"%s\" (%ld)\n",
  220.             RemoteName, buffer2,
  221.             protocolInfo->lpProtocol,
  222.             protocolInfo->iProtocol );
  223.  
  224.     //
  225.     // Send data to and from the service.
  226.     //
  227.  
  228.     DoEcho( s );
  229.  
  230. } // main
  231.  
  232.  
  233. VOID
  234. DoEcho(
  235.     IN SOCKET s )
  236. {
  237.     INT err;
  238.     INT bytesReceived;
  239.     DWORD i;
  240.     DWORD startTime;
  241.     DWORD endTime;
  242.     DWORD transferStartTime;
  243.     DWORD transferEndTime;
  244.     DWORD totalTime;
  245.     INT thisTransferSize;
  246.     DWORD bytesTransferred = 0;
  247.  
  248.     startTime = GetTickCount( );
  249.  
  250.     for ( i = 0; i < TransferCount; i++ )
  251.     {
  252.         thisTransferSize = TransferSize;
  253.  
  254.         transferStartTime = GetTickCount( );
  255.  
  256.         err = send( s, IoBuffer, thisTransferSize, 0 );
  257.  
  258.         if ( err != thisTransferSize )
  259.         {
  260.             printf( "send didn't work, ret = %ld, error = %ld\n",
  261.                     err, GetLastError( ) );
  262.             closesocket( s );
  263.             return;
  264.         }
  265.  
  266.         bytesReceived = 0;
  267.         do {
  268.             err = recv( s, IoBuffer, thisTransferSize, 0 );
  269.  
  270.             if ( err == SOCKET_ERROR )
  271.             {
  272.                 printf( "recv failed: %ld\n", GetLastError( ) );
  273.                 closesocket( s );
  274.                 return;
  275.             }
  276.             else if ( err == 0 && thisTransferSize != 0 )
  277.             {
  278.                 printf( "socket closed prematurely by remote.\n" );
  279.                 return;
  280.             }
  281.  
  282.             bytesReceived += err;
  283.         } while ( bytesReceived < thisTransferSize );
  284.  
  285.         transferEndTime = GetTickCount( );
  286.         printf( "%5ld bytes sent and received in %ld ms\n",
  287.                 thisTransferSize, transferEndTime - transferStartTime );
  288.  
  289.         bytesTransferred += thisTransferSize;
  290.     }
  291.  
  292.     endTime = GetTickCount( );
  293.     totalTime = endTime - startTime;
  294.  
  295.     printf( "\n%ld bytes transferred in %ld iterations, time = %ld ms\n",
  296.             bytesTransferred, TransferCount, totalTime );
  297.     printf( "Rate = %ld KB/s, %ld T/S, %ld ms/iteration\n",
  298.             (bytesTransferred / totalTime) * 2,
  299.             (TransferCount*1000) / totalTime,
  300.             totalTime / TransferCount );
  301.  
  302.     err = closesocket( s );
  303.  
  304.     if ( err == SOCKET_ERROR )
  305.     {
  306.         printf( "closesocket failed: %ld\n", GetLastError( ) );
  307.         return;
  308.     }
  309.  
  310.     return;
  311.  
  312. } // DoEcho
  313.  
  314.  
  315. SOCKET
  316. OpenConnection(
  317.     IN  PTSTR  ServiceName,
  318.     IN  LPGUID ServiceType,
  319.     IN  BOOL   Reliable,
  320.     IN  BOOL   MessageOriented,
  321.     IN  BOOL   StreamOriented,
  322.     IN  BOOL   Connectionless,
  323.     OUT PINT   ProtocolUsed )
  324.  
  325. /*++
  326.  
  327. Routine Description:
  328.  
  329.     Examines the Windows Sockets transport protocols loaded on a machine
  330.     and determines those which support the characteristics requested by
  331.     the caller.  Attempts to locate and connect to the specified service
  332.     on these protocols.
  333.  
  334. Arguments:
  335.  
  336.     ServiceName - a friendly name which identifies the service we want
  337.         to connect to.  On name spaces which support name resolution at
  338.         the service level (e.g.  SAP) this is the name clients will use
  339.         to connect to this service.  On name spaces which support name
  340.         resolution at the host level (e.g.  DNS) this name is ignored
  341.         and applications must use the host name to establish
  342.         communication with this service.
  343.  
  344.     ServiceType - the GUID value which uniquely identifies the type of
  345.         service we provide.  A GUID is created with the UUIDGEN program.
  346.  
  347.     Reliable - if TRUE, the caller requests that only transport protocols
  348.         which support reliable data delivery be used.  If FALSE, both
  349.         reliable and unreliable protocols may be used.
  350.  
  351.     MessageOriented - if TRUE, only message-oriented transport protocols
  352.         should be used.  If FALSE, the caller either does not care
  353.         whether the protocols used are message oriented or desires only
  354.         stream-oriented protocols.
  355.  
  356.     StreamOriented - if TRUE, only stream-oriented transport protocols
  357.         should be used.  If FALSE, the caller either does not care
  358.         whether the protocols used are stream oriented or desires only
  359.         message-oriented protocols.
  360.  
  361.     Connectionless - if TRUE, only connectionless protocols should be
  362.         used.  If FALSE, both connection-oriented and connectionless
  363.         protocols may be used.
  364.  
  365.     ProtocolUsed - if a connection is opened successfully, this
  366.         parameter receives the protocol ID of the protocol used to
  367.         establish the connection.
  368.  
  369. Return Value:
  370.  
  371.     A connected socket handle, or INVALID_SOCKET if the connection
  372.     could not be established.
  373.  
  374. --*/
  375.  
  376. {
  377.     INT protocols[MAX_PROTOCOLS+1];
  378.     AFPROTOCOLS afProtocols[MAX_PROTOCOLS+1];
  379.     BYTE buffer[2048];
  380.     DWORD bytesRequired;
  381.     INT err;
  382.     PPROTOCOL_INFO protocolInfo;
  383.     PCSADDR_INFO csaddrInfo = NULL;
  384.     INT protocolCount;
  385.     INT addressCount;
  386.     INT i;
  387.     DWORD protocolIndex;
  388.     SOCKET s;
  389.  
  390.     //
  391.     // First look up the protocols installed on this machine.  The
  392.     // EnumProtocols() API returns about all the Windows Sockets
  393.     // protocols loaded on this machine, and we'll use this information
  394.     // to identify the protocols which provide the necessary semantics.
  395.     //
  396.  
  397.     bytesRequired = sizeof(buffer);
  398.  
  399.     err = EnumProtocols( NULL, buffer, &bytesRequired );
  400.  
  401.     if ( err <= 0 )
  402.     {
  403.         return INVALID_SOCKET;
  404.     }
  405.  
  406.     //
  407.     // Walk through the available protocols and pick out the ones which
  408.     // support the desired characteristics.
  409.     //
  410.  
  411.     protocolCount = err;
  412.     protocolInfo = (PPROTOCOL_INFO)buffer;
  413.  
  414.     for ( i = 0, protocolIndex = 0;
  415.           i < protocolCount && protocolIndex < MAX_PROTOCOLS;
  416.           i++, protocolInfo++ )
  417.     {
  418.         //
  419.         // If "reliable" support is requested, then check if supported
  420.         // by this protocol.  Reliable support means that the protocol
  421.         // guarantees delivery of data in the order in which it is sent.
  422.         // Note that we assume here that if the caller requested reliable
  423.         // service then they do not want a connectionless protocol.
  424.         //
  425.  
  426.         if ( Reliable )
  427.         {
  428.             //
  429.             // Check to see if the protocol is reliable.  It must
  430.             // guarantee both delivery of all data and the order in
  431.             // which the data arrives.  Also, it must not be a
  432.             // connectionless protocol.
  433.             //
  434.  
  435.             if ( (protocolInfo->dwServiceFlags &
  436.                       XP_GUARANTEED_DELIVERY) == 0 ||
  437.                  (protocolInfo->dwServiceFlags &
  438.                       XP_GUARANTEED_ORDER) == 0 )
  439.             {
  440.                 continue;
  441.             }
  442.  
  443.             if ( (protocolInfo->dwServiceFlags & XP_CONNECTIONLESS) != 0 )
  444.             {
  445.                 continue;
  446.             }
  447.  
  448.             //
  449.             // Check to see that the protocol matches the stream/message
  450.             // characteristics requested.  A stream oriented protocol
  451.             // either has the XP_MESSAGE_ORIENTED bit turned off, or
  452.             // else supports "pseudo stream" capability.  Pseudo stream
  453.             // means that although the underlying protocol is message
  454.             // oriented, the application may open a socket of type
  455.             // SOCK_STREAM and the protocol will hide message boundaries
  456.             // from the application.
  457.             //
  458.  
  459.             if ( StreamOriented &&
  460.                  (protocolInfo->dwServiceFlags & XP_MESSAGE_ORIENTED) != 0 &&
  461.                  (protocolInfo->dwServiceFlags & XP_PSEUDO_STREAM) == 0 )
  462.             {
  463.                 continue;
  464.             }
  465.  
  466.             if ( MessageOriented &&
  467.                  (protocolInfo->dwServiceFlags & XP_MESSAGE_ORIENTED) == 0 )
  468.             {
  469.                 continue;
  470.             }
  471.         }
  472.         else if ( Connectionless )
  473.         {
  474.             //
  475.             // Make sure that this is a connectionless protocol.  In a
  476.             // connectionless protocol, data is sent as discrete
  477.             // datagrams with no connection establishment required.
  478.             // Connectionless protocols typically have no reliability
  479.             // guarantees.
  480.             //
  481.  
  482.             if ( (protocolInfo->dwServiceFlags & XP_CONNECTIONLESS) != 0 )
  483.             {
  484.                 continue;
  485.             }
  486.         }
  487.  
  488.         //
  489.         // This protocol fits all the criteria.  Add it to the list of
  490.         // protocols in which we're interested.
  491.         //
  492.         afProtocols[protocolIndex].iProtocol = protocolInfo->iProtocol;
  493.         afProtocols[protocolIndex].iAddressFamily = AF_UNSPEC;
  494.  
  495.         protocols[protocolIndex++] = protocolInfo->iProtocol;
  496.     }
  497.  
  498.     //
  499.     // Make sure that we found at least one acceptable protocol.  If
  500.     // there no protocols on this machine which meet the caller's
  501.     // requirements then fail here.
  502.     //
  503.  
  504.     if ( protocolIndex == 0 )
  505.     {
  506.         return INVALID_SOCKET;
  507.     }
  508.  
  509.     afProtocols[protocolIndex].iProtocol = 0;
  510.     afProtocols[protocolIndex].iAddressFamily = 0;
  511.  
  512.     protocols[protocolIndex] = 0;
  513.  
  514.     //
  515.     // Now attempt to find the address of the service to which we're
  516.     // connecting.  Note that we restrict the scope of the search to
  517.     // those protocols of interest by passing the protocol array we
  518.     // generated above to RnrGetAddressFromName() or GetAddressByName()
  519.     // depending on whether we are running the client on the same machine
  520.     // as the server rnrsrv.exe is running on.  This forces
  521.     // RnrGetAddressFromName() or GetAddressByName() to return socket
  522.     // addresses for only the protocols we specify, ignoring possible
  523.     // addresses for protocols we cannot support because of the caller's
  524.     // constraints.
  525.     //
  526.  
  527.     bytesRequired = sizeof( buffer );
  528.  
  529.     if ( !strcmp( ServiceName, "localhost" ) )
  530.     {
  531.         //
  532.         // This is a Winsock 1.0 call . . .
  533.         //
  534.         err = GetAddressByName( NS_DEFAULT,
  535.                                 ServiceType,
  536.                                 ServiceName,
  537.                                 protocols,
  538.                                 0,
  539.                                 NULL,
  540.                                 buffer,
  541.                                 &bytesRequired,
  542.                                 NULL,
  543.                                 NULL );
  544.     }
  545.     else
  546.     {
  547.         //
  548.         // This calls into Winsock 2.0 . . .
  549.         //
  550.         err = Rnr20_GetAddressByName( ServiceName,
  551.                                       ServiceType,
  552.                                       NS_ALL,
  553.                                       protocolIndex,
  554.                                       afProtocols,
  555.                                       buffer,
  556.                                       &bytesRequired );
  557.     }
  558.  
  559.     if ( err <= 0 )
  560.     {
  561.         return INVALID_SOCKET;
  562.     }
  563.  
  564.     addressCount = err;
  565.     csaddrInfo = (PCSADDR_INFO) buffer;
  566.  
  567.     //
  568.     // For each address, open a socket and attempt to connect.  Note that
  569.     // if anything fails for a particular protocol we just skip on to
  570.     // the next protocol.  As soon as we have established a connection,
  571.     // quit trying.
  572.     //
  573.  
  574.     for ( i = 0; i < addressCount; i++, csaddrInfo++ )
  575.     {
  576.         //
  577.         // Open the socket.  Note that we manually specify stream type
  578.         // if so requested in case the protocol is natively a message
  579.         // protocol but supports stream semantics.
  580.         //
  581.  
  582.         s = socket( csaddrInfo->LocalAddr.lpSockaddr->sa_family,
  583.                     StreamOriented ? SOCK_STREAM : csaddrInfo->iSocketType,
  584.                     csaddrInfo->iProtocol );
  585.  
  586.         if ( s == INVALID_SOCKET )
  587.         {
  588.             continue;
  589.         }
  590.  
  591.         //
  592.         // Bind the socket to the local address specified.
  593.         //
  594.  
  595.         err = bind( s, csaddrInfo->LocalAddr.lpSockaddr,
  596.                     csaddrInfo->LocalAddr.iSockaddrLength );
  597.  
  598.         if ( err != NO_ERROR )
  599.         {
  600.             closesocket( s );
  601.             continue;
  602.         }
  603.  
  604.         //
  605.         // Attempt to connect the socket to the service.  If this fails,
  606.         // keep trying on other protocols.
  607.         //
  608.  
  609.         err = connect( s, csaddrInfo->RemoteAddr.lpSockaddr,
  610.                        csaddrInfo->RemoteAddr.iSockaddrLength );
  611.  
  612.         if ( err != NO_ERROR )
  613.         {
  614.             closesocket( s );
  615.             continue;
  616.         }
  617.  
  618.         //
  619.         // The socket was successfully connected.  Remember the protocol
  620.         // used and return the socket handle to the caller.
  621.         //
  622.  
  623.         *ProtocolUsed = csaddrInfo->iProtocol;
  624.         return s;
  625.     }
  626.  
  627.     if ( csaddrInfo )
  628.     {
  629.         (void) LocalFree( (HLOCAL) csaddrInfo );
  630.     }
  631.  
  632.     //
  633.     // We failed to connect to the service.
  634.     //
  635.  
  636.     return INVALID_SOCKET;
  637.  
  638. } // OpenConnection
  639.  
  640.  
  641. INT
  642. Rnr20_GetAddressByName(
  643.     IN     PTSTR         szServiceName,
  644.     IN     LPGUID        lpServiceType,
  645.     IN     DWORD         dwNameSpace,
  646.     IN     DWORD         dwNumberOfProtocols,
  647.     IN     LPAFPROTOCOLS lpAfpProtocols,
  648.     IN OUT LPVOID        lpCSAddrInfos,
  649.     IN OUT LPDWORD       lpdwBufferLength )
  650.  
  651. /*++
  652.  
  653. Routine Description:
  654.  
  655.     Calls Winsock 2.0 service lookup routines to find service addresses.
  656.  
  657. Arguments:
  658.  
  659.     szServiceName - a friendly name which identifies the service we want
  660.         to find the address of.
  661.  
  662.     lpServiceType - a GUID that identifies the type of service we want
  663.         to find the address of.
  664.  
  665.     dwNameSpace - The Winsock2 Name Space to get address from (i.e. NS_ALL)
  666.  
  667.     dwNumberOfProtocols - Size of the protocol constraint array, may be zero.
  668.  
  669.     lpAftProtocols -  (Optional) References an array of AFPROTOCOLS structure.
  670.         Only services that utilize these protocols will be returned.
  671.  
  672.     lpCSAddrInfos - On successful return, this will point to an array of
  673.         CSADDR_INFO structures that contains the host address(es). Memory
  674.         is passed in by callee and the length of the buffer is provided by
  675.         lpdwBufferLength.
  676.  
  677.     lpdwBufferLength - On input provides the length in bytes of the buffer
  678.         lpCSAddrInfos. On output returns the length of the buffer used or
  679.         what length the buffer needs to be to store the address.
  680.  
  681. Return Value:
  682.  
  683.     The number of CSADDR_INFO structures returned in lpCSAddrInfos, or
  684.     (INVALID_SOCKET) with a WIN32 error in GetLastError.
  685.  
  686. --*/
  687.  
  688. {
  689.     ULONG            dwLength = 2048;      // Guess at buffer size
  690.     PWSAQUERYSETA    pwsaQuerySet;
  691.     ULONG            err;
  692.     HANDLE           hRnR;
  693.     DWORD            tempSize;
  694.     DWORD            entries = 0;
  695.     DWORD            dwNumberOfCsAddrs;
  696.  
  697.     RtlZeroMemory( lpCSAddrInfos, *lpdwBufferLength );
  698.  
  699.     pwsaQuerySet = (PWSAQUERYSETA) LocalAlloc( LMEM_ZEROINIT, dwLength );
  700.  
  701.     if ( pwsaQuerySet == NULL )
  702.     {
  703.         //
  704.         // Unsuccessful.
  705.         //
  706.         return ERROR_NOT_ENOUGH_MEMORY;
  707.     }
  708.  
  709.     RtlZeroMemory( pwsaQuerySet, dwLength );
  710.  
  711.     //
  712.     // Do a lookup using RNRr.
  713.     //
  714.     pwsaQuerySet->dwSize = sizeof( WSAQUERYSETA );
  715.     pwsaQuerySet->lpszServiceInstanceName = szServiceName;
  716.     pwsaQuerySet->lpServiceClassId = lpServiceType;
  717.     pwsaQuerySet->lpVersion = 0;
  718.     pwsaQuerySet->lpszComment = 0;
  719.     pwsaQuerySet->dwNameSpace = dwNameSpace;
  720.     pwsaQuerySet->lpNSProviderId = 0;
  721.     pwsaQuerySet->lpszContext = 0;
  722.     pwsaQuerySet->dwNumberOfProtocols = dwNumberOfProtocols;
  723.     pwsaQuerySet->lpafpProtocols = lpAfpProtocols;
  724.  
  725.     err = WSALookupServiceBegin( pwsaQuerySet,
  726.                                  LUP_RETURN_NAME |
  727.                                  LUP_RETURN_ADDR,
  728.                                  &hRnR );
  729.  
  730.     if ( err != NO_ERROR )
  731.     {
  732.         err = WSAGetLastError();
  733.  
  734.         //
  735.         // Free memory before returning.
  736.         //
  737.         (void) LocalFree( (HLOCAL) pwsaQuerySet );
  738.  
  739.         //
  740.         // Unsuccessful.
  741.         //
  742.         return (DWORD) err;
  743.     }
  744.  
  745.     //
  746.     // The query was accepted, so execute it via the Next call.
  747.     //
  748.     tempSize = dwLength;
  749.  
  750.     err = WSALookupServiceNext( hRnR,
  751.                                 0,
  752.                                 &tempSize,
  753.                                 pwsaQuerySet );
  754.  
  755.     if ( err != NO_ERROR )
  756.     {
  757.         err = WSAGetLastError();
  758.  
  759.         if ( err == WSA_E_NO_MORE )
  760.         {
  761.             err = 0;
  762.         }
  763.  
  764.         if ( err == WSASERVICE_NOT_FOUND )
  765.         {
  766.             err = WSAHOST_NOT_FOUND;
  767.         }
  768.  
  769.         (void) LocalFree( (HLOCAL) pwsaQuerySet );
  770.  
  771.         //
  772.         // Unsuccessful.
  773.         //
  774.         return (DWORD) err;
  775.  
  776.     }
  777.  
  778.     dwNumberOfCsAddrs = pwsaQuerySet->dwNumberOfCsAddrs;
  779.  
  780.     if ( dwNumberOfCsAddrs > 0 )
  781.     {
  782.         //
  783.         // Make a copy of the CSAddrInfos returned from WSALookupServiceNext()
  784.         //
  785.         DWORD dwCSAddrInfoLen = dwNumberOfCsAddrs * sizeof( CSADDR_INFO );
  786.  
  787.         if ( *lpdwBufferLength > dwCSAddrInfoLen )
  788.         {
  789.             RtlCopyMemory( lpCSAddrInfos,
  790.                            pwsaQuerySet->lpcsaBuffer,
  791.                            dwCSAddrInfoLen );
  792.         }
  793.         else
  794.         {
  795.             *lpdwBufferLength = dwCSAddrInfoLen;
  796.             SetLastError( ERROR_NOT_ENOUGH_MEMORY );
  797.             dwNumberOfCsAddrs = INVALID_SOCKET;
  798.         }
  799.     }
  800.  
  801.     //
  802.     // Close lookup service handle.
  803.     //
  804.     (VOID) WSALookupServiceEnd( hRnR );
  805.  
  806.     //
  807.     // Free memory used for query set info.
  808.     //
  809.     (void) LocalFree( (HLOCAL) pwsaQuerySet );
  810.  
  811.     return dwNumberOfCsAddrs;
  812.  
  813. } // RnrGetHostFromName
  814.  
  815.  
  816.  
  817.