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.

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