Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

815 lines
23 KiB

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