Source code of Windows XP (NT5)
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.

2979 lines
68 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. svccli.cxx
  5. Abstract:
  6. Contains client side code of service location protocol.
  7. Author:
  8. Madan Appiah (madana) 15-May-1995
  9. Environment:
  10. User Mode - Win32
  11. Revision History:
  12. --*/
  13. #include <svcloc.hxx>
  14. //
  15. // This is the IPX address we send to
  16. //
  17. BYTE GlobalSapBroadcastAddress[] = {
  18. AF_IPX, 0, // Address Family
  19. 0x00, 0x00, 0x00, 0x00, // Dest. Net Number
  20. 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, // Dest. Node Number
  21. 0x04, 0x52, // Dest. Socket
  22. 0x04 // Packet type
  23. };
  24. VOID
  25. GetNBUniqueName(
  26. LPSTR NBNameBuf,
  27. DWORD NBNameBufLen
  28. )
  29. {
  30. LPSTR NamePtr = NBNameBuf;
  31. LPSTR NameEndPtr = NBNameBuf + NBNameBufLen;
  32. TcpsvcsDbgAssert( NBNameBufLen >
  33. sizeof(NETBIOS_INET_UNIQUE_NAME) + 1 );
  34. memcpy(
  35. NamePtr,
  36. NETBIOS_INET_UNIQUE_NAME,
  37. NETBIOS_INET_UNIQUE_NAME_LEN
  38. );
  39. NamePtr += NETBIOS_INET_UNIQUE_NAME_LEN;
  40. //
  41. // now append a random char.
  42. //
  43. DWORD RandNum;
  44. RandNum = (DWORD)rand();
  45. RandNum = RandNum % (26 + 10); // 26 alphabets, and 10 numerics
  46. if( RandNum < 10 ) {
  47. *NamePtr = (CHAR)('0'+ RandNum);
  48. }
  49. else {
  50. *NamePtr = (CHAR)('A'+ RandNum - 10);
  51. }
  52. NamePtr++;
  53. TcpsvcsDbgAssert( GlobalComputerName[0] != '\0' );
  54. //
  55. // append computer name.
  56. //
  57. DWORD ComputerNameLen = strlen( GlobalComputerName );
  58. if( ComputerNameLen < (DWORD)(NameEndPtr - NamePtr) ) {
  59. memcpy(
  60. NamePtr,
  61. GlobalComputerName,
  62. ComputerNameLen );
  63. NamePtr += ComputerNameLen;
  64. //
  65. // fill the trailing chars with spaces.
  66. //
  67. memset( NamePtr, ' ', DIFF(NameEndPtr - NamePtr) );
  68. }
  69. else {
  70. memcpy(
  71. NamePtr,
  72. GlobalComputerName,
  73. DIFF(NameEndPtr - NamePtr) );
  74. }
  75. return;
  76. }
  77. DWORD
  78. ProcessSapResponses(
  79. PLIST_ENTRY ResponseList,
  80. LPSAP_ADDRESS_INFO *SapAddresses,
  81. DWORD *NumSapAddresses
  82. )
  83. {
  84. DWORD Error;
  85. PLIST_ENTRY Response;
  86. DWORD NumResponses;
  87. DWORD Size;
  88. LPSAP_ADDRESS_INFO Addresses = NULL;
  89. LPSAP_ADDRESS_INFO Address;
  90. //
  91. // compute number of entries in the list.
  92. //
  93. NumResponses = 0;
  94. for( Response = ResponseList->Flink;
  95. Response != ResponseList;
  96. Response = Response->Flink ) {
  97. NumResponses++;
  98. }
  99. TcpsvcsDbgAssert( NumResponses != 0 );
  100. if( NumResponses == 0 ) {
  101. *SapAddresses = NULL;
  102. *NumSapAddresses = 0;
  103. return( ERROR_SUCCESS );
  104. }
  105. //
  106. // allocate memory for return buffer.
  107. //
  108. Size = sizeof( SAP_ADDRESS_INFO ) * NumResponses;
  109. Addresses = (LPSAP_ADDRESS_INFO)
  110. SvclocHeap->Alloc( Size );
  111. if( Addresses == NULL ) {
  112. Error = ERROR_NOT_ENOUGH_MEMORY;
  113. goto Cleanup;
  114. }
  115. for( Address = Addresses, Response = ResponseList->Flink;
  116. Response != ResponseList;
  117. Address++, Response = Response->Flink ) {
  118. TcpsvcsDbgAssert( (LPBYTE)Address < (LPBYTE)Addresses + Size );
  119. *Address = ((LPSAP_ADDRESS_ENTRY)Response)->Address;
  120. }
  121. *SapAddresses = Addresses;
  122. *NumSapAddresses = NumResponses;
  123. Addresses = NULL;
  124. Error = ERROR_SUCCESS;
  125. Cleanup:
  126. if( Addresses != NULL ) {
  127. SvclocHeap->Free( Addresses );
  128. }
  129. return( Error );
  130. }
  131. DWORD
  132. ProcessSingleSapResponse(
  133. LPSAP_IDENT_HEADER SapResponse,
  134. PLIST_ENTRY ResponsesList
  135. )
  136. {
  137. PLIST_ENTRY Response;
  138. CHAR ServerName[MAX_COMPUTERNAME_LENGTH + 1];
  139. LPSTR ServerNamePtr;
  140. LPBYTE ServerAddress;
  141. TcpsvcsDbgAssert(SapResponse->ServerType == htons(INTERNET_SERVICE_SAP_ID));
  142. //
  143. // check GUID portion of the server name.
  144. //
  145. if( memcmp(
  146. SapResponse->ServerName +
  147. MAX_COMPUTERNAME_LENGTH,
  148. SERVICE_GUID_STR,
  149. 32 ) != 0 ) {
  150. //
  151. // ignore this response.
  152. //
  153. TcpsvcsDbgPrint((
  154. DEBUG_ERRORS,
  155. "GetSapAddress() received unknown (GUID) response.\n" ));
  156. return( ERROR_SUCCESS );
  157. }
  158. //
  159. // server name portion.
  160. //
  161. memcpy(
  162. ServerName,
  163. SapResponse->ServerName,
  164. MAX_COMPUTERNAME_LENGTH );
  165. ServerName[MAX_COMPUTERNAME_LENGTH] = '\0';
  166. //
  167. // chop off padding.
  168. //
  169. ServerNamePtr = ServerName;
  170. while ( *ServerNamePtr != '\0' ) {
  171. if( *ServerNamePtr == '!' ) {
  172. *ServerNamePtr = '\0';
  173. break;
  174. }
  175. ServerNamePtr++;
  176. }
  177. ServerAddress = SapResponse->Address;
  178. //
  179. // find out if the server entry is already in the existing list.
  180. //
  181. for( Response = ResponsesList->Flink;
  182. Response != ResponsesList;
  183. Response = Response->Flink ) {
  184. LPSAP_ADDRESS_ENTRY ResponseEntry;
  185. ResponseEntry = (LPSAP_ADDRESS_ENTRY)Response;
  186. if( memcmp(
  187. ResponseEntry->Address.Address,
  188. ServerAddress,
  189. IPX_ADDRESS_LENGTH ) == 0 ) {
  190. return( ERROR_SUCCESS );
  191. }
  192. if( strcmp(
  193. ResponseEntry->Address.ServerName,
  194. ServerName ) == 0 ) {
  195. return( ERROR_SUCCESS );
  196. }
  197. }
  198. //
  199. // we have unique new entry.
  200. //
  201. //
  202. // allocate memory for the new response.
  203. //
  204. LPSAP_ADDRESS_ENTRY NewResponse;
  205. NewResponse = (LPSAP_ADDRESS_ENTRY)
  206. SvclocHeap->Alloc( sizeof(SAP_ADDRESS_ENTRY) );
  207. if( NewResponse == NULL ) {
  208. return( ERROR_NOT_ENOUGH_MEMORY );
  209. }
  210. strcpy( (LPSTR)NewResponse->Address.ServerName, ServerName );
  211. memcpy(
  212. NewResponse->Address.Address,
  213. ServerAddress,
  214. IPX_ADDRESS_LENGTH );
  215. NewResponse->Address.HopCount = ntohs(SapResponse->HopCount);
  216. //
  217. // add this new entry to the list.
  218. //
  219. InsertTailList( ResponsesList, &NewResponse->Next );
  220. return( ERROR_SUCCESS );
  221. }
  222. DWORD
  223. GetSapAddress(
  224. LPSAP_ADDRESS_INFO *SapAddresses,
  225. DWORD *NumSapAddresses
  226. )
  227. /*++
  228. Routine Description:
  229. This routine discovers all IPX servers by sending sap broadcast and
  230. filtering responses that match our GUID.
  231. Arguments:
  232. SapAddresses - pointer to a location where the pointer to the
  233. addresses buffer is returned. The caller should free this buffer
  234. after use.
  235. NumSapAddresses - pointer a location where the number of addresses
  236. returned in the above buffer is returned.
  237. Return Value:
  238. Windows Error Code.
  239. --*/
  240. {
  241. DWORD Error = ERROR_SUCCESS;
  242. SOCKET SapSocket;
  243. SOCKADDR_IPX SapSocketAddr;
  244. SAP_REQUEST SapRequest;
  245. BYTE DestAddr[SAP_ADDRESS_LENGTH];
  246. LIST_ENTRY ResponsesList;
  247. InitializeListHead(&ResponsesList);
  248. //
  249. // create an IPX socket.
  250. //
  251. SapSocket = socket( AF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  252. if ( SapSocket == INVALID_SOCKET ) {
  253. Error = WSAGetLastError();
  254. goto Cleanup;
  255. }
  256. //
  257. // Set the socket to non-blocking
  258. //
  259. DWORD NonBlocking;
  260. NonBlocking = 1;
  261. if ( ioctlsocket( SapSocket, FIONBIO, &NonBlocking ) ==
  262. SOCKET_ERROR ) {
  263. Error = WSAGetLastError();
  264. goto Cleanup;
  265. }
  266. //
  267. // Allow sending of broadcasts
  268. //
  269. DWORD Value;
  270. Value = 1;
  271. if ( setsockopt( SapSocket,
  272. SOL_SOCKET,
  273. SO_BROADCAST,
  274. (PCHAR) &Value,
  275. sizeof(INT)) == SOCKET_ERROR ) {
  276. Error = WSAGetLastError();
  277. goto Cleanup;
  278. }
  279. //
  280. // Bind the socket
  281. //
  282. memset( &SapSocketAddr, 0, sizeof( SOCKADDR_IPX));
  283. SapSocketAddr.sa_family = AF_IPX;
  284. SapSocketAddr.sa_socket = 0; // no specific port
  285. if ( bind( SapSocket,
  286. (PSOCKADDR) &SapSocketAddr,
  287. sizeof( SOCKADDR_IPX)) == SOCKET_ERROR ) {
  288. Error = WSAGetLastError();
  289. goto Cleanup;
  290. }
  291. //
  292. // Set the extended address option
  293. //
  294. Value = 1;
  295. if ( setsockopt( SapSocket, // Socket Handle
  296. NSPROTO_IPX, // Option Level
  297. IPX_EXTENDED_ADDRESS, // Option Name
  298. (PCHAR)&Value, // Ptr to on/off flag
  299. sizeof(INT)) == SOCKET_ERROR ) {
  300. // Length of flag
  301. Error = WSAGetLastError();
  302. goto Cleanup;
  303. }
  304. //
  305. // Send the Sap query service packet
  306. //
  307. SapRequest.QueryType = htons( 1 ); // General Service Query
  308. SapRequest.ServerType = htons(INTERNET_SERVICE_SAP_ID);
  309. //
  310. // Set the address to send to
  311. //
  312. memcpy( DestAddr, GlobalSapBroadcastAddress, SAP_ADDRESS_LENGTH );
  313. //
  314. // We will send out SAP requests 3 times and wait 1 sec for
  315. // Sap responses the first time, 1 sec the second and 3 sec the
  316. // third time. Once we get MAXSITES responses, we give up.
  317. // We also give up if after processing all replies from a send,
  318. // we find at least one DC in the search domain.
  319. //
  320. DWORD i;
  321. #define SAP_DISCOVERY_RETRIES 1
  322. for ( i = 0; i < SAP_DISCOVERY_RETRIES; i++ ) {
  323. DWORD StartTickCount;
  324. DWORD TimeOut = (i + 1) * 1000;
  325. //
  326. // Send the packet out
  327. //
  328. if ( sendto( SapSocket,
  329. (PCHAR) &SapRequest,
  330. sizeof( SapRequest ),
  331. 0,
  332. (PSOCKADDR) DestAddr,
  333. SAP_ADDRESS_LENGTH ) == SOCKET_ERROR ) {
  334. Error = WSAGetLastError();
  335. goto Cleanup;
  336. }
  337. //
  338. // Loop for incoming packets
  339. //
  340. StartTickCount = GetTickCount();
  341. do {
  342. LPSAP_IDENT_HEADER SapResponse;
  343. DWORD BytesReceived;
  344. BYTE RecvBuffer[SAP_MAXRECV_LENGTH];
  345. Sleep(50); // take a deep breath
  346. BytesReceived =
  347. recvfrom( SapSocket,
  348. (PCHAR)RecvBuffer,
  349. SAP_MAXRECV_LENGTH,
  350. 0,
  351. NULL,
  352. NULL );
  353. if ( BytesReceived == SOCKET_ERROR ) {
  354. Error = WSAGetLastError();
  355. if ( Error == WSAEWOULDBLOCK ) {
  356. //
  357. // no data on socket, continue looping
  358. //
  359. Error = ERROR_SUCCESS;
  360. continue;
  361. }
  362. }
  363. if ( Error != ERROR_SUCCESS ) {
  364. goto Cleanup;
  365. }
  366. //
  367. // if socket closed, return.
  368. //
  369. if ( BytesReceived == 0 ) {
  370. goto ProcessResponse;
  371. }
  372. //
  373. // Skip over query type
  374. //
  375. BytesReceived -= sizeof(USHORT);
  376. SapResponse = (LPSAP_IDENT_HEADER)
  377. ((LPBYTE)RecvBuffer + sizeof(USHORT));
  378. //
  379. // loop through and check all addresses.
  380. //
  381. while ( BytesReceived >= sizeof( SAP_IDENT_HEADER )) {
  382. Error = ProcessSingleSapResponse(
  383. SapResponse,
  384. &ResponsesList );
  385. if( Error != ERROR_SUCCESS ) {
  386. goto Cleanup;
  387. }
  388. BytesReceived -= sizeof( SAP_IDENT_HEADER );
  389. SapResponse++;
  390. }
  391. } while((GetTickCount() - StartTickCount) < TimeOut );
  392. }
  393. //
  394. // Process response list.
  395. //
  396. ProcessResponse :
  397. Error = ProcessSapResponses(
  398. &ResponsesList,
  399. SapAddresses,
  400. NumSapAddresses );
  401. if( Error != ERROR_SUCCESS ) {
  402. goto Cleanup;
  403. }
  404. //
  405. // we are done.
  406. //
  407. Error = ERROR_SUCCESS;
  408. Cleanup:
  409. closesocket( SapSocket );
  410. //
  411. // free response list if any.
  412. //
  413. while( !IsListEmpty( &ResponsesList ) ) {
  414. PLIST_ENTRY ListEntry;
  415. //
  416. // remove the head entry and free.
  417. //
  418. ListEntry = RemoveHeadList( &ResponsesList );
  419. SvclocHeap->Free( ListEntry );
  420. }
  421. return( Error );
  422. }
  423. DWORD
  424. DiscoverIpxServers(
  425. LPSTR ServerName
  426. )
  427. /*++
  428. Routine Description:
  429. This routine discovers all IPX servers using RNR GetAddressByName.
  430. Assume : WSAStartup is called before calling this function.
  431. Arguments:
  432. ServerName : if this value is set non-NULL then discover only the
  433. specified server otherwise diescover all.
  434. Return Value:
  435. Windows Error Code.
  436. --*/
  437. {
  438. DWORD Error;
  439. DWORD NumSapAddresses = 0;
  440. LPSAP_ADDRESS_INFO SapAddresses = NULL;
  441. SOCKADDR DestAddr;
  442. //
  443. // first find out all servers running IPX only.
  444. // performed by doing SAP broadcast.
  445. //
  446. Error = GetSapAddress( &SapAddresses, &NumSapAddresses );
  447. if( Error != ERROR_SUCCESS ) {
  448. goto Cleanup;
  449. }
  450. //
  451. // now process returned buffer entries.
  452. //
  453. DWORD i;
  454. TcpsvcsDbgAssert( NumSapAddresses > 0 );
  455. //
  456. // create a IPX socket to send query message, if it is not created
  457. // before.
  458. //
  459. LOCK_SVC_GLOBAL_DATA();
  460. if( GlobalCliIpxSocket == INVALID_SOCKET ) {
  461. SOCKADDR_IPX IpxSocketAddr;
  462. DWORD Arg;
  463. GlobalCliIpxSocket = socket( PF_IPX, SOCK_DGRAM, NSPROTO_IPX );
  464. if( GlobalCliIpxSocket == INVALID_SOCKET ) {
  465. Error = WSAGetLastError();
  466. UNLOCK_SVC_GLOBAL_DATA();
  467. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  468. "socket() failed, %ld\n", Error ));
  469. goto Cleanup;
  470. }
  471. //
  472. // make this socket non blocking.
  473. //
  474. Arg = 1;
  475. if( (ioctlsocket( GlobalCliIpxSocket, FIONBIO, &Arg )) == SOCKET_ERROR ) {
  476. Error = WSAGetLastError();
  477. UNLOCK_SVC_GLOBAL_DATA();
  478. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  479. "ioctlsocket() failed, %ld\n", Error ));
  480. goto Cleanup;
  481. }
  482. //
  483. // Bind the socket
  484. //
  485. memset( &IpxSocketAddr, 0, sizeof( SOCKADDR_IPX));
  486. IpxSocketAddr.sa_family = AF_IPX;
  487. IpxSocketAddr.sa_socket = 0; // no specific port
  488. if ( bind( GlobalCliIpxSocket,
  489. (PSOCKADDR) &IpxSocketAddr,
  490. sizeof( SOCKADDR_IPX)) == SOCKET_ERROR ) {
  491. Error = WSAGetLastError();
  492. UNLOCK_SVC_GLOBAL_DATA();
  493. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  494. "bind() failed, %ld\n", Error ));
  495. goto Cleanup;
  496. }
  497. //
  498. // add this socket to global list.
  499. //
  500. FD_SET( GlobalCliIpxSocket, &GlobalCliSockets );
  501. }
  502. UNLOCK_SVC_GLOBAL_DATA();
  503. LPSAP_ADDRESS_INFO SapAddressInfo;
  504. SapAddressInfo = SapAddresses;
  505. DestAddr.sa_family = AF_IPX;
  506. for( i = 0; i < (DWORD)NumSapAddresses; i++, SapAddressInfo++ ) {
  507. //
  508. // if we are asked to discover only specific server
  509. // check the server name first before sending the query
  510. // message.
  511. //
  512. if( ServerName != NULL ) {
  513. if( _stricmp(
  514. ServerName,
  515. SapAddressInfo->ServerName ) != 0 ) {
  516. continue;
  517. }
  518. }
  519. //
  520. // send query message to each discovered server.
  521. //
  522. memcpy(
  523. DestAddr.sa_data,
  524. SapAddressInfo->Address,
  525. IPX_ADDRESS_LENGTH );
  526. Error = sendto(
  527. GlobalCliIpxSocket,
  528. (LPCSTR)GlobalCliQueryMsg,
  529. GlobalCliQueryMsgLen,
  530. 0,
  531. &DestAddr,
  532. 2 + IPX_ADDRESS_LENGTH );
  533. if( Error == SOCKET_ERROR ) {
  534. Error = WSAGetLastError();
  535. TcpsvcsDbgPrint(( DEBUG_ERRORS, "sendto() failed, %ld\n", Error ));
  536. continue;
  537. }
  538. }
  539. //
  540. // DONE.
  541. //
  542. Error = ERROR_SUCCESS;
  543. Cleanup:
  544. if( SapAddresses != NULL ) {
  545. SvclocHeap->Free( SapAddresses );
  546. }
  547. if( Error != ERROR_SUCCESS ) {
  548. TcpsvcsDbgPrint(( DEBUG_ERRORS, "DiscoverIpxServers failed, %ld\n", Error ));
  549. }
  550. return( Error );
  551. }
  552. DWORD
  553. DiscoverIpServers(
  554. LPSTR ServerName
  555. )
  556. /*++
  557. Routine Description:
  558. This function sends out a discovery message to all netbios lanas.
  559. Arguments:
  560. UniqueServerName : pointer to a server name string. If this pointer is
  561. NULL, it uses IC group name to discover all IP servers, otherwise
  562. it discovers the bindings of the specified server.
  563. Return Value:
  564. Windows Error Code.
  565. --*/
  566. {
  567. DWORD Error;
  568. SOCKADDR_NB RemoteSocketAddress;
  569. LOCK_SVC_GLOBAL_DATA();
  570. if( GlobalCliNBSockets.fd_count == 0 ) {
  571. SOCKET s;
  572. DWORD Lana;
  573. SOCKADDR_NB SocketAddress;
  574. // make netbios source address.
  575. //
  576. memset( &SocketAddress, 0x0, sizeof(SOCKADDR_NB) );
  577. SocketAddress.snb_family = AF_NETBIOS;
  578. SocketAddress.snb_type = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  579. GetNBUniqueName(
  580. SocketAddress.snb_name,
  581. sizeof(SocketAddress.snb_name) );
  582. //
  583. // enumurate lanas first.
  584. //
  585. LANA_ENUM Lanas;
  586. if( GetEnumNBLana( &Lanas ) ) {
  587. //
  588. // try only the lanas that are returned.
  589. //
  590. DWORD i;
  591. for( i = 0; i < Lanas.length; i++ ) {
  592. if ( MakeNBSocketForLana(
  593. Lanas.lana[i],
  594. (PSOCKADDR)&SocketAddress,
  595. &s ) ) {
  596. //
  597. // successfully made another socket, add to global list.
  598. //
  599. FD_SET( s, &GlobalCliNBSockets );
  600. FD_SET( s, &GlobalCliSockets );
  601. }
  602. }
  603. }
  604. else {
  605. UCHAR Lana;
  606. //
  607. // try all possible lanas and accept all valid lana sockets.
  608. //
  609. for( Lana = 0; Lana < MAX_LANA ; Lana-- ) {
  610. if ( MakeNBSocketForLana(
  611. Lana,
  612. (PSOCKADDR)&SocketAddress,
  613. &s ) ) {
  614. //
  615. // successfully made another socket, add to global
  616. // lists.
  617. //
  618. FD_SET( s, &GlobalCliNBSockets );
  619. FD_SET( s, &GlobalCliSockets );
  620. }
  621. }
  622. }
  623. }
  624. UNLOCK_SVC_GLOBAL_DATA();
  625. if( GlobalCliNBSockets.fd_count == 0 ) {
  626. return( ERROR_SUCCESS );
  627. }
  628. //
  629. //
  630. // make netbios destination address.
  631. //
  632. memset( &RemoteSocketAddress, 0x0, sizeof(SOCKADDR_NB) );
  633. if( ServerName == NULL ) {
  634. //
  635. // if no server name is specified, then send the discovery message
  636. // to IC group name.
  637. //
  638. RemoteSocketAddress.snb_family = AF_NETBIOS;
  639. RemoteSocketAddress.snb_type = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
  640. TcpsvcsDbgAssert(
  641. sizeof(RemoteSocketAddress.snb_name) >=
  642. NETBIOS_INET_GROUP_NAME_LEN );
  643. memcpy(
  644. RemoteSocketAddress.snb_name,
  645. NETBIOS_INET_GROUP_NAME,
  646. NETBIOS_INET_GROUP_NAME_LEN );
  647. }
  648. else {
  649. DWORD ServerNameLen;
  650. //
  651. // send the discovery message to the specified server.
  652. //
  653. RemoteSocketAddress.snb_family = AF_NETBIOS;
  654. RemoteSocketAddress.snb_type = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  655. ServerNameLen = strlen(ServerName);
  656. TcpsvcsDbgAssert(
  657. ServerNameLen <=
  658. sizeof(RemoteSocketAddress.snb_name) );
  659. memcpy(
  660. RemoteSocketAddress.snb_name,
  661. ServerName,
  662. (ServerNameLen >= sizeof(RemoteSocketAddress.snb_name)) ?
  663. sizeof(RemoteSocketAddress.snb_name) :
  664. ServerNameLen );
  665. }
  666. //
  667. // send message to all lanas.
  668. //
  669. DWORD i;
  670. for( i = 0; i < GlobalCliNBSockets.fd_count ; i++ ) {
  671. //
  672. // now send query message.
  673. //
  674. Error = sendto(
  675. GlobalCliNBSockets.fd_array[i],
  676. (LPCSTR)GlobalCliQueryMsg,
  677. GlobalCliQueryMsgLen,
  678. 0,
  679. (PSOCKADDR)&RemoteSocketAddress,
  680. sizeof(RemoteSocketAddress) );
  681. if( Error == SOCKET_ERROR ) {
  682. Error = WSAGetLastError();
  683. TcpsvcsDbgPrint(( DEBUG_ERRORS, "sendto() failed, %ld\n", Error ));
  684. }
  685. }
  686. return( ERROR_SUCCESS );
  687. }
  688. DWORD
  689. ProcessSvclocQueryResponse(
  690. SOCKET ReceivedSocket,
  691. LPBYTE ReceivedMessage,
  692. DWORD ReceivedMessageLength,
  693. SOCKADDR *SourcesAddress,
  694. DWORD SourcesAddressLength
  695. )
  696. /*++
  697. Routine Description:
  698. This function processes the query response message and queues them to
  699. the global list.
  700. Arguments:
  701. ReceivedSocket - socket the message came from.
  702. ReceivedMessage - pointer to a message buffer.
  703. ReceivedMessageLength - length of the above message.
  704. SourcesAddress - address of the sender.
  705. SourcesAddressLength - length of the above address.
  706. Return Value:
  707. Windows Error Code.
  708. --*/
  709. {
  710. DWORD Error;
  711. DWORD NodeLength;
  712. LPCLIENT_QUERY_RESPONSE ResponseNode;
  713. PLIST_ENTRY NextResponse;
  714. LPBYTE EndReceiveMessage;
  715. //
  716. // validate this message.
  717. //
  718. //
  719. // first DWORD in the message is the length of the message.
  720. //
  721. if( *(DWORD *)ReceivedMessage != ReceivedMessageLength ) {
  722. return( ERROR_INVALID_PARAMETER );
  723. }
  724. //
  725. // last DWORD is terminating char.
  726. //
  727. EndReceiveMessage = ReceivedMessage + ReceivedMessageLength;
  728. if( *(DWORD *) (EndReceiveMessage - sizeof(DWORD)) != 0xFFFFFFFF ) {
  729. return( ERROR_INVALID_PARAMETER );
  730. }
  731. //
  732. // validate check sum.
  733. // last but one DWORD is check of the message.
  734. //
  735. DWORD CheckSum;
  736. CheckSum = *(DWORD *) (EndReceiveMessage - 2 * sizeof(DWORD));
  737. DWORD ComputedCheckSum;
  738. ComputedCheckSum =
  739. ComputeCheckSum(
  740. ReceivedMessage + sizeof(DWORD), // skip length field.
  741. ReceivedMessageLength - 3 * sizeof(DWORD) );
  742. // skip last 2 DWORDS too.
  743. if( ComputedCheckSum != CheckSum ) {
  744. return( ERROR_INVALID_PARAMETER );
  745. }
  746. //
  747. // check version number.
  748. //
  749. INET_VERSION_NUM *VersionNum;
  750. VersionNum = (INET_VERSION_NUM *)(ReceivedMessage + sizeof(DWORD));
  751. if( VersionNum->Version.Major != INET_MAJOR_VERSION ) {
  752. return( ERROR_INVALID_PARAMETER );
  753. }
  754. LOCK_SVC_GLOBAL_DATA();
  755. //
  756. // check to see, there is already a response from this server, if so
  757. // update the response message, otherwise add a new entry.
  758. //
  759. for( NextResponse = GlobalCliQueryRespList.Flink;
  760. NextResponse != &GlobalCliQueryRespList;
  761. NextResponse = NextResponse->Flink ) {
  762. LPCLIENT_QUERY_RESPONSE QueryResponse;
  763. QueryResponse = (LPCLIENT_QUERY_RESPONSE)NextResponse;
  764. //
  765. // if either the server addresses match or
  766. // the server names in the message field match, then this
  767. // must be duplicate, so replace with old one.
  768. //
  769. if(
  770. #if 0
  771. //
  772. // this check always succeseed for group name.
  773. //
  774. ( (SourcesAddressLength == QueryResponse->SourcesAddressLength ) && (memcmp(
  775. SourcesAddress,
  776. QueryResponse->SourcesAddress,
  777. SourcesAddressLength ) == 0 ) ) ||
  778. #endif // 0
  779. ( strcmp(
  780. (LPSTR)ReceivedMessage + 2 * sizeof(DWORD),
  781. // skip length and version DWORDS.
  782. (LPSTR)QueryResponse->ResponseBuffer + 2 * sizeof(DWORD) )
  783. == 0 ) ) {
  784. //
  785. // free old response buffer.
  786. //
  787. SvclocHeap->Free( QueryResponse->ResponseBuffer );
  788. //
  789. // copy new response pointer.
  790. //
  791. QueryResponse->ResponseBuffer = ReceivedMessage;
  792. QueryResponse->ResponseBufferLength = ReceivedMessageLength;
  793. QueryResponse->TimeStamp = time( NULL );
  794. //
  795. // done.
  796. //
  797. Error = ERROR_SUCCESS;
  798. goto Cleanup;
  799. }
  800. }
  801. //
  802. // brand new response.
  803. //
  804. NodeLength = sizeof(CLIENT_QUERY_RESPONSE) + SourcesAddressLength;
  805. ResponseNode = (LPCLIENT_QUERY_RESPONSE)SvclocHeap->Alloc( NodeLength );
  806. if( ResponseNode == NULL ) {
  807. Error = ERROR_NOT_ENOUGH_MEMORY;
  808. goto Cleanup;
  809. }
  810. //
  811. // setup sock address pointer.
  812. //
  813. ResponseNode->SourcesAddress = (SOCKADDR *)(ResponseNode + 1);
  814. //
  815. // copy address data.
  816. //
  817. memcpy(
  818. ResponseNode->SourcesAddress,
  819. SourcesAddress,
  820. SourcesAddressLength );
  821. //
  822. // copy other fields.
  823. //
  824. ResponseNode->ReceivedSocket = ReceivedSocket;
  825. ResponseNode->ResponseBuffer = ReceivedMessage;
  826. ResponseNode->ResponseBufferLength = ReceivedMessageLength;
  827. ResponseNode->SourcesAddressLength = SourcesAddressLength;
  828. ResponseNode->TimeStamp = time( NULL );
  829. //
  830. // link this entry to global list.
  831. //
  832. InsertTailList( &GlobalCliQueryRespList, &ResponseNode->NextEntry );
  833. //
  834. // done.
  835. //
  836. Error = ERROR_SUCCESS;
  837. Cleanup:
  838. UNLOCK_SVC_GLOBAL_DATA();
  839. return( Error );
  840. }
  841. DWORD
  842. ReceiveResponses(
  843. WORD Timeout,
  844. BOOL WaitForAllResponses
  845. )
  846. /*++
  847. Routine Description:
  848. This routine receives responses for the query messages sent out to the
  849. servers.
  850. Arguments:
  851. Time - Time to wait for the response messages in secs.
  852. WaitForAllResponses : If this flag is set TRUE, this function wait
  853. complete 'Time' secs for all responses to arrive. Otherwise it
  854. will return after a succcessful response is received.
  855. Return Value:
  856. None.
  857. --*/
  858. {
  859. DWORD Error;
  860. struct timeval SockTimeout;
  861. struct timeval *pSockTimeout;
  862. DWORD TimeoutinMSecs = INFINITE;
  863. DWORD TickCountStart;
  864. if( Timeout != 0 ) {
  865. TimeoutinMSecs = Timeout * 1000;
  866. pSockTimeout = &SockTimeout;
  867. }
  868. else {
  869. pSockTimeout = NULL;
  870. }
  871. //
  872. // now loop for incoming messages.
  873. //
  874. //
  875. // remember current tick out.
  876. //
  877. TickCountStart = GetTickCount();
  878. for( ;; ) {
  879. fd_set ReadSockets;
  880. INT NumReadySockets;
  881. DWORD NumSockets;
  882. DWORD i;
  883. LOCK_SVC_GLOBAL_DATA();
  884. NumSockets = GlobalCliSockets.fd_count;
  885. UNLOCK_SVC_GLOBAL_DATA();
  886. if( NumSockets != 0 ) {
  887. //
  888. // select
  889. //
  890. LOCK_SVC_GLOBAL_DATA();
  891. memcpy( &ReadSockets, &GlobalCliSockets, sizeof(fd_set) );
  892. UNLOCK_SVC_GLOBAL_DATA();
  893. //
  894. // compute time out, if it is not infinity.
  895. //
  896. if( pSockTimeout != NULL ) {
  897. SockTimeout.tv_sec = TimeoutinMSecs / 1000;
  898. SockTimeout.tv_usec = TimeoutinMSecs % 1000;
  899. }
  900. NumReadySockets =
  901. select(
  902. 0, // compatibility argument, ignored.
  903. &ReadSockets, // sockets to test for readability.
  904. NULL, // no write wait
  905. NULL, // no error check.
  906. pSockTimeout ); // NO timeout.
  907. if( NumReadySockets == SOCKET_ERROR ) {
  908. //
  909. // when all sockets are closed, we are asked to return or
  910. // something else has happpened which we can't handle.
  911. //
  912. Error = WSAGetLastError();
  913. goto Cleanup;
  914. }
  915. TcpsvcsDbgAssert( (DWORD)NumReadySockets == ReadSockets.fd_count );
  916. for( i = 0; i < (DWORD)NumReadySockets; i++ ) {
  917. DWORD ReadMessageLength;
  918. struct sockaddr_nb SourcesAddress;
  919. int SourcesAddressLength;
  920. LPBYTE RecvBuffer;
  921. DWORD RecvBufferLength;
  922. RecvBufferLength = SVCLOC_CLI_QUERY_RESP_BUF_SIZE;
  923. RecvBuffer = (LPBYTE)SvclocHeap->Alloc( RecvBufferLength );
  924. if( RecvBuffer == NULL ) {
  925. Error = ERROR_NOT_ENOUGH_MEMORY;
  926. goto Cleanup;
  927. }
  928. //
  929. // read next message.
  930. //
  931. SourcesAddressLength = sizeof(SourcesAddress);
  932. ReadMessageLength =
  933. recvfrom(
  934. ReadSockets.fd_array[i],
  935. (LPSTR)RecvBuffer,
  936. RecvBufferLength,
  937. 0,
  938. (struct sockaddr *)&SourcesAddress,
  939. &SourcesAddressLength );
  940. if( ReadMessageLength == SOCKET_ERROR ) {
  941. //
  942. // when all sockets are closed, we are asked to return
  943. // or something else has happpened which we can't
  944. // handle.
  945. //
  946. Error = WSAGetLastError();
  947. //
  948. // free receive buffer.
  949. //
  950. SvclocHeap->Free( RecvBuffer );
  951. RecvBuffer = NULL;
  952. if( Error == WSAEMSGSIZE ) {
  953. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  954. "recvfrom() received a too large message (%ld).\n",
  955. ReadMessageLength ));
  956. continue; // process next message.
  957. }
  958. goto Cleanup;
  959. }
  960. TcpsvcsDbgAssert( ReadMessageLength <= RecvBufferLength );
  961. //
  962. // received a message.
  963. //
  964. TcpsvcsDbgPrint((
  965. DEBUG_SVCLOC_MESSAGE,
  966. "Received an query response message, %ld.\n",
  967. ReadMessageLength ));
  968. Error = ProcessSvclocQueryResponse(
  969. ReadSockets.fd_array[i],
  970. RecvBuffer,
  971. (DWORD)ReadMessageLength,
  972. (struct sockaddr *)&SourcesAddress,
  973. (DWORD)SourcesAddressLength );
  974. if( Error != ERROR_SUCCESS ) {
  975. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  976. "ProcessSvclocQueryResponse failed, %ld.\n", Error ));
  977. //
  978. // free receive buffer.
  979. //
  980. SvclocHeap->Free( RecvBuffer );
  981. RecvBuffer = NULL;
  982. }
  983. }
  984. }
  985. //
  986. // otherthan NT platform, receive NetBios responses also.
  987. //
  988. if( GlobalPlatformType != VER_PLATFORM_WIN32_NT ) {
  989. LPSVCLOC_NETBIOS_RESPONSE NetBiosResponses = NULL;
  990. DWORD NumResponses;
  991. //
  992. // compute remaining time.
  993. //
  994. if( pSockTimeout != NULL ) {
  995. DWORD NewTickCountStart;
  996. DWORD Elapse;
  997. NewTickCountStart = GetTickCount();
  998. //
  999. // subtract elapse time.
  1000. //
  1001. Elapse = NewTickCountStart - TickCountStart;
  1002. if( Elapse > TimeoutinMSecs ) {
  1003. TimeoutinMSecs = 0;
  1004. }
  1005. else {
  1006. TimeoutinMSecs -= Elapse;
  1007. TickCountStart = NewTickCountStart;
  1008. }
  1009. }
  1010. //
  1011. // receive netbios responses.
  1012. //
  1013. Error = ReceiveNetBiosResponses(
  1014. &NetBiosResponses,
  1015. &NumResponses,
  1016. TimeoutinMSecs,
  1017. WaitForAllResponses );
  1018. if( Error != ERROR_SUCCESS ) {
  1019. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1020. "ReceiveNetBiosResponses failed, %ld.\n", Error ));
  1021. //
  1022. // ignore this error and continue.
  1023. //
  1024. }
  1025. else {
  1026. LPSVCLOC_NETBIOS_RESPONSE NBResp = NetBiosResponses;
  1027. for( i = 0; i < NumResponses; i++, NBResp++ ) {
  1028. Error = ProcessSvclocQueryResponse(
  1029. 0,
  1030. NBResp->ResponseBuffer,
  1031. NBResp->ResponseBufLen,
  1032. (struct sockaddr *)
  1033. &NBResp->SourcesAddress,
  1034. NBResp->SourcesAddrLen );
  1035. if( Error != ERROR_SUCCESS ) {
  1036. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1037. "ProcessSvclocQueryResponse failed, %ld.\n",
  1038. Error ));
  1039. //
  1040. // free response receive buffer.
  1041. //
  1042. SvclocHeap->Free( NBResp->ResponseBuffer );
  1043. //
  1044. // ignore this error and continue.
  1045. //
  1046. }
  1047. }
  1048. //
  1049. // free up response buffer.
  1050. //
  1051. if( NetBiosResponses != NULL ) {
  1052. SvclocHeap->Free( NetBiosResponses );
  1053. }
  1054. }
  1055. }
  1056. else {
  1057. //
  1058. // if we have timed out.
  1059. //
  1060. if( NumReadySockets == 0 ) {
  1061. Error = ERROR_SUCCESS;
  1062. goto Cleanup;
  1063. }
  1064. }
  1065. if( WaitForAllResponses == FALSE ) {
  1066. //
  1067. // return after the first set of responses received.
  1068. //
  1069. Error = ERROR_SUCCESS;
  1070. break;
  1071. }
  1072. //
  1073. // compute remaining time.
  1074. //
  1075. if( pSockTimeout != NULL ) {
  1076. DWORD NewTickCountStart;
  1077. DWORD Elapse;
  1078. NewTickCountStart = GetTickCount();
  1079. //
  1080. // subtract elapse time.
  1081. //
  1082. Elapse = NewTickCountStart - TickCountStart;
  1083. if( Elapse > TimeoutinMSecs ) {
  1084. TimeoutinMSecs = 0;
  1085. Error = ERROR_SUCCESS;
  1086. goto Cleanup;
  1087. }
  1088. else {
  1089. TimeoutinMSecs -= Elapse;
  1090. TickCountStart = NewTickCountStart;
  1091. }
  1092. }
  1093. }
  1094. Cleanup:
  1095. //
  1096. // discovery is completed (successfully or not), indicate so.
  1097. //
  1098. LOCK_SVC_GLOBAL_DATA();
  1099. SetEvent( GlobalDiscoveryInProgressEvent );
  1100. GlobalLastDiscoveryTime = time( NULL );
  1101. UNLOCK_SVC_GLOBAL_DATA();
  1102. return( Error );
  1103. }
  1104. VOID
  1105. ServerDiscoverThread(
  1106. LPVOID Parameter
  1107. )
  1108. /*++
  1109. Routine Description:
  1110. This thread waits for query responses to arrive, when they arrive it
  1111. queues them in them in the global list.
  1112. Arguments:
  1113. Parameter - not used..
  1114. Return Value:
  1115. None.
  1116. --*/
  1117. {
  1118. DWORD Error;
  1119. Error = ReceiveResponses( RESPONSE_WAIT_TIMEOUT, TRUE );
  1120. if( Error != ERROR_SUCCESS ) {
  1121. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1122. "ReceiveResponses returned error (%ld) .\n", Error ));
  1123. }
  1124. LOCK_SVC_GLOBAL_DATA();
  1125. //
  1126. // close thread handle.
  1127. //
  1128. CloseHandle( GlobalCliDiscoverThreadHandle );
  1129. GlobalCliDiscoverThreadHandle = NULL;
  1130. UNLOCK_SVC_GLOBAL_DATA();
  1131. return;
  1132. }
  1133. DWORD
  1134. MakeClientQueryMesage(
  1135. ULONGLONG ServicesMask
  1136. )
  1137. /*++
  1138. Routine Description:
  1139. This function makes client query message and stores it in the global
  1140. data buffer for future use.
  1141. The query message format.
  1142. 1st DWORD : message length.
  1143. 2nd DWORD : message version.
  1144. 3rd ULONGLONG : services mask the client interested in.
  1145. 4th WCHAR[] : client name
  1146. ..
  1147. ..
  1148. Last but one DWORD : check sum.
  1149. LAST DWORD : terminating DWORD 0xFFFFFFFF
  1150. Assume: Global data is locked.
  1151. Arguments:
  1152. ServicesMask - services to query for.
  1153. Return Value:
  1154. Windows Error Code.
  1155. --*/
  1156. {
  1157. LPCLIENT_QUERY_MESSAGE QueryMsg;
  1158. //
  1159. // Test to see query message is already made.
  1160. //
  1161. if( GlobalCliQueryMsg == NULL ) {
  1162. //
  1163. // check to computer name is initilaized.
  1164. //
  1165. if( GlobalComputerName[0] == '\0' ) {
  1166. DWORD ComputerNameLength =
  1167. MAX_COMPUTERNAME_LENGTH + 1;
  1168. //
  1169. // read computer name.
  1170. //
  1171. if( !GetComputerNameA(
  1172. GlobalComputerName,
  1173. &ComputerNameLength ) ) {
  1174. DWORD Error = GetLastError();
  1175. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1176. "GetComputerNameA failed, %ld.\n", Error ));
  1177. return( Error );
  1178. }
  1179. GlobalComputerName[ComputerNameLength] = '\0';
  1180. }
  1181. //
  1182. // compute the space required for the query message.
  1183. //
  1184. DWORD MsgLen;
  1185. MsgLen = sizeof(CLIENT_QUERY_MESSAGE) +
  1186. strlen(GlobalComputerName) * sizeof(CHAR);
  1187. // note the terminating char is included as part of
  1188. // CLIENT_QUERY_MESSAGE size.
  1189. //
  1190. // Ceil to next DWORD.
  1191. //
  1192. MsgLen = ROUND_UP_COUNT(MsgLen, ALIGN_DWORD);
  1193. //
  1194. // add space for checksum and terminating DWORD.
  1195. //
  1196. MsgLen += sizeof(DWORD);
  1197. QueryMsg = (LPCLIENT_QUERY_MESSAGE) SvclocHeap->Alloc( MsgLen );
  1198. if( QueryMsg == NULL ) {
  1199. return( ERROR_NOT_ENOUGH_MEMORY );
  1200. }
  1201. memset( QueryMsg, 0x0, MsgLen );
  1202. //
  1203. // init fields.
  1204. //
  1205. INET_VERSION_NUM MessageVersion;
  1206. MessageVersion.Version.Major = INET_MAJOR_VERSION;
  1207. MessageVersion.Version.Minor = INET_MINOR_VERSION;
  1208. QueryMsg->MsgLength = MsgLen;
  1209. QueryMsg->MsgVersion = MessageVersion.VersionNumber;
  1210. QueryMsg->ServicesMask = ServicesMask;
  1211. strcpy( QueryMsg->ClientName, GlobalComputerName );
  1212. //
  1213. // compute check sum.
  1214. //
  1215. DWORD Checksum;
  1216. Checksum = ComputeCheckSum(
  1217. (LPBYTE)QueryMsg + sizeof(DWORD), // skip length field.
  1218. MsgLen - 3 * sizeof(DWORD) );
  1219. *(LPDWORD)((LPBYTE)QueryMsg + MsgLen - 2 * sizeof(DWORD)) = Checksum;
  1220. *(LPDWORD)((LPBYTE)QueryMsg + MsgLen - sizeof(DWORD)) = 0xFFFFFFFF;
  1221. GlobalCliQueryMsg = (LPBYTE)QueryMsg;
  1222. GlobalCliQueryMsgLen = MsgLen;
  1223. }
  1224. else {
  1225. //
  1226. // set the requested service mask in the message.
  1227. //
  1228. QueryMsg = (LPCLIENT_QUERY_MESSAGE)GlobalCliQueryMsg;
  1229. QueryMsg->ServicesMask |= ServicesMask;
  1230. }
  1231. return( ERROR_SUCCESS );
  1232. }
  1233. DWORD
  1234. CleanupOldResponses(
  1235. VOID
  1236. )
  1237. /*++
  1238. Routine Description:
  1239. This function removes and deletes the server responses that are older
  1240. than INET_SERVER_RESPONSE_TIMEOUT (15 mins).
  1241. ASSUME : the global lock is locked.
  1242. Arguments:
  1243. none.
  1244. Return Value:
  1245. Windows Error Code.
  1246. --*/
  1247. {
  1248. PLIST_ENTRY NextResponse;
  1249. LPCLIENT_QUERY_RESPONSE QueryResponse;
  1250. time_t CurrentTime;
  1251. CurrentTime = time( NULL );
  1252. NextResponse = GlobalCliQueryRespList.Flink;
  1253. while( NextResponse != &GlobalCliQueryRespList ) {
  1254. QueryResponse = (LPCLIENT_QUERY_RESPONSE)NextResponse;
  1255. NextResponse = NextResponse->Flink;
  1256. if( CurrentTime > QueryResponse->TimeStamp +
  1257. INET_SERVER_RESPONSE_TIMEOUT ) {
  1258. RemoveEntryList( (PLIST_ENTRY)QueryResponse );
  1259. //
  1260. // free up resources.
  1261. //
  1262. //
  1263. // free response buffer.
  1264. //
  1265. SvclocHeap->Free( QueryResponse->ResponseBuffer );
  1266. //
  1267. // free this node.
  1268. //
  1269. SvclocHeap->Free( QueryResponse );
  1270. }
  1271. }
  1272. return( ERROR_SUCCESS );
  1273. }
  1274. DWORD
  1275. GetDiscoveredServerInfo(
  1276. LPSTR ServerName,
  1277. IN ULONGLONG ServicesMask,
  1278. LPINET_SERVER_INFO *ServerInfo
  1279. )
  1280. /*++
  1281. Routine Description:
  1282. This function processes the responses received from the servers so far
  1283. and returns the response received from the specified server.
  1284. ASSUME : the global lock is locked.
  1285. Arguments:
  1286. ServerName : name of the server whose info to be queried.
  1287. ServicesMask : services to be queried
  1288. INetServerInfo : pointer to a location where the pointer to a
  1289. INET_SERVER_INFO structure is returned.
  1290. Return Value:
  1291. Windows Error Code.
  1292. --*/
  1293. {
  1294. DWORD Error;
  1295. PLIST_ENTRY NextResponse;
  1296. LPCLIENT_QUERY_RESPONSE QueryResponse;
  1297. LOCK_SVC_GLOBAL_DATA();
  1298. //
  1299. // first clean up timeout server records.
  1300. //
  1301. Error = CleanupOldResponses();
  1302. if( Error != ERROR_SUCCESS ) {
  1303. goto Cleanup;
  1304. }
  1305. //
  1306. // now loop through the list of responses and findout the response
  1307. // from the specified server.
  1308. //
  1309. for( NextResponse = GlobalCliQueryRespList.Flink;
  1310. NextResponse != &GlobalCliQueryRespList;
  1311. NextResponse = NextResponse->Flink ) {
  1312. QueryResponse = (LPCLIENT_QUERY_RESPONSE)NextResponse;
  1313. //
  1314. // check to see this entry is from the specified server.
  1315. //
  1316. if( _stricmp(
  1317. ServerName,
  1318. (LPSTR)QueryResponse->ResponseBuffer + 2 * sizeof(DWORD) )
  1319. // skip length and version DWORDS.
  1320. == 0 ) {
  1321. EMBED_SERVER_INFO *ServerInfoObj;
  1322. ServerInfoObj = new EMBED_SERVER_INFO(
  1323. QueryResponse->ResponseBuffer + sizeof(DWORD), // skip length field.
  1324. QueryResponse->ResponseBufferLength - 3 * sizeof(DWORD) );
  1325. // skip last 2 DWORDS too.
  1326. if( ServerInfoObj == NULL ) {
  1327. Error = ERROR_NOT_ENOUGH_MEMORY;
  1328. goto Cleanup;
  1329. }
  1330. Error = ServerInfoObj->GetStatus();
  1331. if( Error != ERROR_SUCCESS ) {
  1332. delete ServerInfoObj;
  1333. goto Cleanup;
  1334. }
  1335. //
  1336. // check services quaried.
  1337. //
  1338. if( ServicesMask & ServerInfoObj->GetServicesMask() ) {
  1339. //
  1340. // now make server info structure;
  1341. //
  1342. Error = ServerInfoObj->GetServerInfo( ServerInfo );
  1343. }
  1344. else {
  1345. //
  1346. // the server does not support the service(s) quaried.
  1347. //
  1348. Error = ERROR_BAD_NETPATH;
  1349. }
  1350. //
  1351. // delete the object which we don't require anymore.
  1352. //
  1353. delete ServerInfoObj;
  1354. //
  1355. // we are done.
  1356. //
  1357. goto Cleanup;
  1358. }
  1359. }
  1360. //
  1361. // unable to find the specified server.
  1362. //
  1363. Error = ERROR_BAD_NETPATH;
  1364. Cleanup:
  1365. UNLOCK_SVC_GLOBAL_DATA();
  1366. return( Error );
  1367. }
  1368. DWORD
  1369. ProcessDiscoveryResponses(
  1370. IN ULONGLONG ServicesMask,
  1371. OUT LPINET_SERVERS_LIST *INetServersList
  1372. )
  1373. /*++
  1374. Routine Description:
  1375. This function processes the responses received from the servers so far
  1376. and makes INET_SERVERS_LIST.
  1377. Arguments:
  1378. ServicesMask : services to be queried
  1379. INetServersList : pointer to a location where the pointer to a
  1380. INET_SERVERS_LIST structure is returned.
  1381. Return Value:
  1382. Windows Error Code.
  1383. --*/
  1384. {
  1385. DWORD Error;
  1386. PLIST_ENTRY NextResponse;
  1387. LPCLIENT_QUERY_RESPONSE QueryResponse;
  1388. DWORD NumServers;
  1389. LPINET_SERVERS_LIST ServersList;
  1390. LOCK_SVC_GLOBAL_DATA();
  1391. //
  1392. // first clean up timeout server records.
  1393. //
  1394. Error = CleanupOldResponses();
  1395. if( Error != ERROR_SUCCESS ) {
  1396. goto Cleanup;
  1397. }
  1398. //
  1399. // compute number of responses we have.
  1400. //
  1401. NumServers = 0;
  1402. for( NextResponse = GlobalCliQueryRespList.Flink;
  1403. NextResponse != &GlobalCliQueryRespList;
  1404. NextResponse = NextResponse->Flink ) {
  1405. NumServers++;
  1406. }
  1407. //
  1408. // allocate memory for servers list structure.
  1409. //
  1410. ServersList = (LPINET_SERVERS_LIST)
  1411. SvclocHeap->Alloc( sizeof(INET_SERVERS_LIST) );
  1412. if( ServersList == NULL ) {
  1413. Error = ERROR_NOT_ENOUGH_MEMORY;
  1414. goto Cleanup;
  1415. }
  1416. ServersList->NumServers = 0;
  1417. ServersList->Servers = NULL;
  1418. //
  1419. // now allocate memory for the servers info structure pointers array.
  1420. //
  1421. ServersList->Servers = (LPINET_SERVER_INFO *)
  1422. SvclocHeap->Alloc(NumServers * sizeof(LPINET_SERVER_INFO) );
  1423. if( ServersList->Servers == NULL ) {
  1424. Error = ERROR_NOT_ENOUGH_MEMORY;
  1425. goto Cleanup;
  1426. }
  1427. //
  1428. // loop through the list of responses and make response structures.
  1429. //
  1430. for( NextResponse = GlobalCliQueryRespList.Flink;
  1431. NextResponse != &GlobalCliQueryRespList;
  1432. NextResponse = NextResponse->Flink ) {
  1433. EMBED_SERVER_INFO *ServerInfoObj;
  1434. QueryResponse = (LPCLIENT_QUERY_RESPONSE)NextResponse;
  1435. ServerInfoObj = new EMBED_SERVER_INFO(
  1436. QueryResponse->ResponseBuffer + sizeof(DWORD), // skip length field.
  1437. QueryResponse->ResponseBufferLength - 3 * sizeof(DWORD) );
  1438. // skip last 2 DWORDS too.
  1439. if( ServerInfoObj == NULL ) {
  1440. Error = ERROR_NOT_ENOUGH_MEMORY;
  1441. goto Cleanup;
  1442. }
  1443. Error = ServerInfoObj->GetStatus();
  1444. if( Error != ERROR_SUCCESS ) {
  1445. delete ServerInfoObj;
  1446. goto Cleanup;
  1447. }
  1448. //
  1449. // check services quaried.
  1450. //
  1451. if( ServicesMask & ServerInfoObj->GetServicesMask() ) {
  1452. //
  1453. // the server has the one or more of the services quaried.
  1454. // add an entry in the return buffer.
  1455. //
  1456. DWORD i;
  1457. i = ServersList->NumServers;
  1458. //
  1459. // now make server info structure;
  1460. //
  1461. Error = ServerInfoObj->GetServerInfo( &ServersList->Servers[i] );
  1462. if( Error != ERROR_SUCCESS ) {
  1463. TcpsvcsDbgAssert( ServersList->Servers[i] == NULL );
  1464. delete ServerInfoObj;
  1465. ServerInfoObj = NULL;
  1466. goto Cleanup;
  1467. }
  1468. //
  1469. // allocate space for server address.
  1470. //
  1471. LPVOID ServerAddress;
  1472. ServerAddress = SvclocHeap->Alloc( QueryResponse->SourcesAddressLength );
  1473. if( ServerAddress != NULL ) {
  1474. //
  1475. // copy server address.
  1476. //
  1477. TcpsvcsDbgAssert( ServersList->Servers[i]->ServerAddress.BindData == NULL );
  1478. TcpsvcsDbgAssert( ServersList->Servers[i]->ServerAddress.Length == 0 );
  1479. memcpy(
  1480. ServerAddress,
  1481. QueryResponse->SourcesAddress,
  1482. QueryResponse->SourcesAddressLength );
  1483. ServersList->Servers[i]->ServerAddress.BindData = ServerAddress;
  1484. ServersList->Servers[i]->ServerAddress.Length =
  1485. QueryResponse->SourcesAddressLength;
  1486. }
  1487. //
  1488. // we success fully added another server info, indicate so.
  1489. //
  1490. ServersList->NumServers++;
  1491. }
  1492. //
  1493. // delete the object which we don't require anymore.
  1494. //
  1495. delete ServerInfoObj;
  1496. ServerInfoObj = NULL;
  1497. }
  1498. //
  1499. // now set up return pointer.
  1500. //
  1501. *INetServersList = ServersList;
  1502. ServersList = NULL;
  1503. Error = ERROR_SUCCESS;
  1504. Cleanup:
  1505. UNLOCK_SVC_GLOBAL_DATA();
  1506. if( ServersList != NULL ) {
  1507. //
  1508. // free server info structures first.
  1509. //
  1510. if( ServersList->NumServers > 0 ) {
  1511. TcpsvcsDbgAssert( ServersList->Servers != NULL );
  1512. }
  1513. DWORD Index;
  1514. for (Index = 0; Index < ServersList->NumServers; Index++) {
  1515. TcpsvcsDbgAssert( ServersList->Servers[Index] != NULL );
  1516. FreeServerInfo( ServersList->Servers[Index] );
  1517. }
  1518. if( ServersList->Servers != NULL ) {
  1519. SvclocHeap->Free( ServersList->Servers );
  1520. }
  1521. SvclocHeap->Free( ServersList );
  1522. }
  1523. if( Error != ERROR_SUCCESS ) {
  1524. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1525. "ProcessDiscoveryResponses returning error, %ld.", Error ));
  1526. }
  1527. return( Error );
  1528. }
  1529. DWORD
  1530. ProcessNcbResponse(
  1531. NCB *Ncb,
  1532. PLIST_ENTRY RespList,
  1533. DWORD *NumEntries
  1534. )
  1535. {
  1536. LPBYTE RespBuffer;
  1537. DWORD RespBufferLen;
  1538. if ( Ncb->ncb_retcode == NRC_GOODRET ) {
  1539. // DebugBreak();
  1540. //
  1541. // copy response buffer pointer.
  1542. //
  1543. RespBuffer = Ncb->ncb_buffer;
  1544. RespBufferLen = Ncb->ncb_length;
  1545. //
  1546. // allocate a new buffer.
  1547. //
  1548. LPBYTE RecvBuffer;
  1549. RecvBuffer = (LPBYTE )
  1550. SvclocHeap->Alloc( SVCLOC_CLI_QUERY_RESP_BUF_SIZE );
  1551. if( RecvBuffer == NULL ) {
  1552. return( ERROR_NOT_ENOUGH_MEMORY );
  1553. }
  1554. Ncb->ncb_buffer = RecvBuffer;
  1555. Ncb->ncb_length = SVCLOC_CLI_QUERY_RESP_BUF_SIZE;
  1556. //
  1557. // resubmit the NCB with different buffer.
  1558. //
  1559. UCHAR NBErrorCode;
  1560. NBErrorCode = Netbios( Ncb );
  1561. if( (NBErrorCode != NRC_GOODRET) ||
  1562. (Ncb->ncb_retcode != NRC_PENDING) ) {
  1563. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1564. "Netbios() failed, %ld, %ld \n",
  1565. NBErrorCode, Ncb->ncb_retcode ));
  1566. return( ERROR_BAD_NETPATH );
  1567. }
  1568. }
  1569. else {
  1570. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  1571. "Netbios() failed, %ld\n", Ncb->ncb_retcode ));
  1572. return( ERROR_BAD_NETPATH ); // ??
  1573. }
  1574. //
  1575. // create a response entry and add to the list.
  1576. //
  1577. LPSVCLOC_NETBIOS_RESP_ENTRY RespEntry;
  1578. RespEntry = (LPSVCLOC_NETBIOS_RESP_ENTRY)
  1579. SvclocHeap->Alloc( sizeof(SVCLOC_NETBIOS_RESP_ENTRY) );
  1580. if( RespEntry == NULL ) {
  1581. return( ERROR_NOT_ENOUGH_MEMORY );;
  1582. }
  1583. RespEntry->Resp.ResponseBuffer = RespBuffer;
  1584. RespEntry->Resp.ResponseBufLen = RespBufferLen;
  1585. RespEntry->Resp.SourcesAddress.snb_family = AF_NETBIOS;
  1586. RespEntry->Resp.SourcesAddress.snb_type =
  1587. TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  1588. memcpy(
  1589. RespEntry->Resp.SourcesAddress.snb_name,
  1590. Ncb->ncb_callname,
  1591. sizeof(Ncb->ncb_callname) );
  1592. RespEntry->Resp.SourcesAddrLen = sizeof(SOCKADDR_NB);
  1593. (*NumEntries)++;
  1594. InsertTailList( RespList, (PLIST_ENTRY)RespEntry );
  1595. return( ERROR_SUCCESS );
  1596. }
  1597. VOID
  1598. NcbPostHandler(
  1599. NCB *Ncb
  1600. )
  1601. {
  1602. ProcessNcbResponse(
  1603. Ncb,
  1604. &GlobalWin31NBRespList,
  1605. &GlobalWin31NumNBResps
  1606. );
  1607. return;
  1608. }
  1609. DWORD
  1610. DiscoverNetBiosServers(
  1611. LPSTR ServerName
  1612. )
  1613. /*++
  1614. Routine Description:
  1615. This function sends out discovery message over netbios NBCs
  1616. Arguments:
  1617. ServerName : name of the specific server to discover.
  1618. Return Value:
  1619. Windows Error Code.
  1620. --*/
  1621. {
  1622. NCB *Ncbs = NULL;
  1623. LANA_ENUM Lanas;
  1624. DWORD Error = ERROR_SUCCESS;
  1625. UCHAR NBErrorCode = NRC_GOODRET;
  1626. UCHAR UniqueName[NCBNAMSZ];
  1627. // DebugBreak();
  1628. LOCK_SVC_GLOBAL_DATA();
  1629. if( !GetNetBiosLana( &Lanas ) ) {
  1630. return( ERROR_BAD_NETPATH );
  1631. }
  1632. TcpsvcsDbgAssert( Lanas.length != 0 );
  1633. if( Lanas.length == 0 ) {
  1634. return( ERROR_BAD_NETPATH );
  1635. }
  1636. Ncbs = (NCB *) SvclocHeap->Alloc( sizeof(NCB ) * Lanas.length );
  1637. if( Ncbs == NULL ) {
  1638. Error = ERROR_NOT_ENOUGH_MEMORY;
  1639. goto Cleanup;
  1640. }
  1641. memset( Ncbs, 0x0, sizeof(NCB) * Lanas.length );
  1642. GetNBUniqueName( (LPSTR)UniqueName, NCBNAMSZ );
  1643. //
  1644. // alloc memory for the pending recvs.
  1645. //
  1646. #define NUM_RECV_PENDING_NCBS_PER_LANA 3
  1647. GlobalNumNBPendingRecvs = 0;
  1648. GlobalNBPendingRecvs = (NCB *)
  1649. SvclocHeap->Alloc(
  1650. sizeof(NCB ) *
  1651. Lanas.length *
  1652. NUM_RECV_PENDING_NCBS_PER_LANA );
  1653. if( GlobalNBPendingRecvs == NULL ) {
  1654. Error = ERROR_NOT_ENOUGH_MEMORY;
  1655. goto Cleanup;
  1656. }
  1657. DWORD i;
  1658. for( i = 0; i < Lanas.length; i++ ) {
  1659. NCB *PendingRecv;
  1660. LPBYTE RecvBuffer;
  1661. HANDLE EventHandle;
  1662. Ncbs[i].ncb_command = NCBADDNAME;
  1663. memcpy( Ncbs[i].ncb_name, UniqueName, NCBNAMSZ );
  1664. //
  1665. // add name.
  1666. //
  1667. Ncbs[i].ncb_lana_num = Lanas.lana[i];
  1668. // DebugBreak();
  1669. NBErrorCode = Netbios( &Ncbs[i] );
  1670. if( Ncbs[i].ncb_retcode != NRC_GOODRET ) {
  1671. NBErrorCode = Ncbs[i].ncb_retcode;
  1672. }
  1673. if( NBErrorCode != NRC_GOODRET ) {
  1674. goto Cleanup;
  1675. }
  1676. //
  1677. // post pending receives.
  1678. //
  1679. DWORD j;
  1680. for( j = 0; j < NUM_RECV_PENDING_NCBS_PER_LANA; j++ ) {
  1681. TcpsvcsDbgAssert(
  1682. GlobalNumNBPendingRecvs <
  1683. ( (DWORD)Lanas.length *
  1684. NUM_RECV_PENDING_NCBS_PER_LANA) );
  1685. PendingRecv =
  1686. &GlobalNBPendingRecvs[GlobalNumNBPendingRecvs];
  1687. memset( PendingRecv, 0x0, sizeof(NCB) );
  1688. memcpy(
  1689. PendingRecv->ncb_name,
  1690. Ncbs[i].ncb_name,
  1691. NCBNAMSZ );
  1692. PendingRecv->ncb_lana_num = Lanas.lana[i];
  1693. PendingRecv->ncb_command = NCBDGRECV | ASYNCH;
  1694. PendingRecv->ncb_rto = SVCLOC_NB_RECV_TIMEOUT / 2;
  1695. PendingRecv->ncb_num = Ncbs[i].ncb_num;
  1696. RecvBuffer = (LPBYTE)
  1697. SvclocHeap->Alloc( SVCLOC_CLI_QUERY_RESP_BUF_SIZE );
  1698. if( RecvBuffer == NULL ) {
  1699. Error = ERROR_NOT_ENOUGH_MEMORY;
  1700. goto Cleanup;
  1701. }
  1702. PendingRecv->ncb_buffer = RecvBuffer;
  1703. PendingRecv->ncb_length = SVCLOC_CLI_QUERY_RESP_BUF_SIZE;
  1704. if( GlobalPlatformType == VER_PLATFORM_WIN32s ) {
  1705. PendingRecv->ncb_post = NcbPostHandler ;
  1706. }
  1707. else {
  1708. //
  1709. // create an event.
  1710. //
  1711. EventHandle = IIS_CREATE_EVENT(
  1712. "NCB::ncb_event",
  1713. PendingRecv,
  1714. FALSE, // automatic reset
  1715. FALSE // initial state: NOT signalled
  1716. );
  1717. if( EventHandle == NULL ) {
  1718. Error = GetLastError();
  1719. SvclocHeap->Free( RecvBuffer );
  1720. goto Cleanup;
  1721. }
  1722. PendingRecv->ncb_event = EventHandle;
  1723. }
  1724. // DebugBreak();
  1725. NBErrorCode = Netbios( PendingRecv );
  1726. if( (PendingRecv->ncb_retcode != NRC_PENDING) &&
  1727. (PendingRecv->ncb_retcode != NRC_GOODRET) ) {
  1728. NBErrorCode = PendingRecv->ncb_retcode;
  1729. }
  1730. if( NBErrorCode != NRC_GOODRET ) {
  1731. SvclocHeap->Free( RecvBuffer );
  1732. CloseHandle( EventHandle );
  1733. goto Cleanup;
  1734. }
  1735. GlobalNumNBPendingRecvs++;
  1736. }
  1737. }
  1738. //
  1739. // send discovery message to all lanas.
  1740. //
  1741. for( i = 0; i < Lanas.length; i++ ) {
  1742. Ncbs[i].ncb_command = NCBDGSEND;
  1743. Ncbs[i].ncb_lana_num = Lanas.lana[i];
  1744. Ncbs[i].ncb_retcode = NRC_GOODRET;
  1745. //
  1746. // setup sender's name.
  1747. //
  1748. if( ServerName == NULL ) {
  1749. //
  1750. // if no server name is specified, then send the discovery message
  1751. // to IC group name.
  1752. //
  1753. TcpsvcsDbgAssert(
  1754. NETBIOS_INET_GROUP_NAME_LEN ==
  1755. NCBNAMSZ );
  1756. memcpy(
  1757. Ncbs[i].ncb_callname,
  1758. NETBIOS_INET_GROUP_NAME,
  1759. NETBIOS_INET_GROUP_NAME_LEN );
  1760. }
  1761. else {
  1762. DWORD ServerNameLen;
  1763. //
  1764. // send the discovery message to the specified server.
  1765. //
  1766. ServerNameLen = strlen(ServerName);
  1767. TcpsvcsDbgAssert( ServerNameLen <= NCBNAMSZ );
  1768. memset(
  1769. Ncbs[i].ncb_callname,
  1770. 0x0,
  1771. NCBNAMSZ );
  1772. memcpy(
  1773. Ncbs[i].ncb_callname,
  1774. ServerName,
  1775. (ServerNameLen >= NCBNAMSZ) ? NCBNAMSZ : ServerNameLen );
  1776. }
  1777. //
  1778. // setup message buffer.
  1779. //
  1780. Ncbs[i].ncb_buffer = GlobalCliQueryMsg;
  1781. Ncbs[i].ncb_length = (WORD)GlobalCliQueryMsgLen;
  1782. // DebugBreak();
  1783. NBErrorCode = Netbios( &Ncbs[i] );
  1784. if( Ncbs[i].ncb_retcode != NRC_GOODRET ) {
  1785. NBErrorCode = Ncbs[i].ncb_retcode;
  1786. }
  1787. if( NBErrorCode != NRC_GOODRET ) {
  1788. // DebugBreak();
  1789. goto Cleanup;
  1790. }
  1791. }
  1792. Cleanup:
  1793. if( (Error != ERROR_SUCCESS) ||
  1794. (NBErrorCode != NRC_GOODRET) ) {
  1795. for( i = 0; i < GlobalNumNBPendingRecvs; i++ ) {
  1796. NCB Ncb;
  1797. NCB *PendingEntry;
  1798. BOOL CancelNcb;
  1799. memset( &Ncb, 0x0, sizeof(NCB) );
  1800. //
  1801. // cancel pending receives and free resources.
  1802. //
  1803. Ncb.ncb_command = NCBCANCEL;
  1804. Ncb.ncb_length = sizeof( NCB );
  1805. PendingEntry = &GlobalNBPendingRecvs[i];
  1806. CancelNcb = FALSE;
  1807. if( GlobalPlatformType == VER_PLATFORM_WIN32s ) {
  1808. if( PendingEntry->ncb_retcode == NRC_PENDING ) {
  1809. CancelNcb = TRUE;
  1810. }
  1811. }
  1812. else {
  1813. //
  1814. // check to see the event is signalled.
  1815. //
  1816. DWORD Wait;
  1817. Wait = WaitForSingleObject(
  1818. PendingEntry->ncb_event,
  1819. 0 );
  1820. if( Wait == WAIT_TIMEOUT ) {
  1821. CancelNcb = TRUE;
  1822. }
  1823. }
  1824. if( CancelNcb == TRUE ) {
  1825. UCHAR NcbError;
  1826. Ncb.ncb_retcode = NRC_GOODRET;
  1827. Ncb.ncb_buffer = (LPBYTE)PendingEntry;
  1828. Ncb.ncb_lana_num = PendingEntry->ncb_lana_num;
  1829. // DebugBreak();
  1830. NcbError = Netbios( &Ncb );
  1831. if( (NcbError != NRC_GOODRET) ||
  1832. (Ncb.ncb_retcode != NRC_GOODRET) ) {
  1833. TcpsvcsDbgPrint((
  1834. DEBUG_ERRORS,
  1835. "Netbios() failed, %ld, %ld \n",
  1836. (DWORD)NcbError,
  1837. (DWORD)Ncb.ncb_retcode ));
  1838. }
  1839. }
  1840. //
  1841. // free receive buffer.
  1842. //
  1843. SvclocHeap->Free( PendingEntry->ncb_buffer );
  1844. CloseHandle( PendingEntry->ncb_event );
  1845. }
  1846. if( GlobalNBPendingRecvs != NULL ) {
  1847. SvclocHeap->Free( GlobalNBPendingRecvs );
  1848. GlobalNBPendingRecvs = NULL;
  1849. }
  1850. GlobalNumNBPendingRecvs = 0;
  1851. UNLOCK_SVC_GLOBAL_DATA();
  1852. TcpsvcsDbgPrint((
  1853. DEBUG_ERRORS,
  1854. "DiscoveryNetBiosServers failed,"
  1855. "NBErrorCode = %ld, Error = %ld \n",
  1856. (DWORD)NBErrorCode, Error ));
  1857. return( ERROR_BAD_NETPATH );
  1858. }
  1859. if( Ncbs != NULL ) {
  1860. SvclocHeap->Free(Ncbs);
  1861. }
  1862. UNLOCK_SVC_GLOBAL_DATA();
  1863. return( ERROR_SUCCESS );
  1864. }
  1865. DWORD
  1866. ReceiveNetBiosResponses(
  1867. LPSVCLOC_NETBIOS_RESPONSE *NetBiosResponses,
  1868. DWORD *NumResponses,
  1869. DWORD TimeoutinMSecs,
  1870. BOOL WaitForAllResponses
  1871. )
  1872. /*++
  1873. Routine Description:
  1874. This function collects all responses that are received for the NetBios
  1875. discovery.
  1876. Arguments:
  1877. NetBiosResponses : pointer to a location where the responses buffer
  1878. is returned.
  1879. NumResponses : pointer to a location where the number of responses in
  1880. the above buffer is returned
  1881. TimeoutinMSecs : wait timeout for responses.
  1882. WaitForAllResponses : If this flag is set TRUE, this function wait
  1883. complete 'Time' secs for all responses to arrive. Otherwise it
  1884. will return after a succcessful response is received.
  1885. Return Value:
  1886. Windows Error Code.
  1887. --*/
  1888. {
  1889. DWORD Error;
  1890. DWORD i;
  1891. NCB *PendingRecvs;
  1892. DWORD NumPendingRecvs;
  1893. HANDLE *WaitHandles = NULL;
  1894. LIST_ENTRY RespListHead;
  1895. PLIST_ENTRY RespList;
  1896. DWORD NumResps;
  1897. // DebugBreak();
  1898. *NumResponses = 0;
  1899. //
  1900. // init.
  1901. //
  1902. InitializeListHead( &RespListHead );
  1903. RespList = &RespListHead;
  1904. NumResps = 0;
  1905. //
  1906. // copy receive list.
  1907. //
  1908. LOCK_SVC_GLOBAL_DATA();
  1909. PendingRecvs = GlobalNBPendingRecvs;
  1910. NumPendingRecvs = GlobalNumNBPendingRecvs;
  1911. GlobalNBPendingRecvs = NULL;
  1912. GlobalNumNBPendingRecvs = 0;
  1913. UNLOCK_SVC_GLOBAL_DATA();
  1914. if( NumPendingRecvs == 0 ) {
  1915. //
  1916. // we are done.
  1917. //
  1918. Error = ERROR_SUCCESS;
  1919. goto Cleanup;
  1920. }
  1921. if( GlobalPlatformType == VER_PLATFORM_WIN32s ) {
  1922. //
  1923. // wait for responses to arrive.
  1924. //
  1925. Sleep( TimeoutinMSecs );
  1926. //
  1927. // get the list of responses that have been gathered by the
  1928. // handler routine.
  1929. //
  1930. RespList = &GlobalWin31NBRespList;
  1931. NumResps = GlobalWin31NumNBResps;
  1932. }
  1933. else {
  1934. WaitHandles = (HANDLE *)
  1935. SvclocHeap->Alloc( NumPendingRecvs * sizeof(HANDLE) );
  1936. if( WaitHandles == NULL ) {
  1937. Error = ERROR_NOT_ENOUGH_MEMORY;
  1938. goto Cleanup;
  1939. }
  1940. HANDLE *WaitHandleEntry;
  1941. WaitHandleEntry = WaitHandles;
  1942. for( i = 0; i < NumPendingRecvs; i++ ) {
  1943. *WaitHandleEntry = PendingRecvs[i].ncb_event;
  1944. WaitHandleEntry++;
  1945. }
  1946. //
  1947. // wait for all pending receives.
  1948. //
  1949. DWORD StartTime;
  1950. StartTime = GetTickCount();
  1951. for( ;; ) {
  1952. DWORD Wait;
  1953. NCB *SignalledNcb;
  1954. Wait = WaitForMultipleObjects(
  1955. NumPendingRecvs,
  1956. WaitHandles,
  1957. FALSE, // wait for one.
  1958. TimeoutinMSecs );
  1959. if( Wait == WAIT_FAILED ) {
  1960. Error = GetLastError();
  1961. goto Cleanup;
  1962. }
  1963. if( Wait == WAIT_TIMEOUT ) {
  1964. break;
  1965. }
  1966. //
  1967. // one of the handle has been signalled.
  1968. //
  1969. Wait -= WAIT_OBJECT_0; // index to the handle.
  1970. TcpsvcsDbgAssert( Wait < NumPendingRecvs );
  1971. SignalledNcb = &PendingRecvs[Wait];
  1972. Error = ProcessNcbResponse(
  1973. &PendingRecvs[Wait],
  1974. RespList,
  1975. &NumResps );
  1976. TcpsvcsDbgAssert( Error == ERROR_SUCCESS );
  1977. if( Error != ERROR_SUCCESS ) {
  1978. goto Cleanup;
  1979. }
  1980. //
  1981. // recompute wait time.
  1982. //
  1983. DWORD EndTime;
  1984. DWORD Elapse;
  1985. EndTime = GetTickCount();
  1986. Elapse = EndTime - StartTime;
  1987. //
  1988. // set TIMEOUT to zero if we are asked to return after a first
  1989. // set of responses received or if the given time elapses.
  1990. //
  1991. if( (WaitForAllResponses == FALSE) ||
  1992. (Elapse > TimeoutinMSecs) ) {
  1993. TimeoutinMSecs = 0;
  1994. }
  1995. else {
  1996. TimeoutinMSecs -= Elapse;
  1997. }
  1998. StartTime = EndTime;
  1999. }
  2000. }
  2001. if( NumResps == 0 ) {
  2002. //
  2003. // we are done.
  2004. //
  2005. Error = ERROR_SUCCESS;
  2006. goto Cleanup;
  2007. }
  2008. //
  2009. // allocate space for return structures.
  2010. //
  2011. LPSVCLOC_NETBIOS_RESPONSE RetResps;
  2012. RetResps = (LPSVCLOC_NETBIOS_RESPONSE)
  2013. SvclocHeap->Alloc(
  2014. NumResps * sizeof(SVCLOC_NETBIOS_RESPONSE) );
  2015. if( RetResps == NULL ) {
  2016. Error = ERROR_NOT_ENOUGH_MEMORY;
  2017. goto Cleanup;
  2018. }
  2019. //
  2020. // copy entries from list to return array.
  2021. //
  2022. DWORD NumRetEntries;
  2023. PLIST_ENTRY RetEntry;
  2024. NumRetEntries = 0;
  2025. for( RetEntry = RespList->Flink;
  2026. RetEntry != RespList;
  2027. RetEntry = RetEntry->Flink ) {
  2028. LPSVCLOC_NETBIOS_RESP_ENTRY REntry;
  2029. REntry = (LPSVCLOC_NETBIOS_RESP_ENTRY)RetEntry;
  2030. RetResps[NumRetEntries] = REntry->Resp;
  2031. //
  2032. // don't free up the returned response buffer.
  2033. //
  2034. REntry->Resp.ResponseBuffer = NULL;
  2035. NumRetEntries++;
  2036. }
  2037. TcpsvcsDbgAssert( NumRetEntries == NumResps );
  2038. *NumResponses = NumRetEntries;
  2039. *NetBiosResponses = RetResps;
  2040. Error = ERROR_SUCCESS;
  2041. Cleanup:
  2042. if( WaitHandles != NULL ) {
  2043. SvclocHeap->Free( WaitHandles );
  2044. }
  2045. //
  2046. // free response list.
  2047. //
  2048. while ( !IsListEmpty(RespList) ) {
  2049. PLIST_ENTRY Entry;
  2050. Entry = RemoveHeadList( RespList );
  2051. //
  2052. // free response buffer if it is not used.
  2053. //
  2054. if( ((LPSVCLOC_NETBIOS_RESP_ENTRY)
  2055. Entry)->Resp.ResponseBuffer != NULL ) {
  2056. SvclocHeap->Free(
  2057. ((LPSVCLOC_NETBIOS_RESP_ENTRY)
  2058. Entry)->Resp.ResponseBuffer );
  2059. }
  2060. SvclocHeap->Free( Entry );
  2061. }
  2062. //
  2063. // cancel all pending recvs and delete names.
  2064. //
  2065. if( NumPendingRecvs != 0 ) {
  2066. NCB Ncb;
  2067. memset( &Ncb, 0x0, sizeof(NCB) );
  2068. Ncb.ncb_command = NCBCANCEL;
  2069. Ncb.ncb_length = sizeof( NCB );
  2070. for( i = 0; i < NumPendingRecvs; i++ ) {
  2071. NCB *PendingEntry;
  2072. UCHAR NcbError;
  2073. DWORD Wait;
  2074. BOOL CancelNcb;
  2075. PendingEntry = &PendingRecvs[i];
  2076. CancelNcb = FALSE;
  2077. if( GlobalPlatformType == VER_PLATFORM_WIN32s ) {
  2078. if( PendingEntry->ncb_retcode == NRC_PENDING ) {
  2079. CancelNcb = TRUE;
  2080. }
  2081. }
  2082. else {
  2083. //
  2084. // check to see the event is signalled.
  2085. //
  2086. DWORD Wait;
  2087. Wait = WaitForSingleObject(
  2088. PendingEntry->ncb_event,
  2089. 0 );
  2090. if( Wait == WAIT_TIMEOUT ) {
  2091. CancelNcb = TRUE;
  2092. }
  2093. }
  2094. if( CancelNcb == TRUE ) {
  2095. Ncb.ncb_retcode = NRC_GOODRET;
  2096. Ncb.ncb_buffer = (LPBYTE)PendingEntry;
  2097. Ncb.ncb_length = sizeof( NCB );
  2098. Ncb.ncb_lana_num = PendingEntry->ncb_lana_num;
  2099. Ncb.ncb_command = NCBCANCEL;
  2100. NcbError = Netbios( &Ncb );
  2101. if( (NcbError != NRC_GOODRET) ||
  2102. (Ncb.ncb_retcode != NRC_GOODRET) ) {
  2103. TcpsvcsDbgPrint((
  2104. DEBUG_ERRORS,
  2105. "Netbios() failed, %ld, %ld \n",
  2106. (DWORD)NcbError,
  2107. (DWORD)Ncb.ncb_retcode ));
  2108. }
  2109. }
  2110. //
  2111. // delete name.
  2112. //
  2113. Ncb.ncb_retcode = NRC_GOODRET;
  2114. memcpy(
  2115. Ncb.ncb_name,
  2116. PendingEntry->ncb_name,
  2117. sizeof( Ncb.ncb_name ) );
  2118. Ncb.ncb_lana_num = PendingEntry->ncb_lana_num;
  2119. Ncb.ncb_command = NCBDELNAME;
  2120. NcbError = Netbios( &Ncb );
  2121. if( (NcbError != NRC_GOODRET) ||
  2122. (Ncb.ncb_retcode != NRC_GOODRET) ) {
  2123. TcpsvcsDbgPrint((
  2124. DEBUG_ERRORS,
  2125. "Netbios() failed, %ld, %ld \n",
  2126. (DWORD)NcbError,
  2127. (DWORD)Ncb.ncb_retcode ));
  2128. }
  2129. //
  2130. // free receive buffer.
  2131. //
  2132. SvclocHeap->Free( PendingEntry->ncb_buffer );
  2133. CloseHandle( PendingEntry->ncb_event );
  2134. }
  2135. SvclocHeap->Free( PendingRecvs );
  2136. }
  2137. return( Error );
  2138. }