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

1134 lines
32 KiB

  1. /*++
  2. Copyright (c) 1990 Microsoft Corporation
  3. Module Name:
  4. msgmain.c
  5. Abstract:
  6. This is the main routine for the NT OS/2 LAN Manager Messenger Service.
  7. Functions in the file include:
  8. SvcEntry_Messenger
  9. ParseArgs
  10. Author:
  11. Dan Lafferty (danl) 20-Mar-1991
  12. Environment:
  13. User Mode - Win32
  14. Revision History:
  15. 27-Feb-1999 jschwart
  16. Remove polling loop to detect lana changes -- use PnP events instead
  17. 15-Dec-1998 jschwart
  18. Convert messenger to use NT thread pool APIs instead of Service
  19. Controller thread pool
  20. 19-Aug-1997 wlees
  21. Add polling loop to detect lana changes.
  22. Provide synchronization between rpc routines and Pnp reconfiguration
  23. 14-Jun-1994 danl
  24. Fixed problem where messenger put up an empty message as if it
  25. received a mailslot message during init. The problem was the
  26. order of the following events: CreateMailslot -> wait on handle ->
  27. submit an async _read with that handle.
  28. The new order was changed to: CreateMailslot -> submit async _read ->
  29. wait on handle.
  30. This causes the handle to not get signaled right away.
  31. 20-Mar-1991 danl
  32. created
  33. --*/
  34. //
  35. // INCLUDES
  36. //
  37. #include "msrv.h" // AdapterThread prototype,SESSION_STATUS
  38. #include <winuser.h> // RegisterDeviceNotification
  39. #include <dbt.h> // DEV_BROADCAST_DEVICEINTERFACE
  40. #include <tstring.h> // Unicode string macros
  41. #include <winsock2.h> // Windows sockets
  42. #include <netlib.h> // UNUSED macro
  43. #include "msgdbg.h" // MSG_LOG & STATIC definitions
  44. #include "msgdata.h" // msrv_status
  45. #include "msgsvc.h" // Messenger RPC interface
  46. #include "msgsvcsend.h" // Broadcast message send interface
  47. #include <iphlpapi.h> // Address change notification
  48. //
  49. // GLOBALS
  50. //
  51. //
  52. // Handles for messenger work items. These are necessary since
  53. // the Rtl thread pool work items aren't automatically deleted
  54. // when the callback is called.
  55. //
  56. HANDLE g_hGrpEvent;
  57. HANDLE g_hNetEvent;
  58. HANDLE g_hNetTimeoutEvent;
  59. HANDLE g_hAddrChangeEvent;
  60. //
  61. // PNP device notification handle
  62. //
  63. HANDLE g_hPnPNotify;
  64. //
  65. // Warning: this definitions of GUID_NDIS_XXX is in ndisguid.h
  66. // but dragging that file in drags in a whole bunch of guids that
  67. // won't get thrown out by the linker.
  68. //
  69. static const GUID GUID_NDIS_LAN_CLASS =
  70. {0xad498944,0x762f,0x11d0,{0x8d,0xcb,0x00,0xc0,0x4f,0xc3,0x35,0x8c}};
  71. //
  72. // Global buffer pointers used to hold Alerter print text
  73. //
  74. LPSTR g_lpAlertSuccessMessage;
  75. DWORD g_dwAlertSuccessLen;
  76. LPSTR g_lpAlertFailureMessage;
  77. DWORD g_dwAlertFailureLen;
  78. //
  79. // Local Function Prototypes
  80. //
  81. STATIC VOID
  82. Msgdummy_complete(
  83. short c,
  84. int a,
  85. char b
  86. );
  87. VOID
  88. MsgAddrChange(
  89. PVOID pvContext,
  90. BOOLEAN fWaitStatus
  91. );
  92. VOID
  93. MsgGrpEventCompletion(
  94. PVOID pvContext, // This passed in as context.
  95. BOOLEAN fWaitStatus
  96. );
  97. VOID
  98. MsgrShutdownInternal(
  99. void
  100. );
  101. VOID
  102. SvchostPushServiceGlobals(
  103. PSVCHOST_GLOBAL_DATA pGlobals
  104. )
  105. {
  106. MsgsvcGlobalData = pGlobals;
  107. }
  108. VOID
  109. ServiceMain(
  110. IN DWORD argc,
  111. IN LPTSTR argv[]
  112. )
  113. /*++
  114. Routine Description:
  115. This is the main routine for the Messenger Service
  116. Arguments:
  117. Return Value:
  118. None.
  119. Note:
  120. --*/
  121. {
  122. DWORD msgrState;
  123. NTSTATUS ntStatus;
  124. BOOL fGrpThreadCreated = FALSE;
  125. BOOL fNetThreadCreated = FALSE;
  126. DWORD dwAddrStatus = NO_ERROR;
  127. HANDLE hTcpip;
  128. DEV_BROADCAST_DEVICEINTERFACE dbdPnpFilter;
  129. //
  130. // Make sure svchost.exe gave us the global data
  131. //
  132. ASSERT(MsgsvcGlobalData != NULL);
  133. MsgCreateWakeupEvent(); // do this once
  134. msgrState = MsgInitializeMsgr(argc, argv);
  135. if (msgrState != RUNNING)
  136. {
  137. MSG_LOG(ERROR,"[MSG],Shutdown during initialization\n",0);
  138. MsgsvcGlobalData->NetBiosClose();
  139. //
  140. // To get here, the msgrState must either be STOPPING or STOPPED.
  141. // Shutdown the Messenger Service
  142. //
  143. if (msgrState == STOPPING) {
  144. MsgrShutdown();
  145. MsgStatusUpdate(STOPPED);
  146. }
  147. MSG_LOG(TRACE,"MESSENGER_main: Messenger main thread is returning\n\n",0);
  148. return;
  149. }
  150. else
  151. {
  152. //
  153. // Read the Group Mailslot
  154. //
  155. MSG_LOG0(GROUP,"MESSENGER_main: Submit the Group Mailslot ReadFile\n");
  156. MsgReadGroupMailslot();
  157. //
  158. // Submit the work item that will wait on the mailslot handle.
  159. // When the handle becomes signaled, the MsgGrpEventCompletion
  160. // function will be called.
  161. //
  162. MSG_LOG1(GROUP,"MESSENGER_main: Mailslot handle to wait on "
  163. " = 0x%lx\n",GrpMailslotHandle);
  164. ntStatus = RtlRegisterWait(&g_hGrpEvent, // Work item handle
  165. GrpMailslotHandle, // Waitable handle
  166. MsgGrpEventCompletion, // Callback
  167. NULL, // pContext
  168. INFINITE, // Timeout
  169. WT_EXECUTEONLYONCE); // One-shot
  170. if (!NT_SUCCESS(ntStatus)) {
  171. //
  172. // We want to exit in this case
  173. //
  174. MSG_LOG1(ERROR,"MESSENGER_main: RtlRegisterWait failed %#x\n",
  175. ntStatus);
  176. goto ErrorExit;
  177. }
  178. fGrpThreadCreated = TRUE;
  179. ntStatus = RtlRegisterWait(&g_hNetEvent, // Work item handle
  180. wakeupEvent, // Waitable handle
  181. MsgNetEventCompletion, // Callback
  182. NULL, // pContext
  183. INFINITE, // Timeout
  184. WT_EXECUTEONLYONCE | // One-shot and potentially lengthy
  185. WT_EXECUTELONGFUNCTION);
  186. if (!NT_SUCCESS(ntStatus)) {
  187. //
  188. // We want to exit in this case
  189. //
  190. MSG_LOG1(ERROR,"MESSENGER_main: RtlRegisterWait for Net event failed %#x\n",
  191. ntStatus);
  192. goto ErrorExit;
  193. }
  194. fNetThreadCreated = TRUE;
  195. AddrChangeEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
  196. if (!AddrChangeEvent)
  197. {
  198. dwAddrStatus = GetLastError();
  199. MSG_LOG1(ERROR, "MESSENGER_main: CreateEvent failed %d\n", dwAddrStatus);
  200. goto ErrorExit;
  201. }
  202. RtlZeroMemory(&AddrChangeOverlapped, sizeof(OVERLAPPED));
  203. AddrChangeOverlapped.hEvent = AddrChangeEvent;
  204. dwAddrStatus = NotifyAddrChange(&hTcpip, &AddrChangeOverlapped);
  205. if ((dwAddrStatus != ERROR_SUCCESS) && (dwAddrStatus != ERROR_IO_PENDING))
  206. {
  207. MSG_LOG1(ERROR, "MESSENGER_main: NotifyAddrChange failed %d\n", dwAddrStatus);
  208. goto ErrorExit;
  209. }
  210. ntStatus = RtlRegisterWait(&g_hAddrChangeEvent, // Work item handle
  211. AddrChangeEvent, // Waitable handle
  212. MsgAddrChange, // Callback
  213. NULL, // pContext
  214. INFINITE, // Timeout
  215. WT_EXECUTELONGFUNCTION); // Potentially lengthy
  216. if (!NT_SUCCESS(ntStatus)) {
  217. //
  218. // We want to exit in this case
  219. //
  220. MSG_LOG1(ERROR,"MESSENGER_main: RtlRegisterWait for AddrChange failed %#x\n",
  221. ntStatus);
  222. goto ErrorExit;
  223. }
  224. //
  225. // Register for device notifications. Specifically, we're interested
  226. // in network adapters coming and going. If this fails, we exit.
  227. //
  228. MSG_LOG1(TRACE, "SvcEntry_Messenger: Calling RegisterDeviceNotification...\n", 0);
  229. ZeroMemory (&dbdPnpFilter, sizeof(dbdPnpFilter));
  230. dbdPnpFilter.dbcc_size = sizeof(dbdPnpFilter);
  231. dbdPnpFilter.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
  232. dbdPnpFilter.dbcc_classguid = GUID_NDIS_LAN_CLASS;
  233. g_hPnPNotify = RegisterDeviceNotification (
  234. MsgrStatusHandle,
  235. &dbdPnpFilter,
  236. DEVICE_NOTIFY_SERVICE_HANDLE);
  237. if (!g_hPnPNotify)
  238. {
  239. //
  240. // We want to exit in this case
  241. //
  242. MSG_LOG1(ERROR, "SvcEntry_Messenger: RegisterDeviceNotificationFailed %d!\n",
  243. GetLastError());
  244. goto ErrorExit;
  245. }
  246. MSG_LOG(TRACE,"MESSENGER_main: Messenger main thread is returning\n\n",0);
  247. return;
  248. }
  249. ErrorExit:
  250. //
  251. // We want to stop the messenger in this case.
  252. //
  253. MsgBeginForcedShutdown(PENDING, GetLastError());
  254. //
  255. // In Hydra case, the display thread never goes asleep.
  256. //
  257. if (!g_IsTerminalServer)
  258. {
  259. MsgDisplayThreadWakeup();
  260. }
  261. //
  262. // MsgNetEventCompletion will shut down the group thread, call
  263. // MsgrShutdown, and update the status to SERVICE_STOPPED
  264. //
  265. if (fNetThreadCreated)
  266. {
  267. MsgConfigurationLock(MSG_GET_SHARED, "SvcEntry_Messenger");
  268. SetEvent(wakeupEvent);
  269. MsgConfigurationLock(MSG_RELEASE, "SvcEntry_Messenger");
  270. }
  271. else
  272. {
  273. if (fGrpThreadCreated)
  274. {
  275. MsgGrpThreadShutdown();
  276. }
  277. MsgrShutdown();
  278. MsgStatusUpdate(STOPPED);
  279. }
  280. return;
  281. }
  282. VOID
  283. MsgrShutdown(
  284. )
  285. /*++
  286. Routine Description:
  287. Tidies up the network card prior to exiting. All message server async
  288. NCBs are cancelled, and message names are deleted.
  289. When this routine is entered, it is expected that all the worker
  290. threads have been notified of the impending shutdown. This routine
  291. starts out by waiting for all of them to terminate. Then it continues
  292. with cleaning up the NCB's and deleting names.
  293. Arguments:
  294. none
  295. Return Value:
  296. none
  297. --*/
  298. {
  299. NET_API_STATUS status;
  300. DWORD neti; // Network index
  301. DWORD ncb_i,i; // ncb array index
  302. NCB l_ncb; // local ncb
  303. UCHAR ncbStatus;
  304. int nbStatus;
  305. DWORD index;
  306. PNCB_DATA pNcbData;
  307. PNCB pNcb;
  308. RPC_BINDING_VECTOR *bindingVector = NULL;
  309. MSG_LOG(TRACE," in MsgrShutdown\n",0);
  310. // *** SHUTDOWN HINT ***
  311. MsgStatusUpdate (STOPPING);
  312. // Shutdown winsock
  313. WSACleanup();
  314. // *** SHUTDOWN HINT ***
  315. MsgStatusUpdate (STOPPING);
  316. //
  317. // Shut down the RPC interfaces
  318. //
  319. status = RpcServerInqBindings(&bindingVector);
  320. if (status != ERROR_SUCCESS) {
  321. MSG_LOG(ERROR, "RpcServerInqBindings failed with %d\n", status);
  322. }
  323. if (bindingVector != NULL) {
  324. status = RpcEpUnregister(msgsvcsend_ServerIfHandle, bindingVector, NULL);
  325. if (status != ERROR_SUCCESS && status != EPT_S_NOT_REGISTERED) {
  326. MSG_LOG(ERROR, "RpcEpUnregister failed with %d\n", status);
  327. }
  328. status = RpcBindingVectorFree(&bindingVector);
  329. }
  330. status = RpcServerUnregisterIf(msgsvcsend_ServerIfHandle, NULL, FALSE);
  331. if (status != ERROR_SUCCESS) {
  332. MSG_LOG(ERROR,
  333. "MsgrShutdown: Failed to unregister msgsend rpc interface %d\n",
  334. status);
  335. }
  336. MSG_LOG(TRACE,"MsgrShutdown: Shut down RPC server\n",0);
  337. MsgsvcGlobalData->StopRpcServer( msgsvc_ServerIfHandle );
  338. // *** SHUTDOWN HINT ***
  339. MsgStatusUpdate (STOPPING);
  340. // Release lana state
  341. if (g_hPnPNotify != NULL)
  342. {
  343. if (!UnregisterDeviceNotification(g_hPnPNotify))
  344. {
  345. //
  346. // Note that if this call fails, PnP will get an error back from the
  347. // SCM the next time it tries to send us a PnP message (since the
  348. // service will no longer be running) -- it shouldn't crash things
  349. //
  350. MSG_LOG(ERROR, "MsgrShutdown: UnregisterDeviceNotification failed %d!\n",
  351. GetLastError());
  352. }
  353. }
  354. MsgrShutdownInternal();
  355. // *** SHUTDOWN HINT ***
  356. MsgStatusUpdate (STOPPING);
  357. //
  358. // Stop the display thread
  359. // Note: here the RPC server is stopped so we can stop the display thread
  360. // (NB: a RPC API call may call MsgDisplayThreadWakeup)
  361. //
  362. MsgDisplayEnd();
  363. //
  364. // All cleaning up done. Now free up all resources. The list of
  365. // possible resources is as follows:
  366. //
  367. // memory to free: Handles to Close:
  368. // --------------- -----------------
  369. // ncbArray wakeupSems
  370. // mpncbistate threadHandles
  371. // net_lana_num
  372. // MessageFileName
  373. // dataPtr
  374. //
  375. MSG_LOG(TRACE,"MsgrShutdown: Free up Messenger Resources\n",0);
  376. // Group mailslot for domain messaging
  377. MsgGrpThreadShutdown();
  378. CLOSE_HANDLE(GrpMailslotHandle, INVALID_HANDLE_VALUE);
  379. MsgCloseWakeupEvent(); // do this once
  380. DEREGISTER_WORK_ITEM(g_hAddrChangeEvent);
  381. CLOSE_HANDLE(AddrChangeEvent, NULL);
  382. MsgThreadCloseAll(); // Thread Handles
  383. LocalFree(MessageFileName);
  384. MessageFileName = NULL;
  385. LocalFree(GlobalAllocatedMsgTitle);
  386. GlobalAllocatedMsgTitle = NULL;
  387. LocalFree(g_lpAlertSuccessMessage);
  388. g_lpAlertSuccessMessage = NULL;
  389. g_dwAlertSuccessLen = 0;
  390. LocalFree(g_lpAlertFailureMessage);
  391. g_lpAlertFailureMessage = NULL;
  392. g_dwAlertFailureLen = 0;
  393. MSG_LOG(TRACE,"MsgrShutdown: Done with shutdown\n",0);
  394. return;
  395. }
  396. void
  397. MsgrShutdownInternal(
  398. void
  399. )
  400. /*++
  401. Routine Description:
  402. Release all state related to the lana's known to the system.
  403. Arguments:
  404. None
  405. Return Value:
  406. None
  407. --*/
  408. {
  409. NET_API_STATUS status;
  410. DWORD neti; // Network index
  411. DWORD ncb_i,i; // ncb array index
  412. NCB l_ncb; // local ncb
  413. PMSG_SESSION_STATUS psess_stat;
  414. UCHAR ncbStatus;
  415. int nbStatus;
  416. DWORD index;
  417. PNCB_DATA pNcbData;
  418. PNCB pNcb;
  419. MSG_LOG(TRACE," in MsgrShutdownInternal\n",0);
  420. if (GlobalData.NetData != NULL)
  421. {
  422. psess_stat = LocalAlloc(LMEM_FIXED, sizeof(MSG_SESSION_STATUS));
  423. if (psess_stat == NULL)
  424. {
  425. //
  426. // Not much else we can do here...
  427. //
  428. MSG_LOG(ERROR, "MsgrShutdownInternal: LocalAlloc FAILED!\n",0);
  429. return;
  430. }
  431. //
  432. // Now clean up the NCB's
  433. //
  434. MSG_LOG(TRACE,"MsgrShutdown: Clean up NCBs\n",0);
  435. for ( neti = 0; neti < SD_NUMNETS(); neti++ ) // For all nets
  436. {
  437. clearncb(&l_ncb);
  438. //
  439. // First check for any incomplete Async NCBs and cancel them.
  440. // As a precaution set the function handler for all the
  441. // async NCBs to point to a dummy function which will not reissue
  442. // the NCBs when the complete with cancelled status.
  443. //
  444. l_ncb.ncb_lana_num = GETNETLANANUM(neti); // Use the LANMAN adapter
  445. l_ncb.ncb_command = NCBCANCEL; // Cancel (wait)
  446. for(ncb_i = 0; ncb_i < NCBMAX(neti); ++ncb_i)
  447. {
  448. pNcbData = GETNCBDATA(neti,ncb_i);
  449. pNcb = &pNcbData->Ncb;
  450. pNcbData->IFunc = (LPNCBIFCN)Msgdummy_complete;// Set function pointer
  451. if((pNcb->ncb_cmd_cplt == (UCHAR) 0xff) &&
  452. (pNcb->ncb_retcode == (UCHAR) 0xff)) {
  453. //
  454. // If pending NCB found
  455. //
  456. l_ncb.ncb_buffer = (PCHAR) pNcb;
  457. //
  458. // There will always be an NCB reserved for cancels in the rdr
  459. // but it may be in use so loop if the cancel status
  460. // is NRC_NORES.
  461. //
  462. while( (ncbStatus = Msgsendncb(&l_ncb, neti)) == NRC_NORES) {
  463. //
  464. // Wait for half a sec
  465. //
  466. Sleep(500L);
  467. }
  468. MSG_LOG(TRACE,"Shutdown:Net #%d\n",neti);
  469. MSG_LOG(TRACE,"Shutdown:Attempt to cancel rc = 0x%x\n",
  470. ncbStatus);
  471. //
  472. // Now loop waiting for the cancelled ncb to complete.
  473. // Any ncbs types which are not valid to cancel (eg Delete
  474. // name) must complete so a wait loop here is safe.
  475. //
  476. // NT Change - This will only loop for 30 seconds before
  477. // leaving - whether or not the CANCEL is complete.
  478. //
  479. status = NERR_InternalError;
  480. for (i=0; i<60; i++) {
  481. if (pNcb->ncb_cmd_cplt != (UCHAR) 0xff) {
  482. status = NERR_Success;
  483. break;
  484. }
  485. //
  486. // Wait for half a sec
  487. //
  488. Sleep(500L);
  489. }
  490. if (status != NERR_Success) {
  491. MSG_LOG(ERROR,
  492. "MsgrShutdown: NCBCANCEL did not complete\n",0);
  493. }
  494. }
  495. }
  496. //
  497. // All asyncronous ncbs cancelled completed. Now delete any
  498. // messaging names active on the network card.
  499. //
  500. MSG_LOG(TRACE,"MsgrShutdown: All Async NCBs are cancelled\n",0);
  501. MSG_LOG(TRACE,"MsgrShutdown: Delete messaging names\n",0);
  502. for(i = 0; i < NCBMAX(neti); ++i) // Loop to find active names slot
  503. {
  504. //
  505. // If any of the NFDEL or NFDEL_PENDING flags are set for
  506. // this name slot then there is no name on the card associated
  507. // with it.
  508. //
  509. clearncb(&l_ncb);
  510. if(!(SD_NAMEFLAGS(neti, i) &
  511. (NFDEL | NFDEL_PENDING)))
  512. {
  513. //
  514. // If there is a session active on this name, hang it up
  515. // now or the delete name will fail
  516. //
  517. l_ncb.ncb_command = NCBSSTAT; // session status (wait)
  518. memcpy(l_ncb.ncb_name, (SD_NAMES(neti, i)), NCBNAMSZ);
  519. l_ncb.ncb_buffer = (char far *)psess_stat;
  520. l_ncb.ncb_length = sizeof(MSG_SESSION_STATUS);
  521. l_ncb.ncb_lana_num = GETNETLANANUM(neti);
  522. nbStatus = Msgsendncb(&l_ncb, neti);
  523. if(nbStatus == NRC_GOODRET) // If success
  524. {
  525. for (index=0; index < psess_stat->SessHead.num_sess ;index++) {
  526. l_ncb.ncb_command = NCBHANGUP; // Hangup (wait)
  527. l_ncb.ncb_lsn = psess_stat->SessBuffer[index].lsn;
  528. l_ncb.ncb_lana_num = GETNETLANANUM(neti);
  529. nbStatus = Msgsendncb(&l_ncb, neti);
  530. MSG_LOG3(TRACE,"HANGUP NetBios for Net #%d Session #%d "
  531. "status = 0x%x\n",
  532. neti,
  533. psess_stat->SessBuffer[index].lsn,
  534. nbStatus);
  535. }
  536. }
  537. else {
  538. MSG_LOG2(TRACE,"SessionSTAT NetBios Net #%d failed = 0x%x\n",
  539. neti, nbStatus);
  540. }
  541. //
  542. // With the current design of the message server there can
  543. // be only one session per name so the name should now be
  544. // clear of sessions and the delete name should work.
  545. //
  546. l_ncb.ncb_command = NCBDELNAME; // Del name (wait)
  547. l_ncb.ncb_lana_num = GETNETLANANUM(neti);
  548. //
  549. // Name is still in l_ncb.ncb_name from previous SESSTAT
  550. //
  551. nbStatus = Msgsendncb(&l_ncb, neti);
  552. MSG_LOG2(TRACE,"DELNAME NetBios Net #%d status = 0x%x\n",
  553. neti, nbStatus);
  554. }
  555. }
  556. } // End for all nets loop
  557. LocalFree(psess_stat);
  558. }
  559. MsgsvcGlobalData->NetBiosClose();
  560. MsgCloseWakeupSems(); // wakeupSems
  561. MsgFreeSharedData();
  562. if (wakeupSem != NULL) {
  563. MsgFreeSupportSeg(); // wakeupSem
  564. }
  565. }
  566. VOID
  567. Msgdummy_complete(
  568. short c,
  569. int a,
  570. char b
  571. )
  572. {
  573. // just to shut up compiler
  574. MSG_LOG(TRACE,"In dummy_complete module\n",0);
  575. UNUSED (a);
  576. UNUSED (b);
  577. UNUSED (c);
  578. }
  579. VOID
  580. MsgNetEventCompletion(
  581. PVOID pvContext, // This passed in as context.
  582. BOOLEAN fWaitStatus
  583. )
  584. /*++
  585. Routine Description:
  586. This function is called when the event handle for one of the
  587. nets becomes signaled.
  588. Arguments:
  589. pvContext - This should always be zero.
  590. fWaitStatus - TRUE if we're being called because of a timeout.
  591. FALSE if we're being called because the waitable
  592. event was signalled
  593. Return Value:
  594. None
  595. --*/
  596. {
  597. DWORD neti, numNets;
  598. DWORD msgrState;
  599. BOOL ncbComplete = FALSE;
  600. NET_API_STATUS success;
  601. NTSTATUS ntStatus;
  602. if (fWaitStatus)
  603. {
  604. //
  605. // We timed out (i.e., this came from the control handler)
  606. //
  607. DEREGISTER_WORK_ITEM(g_hNetTimeoutEvent);
  608. }
  609. else
  610. {
  611. //
  612. // We were signalled
  613. //
  614. DEREGISTER_WORK_ITEM(g_hNetEvent);
  615. }
  616. //
  617. // Sychronize this routine in the following manner:
  618. //
  619. // 1. Protection against two threads executing simultaneously while
  620. // the service is marked RUNNING is done by exclusively acquiring
  621. // the MsgConfigurationLock below.
  622. //
  623. // 2. Protection against one thread executing below while another
  624. // thread stops and cleans up the Messenger (and frees/NULLs out
  625. // the data touched in the routines called below) is done by
  626. // the MsgrBlockStateChange call below -- it blocks other threads
  627. // executing MsgrShutdown since the first thing that routine does
  628. // is to call MsgStatusUpdate, which requires the exclusive
  629. // resource that MsgrBlockStateChange acquires shared. This also
  630. // blocks threads here until MsgrShutdown is done changing the
  631. // state to STOPPING, which will prevent the same race condition.
  632. //
  633. //
  634. // Lock out other activity during reconfiguration -- grab this
  635. // before blocking state changes to avoid deadlocking with other
  636. // threads that grab the config lock first and then check the
  637. // service's state.
  638. //
  639. MsgConfigurationLock(MSG_GET_EXCLUSIVE, "MsgNetEventCompletion" );
  640. MsgrBlockStateChange();
  641. msgrState = GetMsgrState();
  642. if (msgrState == STOPPED)
  643. {
  644. MsgrUnblockStateChange();
  645. MsgConfigurationLock(MSG_RELEASE, "MsgNetEventCompletion" );
  646. return;
  647. }
  648. if (msgrState == STOPPING)
  649. {
  650. //
  651. // Net 0 is considered the main Net, and this thread will
  652. // stay around until all the other messenger threads are
  653. // done shutting down.
  654. // Threads for all the other nets simply return.
  655. //
  656. MsgrShutdown();
  657. MsgStatusUpdate(STOPPED);
  658. MsgrUnblockStateChange();
  659. MsgConfigurationLock(MSG_RELEASE, "MsgNetEventCompletion" );
  660. MSG_LOG(TRACE,"MsgNetEventCompletion: Messenger main thread is returning\n\n",0);
  661. return;
  662. }
  663. //
  664. // Look through the NCB's for all nets and service all
  665. // NCB's that are complete. Continue looping until one pass
  666. // is made through the loop without any complete NCB's being found.
  667. //
  668. do
  669. {
  670. ncbComplete = FALSE;
  671. MSG_LOG0(TRACE,"MsgNetEventCompletion: Loop through all nets to look "
  672. "for any complete NCBs\n");
  673. for ( neti = 0; neti < SD_NUMNETS(); neti++ )
  674. {
  675. //
  676. // For all nets
  677. //
  678. ncbComplete |= MsgServeNCBs((DWORD) neti);
  679. MsgServeNameReqs((DWORD) neti);
  680. }
  681. }
  682. while (ncbComplete);
  683. numNets = MsgGetNumNets();
  684. //
  685. // Only rescan if the number of LANAs has changed, as this callback can be invoked
  686. // multiple times in the course of one PnP event and when a message is received
  687. //
  688. if (numNets != SD_NUMNETS())
  689. {
  690. MSG_LOG2(ERROR,"MsgNetEventCompletion: number of lanas changed from %d to %d\n",
  691. SD_NUMNETS(), numNets );
  692. //
  693. // The number of LAN Adapters has changed -- reinitialize data structures
  694. //
  695. // Note that by doing so, we lose all aliases other than usernames and machinename
  696. //
  697. MsgrShutdownInternal();
  698. success = MsgrInitializeMsgrInternal1();
  699. if (success == NERR_Success)
  700. {
  701. success = MsgrInitializeMsgrInternal2();
  702. }
  703. if (success != NERR_Success)
  704. {
  705. MSG_LOG1(ERROR,
  706. "MsgNetEventCompletion: reinit of LANAs failed %d - shutdown\n",
  707. success);
  708. MsgBeginForcedShutdown(PENDING, success);
  709. MsgrUnblockStateChange();
  710. MsgConfigurationLock(MSG_RELEASE, "MsgNetEventCompletion" );
  711. return;
  712. }
  713. //
  714. // Loop again to see if any NCBs completed while we were reinitializing
  715. //
  716. do
  717. {
  718. ncbComplete = FALSE;
  719. MSG_LOG0(TRACE,"MsgNetEventCompletion: Loop through all nets to look "
  720. "for any complete NCBs\n");
  721. for ( neti = 0; neti < SD_NUMNETS(); neti++ ) { // For all nets
  722. ncbComplete |= MsgServeNCBs((DWORD)neti);
  723. MsgServeNameReqs((DWORD)neti);
  724. }
  725. }
  726. while (ncbComplete);
  727. }
  728. if (!fWaitStatus)
  729. {
  730. //
  731. // Setup for the next request if we were signalled
  732. // (submit another WorkItem to the Rtl thread pool)
  733. //
  734. MSG_LOG0(TRACE,"MsgNetEventCompletion: Setup for next Net Event\n");
  735. ntStatus = RtlRegisterWait(&g_hNetEvent, // Work item handle
  736. wakeupEvent, // Waitable handle
  737. MsgNetEventCompletion, // Callback
  738. NULL, // pContext
  739. INFINITE, // Timeout
  740. WT_EXECUTEONLYONCE | // One-shot and potentially lengthy
  741. WT_EXECUTELONGFUNCTION);
  742. if (!NT_SUCCESS(ntStatus))
  743. {
  744. //
  745. // If we can't add the work item, then we won't ever listen
  746. // for these kind of messages again.
  747. //
  748. MSG_LOG1(ERROR,"MsgNetEventCompletion: RtlRegisterWait failed %#x\n",
  749. ntStatus);
  750. }
  751. }
  752. MsgrUnblockStateChange();
  753. MsgConfigurationLock(MSG_RELEASE, "MsgNetEventCompletion" );
  754. //
  755. // This thread has done all that it can do. So we can return it
  756. // to the thread pool.
  757. //
  758. return;
  759. }
  760. VOID
  761. MsgGrpEventCompletion(
  762. PVOID pvContext, // This passed in as context.
  763. BOOLEAN fWaitStatus
  764. )
  765. /*++
  766. Routine Description:
  767. This function is called when the mailslot handle for group
  768. (domain-wide) messages becomes signalled.
  769. Arguments:
  770. pvContext - not used
  771. fWaitStatus - TRUE if we're being called because of a timeout.
  772. FALSE if we're being called because the waitable
  773. event was signalled
  774. Return Value:
  775. None
  776. --*/
  777. {
  778. DWORD msgrState;
  779. NTSTATUS ntStatus;
  780. MSG_LOG0(GROUP,"MsgGroupEventCompletion: entry point\n");
  781. //
  782. // We registered an infinite wait, so we can't have timed
  783. // out (TRUE indicates a timeout)
  784. //
  785. ASSERT(fWaitStatus == FALSE);
  786. DEREGISTER_WORK_ITEM(g_hGrpEvent);
  787. msgrState = MsgServeGroupMailslot();
  788. if (msgrState == STOPPING || msgrState == STOPPED)
  789. {
  790. //
  791. // Close the Mailslot Handle
  792. //
  793. CLOSE_HANDLE(GrpMailslotHandle, INVALID_HANDLE_VALUE);
  794. MSG_LOG0(TRACE,"MsgGroupEventCompletion: No longer listening for "
  795. "group messages\n");
  796. }
  797. else {
  798. //
  799. // Read the Group Mailslot
  800. //
  801. MsgReadGroupMailslot();
  802. //
  803. // Setup for the next request.
  804. // (submit another WorkItem to the Rtl thread pool.)
  805. //
  806. MSG_LOG0(TRACE,"MsgGroupEventCompletion: Setup for next Group Event\n");
  807. MSG_LOG1(GROUP,"MsgGroupEventCompletion: Mailslot handle to wait on "
  808. " = 0x%lx\n",GrpMailslotHandle);
  809. ntStatus = RtlRegisterWait(&g_hGrpEvent, // Work item handle
  810. GrpMailslotHandle, // Waitable handle
  811. MsgGrpEventCompletion, // Callback
  812. NULL, // pContext
  813. INFINITE, // Timeout
  814. WT_EXECUTEONLYONCE); // One-shot
  815. if (!NT_SUCCESS(ntStatus)) {
  816. //
  817. // If we can't add the work item, then we won't ever listen
  818. // for these kind of messages again.
  819. //
  820. MSG_LOG1(ERROR,"MsgGrpEventCompletion: RtlRegisterWait failed %#x\n",
  821. ntStatus);
  822. }
  823. }
  824. //
  825. // This thread has done all that it can do. So we can return it
  826. // to the thread pool.
  827. //
  828. return;
  829. }
  830. VOID
  831. MsgAddrChange(
  832. PVOID pvContext, // This passed in as context.
  833. BOOLEAN fWaitStatus
  834. )
  835. /*++
  836. Routine Description:
  837. xxx
  838. Arguments:
  839. pvContext - not used
  840. fWaitStatus - TRUE if we're being called because of a timeout.
  841. FALSE if we're being called because the waitable
  842. event was signalled
  843. Return Value:
  844. None
  845. --*/
  846. {
  847. DWORD msgrState;
  848. DWORD status;
  849. HANDLE hTcpip;
  850. msgrState = GetMsgrState();
  851. if ((msgrState == STOPPED) || (msgrState == STOPPING))
  852. {
  853. return;
  854. }
  855. MsgConfigurationLock(MSG_GET_SHARED, "MsgAddrChange");
  856. SetEvent(wakeupEvent);
  857. MsgConfigurationLock(MSG_RELEASE, "MsgAddrChange");
  858. status = NotifyAddrChange(&hTcpip, &AddrChangeOverlapped);
  859. if ((status != ERROR_SUCCESS) && (status != ERROR_IO_PENDING))
  860. {
  861. MSG_LOG0(ERROR, "MESSENGER_main: NotifyAddrChange failed %X\n");
  862. }
  863. return;
  864. }