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.

675 lines
22 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 1999
  5. //
  6. // File: srequest.hxx
  7. //
  8. // Contents: Server side of catalog and query requests
  9. //
  10. // Classes: CPipeServer
  11. // CRequestServer
  12. // CServerItem
  13. // CRequestQueue
  14. //
  15. // History: 16-Sep-96 dlee Created.
  16. //
  17. //--------------------------------------------------------------------------
  18. #pragma once
  19. #include <circq.hxx>
  20. #include <thash.hxx>
  21. #include <cisvcex.hxx>
  22. #define CI_PIPE_TESTING CIDBG
  23. //+-------------------------------------------------------------------------
  24. //
  25. // Class: CPipeServer
  26. //
  27. // Synopsis: Base class for a server named pipe
  28. //
  29. // History: 16-Sep-96 dlee Created.
  30. //
  31. //--------------------------------------------------------------------------
  32. class CPipeServer
  33. {
  34. public:
  35. CPipeServer( const WCHAR * pwcName,
  36. ULONG cmsDefaultClientTimeout,
  37. SECURITY_DESCRIPTOR * pSecurityDescriptor );
  38. ~CPipeServer()
  39. {
  40. prxDebugOut(( DEB_ITRACE, "~destructing pipe 0x%x\n", _hPipe ));
  41. BOOL fCloseOk = CloseHandle( _hPipe );
  42. Win4Assert( fCloseOk );
  43. }
  44. void Write( void * pv,
  45. unsigned cb,
  46. LPOVERLAPPED_COMPLETION_ROUTINE pRoutine )
  47. {
  48. prxDebugOut(( DEB_ITRACE, "WriteFileEx cb %d this 0x%x pipe 0x%x\n",
  49. cb, this, _hPipe ));
  50. // hEvent is documented as a good place to pass user data
  51. _overlapped.hEvent = (HANDLE) this;
  52. if ( ! WriteFileEx( _hPipe, pv, cb, &_overlapped, pRoutine ) )
  53. THROW( CException() );
  54. }
  55. void Read( void * pv,
  56. unsigned cb,
  57. LPOVERLAPPED_COMPLETION_ROUTINE pRoutine )
  58. {
  59. prxDebugOut(( DEB_ITRACE, "ReadFileEx cb %d this 0x%x, pipe 0x%x\n",
  60. cb, this, _hPipe ));
  61. // hEvent is documented as a good place to pass user data
  62. _overlapped.hEvent = (HANDLE) this;
  63. if ( ! ReadFileEx( _hPipe, pv, cb, &_overlapped, pRoutine ) )
  64. THROW( CException() );
  65. }
  66. void WriteSync( void *pv, DWORD cb );
  67. BYTE * ReadRemainingSync( void *pvSoFar, DWORD & cbSoFar );
  68. BOOL Connect();
  69. BOOL Disconnect()
  70. {
  71. prxDebugOut(( DEB_ITRACE, "disconnecting from pipe 0x%x\n", _hPipe ));
  72. return DisconnectNamedPipe( _hPipe );
  73. }
  74. HANDLE GetEvent() { return _event.GetHandle(); }
  75. void ResetEvent() { _event.Reset(); }
  76. HANDLE GetPipe() { return _hPipe; }
  77. void CancelIO() { CancelIo( _hPipe ); }
  78. private:
  79. OVERLAPPED _overlapped; // 2 uint_ptr + 3 dwords
  80. HANDLE _hPipe;
  81. CEventSem _event;
  82. CEventSem _eventWrite;
  83. };
  84. //+-------------------------------------------------------------------------
  85. //
  86. // Class: CRequestServer
  87. //
  88. // Synopsis: Class for a catalog/query server connection
  89. //
  90. // History: 16-Sep-96 dlee Created.
  91. // 21-Oct-99 KLam Added FixVariantPointers and Win64 data
  92. //
  93. //--------------------------------------------------------------------------
  94. const LONGLONG sigCRequestServer = 0x2076727374737172; // "rqstsrv"
  95. class CRequestQueue;
  96. class CWorkQueue;
  97. class CClientDocStore;
  98. enum RequestState { stateContinue,
  99. stateDisconnect,
  100. statePending };
  101. struct SCWorkItem
  102. {
  103. ECiSvcActionType type; // state to be changed to
  104. ICiCDocStore * pDocStore; // pointer to docstore to be shutdown
  105. BOOL fNoQueryRW; // TRUE if NoQuery and read/write
  106. // NoQuery and read-only otherwise
  107. WCHAR * StoppedCat; // name of stopped catalog (to be restarted)
  108. // NULL if no catalog is stopped
  109. }; //work item for state change events
  110. class CRequestServer : public CPipeServer, public PWorkItem
  111. {
  112. public:
  113. CRequestServer( const WCHAR * pwcPipe,
  114. ULONG cmsDefaultClientTimeout,
  115. CRequestQueue & requestQueue,
  116. CWorkQueue & workQueue );
  117. void AddRef() { InterlockedIncrement( & _cRefs ); }
  118. void Release();
  119. BOOL IsAvailable()
  120. {
  121. // if the refcount is 1, it's available ( not in DoIt() )
  122. return ( 1 == _cRefs ) && !IsBeingRemoved();
  123. }
  124. BOOL NoOutstandingAPCs()
  125. {
  126. return pipeStateNone == _state ||
  127. pipeStatePending == _state;
  128. }
  129. void DoIt( CWorkThread * pThread );
  130. void DeferredAPC();
  131. void Cleanup();
  132. void CompleteNotification( DWORD dwChangeType );
  133. void QueryQuiesced( BOOL fSuccess, SCODE sc );
  134. void SetPQuery( PQuery * pQuery )
  135. {
  136. Win4Assert( 0 == _pQuery );
  137. _pQuery = pQuery;
  138. }
  139. HANDLE GetWorkerThreadHandle()
  140. {
  141. return _hWorkThread;
  142. }
  143. static void WINAPI CancelAPCRoutine( DWORD_PTR dwParam );
  144. void SetLastTouchedTime(DWORD dwLastTouched) { _dwLastTouched = dwLastTouched; }
  145. DWORD GetLastTouchedTime() { return _dwLastTouched; }
  146. void BeingRemoved( CEventSem * pevtDone ) { _pevtDone = pevtDone; };
  147. BOOL IsBeingRemoved() const { return 0 != _pevtDone; }
  148. ICiCDocStore * GetDocStore() { return _xDocStore.GetPointer(); }
  149. private:
  150. static void WINAPI QuiesceAPCRoutine( DWORD_PTR dwParam );
  151. void Quiesce();
  152. enum PipeState { pipeStateNone = 10,
  153. pipeStateRead,
  154. pipeStateWrite,
  155. pipeStatePending };
  156. static void WINAPI APCRoutine( DWORD dwError,
  157. DWORD cbTransferred,
  158. LPOVERLAPPED pOverlapped );
  159. RequestState HandleRequestNoThrow( DWORD cbRequest,
  160. DWORD & cbToWrite );
  161. #ifdef _WIN64
  162. void FixColumns ( CTableColumnSet * pCols32 );
  163. void FixRows ( BYTE * pbReply,
  164. BYTE * pbResults,
  165. ULONG cbResults,
  166. ULONG_PTR ulpClientBase,
  167. ULONG cRows,
  168. ULONG cbRowWidth );
  169. void FixVariantPointers ( PROPVARIANT32 *pVar32,
  170. PROPVARIANT *pVar64,
  171. BYTE *pbResults,
  172. ULONG_PTR ulClientBase );
  173. #endif
  174. void DoAPC( DWORD dwError, DWORD cbTransferred );
  175. ~CRequestServer()
  176. {
  177. prxDebugOut(( DEB_ITRACE, "deleting server pipe 0x%x\n", GetPipe() ));
  178. Win4Assert( NoOutstandingAPCs() );
  179. Win4Assert( 0 == _cRefs );
  180. Win4Assert( 0 == _pQuery );
  181. Win4Assert( 0 == _pWorkThread );
  182. Win4Assert( INVALID_HANDLE_VALUE == _hWorkThread );
  183. Win4Assert( 0 == _pevtDone );
  184. }
  185. int GetClientVersion() { return pmCiVersion( _iClientVersion ); }
  186. BOOL IsClient64() { return IsCi64( _iClientVersion ); }
  187. BOOL IsClientRemote() { return _fClientIsRemote; }
  188. void * _Buffer() { return _abBuffer; }
  189. void * _ActiveBuffer()
  190. {
  191. if ( _xTempBuffer.IsNull() )
  192. return _abBuffer;
  193. return _xTempBuffer.Get();
  194. }
  195. DWORD _BufferSize() { return sizeof _abBuffer; }
  196. void FormScopeRestriction( CiMetaData & eType, XRestriction & rst );
  197. void FreeQuery()
  198. {
  199. // insures only one thread will delete the PQuery
  200. PQuery * pInitial = (PQuery *) InterlockedCompareExchangePointer(
  201. (void **) &_pQuery,
  202. NULL,
  203. _pQuery );
  204. delete pInitial; // may be 0
  205. #ifdef _WIN64
  206. // Free the column descriptions
  207. _xCols64.Free();
  208. _xCols32.Free();
  209. #endif
  210. }
  211. typedef RequestState (CRequestServer:: * ProxyMessageFunction)(
  212. DWORD cbRequest,
  213. DWORD & cbToWrite );
  214. static const ProxyMessageFunction _aMsgFunctions[ cProxyMessages ];
  215. static const BOOL _afImpersonate[ cProxyMessages ];
  216. RequestState DoObsolete( DWORD, DWORD & );
  217. RequestState DoConnect( DWORD, DWORD & );
  218. RequestState DoDisconnect( DWORD, DWORD & );
  219. RequestState DoCreateQuery( DWORD, DWORD & );
  220. RequestState DoFreeCursor( DWORD, DWORD & );
  221. RequestState DoGetRows( DWORD, DWORD & );
  222. RequestState DoRatioFinished( DWORD, DWORD & );
  223. RequestState DoCompareBmk( DWORD, DWORD & );
  224. RequestState DoGetApproximatePosition( DWORD, DWORD & );
  225. RequestState DoSetBindings( DWORD, DWORD & );
  226. RequestState DoGetNotify( DWORD, DWORD & );
  227. RequestState DoSendNotify( DWORD, DWORD & );
  228. RequestState DoSetWatchMode( DWORD, DWORD & );
  229. RequestState DoGetWatchInfo( DWORD, DWORD & );
  230. RequestState DoShrinkWatchRegion( DWORD, DWORD & );
  231. RequestState DoRefresh( DWORD, DWORD & );
  232. RequestState DoGetQueryStatus( DWORD, DWORD & );
  233. RequestState DoCiState( DWORD, DWORD & );
  234. RequestState DoBeginCacheTransaction( DWORD, DWORD & );
  235. RequestState DoSetupCache( DWORD, DWORD & );
  236. RequestState DoEndCacheTransaction( DWORD, DWORD & );
  237. RequestState DoForceMerge( DWORD, DWORD & );
  238. RequestState DoAbortMerge( DWORD, DWORD & );
  239. RequestState DoFetchValue( DWORD, DWORD & );
  240. RequestState DoWorkIdToPath( DWORD, DWORD & );
  241. RequestState DoUpdateDocuments( DWORD, DWORD & );
  242. RequestState DoGetQueryStatusEx( DWORD, DWORD & );
  243. RequestState DoRestartPosition( DWORD, DWORD & );
  244. RequestState DoStopAsynch( DWORD, DWORD & );
  245. RequestState DoStartWatching( DWORD, DWORD & );
  246. RequestState DoStopWatching( DWORD, DWORD & );
  247. RequestState DoSetCatState( DWORD, DWORD & );
  248. PipeState _state; // none, read, write, or pending
  249. long _cRefs; // refcount
  250. int _iClientVersion; // version of the client
  251. BOOL _fClientIsRemote; // TRUE if client is remote
  252. XInterface<ICiCDocStore> _xDocStore; // Set if a docstore is found
  253. PQuery * _pQuery; // set if a query is active
  254. CWorkThread * _pWorkThread; // worker thread for this server
  255. HANDLE _hWorkThread; // worker thread for this server
  256. XArray<BYTE> _xTempBuffer; // buffer for big reads/writes
  257. XArray<WCHAR> _xClientMachine; // name of the client's machine
  258. XArray<WCHAR> _xClientUser; // name of the client
  259. XArray<BYTE> _xFetchedValue; // state for pmFetchValue
  260. DWORD _cbFetchedValueSoFar; // state for pmFetchValue
  261. DWORD _cbPendingWrite; // bytes to write at completion
  262. SCODE _scPendingStatus; // status code for completed op
  263. DWORD _dwDeferredAPCError; // completion status of deferred APC
  264. DWORD _cbDeferredAPCTransferred; // deferred APC byte count
  265. CRequestQueue & _requestQueue; // the 1 and only request queue
  266. CWorkQueue & _workQueue; // the 1 and only work queue
  267. XInterface<IDBProperties> _xDbProperties; // properties from connect
  268. DWORD _dwLastTouched;
  269. CEventSem * _pevtDone; // set when the instance dies
  270. #ifdef _WIN64
  271. unsigned _cbRowWidth64;
  272. unsigned _cbRowWidth32;
  273. XPtr<CTableColumnSet> _xCols64;
  274. XPtr<CTableColumnSet> _xCols32;
  275. #endif
  276. // this buffer must be 8-byte aligned and large enough to read
  277. // any request except pmCreateQuery and pmSetBindings
  278. LONGLONG _abBuffer[ 2048 / sizeof LONGLONG ];
  279. };
  280. //+-------------------------------------------------------------------------
  281. //
  282. // Class: XAPCWorkerThread
  283. //
  284. // Synopsis: Refcounts a worker thread and sets the "processing APC"
  285. // state.
  286. //
  287. // History: 17-Jul-00 dlee Created.
  288. //
  289. //--------------------------------------------------------------------------
  290. class XAPCWorkerThread
  291. {
  292. public:
  293. XAPCWorkerThread( CWorkQueue & workQueue, CWorkThread * pWorkThread ) :
  294. _workQueue( workQueue ),
  295. _pWorkThread( pWorkThread )
  296. {
  297. _workQueue.AddRef( _pWorkThread );
  298. _pWorkThread->SetProcessingAPC( TRUE );
  299. }
  300. ~XAPCWorkerThread()
  301. {
  302. _pWorkThread->SetProcessingAPC( FALSE );
  303. _workQueue.Release( _pWorkThread );
  304. }
  305. private:
  306. CWorkQueue & _workQueue;
  307. CWorkThread * _pWorkThread;
  308. };
  309. //+-------------------------------------------------------------------------
  310. //
  311. // Class: CServerItem
  312. //
  313. // Synopsis: Encapsulates a CRequestServer for use in the circular queue,
  314. // which requires many of the methods implemented below.
  315. //
  316. // History: 16-Sep-96 dlee Created.
  317. //
  318. //--------------------------------------------------------------------------
  319. class CServerItem
  320. {
  321. public:
  322. CServerItem() : _pServer( 0 ) {}
  323. CServerItem( CRequestServer *pServer ) : _pServer( pServer ) {}
  324. ~CServerItem()
  325. {
  326. Free();
  327. }
  328. void Create( const WCHAR * pwcName,
  329. ULONG cmsDefaultClientTimeout,
  330. CRequestQueue & requestQueue,
  331. CWorkQueue & workQueue )
  332. {
  333. Win4Assert( 0 == _pServer );
  334. _pServer = new CRequestServer( pwcName,
  335. cmsDefaultClientTimeout,
  336. requestQueue,
  337. workQueue );
  338. }
  339. void Acquire( CServerItem & item )
  340. {
  341. item = *this;
  342. _pServer = 0;
  343. }
  344. CServerItem & operator = (CServerItem & src )
  345. {
  346. Win4Assert( 0 == _pServer );
  347. _pServer = src._pServer;
  348. src._pServer = 0;
  349. return *this;
  350. }
  351. CRequestServer * Get()
  352. {
  353. return _pServer;
  354. }
  355. void Free()
  356. {
  357. if ( 0 != _pServer )
  358. {
  359. _pServer->Release();
  360. _pServer = 0;
  361. }
  362. }
  363. CRequestServer * Acquire()
  364. {
  365. CRequestServer *p = _pServer;
  366. _pServer = 0;
  367. return p;
  368. }
  369. private:
  370. CRequestServer * _pServer;
  371. };
  372. //+-------------------------------------------------------------------------
  373. //
  374. // Class: CRequestQueue
  375. //
  376. // Synopsis: Handles the main work of the service and the caching of
  377. // request servers.
  378. //
  379. // History: 16-Sep-96 dlee Created.
  380. // 30-Mar-98 kitmanh Added new flag _fNetPause
  381. // 14-Apr-98 kitmanh Renamed _evtStopWork to
  382. // _evtStateChange and StopWork() to
  383. // WakeForStateChange()
  384. // 14-Apr-98 kitmanh Added a DynArrayInPlace,
  385. // StateChangeArray for work items
  386. // related to state change
  387. //
  388. //--------------------------------------------------------------------------
  389. class CRequestQueue
  390. {
  391. public:
  392. CRequestQueue( unsigned cMaxCachedRequests,
  393. unsigned cMaxRequests,
  394. unsigned cmsDefaultClientTimeout,
  395. BOOL fMinimizeWorkingSet,
  396. unsigned cMinClientIdleTime,
  397. unsigned cmsStartupDelay,
  398. const GUID & guidDocStoreClient );
  399. ~CRequestQueue()
  400. {
  401. ClearSCArray();
  402. #if CI_PIPE_TESTING
  403. if ( 0 != _hTraceDll )
  404. {
  405. FreeLibrary( _hTraceDll );
  406. _hTraceDll = 0;
  407. }
  408. #endif // CI_PIPE_TESTING
  409. }
  410. void DoWork();
  411. void RecycleRequestServerNoThrow( CRequestServer *pServer );
  412. void WakeForStateChange() { _evtStateChange.Set(); }
  413. void IncrementPendingItems() { InterlockedIncrement( &_cPendingItems ); }
  414. void DecrementPendingItems() { InterlockedDecrement( &_cPendingItems ); }
  415. void AddToListNoThrow( CRequestServer * pServer )
  416. {
  417. CLock lock( _mutex );
  418. _tableActiveServers.AddEntry( pServer );
  419. }
  420. void RemoveFromListNoThrow( CRequestServer * pServer )
  421. {
  422. CLock lock( _mutex );
  423. BOOL fDeleted = _tableActiveServers.DeleteEntry( pServer );
  424. Win4Assert( fDeleted );
  425. }
  426. BOOL IsShutdown() const { return _fShutdown; }
  427. BOOL IsNetPause() const { return _fNetPause; }
  428. BOOL IsNetContinue() const { return _fNetContinue; }
  429. BOOL IsNetStop() const { return _fNetStop; }
  430. // Reset some member variables and reset the _evtStateChange event for restarting
  431. // up from NetPause or NetContinue
  432. void ReStart()
  433. {
  434. CLock lock( _mutex );
  435. _fShutdown = FALSE;
  436. _fNetPause = FALSE;
  437. _fNetContinue = FALSE;
  438. _fNetStop = FALSE;
  439. ClearSCArray();
  440. _evtStateChange.Reset();
  441. }
  442. void WrestReqServerFromIdleClient();
  443. CMutexSem & GetTheMutex() { return _mutex; }
  444. void SetNetPause()
  445. {
  446. CLock lock( _mutex );
  447. _fNetPause = TRUE;
  448. }
  449. void SetNetContinue()
  450. {
  451. CLock lock( _mutex );
  452. _fNetContinue = TRUE;
  453. }
  454. void SetNetStop()
  455. {
  456. CLock lock( _mutex );
  457. _fNetStop = TRUE;
  458. }
  459. SECURITY_DESCRIPTOR * GetSecurityDescriptor()
  460. {
  461. Win4Assert( !_xSecurityDescriptor.IsNull() );
  462. return (SECURITY_DESCRIPTOR *) _xSecurityDescriptor.GetPointer();
  463. }
  464. void AddSCItem( SCWorkItem * newItem, WCHAR const * wcStoppedCat )
  465. {
  466. XPtrST<WCHAR> xBuf;
  467. if ( wcStoppedCat )
  468. {
  469. // Validate it looks like a good path
  470. unsigned cwc = wcslen( wcStoppedCat );
  471. if ( cwc >= MAX_PATH )
  472. THROW( CException( E_INVALIDARG ) );
  473. xBuf.Set( new WCHAR[ cwc + 1 ] );
  474. newItem->StoppedCat = xBuf.GetPointer();
  475. RtlCopyMemory( newItem->StoppedCat, wcStoppedCat, sizeof WCHAR * ( cwc + 1 ) );
  476. }
  477. else
  478. newItem->StoppedCat = 0;
  479. CLock lockx( _mutex );
  480. _stateChangeArray.Add( *newItem, _stateChangeArray.Count() );
  481. xBuf.Acquire();
  482. }
  483. DWORD SCArrayCount()
  484. {
  485. CLock lockx( _mutex );
  486. return _stateChangeArray.Count();
  487. }
  488. SCWorkItem * GetSCItem( DWORD iSCArray )
  489. {
  490. return &(_stateChangeArray.Get( iSCArray ));
  491. }
  492. void ClearSCArray()
  493. {
  494. for ( unsigned i = 0; i < _stateChangeArray.Count(); i++ )
  495. {
  496. SCWorkItem * WorkItem = GetSCItem(i);
  497. if ( WorkItem->StoppedCat )
  498. {
  499. delete [] WorkItem->StoppedCat;
  500. }
  501. }
  502. _stateChangeArray.Clear();
  503. }
  504. BOOL AreDocStoresOpen() const { return _fDocStoresOpen; }
  505. ICiCDocStoreLocator * DocStoreLocator();
  506. #if CI_PIPE_TESTING
  507. typedef SCODE (* PipeTraceServerBeforeCall) ( HANDLE hPipe,
  508. ULONG cbWrite,
  509. void * pvWrite,
  510. ULONG & rcbWritten,
  511. void *& rpvWritten );
  512. typedef SCODE (* PipeTraceServerAfterCall) ( HANDLE hPipe,
  513. ULONG cbWrite,
  514. void * pvWrite,
  515. ULONG cbWritten,
  516. void * pvWritten );
  517. typedef SCODE (* PipeTraceServerReadCall) ( HANDLE hPipe,
  518. ULONG cbRead,
  519. void * pvRead );
  520. PipeTraceServerBeforeCall _pTraceBefore;
  521. PipeTraceServerAfterCall _pTraceAfter;
  522. PipeTraceServerReadCall _pTraceRead;
  523. HINSTANCE _hTraceDll;
  524. BOOL IsPipeTracingEnabled() { return 0 != _hTraceDll; }
  525. #endif // CI_PIPE_TESTING
  526. private:
  527. void ShutdownActiveServers( ICiCDocStore * pDocStore );
  528. void Shutdown();
  529. void OpenAllDocStores();
  530. void FreeCachedServers();
  531. BOOL _fShutdown;
  532. BOOL _fMinimizeWorkingSet;
  533. BOOL _fNetPause;
  534. BOOL _fNetContinue;
  535. BOOL _fNetStop;
  536. LONG _cBusyItems;
  537. LONG _cPendingItems;
  538. DWORD _cmsDefaultClientTimeout;
  539. DWORD _cMaxSimultaneousRequests;
  540. DWORD _cmsStartupDelay;
  541. CAutoEventSem _event;
  542. CEventSem _evtStateChange;
  543. CWorkQueue _workQueue;
  544. CDynArrayInPlace<SCWorkItem> _stateChangeArray;
  545. CMutexSem _mutex;
  546. THashTable<CRequestServer *> _tableActiveServers;
  547. TFifoCircularQueue<CServerItem> _queueCachedServers;
  548. DWORD _cMinClientIdleTime;
  549. XArray<BYTE> _xSecurityDescriptor;
  550. GUID _guidDocStoreClient;
  551. BOOL _fDocStoresOpen;
  552. };