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.

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