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.

1083 lines
30 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: dmnslave.cxx
  7. //
  8. // Contents: The slave thread that executes executes commands on behalf of
  9. // the DownLevel daemon process.
  10. //
  11. // History: 1-31-96 srikants Created
  12. // 1-06-97 srikants Renamed to dmnslave.cxx from dlslave.cxx
  13. //
  14. //----------------------------------------------------------------------------
  15. #include <pch.cxx>
  16. #pragma hdrstop
  17. #include <cci.hxx>
  18. #include <glbconst.hxx>
  19. #include "dmnslave.hxx"
  20. #include "cimanger.hxx"
  21. const WCHAR * wcsCiDaemonImage = L"%systemroot%\\system32\\cidaemon.exe";
  22. //+---------------------------------------------------------------------------
  23. //
  24. // Member: CDaemonSlave::GetInheritableHandle
  25. //
  26. // Synopsis: Creates an inheritable handle of this process for
  27. // synchronization purposes only.
  28. //
  29. // Arguments: [hTarget] - The inherited handle.
  30. //
  31. // Returns: STATUS_SUCCESS if successful.
  32. // An error code otherwise.
  33. //
  34. // History: 2-02-96 srikants Created
  35. //
  36. //----------------------------------------------------------------------------
  37. DWORD CDaemonSlave::GetInheritableHandle( HANDLE & hTarget )
  38. {
  39. HANDLE hSelf = GetCurrentProcess();
  40. BOOL fSuccess = DuplicateHandle( hSelf, // source process
  41. hSelf, // source handle
  42. hSelf, // destination process
  43. &hTarget, // target handle
  44. SYNCHRONIZE, // desired access
  45. TRUE, // inheritable
  46. 0 // dwOptions
  47. );
  48. if (fSuccess)
  49. return STATUS_SUCCESS;
  50. return GetLastError();
  51. } //GetInheritableHandle
  52. //+---------------------------------------------------------------------------
  53. //
  54. // Member: CDaemonSlave::CDaemonSlave ~ctor
  55. //
  56. // Synopsis: Constructor of the class that is manages the slave thread
  57. // in CI. This thread will execute the commands specified by
  58. // the DownLevel Daemon process.
  59. //
  60. // Arguments: [cicat] -
  61. // [pwcsCatRoot] - Catalog path.
  62. // [nameGen] - mutex name
  63. // [pwcsCatName] - 0 or the friendly name
  64. //
  65. // History: 1-31-96 srikants Created
  66. //
  67. //----------------------------------------------------------------------------
  68. CDaemonSlave::CDaemonSlave(
  69. CCiManager & ciManager,
  70. CCI * pCci,
  71. WCHAR const * pwcsCatRoot,
  72. CSharedNameGen & nameGen,
  73. const GUID & clsidDaemonClientMgr)
  74. : _ciManager(ciManager),
  75. _pCci(pCci),
  76. #pragma warning( disable : 4355 ) // this used in base initialization
  77. _thrSlave(SlaveThread, this, TRUE),
  78. #pragma warning( default : 4355 )
  79. _fAbort(FALSE),
  80. _smemMutex( nameGen.GetMutexName() ),
  81. _sharedMem( nameGen.GetSharedMemName(),MAX_DL_SHARED_MEM),
  82. _evtCi( nameGen.GetCiEventName() ),
  83. _evtDaemon( nameGen.GetDaemonEventName() ),
  84. _pProcess(0),
  85. _hParent(INVALID_HANDLE_VALUE),
  86. _state(eDeathNotified),
  87. _daemonExitStatus(0),
  88. _cbStartupData(0),
  89. _clsidDaemonClientMgr(clsidDaemonClientMgr)
  90. {
  91. //
  92. // Initialize both the events to be in an "unsignalled" state.
  93. //
  94. _evtCi.Reset();
  95. _evtDaemon.Reset();
  96. //
  97. // Initialize the shared memory.
  98. //
  99. _pLayout = (CFilterSharedMemLayout *) _sharedMem.Map();
  100. _pLayout->Init();
  101. Win4Assert( 0 != pwcsCatRoot );
  102. ULONG len = wcslen( pwcsCatRoot );
  103. _wszCatRoot.Init( len+1 );
  104. RtlCopyMemory( _wszCatRoot.GetPointer(), pwcsCatRoot, (len+1) * sizeof(WCHAR) );
  105. DWORD dwError = GetInheritableHandle( _hParent );
  106. if ( STATUS_SUCCESS != dwError )
  107. {
  108. ciDebugOut(( DEB_ERROR, "Cannot duplicate a handle to self. Error 0x%X\n",
  109. dwError ));
  110. THROW( CException( HRESULT_FROM_WIN32( dwError) ) );
  111. }
  112. Win4Assert( INVALID_HANDLE_VALUE != _hParent );
  113. SHandle xSafeHandle(_hParent);
  114. //
  115. // First resume the slave thread and then resume the daemon process.
  116. // The slave should run at a lower priority than queries.
  117. //
  118. if ( IDLE_PRIORITY_CLASS == _ciManager._GetFrameworkParams().GetThreadClassFilter() )
  119. {
  120. _thrSlave.SetPriority( THREAD_PRIORITY_BELOW_NORMAL );
  121. }
  122. else
  123. {
  124. _thrSlave.SetPriority( THREAD_PRIORITY_NORMAL );
  125. }
  126. _thrSlave.Resume();
  127. xSafeHandle.Acquire();
  128. }
  129. //+---------------------------------------------------------------------------
  130. //
  131. // Member: CDaemonSlave::StartFiltering
  132. //
  133. // Synopsis: Signal to indicate that it is okay to start the daemon
  134. // process.
  135. //
  136. // History: 12-30-96 srikants Created
  137. //
  138. //----------------------------------------------------------------------------
  139. void CDaemonSlave::StartFiltering(
  140. BYTE const * pbStartupData,
  141. ULONG cbStartupData )
  142. {
  143. // ====================================================
  144. CLock lock(_mutex);
  145. if ( eReadyToStart == _state || eRunning == _state )
  146. return;
  147. if ( eDeathNotified != _state )
  148. {
  149. ciDebugOut(( DEB_ERROR,
  150. "StartFiltering called in an invalid state (%d)\n",
  151. _state ));
  152. THROW( CException( CI_E_INVALID_STATE ) );
  153. }
  154. //
  155. // Make a local copy of the startup data.
  156. //
  157. if ( _xbStartupData.Count() < cbStartupData )
  158. {
  159. _xbStartupData.Free();
  160. _xbStartupData.Set( cbStartupData,
  161. new BYTE [cbStartupData] );
  162. }
  163. RtlCopyMemory( _xbStartupData.GetPointer(), pbStartupData, cbStartupData );
  164. _cbStartupData = cbStartupData;
  165. _state = eReadyToStart;
  166. _evtCi.Set();
  167. // ====================================================
  168. }
  169. //+---------------------------------------------------------------------------
  170. //
  171. // Member: CDaemonSlave::StartProcess
  172. //
  173. // Synopsis: Creates the DL daemon process if it is not already started.
  174. //
  175. // History: 1-31-96 srikants Created
  176. //
  177. //----------------------------------------------------------------------------
  178. void CDaemonSlave::StartProcess()
  179. {
  180. if ( 0 == _pProcess )
  181. {
  182. WCHAR wszCommandLine[ MAX_PATH + 50 ];
  183. swprintf( wszCommandLine,L"\"%ls\" %ls \"%ls\" %ul %ul",
  184. DL_DAEMON_EXE_NAME,
  185. DL_DAEMON_ARG1_W,
  186. _wszCatRoot.GetPointer(),
  187. _sharedMem.SizeLow(),
  188. GetCurrentProcessId() );
  189. XInterface<ICiCAdviseStatus> xAdviseStatus;
  190. SCODE sc = _ciManager._xDocStore->QueryInterface( IID_ICiCAdviseStatus,
  191. xAdviseStatus.GetQIPointer() );
  192. if ( S_OK != sc )
  193. {
  194. Win4Assert( xAdviseStatus.IsNull() );
  195. THROW( CException( sc ) );
  196. }
  197. _pProcess = new CProcess( DL_DAEMON_EXE_NAME,
  198. wszCommandLine,
  199. TRUE, // suspended
  200. xAdviseStatus.GetPointer() );
  201. }
  202. } //StartProcess
  203. //+---------------------------------------------------------------------------
  204. //
  205. // Member: CDaemonSlave::~CDaemonSlave
  206. //
  207. // Synopsis: Destructor of the CDaemonSlave class. Kills the slave thread
  208. // and then kills the daemon process.
  209. //
  210. // History: 1-31-96 srikants Created
  211. //
  212. //----------------------------------------------------------------------------
  213. CDaemonSlave::~CDaemonSlave()
  214. {
  215. _fAbort = TRUE;
  216. //
  217. // Kill the thread first. Otherwise, the process will be recreated
  218. // by the thread.
  219. //
  220. KillThread();
  221. KillProcess();
  222. //
  223. // Close the handle to ourselves.
  224. //
  225. CloseHandle(_hParent);
  226. }
  227. //+---------------------------------------------------------------------------
  228. //
  229. // Member: CDaemonSlave::KillProcess
  230. //
  231. // Synopsis: Kills the downlevel daemon process.
  232. //
  233. // History: 1-31-96 srikants Created
  234. //
  235. //----------------------------------------------------------------------------
  236. void CDaemonSlave::KillProcess()
  237. {
  238. // =====================================================
  239. CLock lock(_mutex);
  240. if ( _pProcess )
  241. {
  242. //
  243. // Get the process exit code.
  244. //
  245. SaveDaemonExitCode();
  246. TRY
  247. {
  248. delete _pProcess;
  249. _pProcess = 0;
  250. _state = eDied;
  251. _ciManager.ProcessCiDaemonTermination( _daemonExitStatus );
  252. _state = eDeathNotified;
  253. }
  254. CATCH ( CException, e )
  255. {
  256. ciDebugOut(( DEB_ERROR, "Error while killing process. 0x%X\n",
  257. e.GetErrorCode() ));
  258. }
  259. END_CATCH
  260. _evtCi.Reset();
  261. _pProcess = 0;
  262. }
  263. //
  264. // The process has either not started at all (_pProcess==0), or it has been notified, or it
  265. // has died.
  266. //
  267. Win4Assert( eReadyToStart == _state
  268. || eDeathNotified == _state
  269. || eDied == _state );
  270. // =====================================================
  271. }
  272. //+---------------------------------------------------------------------------
  273. //
  274. // Member: CDaemonSlave::RestartDaemon
  275. //
  276. // Synopsis: Starts the daemon process.
  277. //
  278. // History: 1-31-96 srikants Created
  279. //
  280. //----------------------------------------------------------------------------
  281. void CDaemonSlave::RestartDaemon()
  282. {
  283. Win4Assert( eReadyToStart == _state );
  284. StartProcess();
  285. _pProcess->Resume();
  286. }
  287. //+---------------------------------------------------------------------------
  288. //
  289. // Member: CDaemonSlave::KillThread
  290. //
  291. // Synopsis: Kills the slave thread.
  292. //
  293. // History: 1-31-96 srikants Created
  294. //
  295. //----------------------------------------------------------------------------
  296. void CDaemonSlave::KillThread()
  297. {
  298. _evtCi.Set();
  299. _thrSlave.WaitForDeath();
  300. }
  301. //+---------------------------------------------------------------------------
  302. //
  303. // Member: CDaemonSlave::InitiateShutdown
  304. //
  305. // Synopsis: Initiates the shutdown of the slave thread.
  306. //
  307. // History: 12-30-96 srikants Added comment header.
  308. //
  309. //----------------------------------------------------------------------------
  310. void CDaemonSlave::InitiateShutdown()
  311. {
  312. _fAbort = TRUE;
  313. _evtCi.Set();
  314. }
  315. //+---------------------------------------------------------------------------
  316. //
  317. // Member: CDaemonSlave::SlaveThread
  318. //
  319. // Synopsis: The slave thread in CI.
  320. //
  321. // Arguments: [self] -
  322. //
  323. // History: 1-31-96 srikants Created
  324. //
  325. //----------------------------------------------------------------------------
  326. DWORD CDaemonSlave::SlaveThread( void * self )
  327. {
  328. ((CDaemonSlave *) self)->DoWork();
  329. return 0;
  330. }
  331. //+---------------------------------------------------------------------------
  332. //
  333. // Member: CDaemonSlave::FilterReady
  334. //
  335. // Synopsis: Executes the FilterReady() call on behalf of the DL Daemon.
  336. //
  337. // Returns: Status of the operation.
  338. //
  339. // History: 1-31-96 srikants Created
  340. //
  341. //----------------------------------------------------------------------------
  342. SCODE CDaemonSlave::FilterReady()
  343. {
  344. CFilterReadyLayout & data = _pLayout->GetFilterReady();
  345. Win4Assert( data.IsValid() );
  346. SCODE status = S_OK;
  347. Win4Assert( 0 != _pCci );
  348. ULONG cb = 0;
  349. do
  350. {
  351. cb = data.GetCount();
  352. BYTE * docBuffer = data.GetBuffer();
  353. ULONG cMaxDocs = data.GetMaxDocs();
  354. if ( 0 != _pCci )
  355. {
  356. status = _pCci->FilterReady( docBuffer, cb, cMaxDocs );
  357. }
  358. else
  359. {
  360. status = STATUS_NOT_FOUND;
  361. }
  362. _ciManager._HandleFilterReadyStatus( status );
  363. }
  364. while ( FILTER_S_DISK_FULL == status );
  365. data.SetCount( cb );
  366. return status;
  367. }
  368. //+---------------------------------------------------------------------------
  369. //
  370. // Member: CDaemonSlave::FilterMore
  371. //
  372. // Synopsis: Executes the FilterMore() call.
  373. //
  374. // History: 1-31-96 srikants Created
  375. //
  376. //----------------------------------------------------------------------------
  377. SCODE CDaemonSlave::FilterMore()
  378. {
  379. CFilterMoreDoneLayout & data = _pLayout->GetFilterMore();
  380. Win4Assert( data.IsValid() );
  381. SCODE status = S_OK;
  382. Win4Assert( 0 != _pCci );
  383. if ( 0 != _pCci )
  384. {
  385. STATUS const * pStatus = data.GetStatusArray();
  386. ULONG cStatus = data.GetCount();
  387. status = _pCci->FilterMore( pStatus, cStatus );
  388. }
  389. else
  390. {
  391. status = STATUS_NOT_FOUND;
  392. }
  393. return status;
  394. }
  395. //+---------------------------------------------------------------------------
  396. //
  397. // Member: CDaemonSlave::FilterDataReady
  398. //
  399. // History: 1-31-96 srikants Created
  400. //
  401. //----------------------------------------------------------------------------
  402. SCODE CDaemonSlave::FilterDataReady()
  403. {
  404. CFilterDataLayout & data = _pLayout->GetFilterDataReady();
  405. Win4Assert( data.IsValid() );
  406. SCODE status = S_OK;
  407. Win4Assert( 0 != _pCci );
  408. if ( 0 != _pCci )
  409. {
  410. BYTE const * pEntryBuf = data.GetBuffer();
  411. ULONG cb = data.GetSize();
  412. status = _pCci->FilterDataReady( pEntryBuf, cb );
  413. }
  414. else
  415. {
  416. status = STATUS_NOT_FOUND;
  417. }
  418. return S_OK;
  419. }
  420. //+---------------------------------------------------------------------------
  421. //
  422. // Member: CDaemonSlave::FilterDone
  423. //
  424. // History: 1-31-96 srikants Created
  425. //
  426. //----------------------------------------------------------------------------
  427. SCODE CDaemonSlave::FilterDone()
  428. {
  429. CFilterMoreDoneLayout & data = _pLayout->GetFilterDone();
  430. Win4Assert( data.IsValid() );
  431. SCODE status = S_OK;
  432. Win4Assert( 0 != _pCci );
  433. if ( 0 != _pCci )
  434. {
  435. STATUS const * pStatus = data.GetStatusArray();
  436. ULONG cStatus = data.GetCount();
  437. status = _pCci->FilterDone( pStatus, cStatus );
  438. }
  439. else
  440. {
  441. status = STATUS_NOT_FOUND;
  442. }
  443. return status;
  444. }
  445. //+---------------------------------------------------------------------------
  446. //
  447. // Member: CDaemonSlave::FilterStoreValue
  448. //
  449. // History: 1-31-96 srikants Created
  450. //
  451. //----------------------------------------------------------------------------
  452. SCODE CDaemonSlave::FilterStoreValue()
  453. {
  454. CFilterStoreValueLayout & data = _pLayout->GetFilterStoreValueLayout();
  455. Win4Assert( data.IsValid() );
  456. CMemDeSerStream deSer( data.GetBuffer(), data.GetCount() );
  457. CFullPropSpec ps( deSer );
  458. if ( !ps.IsValid() )
  459. THROW( CException( E_OUTOFMEMORY ) );
  460. CStorageVariant var( deSer );
  461. if ( !var.IsValid() )
  462. THROW( CException( E_OUTOFMEMORY ) );
  463. WORKID widFake = data.GetWorkid();
  464. BOOL fSuccess;
  465. _pCci->FilterStoreValue( widFake, ps, var, fSuccess );
  466. data.SetStatus( fSuccess );
  467. return S_OK;
  468. }
  469. //+---------------------------------------------------------------------------
  470. //
  471. // Member: CDaemonSlave::FilterStoreSecurity
  472. //
  473. // History: 06 Feb 96 AlanW Created
  474. //
  475. //----------------------------------------------------------------------------
  476. SCODE CDaemonSlave::FilterStoreSecurity()
  477. {
  478. CFilterStoreSecurityLayout & data = _pLayout->GetFilterStoreSecurityLayout();
  479. Win4Assert( data.IsValid() );
  480. PSECURITY_DESCRIPTOR pSD = data.GetSD();
  481. ULONG cbSD = data.GetCount();
  482. WORKID widFake = data.GetWorkid();
  483. BOOL fSuccess;
  484. _pCci->FilterStoreSecurity( widFake, pSD, cbSD, fSuccess );
  485. data.SetStatus( fSuccess );
  486. return S_OK;
  487. } //FilterStoreSecurity
  488. //+---------------------------------------------------------------------------
  489. //
  490. // Member: CDaemonSlave::FPSToPROPID, public
  491. //
  492. // Synopsis: Converts FULLPROPSPEC to PROPID
  493. //
  494. // Returns: S_OK on success
  495. //
  496. // History: 29-Dec-1997 KyleP Created
  497. //
  498. //----------------------------------------------------------------------------
  499. SCODE CDaemonSlave::FPSToPROPID()
  500. {
  501. CFPSToPROPIDLayout & data = _pLayout->GetFPSToPROPID();
  502. Win4Assert( data.IsValid() );
  503. CMemDeSerStream deSer( data.GetBuffer(), data.GetCount() );
  504. CFullPropSpec fps( deSer );
  505. if ( !fps.IsValid() )
  506. return E_INVALIDARG;
  507. SCODE status = S_OK;
  508. Win4Assert( 0 != _pCci );
  509. if ( 0 != _pCci )
  510. {
  511. status = _pCci->FPSToPROPID( fps, *(PROPID *)data.GetBuffer() );
  512. unsigned cb;
  513. if ( SUCCEEDED(status) )
  514. cb = sizeof(PROPID);
  515. else
  516. cb = 0;
  517. data.SetCount( cb );
  518. }
  519. else
  520. {
  521. status = STATUS_NOT_FOUND;
  522. }
  523. return status;
  524. } //FPSToPROPID
  525. //+---------------------------------------------------------------------------
  526. //
  527. // Member: CDaemonSlave::GetClientStartupData
  528. //
  529. // Synopsis: Retrieves the client startup data.
  530. //
  531. // History: 12-19-96 srikants Created
  532. //
  533. //----------------------------------------------------------------------------
  534. SCODE CDaemonSlave::GetClientStartupData()
  535. {
  536. CFilterStartupDataLayout & data = _pLayout->GetStartupData();
  537. Win4Assert( data.IsValid() );
  538. SCODE status = S_OK;
  539. Win4Assert( 0 != _pCci );
  540. if ( 0 != _pCci )
  541. {
  542. data.SetData( _clsidDaemonClientMgr,
  543. _xbStartupData.GetPointer(),
  544. _cbStartupData );
  545. }
  546. else
  547. {
  548. status = STATUS_NOT_FOUND;
  549. }
  550. return status;
  551. } //GetClientStartupData
  552. //+---------------------------------------------------------------------------
  553. //
  554. // Member: CDaemonSlave::DoSlaveWork
  555. //
  556. // Synopsis: The "de-multiplexor" which figures out what work was signalled
  557. // by the daemon process.
  558. //
  559. // History: 1-31-96 srikants Created
  560. //
  561. //----------------------------------------------------------------------------
  562. void CDaemonSlave::DoSlaveWork()
  563. {
  564. if ( _fAbort )
  565. return;
  566. CIPLock lock(_smemMutex);
  567. Win4Assert( 0 != _pLayout );
  568. CFilterSharedMemLayout::EFilterWorkType workType = _pLayout->GetWorkType();
  569. SCODE status = S_OK;
  570. TRY
  571. {
  572. switch ( workType )
  573. {
  574. case CFilterSharedMemLayout::eNone:
  575. break;
  576. case CFilterSharedMemLayout::eFilterReady:
  577. {
  578. status = FilterReady();
  579. break;
  580. }
  581. case CFilterSharedMemLayout::eFilterDataReady:
  582. {
  583. status = FilterDataReady();
  584. break;
  585. }
  586. case CFilterSharedMemLayout::eFilterMore:
  587. {
  588. status = FilterMore();
  589. break;
  590. }
  591. case CFilterSharedMemLayout::eFilterDone:
  592. {
  593. status = FilterDone();
  594. break;
  595. }
  596. case CFilterSharedMemLayout::eFilterStoreValue:
  597. {
  598. status = FilterStoreValue();
  599. break;
  600. }
  601. case CFilterSharedMemLayout::eFilterStoreSecurity:
  602. {
  603. status = FilterStoreSecurity();
  604. break;
  605. }
  606. case CFilterSharedMemLayout::eFPSToPROPID:
  607. {
  608. status = FPSToPROPID();
  609. break;
  610. }
  611. case CFilterSharedMemLayout::eFilterStartupData:
  612. {
  613. status = GetClientStartupData();
  614. break;
  615. }
  616. default:
  617. ciDebugOut(( DEB_ERROR, "Unknown work code from daemon\n",
  618. workType ));
  619. Win4Assert( !"Unknown work code");
  620. status = STATUS_INVALID_PARAMETER;
  621. break;
  622. }
  623. }
  624. CATCH( CException, e )
  625. {
  626. status = e.GetErrorCode();
  627. ciDebugOut(( DEB_WARN,
  628. "Error (0x%X) caught while doing slave work\n",
  629. status ));
  630. if ( IsCiCorruptStatus( e.GetErrorCode() ) )
  631. RETHROW();
  632. }
  633. END_CATCH
  634. if ( IsDiskLowError(status) )
  635. {
  636. BOOL fLow;
  637. _pCci->VerifyIfLowOnDiskSpace(fLow);
  638. }
  639. //
  640. // Set the status of the operation and wake up the daemon process.
  641. //
  642. _pLayout->SetStatus( status );
  643. _evtDaemon.Set();
  644. } //DoSlaveWork
  645. //+---------------------------------------------------------------------------
  646. //
  647. // Member: CDaemonSlave::DoStateMachineWork
  648. //
  649. // Synopsis: Does state machine book keeping work. If necessary, it will
  650. // restart the cidaemon process.
  651. //
  652. // History: 12-30-96 srikants Created
  653. //
  654. //----------------------------------------------------------------------------
  655. void CDaemonSlave::DoStateMachineWork()
  656. {
  657. // =======================================
  658. CLock lock(_mutex);
  659. Win4Assert( eRunning != _state );
  660. if ( _state == eReadyToStart && !IsProcessLowOnResources() )
  661. {
  662. RestartDaemon();
  663. _state = eRunning;
  664. }
  665. else if ( _state == eDied )
  666. {
  667. _ciManager.ProcessCiDaemonTermination( _daemonExitStatus );
  668. _state = eDeathNotified;
  669. }
  670. // =======================================
  671. } //DoStateMachineWork
  672. //+---------------------------------------------------------------------------
  673. //
  674. // Member: CDaemonSlave::SaveDaemonExitCode
  675. //
  676. // Synopsis: Saves the exit code of the daemon process.
  677. //
  678. // History: 12-30-96 srikants Created
  679. //
  680. //----------------------------------------------------------------------------
  681. void CDaemonSlave::SaveDaemonExitCode()
  682. {
  683. Win4Assert( 0 != _pProcess );
  684. HANDLE hProcess = _pProcess->GetHandle();
  685. DWORD dwExitCode;
  686. if ( GetExitCodeProcess( hProcess, &dwExitCode ) )
  687. _daemonExitStatus = dwExitCode;
  688. else
  689. _daemonExitStatus = E_FAIL;
  690. } //SaveDaemonExitCode
  691. //+---------------------------------------------------------------------------
  692. //
  693. // Member: CDaemonSlave::IsProcessLowOnResources
  694. //
  695. // Synopsis: Tests if the daemon process died because of being low on
  696. // resources.
  697. //
  698. // Returns: Returns TRUE if the daemon process died with low resource
  699. // condition (low on memory or disk). FALSE o/w.
  700. //
  701. // History: 3-11-96 srikants Created
  702. //
  703. //----------------------------------------------------------------------------
  704. BOOL CDaemonSlave::IsProcessLowOnResources() const
  705. {
  706. Win4Assert( 0 == _pProcess );
  707. return _IsResourceLowError( _daemonExitStatus );
  708. }
  709. static WCHAR const * my_wcsistr( WCHAR const * wcsString, WCHAR const * wcsPattern )
  710. {
  711. if ( (wcsPattern == 0) || (*wcsPattern == 0) )
  712. return wcsString;
  713. ULONG cwcPattern = wcslen(wcsPattern);
  714. while ( *wcsString != 0 )
  715. {
  716. while ( (*wcsString != 0) &&
  717. (towupper(*wcsString) != towupper(*wcsPattern)) )
  718. wcsString++;
  719. if ( 0 == *wcsString )
  720. return 0;
  721. if ( _wcsnicmp( wcsString, wcsPattern, cwcPattern) == 0 )
  722. return wcsString;
  723. wcsString++;
  724. }
  725. return 0;
  726. } //my_wcsistr
  727. //+---------------------------------------------------------------------------
  728. //
  729. // Functions: IsInDebugger
  730. //
  731. // Synopsis: Tests if a process is being debugged
  732. //
  733. // Arguments: [hProcess] -- The process handle to test.
  734. //
  735. // Returns: Returns TRUE if the process is being debugged.
  736. //
  737. // History: 4-23-98 dlee Created
  738. //
  739. //----------------------------------------------------------------------------
  740. BOOL IsInDebugger( HANDLE hProcess )
  741. {
  742. //
  743. // Is the child process cdb, ntsd, or windbg? If so, the daemon was started
  744. // via ImageFileExecutionOptions, and we can safely assume it's in a debugger.
  745. //
  746. const ULONG cbBuffer = sizeof(UNICODE_STRING) + ( MAX_PATH * sizeof WCHAR );
  747. XArray<BYTE> xBuf( cbBuffer );
  748. PUNICODE_STRING pBuffer = (PUNICODE_STRING) xBuf.Get();
  749. NTSTATUS s = NtQueryInformationProcess( hProcess,
  750. ProcessImageFileName,
  751. pBuffer,
  752. cbBuffer,
  753. 0 );
  754. if ( STATUS_SUCCESS != s )
  755. return FALSE;
  756. // Null-terminate the buffer
  757. pBuffer->Buffer[ pBuffer->Length / sizeof WCHAR ] = 0;
  758. // The buffer now looks something like "\Device\HarddiskVolume2\WINDOWS\system32\ntsd.exe"
  759. if ( ( 0 != my_wcsistr( pBuffer->Buffer, L"ntsd.exe" ) ) ||
  760. ( 0 != my_wcsistr( pBuffer->Buffer, L"cdb.exe" ) ) ||
  761. ( 0 != my_wcsistr( pBuffer->Buffer, L"windbg.exe" ) ) )
  762. return TRUE;
  763. //
  764. // So it's not a debugger. Is the child process in a debugger?
  765. // First get the base address of the process.
  766. //
  767. PROCESS_BASIC_INFORMATION bi;
  768. s = NtQueryInformationProcess( hProcess,
  769. ProcessBasicInformation,
  770. (PVOID) &bi,
  771. sizeof bi,
  772. 0 );
  773. if ( STATUS_SUCCESS != s )
  774. return FALSE;
  775. PEB Peb;
  776. if ( ReadProcessMemory( hProcess, bi.PebBaseAddress, &Peb, sizeof PEB, 0 ) )
  777. return Peb.BeingDebugged;
  778. return FALSE;
  779. } //IsInDebugger
  780. //+---------------------------------------------------------------------------
  781. //
  782. // Member: CDaemonSlave::DoWork
  783. //
  784. // Synopsis: Main worker thread.
  785. //
  786. // History: 1-31-96 srikants Created
  787. //
  788. //----------------------------------------------------------------------------
  789. void CDaemonSlave::DoWork()
  790. {
  791. const cHandles = 2;
  792. HANDLE aHandles[cHandles];
  793. const iCiWork = 0; // Index of the ci work event.
  794. const iDaemonProcess = 1; // Index of the daemon process.
  795. aHandles[iCiWork] = _evtCi.GetHandle();
  796. BOOL fContinue = TRUE;
  797. while ( fContinue )
  798. {
  799. if ( !_fAbort )
  800. {
  801. TRY
  802. {
  803. DWORD nHandles = 1;
  804. if ( 0 != _pProcess )
  805. {
  806. aHandles[iDaemonProcess] = _pProcess->GetHandle();
  807. nHandles++;
  808. }
  809. DWORD timeout = _ciManager._GetFrameworkParams().GetDaemonResponseTimeout() * 60 * 1000;
  810. DWORD status = WaitForMultipleObjects( nHandles,
  811. aHandles,
  812. FALSE,
  813. timeout );
  814. if ( WAIT_FAILED == status )
  815. {
  816. ciDebugOut(( DEB_ERROR, "WaitForMultipleObjects failed with error 0x%X\n",
  817. GetLastError() ));
  818. //
  819. // Don't restart the daemon process immediately. Wait for
  820. // the timeout period.
  821. //
  822. KillProcess();
  823. }
  824. else if ( WAIT_TIMEOUT == status )
  825. {
  826. // The process is probably looping. We should kill it and
  827. // restart.
  828. if ( eRunning == _state )
  829. {
  830. if ( 0 != _pProcess )
  831. {
  832. BOOL fDbg = IsInDebugger( _pProcess->GetHandle() );
  833. ciDebugOut(( DEB_ERROR,
  834. "Daemon is looping, killing? %s\n",
  835. fDbg ? "no" : "yes" ));
  836. if ( !fDbg )
  837. KillProcess();
  838. }
  839. }
  840. else
  841. {
  842. DoStateMachineWork();
  843. }
  844. }
  845. else
  846. {
  847. //
  848. // An event was signalled.
  849. //
  850. DWORD iWake = status - WAIT_OBJECT_0;
  851. if ( iCiWork == iWake )
  852. {
  853. //
  854. // We have been given some work. Do it.
  855. //
  856. // =========================================
  857. {
  858. CLock lock(_mutex);
  859. _evtCi.Reset();
  860. }
  861. // =========================================
  862. if ( eRunning == _state )
  863. DoSlaveWork();
  864. else
  865. DoStateMachineWork();
  866. }
  867. else if ( iDaemonProcess == iWake )
  868. {
  869. //
  870. // The daemon process died.
  871. //
  872. ciDebugOut(( DEB_ERROR, "Daemon process died\n" ));
  873. KillProcess();
  874. }
  875. }
  876. }
  877. CATCH(CException, e )
  878. {
  879. ciDebugOut(( DEB_ERROR, "Error in the Slave Thread - 0x%X\n",
  880. e.GetErrorCode() ));
  881. _ciManager.ProcessError( e.GetErrorCode() );
  882. if ( IsCiCorruptStatus( e.GetErrorCode() ) )
  883. {
  884. KillProcess();
  885. fContinue = FALSE;
  886. }
  887. }
  888. END_CATCH
  889. }
  890. else
  891. {
  892. fContinue = FALSE;
  893. }
  894. }
  895. } //DoWork