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.

1052 lines
24 KiB

  1. /*++
  2. Copyright (c) 1994 Microsoft Corporation
  3. Module Name:
  4. svcsrv.cxx
  5. Abstract:
  6. Contains server 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. DWORD
  16. MakeResponseBuffer(
  17. VOID
  18. )
  19. /*++
  20. Routine Description:
  21. This function sets up the response buffer sent to the client.
  22. Arguments:
  23. NONE.
  24. Return Value:
  25. Windows Error Code.
  26. --*/
  27. {
  28. DWORD ReqMsgLength;
  29. //
  30. // compute space required for all services info and server info.
  31. //
  32. ReqMsgLength = GlobalSrvInfoObj->ComputeResponseLength();
  33. //
  34. // add space for the head and tail.
  35. //
  36. ReqMsgLength += (
  37. sizeof(DWORD) + // for message length.
  38. sizeof(DWORD) + // for check sum
  39. sizeof(DWORD)); // for termination dword.
  40. if( ReqMsgLength <= GlobalSrvAllotedRespMsgLen ) {
  41. //
  42. // wipe of previous response buffer content.
  43. //
  44. TcpsvcsDbgAssert(
  45. GlobalSrvRespMsgLength <=
  46. GlobalSrvAllotedRespMsgLen );
  47. memset( GlobalSrvRespMsg, 0x0, GlobalSrvRespMsgLength );
  48. GlobalSrvRespMsgLength = ReqMsgLength;
  49. }
  50. else {
  51. LPBYTE NewBuffer;
  52. DWORD NewBufferLength;
  53. NewBufferLength = (ReqMsgLength & ~(0x400 - 1)) + 0x400;
  54. // ceil in KBytes
  55. NewBuffer = (LPBYTE)SvclocHeap->Alloc( NewBufferLength );
  56. if( NewBuffer == NULL ) {
  57. return( ERROR_NOT_ENOUGH_MEMORY );
  58. }
  59. //
  60. // free old buffer.
  61. //
  62. SvclocHeap->Free( GlobalSrvRespMsg );
  63. GlobalSrvRespMsg = NewBuffer;
  64. GlobalSrvAllotedRespMsgLen = NewBufferLength;
  65. GlobalSrvRespMsgLength = ReqMsgLength;
  66. }
  67. //
  68. // copy server and services info.
  69. //
  70. DWORD Error;
  71. Error = GlobalSrvInfoObj->MakeResponseMessage(
  72. GlobalSrvRespMsg + sizeof(DWORD),
  73. GlobalSrvRespMsgLength - 3 * sizeof(DWORD) );
  74. if( Error != ERROR_SUCCESS ) {
  75. GlobalSrvRespMsgLength = 0;
  76. return( Error );
  77. }
  78. *(DWORD *)GlobalSrvRespMsg = GlobalSrvRespMsgLength;
  79. LPBYTE EndMessageBuffer;
  80. EndMessageBuffer = GlobalSrvRespMsg + GlobalSrvRespMsgLength;
  81. //
  82. // fill in check sum.
  83. //
  84. *(DWORD *)(EndMessageBuffer - 2 * sizeof(DWORD) ) =
  85. ComputeCheckSum(
  86. GlobalSrvRespMsg + sizeof(DWORD),
  87. GlobalSrvRespMsgLength - 3 * sizeof(DWORD) );
  88. *(DWORD *)(EndMessageBuffer - sizeof(DWORD) ) = 0xFFFFFFFF;
  89. //
  90. // DONE.
  91. //
  92. return( ERROR_SUCCESS );
  93. }
  94. DWORD
  95. ServerRegisterAndListen(
  96. VOID
  97. )
  98. /*++
  99. Routine Description:
  100. This function call registers the server and creates a thread to listen
  101. to the discovery requests. Also it initializes the winsock data structures.
  102. ASSUME : global data crit sect is locked.
  103. Arguments:
  104. none.
  105. Return Value:
  106. Windows Error Code.
  107. --*/
  108. {
  109. DWORD Error;
  110. SOCKET IpxSocket;
  111. int SocketAddressLength;
  112. SOCKADDR_IPX IpxSocketAddress;
  113. SERVICE_INFOA ServiceInfo;
  114. SERVICE_ADDRESSES ServiceAddresses;
  115. PSERVICE_ADDRESS ServiceAddr;
  116. DWORD StatusSetService;
  117. CHAR SapSvcName[SAP_SERVICE_NAME_LEN + 1];
  118. //
  119. // init winsock.
  120. //
  121. if ( !GlobalWinsockStarted ) {
  122. Error = WSAStartup( WS_VERSION_REQUIRED, &GlobalWinsockStartupData );
  123. if( Error != ERROR_SUCCESS ) {
  124. goto Cleanup;
  125. }
  126. GlobalWinsockStarted = TRUE;
  127. }
  128. //
  129. // cleanup global socket array.
  130. //
  131. memset( &GlobalSrvSockets, 0x0, sizeof(GlobalSrvSockets) );
  132. //
  133. // make IPX local socket address.
  134. //
  135. IpxSocket = socket(AF_IPX, SOCK_DGRAM, NSPROTO_IPX);
  136. if( IpxSocket == INVALID_SOCKET ) {
  137. Error = WSAGetLastError();
  138. goto NBRegister;
  139. }
  140. //
  141. // make this socket non blocking.
  142. //
  143. DWORD Arg;
  144. Arg = 1;
  145. if( (ioctlsocket( IpxSocket, FIONBIO, &Arg )) == SOCKET_ERROR ) {
  146. Error = WSAGetLastError();
  147. closesocket( IpxSocket );
  148. goto NBRegister;
  149. }
  150. //
  151. // get socket address.
  152. //
  153. memset( &IpxSocketAddress, 0x0, sizeof(SOCKADDR_IPX) );
  154. IpxSocketAddress.sa_family = PF_IPX;
  155. if( bind(
  156. IpxSocket,
  157. (PSOCKADDR)&IpxSocketAddress,
  158. sizeof(SOCKADDR_IPX) ) == SOCKET_ERROR ) {
  159. Error = WSAGetLastError();
  160. closesocket( IpxSocket );
  161. goto NBRegister;
  162. }
  163. //
  164. // now query address.
  165. //
  166. SocketAddressLength = sizeof( IpxSocketAddress );
  167. if( getsockname(
  168. IpxSocket,
  169. (PSOCKADDR)&IpxSocketAddress,
  170. &SocketAddressLength ) == SOCKET_ERROR ) {
  171. Error = WSAGetLastError();
  172. closesocket( IpxSocket );
  173. goto NBRegister;
  174. }
  175. Error = MakeSapServiceName( SapSvcName, sizeof(SapSvcName) );
  176. if( Error != ERROR_SUCCESS ) {
  177. closesocket( IpxSocket );
  178. goto NBRegister;
  179. }
  180. //
  181. // prepare service address.
  182. //
  183. ServiceAddresses.dwAddressCount = 1;
  184. ServiceAddr = &ServiceAddresses.Addresses[0];
  185. ServiceAddr->dwAddressType = PF_IPX;
  186. ServiceAddr->dwAddressFlags = 0;
  187. ServiceAddr->dwAddressLength = SocketAddressLength;
  188. ServiceAddr->dwPrincipalLength = 0;
  189. ServiceAddr->lpAddress = (LPBYTE)&IpxSocketAddress;
  190. ServiceAddr->lpPrincipal = NULL;
  191. //
  192. // prepare service info.
  193. //
  194. ServiceInfo.lpServiceType = &GlobalSapGuid;
  195. ServiceInfo.lpServiceName = SapSvcName;
  196. ServiceInfo.lpComment = NULL ;
  197. ServiceInfo.lpLocale = 0;
  198. ServiceInfo.dwDisplayHint = 0;
  199. ServiceInfo.dwVersion =
  200. MAKEWORD( INET_MAJOR_VERSION, INET_MINOR_VERSION ) ;
  201. ServiceInfo.dwTime = 0; // ??
  202. ServiceInfo.lpMachineName = GlobalComputerName;
  203. ServiceInfo.lpServiceAddress = &ServiceAddresses;
  204. ServiceInfo.ServiceSpecificInfo.pBlobData = 0;
  205. ServiceInfo.ServiceSpecificInfo.cbSize = 0;
  206. //
  207. // register service info.
  208. //
  209. if( SetServiceA(
  210. NS_SAP,
  211. SERVICE_REGISTER,
  212. 0,
  213. &ServiceInfo,
  214. 0,
  215. &StatusSetService ) == SOCKET_ERROR ) {
  216. Error = WSAGetLastError();
  217. closesocket( IpxSocket );
  218. goto NBRegister;
  219. }
  220. if( StatusSetService != ERROR_SUCCESS ) {
  221. Error = StatusSetService;
  222. closesocket( IpxSocket );
  223. goto NBRegister;
  224. }
  225. GlobalRNRRegistered = TRUE;
  226. //
  227. // remember this Ipx socket in our global socket array.
  228. //
  229. FD_SET( IpxSocket, &GlobalSrvSockets );
  230. Error = ERROR_SUCCESS;
  231. NBRegister:
  232. if( Error != ERROR_SUCCESS ) {
  233. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  234. "Ipx Registration failed, %ld.\n", Error ));
  235. }
  236. //
  237. // now create sockets for NET BIOS 1C group name and UNIQUE server
  238. // name.
  239. //
  240. SOCKADDR_NB NB1CSocketAddress;
  241. SOCKADDR_NB NBUniqueSocketAddress;
  242. SOCKET NBSocket;
  243. memset( &NB1CSocketAddress, 0x0, sizeof(SOCKADDR_NB) );
  244. NB1CSocketAddress.snb_family = AF_NETBIOS;
  245. NB1CSocketAddress.snb_type = TDI_ADDRESS_NETBIOS_TYPE_GROUP;
  246. TcpsvcsDbgAssert(
  247. sizeof(NB1CSocketAddress.snb_name) >=
  248. NETBIOS_INET_GROUP_NAME_LEN );
  249. memcpy(
  250. NB1CSocketAddress.snb_name,
  251. NETBIOS_INET_GROUP_NAME,
  252. NETBIOS_INET_GROUP_NAME_LEN );
  253. memset( &NBUniqueSocketAddress, 0x0, sizeof(SOCKADDR_NB) );
  254. NBUniqueSocketAddress.snb_family = AF_NETBIOS;
  255. NBUniqueSocketAddress.snb_type = TDI_ADDRESS_NETBIOS_TYPE_UNIQUE;
  256. TcpsvcsDbgAssert( GlobalComputerName[0] != '\0' );
  257. MakeUniqueServerName(
  258. (LPBYTE)NBUniqueSocketAddress.snb_name,
  259. sizeof(NBUniqueSocketAddress.snb_name),
  260. GlobalComputerName );
  261. //
  262. // enumurate lanas first.
  263. //
  264. LANA_ENUM Lanas;
  265. if( GetEnumNBLana( &Lanas ) ) {
  266. //
  267. // try only the lanas that are returned.
  268. //
  269. TcpsvcsDbgAssert( Lanas.length > 0 );
  270. DWORD i;
  271. for( i = 0; i < Lanas.length; i++ ) {
  272. //
  273. // create a socket for this lana to bind with the IC name.
  274. //
  275. if ( MakeNBSocketForLana(
  276. Lanas.lana[i],
  277. (PSOCKADDR)&NB1CSocketAddress,
  278. &NBSocket ) ) {
  279. //
  280. // add the sockets to our global list.
  281. //
  282. FD_SET( NBSocket, &GlobalSrvSockets );
  283. }
  284. //
  285. // now create a socket for this lana to bind with the unique
  286. // server name.
  287. //
  288. if ( MakeNBSocketForLana(
  289. Lanas.lana[i],
  290. (PSOCKADDR)&NBUniqueSocketAddress,
  291. &NBSocket ) ) {
  292. //
  293. // add the sockets to our global list.
  294. //
  295. FD_SET( NBSocket, &GlobalSrvSockets );
  296. }
  297. }
  298. }
  299. else {
  300. UCHAR Lana;
  301. //
  302. // try all possible lanas and accept all valid lana sockets.
  303. //
  304. for( Lana = 0; Lana < MAX_LANA ; Lana-- ) {
  305. //
  306. // create a socket for this lana to bind with the IC name.
  307. //
  308. if ( MakeNBSocketForLana(
  309. Lana,
  310. (PSOCKADDR)&NB1CSocketAddress,
  311. &NBSocket ) ) {
  312. //
  313. // add the sockets to our global list.
  314. //
  315. FD_SET( NBSocket, &GlobalSrvSockets );
  316. }
  317. //
  318. // now create a socket for this lana to bind with the unique
  319. // server name.
  320. //
  321. if ( MakeNBSocketForLana(
  322. Lana,
  323. (PSOCKADDR)&NBUniqueSocketAddress,
  324. &NBSocket ) ) {
  325. //
  326. // add the sockets to our global list.
  327. //
  328. FD_SET( NBSocket, &GlobalSrvSockets );
  329. }
  330. }
  331. }
  332. //
  333. // we should have at least one socket to listen on, otherwise,
  334. // it is an error, return so.
  335. //
  336. if( GlobalSrvSockets.fd_count == 0 ) {
  337. TcpsvcsDbgPrint(( DEBUG_ERRORS, "Failed to get any Lanas, Service locator disabled\n" ));
  338. Error = ERROR_NO_NETWORK;
  339. goto Cleanup;
  340. }
  341. //
  342. // create listen thread.
  343. //
  344. DWORD ThreadId;
  345. GlobalSrvListenThreadHandle =
  346. CreateThread(
  347. NULL, // default security
  348. 0, // default stack size
  349. (LPTHREAD_START_ROUTINE)SocketListenThread,
  350. NULL, // no parameter
  351. 0, // creatation flag, no suspend
  352. &ThreadId );
  353. if( GlobalSrvListenThreadHandle == NULL ) {
  354. Error = GetLastError();
  355. goto Cleanup;
  356. }
  357. Error = ERROR_SUCCESS;
  358. Cleanup:
  359. if( Error != ERROR_SUCCESS ) {
  360. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  361. "ServerRegisterAndListen failed, %ld.\n", Error ));
  362. //
  363. // if we are not successful, cleanup
  364. // before we return.
  365. //
  366. DWORD LocalError;
  367. //
  368. // The routine is expecting the global lock to be taken
  369. //
  370. LOCK_SVC_GLOBAL_DATA();
  371. LocalError = ServerDeregisterAndStopListen();
  372. UNLOCK_SVC_GLOBAL_DATA();
  373. TcpsvcsDbgAssert( LocalError == ERROR_SUCCESS );
  374. }
  375. return( Error );
  376. }
  377. DWORD
  378. ProcessSvclocQuery(
  379. SOCKET ReceivedSocket,
  380. LPBYTE ReceivedMessage,
  381. DWORD ReceivedMessageLength,
  382. struct sockaddr *SourcesAddress,
  383. DWORD SourcesAddressLength
  384. )
  385. /*++
  386. Routine Description:
  387. This function processes the query message and sends response to the
  388. query.
  389. The query message format.
  390. 1st DWORD : message length.
  391. 2nd DWORD : message version.
  392. 3rd DWORD : services mask the client interested in.
  393. 4th DWORD : client name
  394. ..
  395. ..
  396. Last but one DWORD : check sum.
  397. LAST DWORD : terminating DWORD 0xFFFFFFFF
  398. Arguments:
  399. ReceivedMessage - pointer to a message buffer.
  400. ReceivedMessageLength - length of the above message.
  401. SourcesAddress - address of the sender.
  402. SourcesAddressLength - length of the above address.
  403. Return Value:
  404. Windows Error Code.
  405. --*/
  406. {
  407. DWORD Error;
  408. LPBYTE MessagePtr;
  409. LPBYTE MessageEndPtr;
  410. MessagePtr = ReceivedMessage;
  411. MessageEndPtr = ReceivedMessage + ReceivedMessageLength;
  412. //
  413. // message length should be multiple of sizeof(DWORD).
  414. //
  415. if( ReceivedMessageLength % sizeof(DWORD) != 0 ) {
  416. return( ERROR_INVALID_PARAMETER );
  417. }
  418. //
  419. // message length should match.
  420. //
  421. DWORD MsgLength;
  422. MsgLength = *(DWORD *)MessagePtr;
  423. MessagePtr += sizeof(DWORD);
  424. if( MsgLength != ReceivedMessageLength ) {
  425. return( ERROR_INVALID_PARAMETER );
  426. }
  427. //
  428. // message should terminate with 0xFFFFFFFF
  429. //
  430. if( *(DWORD *)(MessageEndPtr - sizeof(DWORD)) != 0xFFFFFFFF ) {
  431. return( ERROR_INVALID_PARAMETER );
  432. }
  433. //
  434. // verify checksum.
  435. //
  436. DWORD CheckSum;
  437. CheckSum = ComputeCheckSum(
  438. ReceivedMessage + sizeof(DWORD),
  439. ReceivedMessageLength - (3 * sizeof(DWORD)) );
  440. if( CheckSum != *(DWORD *)(MessageEndPtr - 2 * sizeof(DWORD)) ) {
  441. return( ERROR_INVALID_PARAMETER );
  442. }
  443. #if 0
  444. // IIS5.0: We want to respond to all server discovery messages
  445. // since it is potentially useful to clients to find all versions
  446. // of IIS. The server will send back a message specifying it's
  447. // own version number and it is up to the client to determine
  448. // if they want this server's information.
  449. //
  450. // validate version number.
  451. //
  452. INET_VERSION_NUM VersionNumber;
  453. VersionNumber.VersionNumber = *(DWORD *)MessagePtr;
  454. MessagePtr += sizeof(DWORD);
  455. if( (VersionNumber.Version.Major != INET_MAJOR_VERSION) ||
  456. (VersionNumber.Version.Minor != INET_MINOR_VERSION) ) {
  457. //
  458. // in future, we can apply different logic to reject messages with
  459. // differnet version number.
  460. //
  461. return( ERROR_INVALID_PARAMETER );
  462. }
  463. #endif
  464. //
  465. // get services mask.
  466. //
  467. ULONGLONG ServicesMask;
  468. ServicesMask = *(ULONGLONG *)MessagePtr;
  469. MessagePtr += sizeof(ULONGLONG);
  470. //
  471. // if we aren't supporting any of the clients requested services,
  472. // ignore these message.
  473. //
  474. if( (ServicesMask & GlobalSrvInfoObj->GetServicesMask()) == 0) {
  475. return( ERROR_INVALID_PARAMETER );
  476. }
  477. //
  478. // retrieve the computer name from the message. currently
  479. // it has been used just for debugging purpose. It can be used for
  480. // something else in future.
  481. //
  482. LPSTR ClientComputerName;
  483. LPSTR ComputerNamePtr;
  484. ClientComputerName = (LPSTR)MessagePtr;
  485. //
  486. // validate computer name.
  487. //
  488. ComputerNamePtr = ClientComputerName;
  489. while( (*ComputerNamePtr != '\0') &&
  490. ((LPBYTE)ComputerNamePtr < MessageEndPtr) ) {
  491. ComputerNamePtr++;
  492. }
  493. if( (LPBYTE)ComputerNamePtr >= MessageEndPtr ) {
  494. return( ERROR_INVALID_PARAMETER );
  495. }
  496. TcpsvcsDbgPrint((
  497. DEBUG_SVCLOC_MESSAGE,
  498. "Received a valid discovery message from, %ws.\n",
  499. ClientComputerName ));
  500. //
  501. // send response message to client.
  502. //
  503. LOCK_SVC_GLOBAL_DATA();
  504. TcpsvcsDbgAssert( GlobalSrvRespMsgLength != 0 );
  505. if( GlobalSrvRespMsgLength != 0 ) {
  506. Error = sendto(
  507. ReceivedSocket,
  508. (LPCSTR)GlobalSrvRespMsg,
  509. GlobalSrvRespMsgLength,
  510. 0,
  511. SourcesAddress,
  512. SourcesAddressLength );
  513. if( Error == SOCKET_ERROR ) {
  514. Error = WSAGetLastError();
  515. TcpsvcsDbgPrint(( DEBUG_ERRORS, "sendto failed, %ld.\n", Error ));
  516. }
  517. else {
  518. Error = ERROR_SUCCESS;
  519. }
  520. }
  521. else {
  522. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  523. "GlobalSrvRespMsgLength is zero.\n" ));
  524. Error = ERROR_INVALID_PARAMETER;
  525. }
  526. UNLOCK_SVC_GLOBAL_DATA();
  527. return( Error );
  528. }
  529. VOID
  530. SocketListenThread(
  531. LPVOID Parameter
  532. )
  533. /*++
  534. Routine Description:
  535. This function is the main thread for the service location protocol. It
  536. receives messages that arrive from all sockets (that have
  537. been established by the ServerRegisterAndListen call) and response to
  538. each of the messages. This thread will stop when all sockets are
  539. closed by the ServerDeregisterAndStopListen call.
  540. Arguments:
  541. none.
  542. Return Value:
  543. none.
  544. --*/
  545. {
  546. fd_set ReadSockets;
  547. int NumReadySockets;
  548. DWORD Error;
  549. BOOL BoolError;
  550. //
  551. // increase the priority of this thread, so that it could handle as
  552. // many discovery queries as possible.
  553. //
  554. BoolError = SetThreadPriority(
  555. GetCurrentThread(),
  556. THREAD_PRIORITY_ABOVE_NORMAL );
  557. if(BoolError) {
  558. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  559. "SetThreadPriority, %ld.\n", GetLastError() ));
  560. }
  561. for( ;; ) {
  562. //
  563. // COMMENT
  564. // select on all above sockets.
  565. //
  566. //
  567. // copy all sockets.
  568. //
  569. LOCK_SVC_GLOBAL_DATA();
  570. memcpy(&ReadSockets, &GlobalSrvSockets, sizeof(GlobalSrvSockets));
  571. UNLOCK_SVC_GLOBAL_DATA();
  572. //
  573. // do select now.
  574. //
  575. NumReadySockets =
  576. select(
  577. 0, // compatibility argument, ignored.
  578. &ReadSockets, // sockets to test for readability.
  579. NULL, // no write wait
  580. NULL, // no error check.
  581. NULL ); // NO timeout.
  582. if( NumReadySockets == SOCKET_ERROR ) {
  583. //
  584. // ALL sockets are closed and we are asked to return or
  585. // something else has happpened which we can't handle.
  586. //
  587. Error = WSAGetLastError();
  588. goto Cleanup;
  589. }
  590. TcpsvcsDbgAssert( (DWORD)NumReadySockets == ReadSockets.fd_count );
  591. DWORD i;
  592. for( i = 0; i < (DWORD)NumReadySockets; i++ ) {
  593. DWORD ReadMessageLength;
  594. struct sockaddr_nb SourcesAddress;
  595. int SourcesAddressLength;
  596. //
  597. // read next message.
  598. //
  599. SourcesAddressLength = sizeof(SourcesAddress);
  600. ReadMessageLength =
  601. recvfrom(
  602. ReadSockets.fd_array[i],
  603. (LPSTR)GlobalSrvRecvBuf,
  604. GlobalSrvRecvBufLength,
  605. 0,
  606. (struct sockaddr *)&SourcesAddress,
  607. &SourcesAddressLength );
  608. if( ReadMessageLength == SOCKET_ERROR ) {
  609. //
  610. // ALL sockets are closed and we are asked to return or
  611. // something else has happpened which we can't handle.
  612. //
  613. Error = WSAGetLastError();
  614. continue;
  615. }
  616. TcpsvcsDbgAssert( ReadMessageLength <= GlobalSrvRecvBufLength );
  617. //
  618. // received a message.
  619. //
  620. TcpsvcsDbgPrint((
  621. DEBUG_SVCLOC_MESSAGE,
  622. "Received a discovery message, %ld.\n",
  623. ReadMessageLength ));
  624. Error = ProcessSvclocQuery(
  625. ReadSockets.fd_array[i],
  626. GlobalSrvRecvBuf,
  627. (DWORD)ReadMessageLength,
  628. (struct sockaddr *)&SourcesAddress,
  629. (DWORD)SourcesAddressLength );
  630. if( Error != ERROR_SUCCESS ) {
  631. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  632. "SendSvclocResponse failed, %ld.\n", Error ));
  633. }
  634. }
  635. }
  636. Cleanup:
  637. TcpsvcsDbgPrint(( DEBUG_ERRORS, "SocketListenThread returning, %ld.\n", Error ));
  638. return;
  639. }
  640. DWORD
  641. ServerDeregisterAndStopListen(
  642. VOID
  643. )
  644. /*++
  645. Routine Description:
  646. This function call stops the discovery thread and deregisters the
  647. server name. Also it cleans up the winsock data structures.
  648. ASSUME : global data crit sect is locked.
  649. Arguments:
  650. none.
  651. Return Value:
  652. Windows Error Code.
  653. --*/
  654. {
  655. DWORD Error;
  656. DWORD i;
  657. //
  658. // close all sockets, if any opened.
  659. //
  660. for( i = 0; i < GlobalSrvSockets.fd_count; i++ ) {
  661. Error = closesocket( GlobalSrvSockets.fd_array[i] );
  662. if( Error == SOCKET_ERROR ) {
  663. Error = WSAGetLastError();
  664. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  665. "closesocket call failed, %ld\n", Error ));
  666. }
  667. }
  668. //
  669. // invalidate GlobalSrvSockets count
  670. //
  671. GlobalSrvSockets.fd_count = 0;
  672. //
  673. // closing all above sockets should stop the service location thread,
  674. // check to see this is the case and close the thread handle.
  675. //
  676. if( GlobalSrvListenThreadHandle != NULL ) {
  677. //
  678. // The thread may take this critical section, release it around
  679. // the wait to prevent a deadlock
  680. //
  681. UNLOCK_SVC_GLOBAL_DATA();
  682. //
  683. // Wait for the service location thread to stop, but don't wait
  684. // for longer than THREAD_TERMINATION_TIMEOUT msecs (60 secs)
  685. //
  686. DWORD WaitStatus =
  687. WaitForSingleObject(
  688. GlobalSrvListenThreadHandle,
  689. 30000
  690. );
  691. TcpsvcsDbgAssert( WaitStatus != WAIT_FAILED );
  692. if( WaitStatus == WAIT_FAILED ) {
  693. TcpsvcsDbgPrint((DEBUG_ERRORS,
  694. "WaitForSingleObject call failed, %ld\n", GetLastError() ));
  695. }
  696. CloseHandle( GlobalSrvListenThreadHandle );
  697. GlobalSrvListenThreadHandle = NULL;
  698. LOCK_SVC_GLOBAL_DATA();
  699. }
  700. //
  701. // deregister rnr.
  702. //
  703. if( GlobalRNRRegistered ) {
  704. SOCKADDR_IPX IpxSocketAddress;
  705. SERVICE_INFO ServiceInfo;
  706. SERVICE_ADDRESSES ServiceAddresses;
  707. PSERVICE_ADDRESS ServiceAddr;
  708. DWORD StatusSetService;
  709. CHAR SapSvcName[SAP_SERVICE_NAME_LEN + 1];
  710. CHAR *SapSvcNamePtr;
  711. Error = MakeSapServiceName( SapSvcName, sizeof(SapSvcName) );
  712. if( Error != ERROR_SUCCESS ) {
  713. SapSvcNamePtr = NULL;
  714. }
  715. else {
  716. SapSvcNamePtr = SapSvcName;
  717. }
  718. //
  719. // prepare service address.
  720. //
  721. ServiceAddresses.dwAddressCount = 1;
  722. ServiceAddr = &ServiceAddresses.Addresses[0];
  723. memset( &IpxSocketAddress, 0x0, sizeof(IpxSocketAddress) );
  724. ServiceAddr->dwAddressType = PF_IPX;
  725. ServiceAddr->dwAddressFlags = 0;
  726. ServiceAddr->dwAddressLength = sizeof( IpxSocketAddress );
  727. ServiceAddr->dwPrincipalLength = 0;
  728. ServiceAddr->lpAddress = (LPBYTE)&IpxSocketAddress;
  729. ServiceAddr->lpPrincipal = NULL;
  730. //
  731. // prepare service info.
  732. //
  733. ServiceInfo.lpServiceType = &GlobalSapGuid;
  734. ServiceInfo.lpServiceName = SapSvcNamePtr;
  735. ServiceInfo.lpComment = NULL ;
  736. ServiceInfo.lpLocale = 0;
  737. ServiceInfo.dwDisplayHint = 0;
  738. ServiceInfo.dwVersion =
  739. MAKEWORD( INET_MAJOR_VERSION, INET_MINOR_VERSION ) ;
  740. ServiceInfo.dwTime = 0; // ??
  741. ServiceInfo.lpMachineName = GlobalComputerName;
  742. ServiceInfo.lpServiceAddress = &ServiceAddresses;
  743. ServiceInfo.ServiceSpecificInfo.pBlobData = 0;
  744. ServiceInfo.ServiceSpecificInfo.cbSize = 0;
  745. //
  746. // register service info.
  747. //
  748. if( SetServiceA(
  749. NS_SAP,
  750. SERVICE_DEREGISTER,
  751. 0,
  752. &ServiceInfo,
  753. 0,
  754. &StatusSetService ) == SOCKET_ERROR ) {
  755. Error = WSAGetLastError();
  756. TcpsvcsDbgPrint(( DEBUG_ERRORS,
  757. "SetServiceW call failed, %ld\n", Error ));
  758. }
  759. GlobalRNRRegistered = FALSE;
  760. }
  761. //
  762. // DONE.
  763. //
  764. return( ERROR_SUCCESS );
  765. }
  766.