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.

639 lines
20 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 Cleanup();
  131. void CompleteNotification( DWORD dwChangeType );
  132. void QueryQuiesced( BOOL fSuccess, SCODE sc );
  133. void SetPQuery( PQuery * pQuery )
  134. {
  135. Win4Assert( 0 == _pQuery );
  136. _pQuery = pQuery;
  137. }
  138. HANDLE GetWorkerThreadHandle()
  139. {
  140. return _hWorkThread;
  141. }
  142. static void WINAPI CancelAPCRoutine( DWORD_PTR dwParam );
  143. void SetLastTouchedTime(DWORD dwLastTouched) { _dwLastTouched = dwLastTouched; }
  144. DWORD GetLastTouchedTime() { return _dwLastTouched; }
  145. void BeingRemoved( CEventSem * pevtDone ) { _pevtDone = pevtDone; };
  146. BOOL IsBeingRemoved() const { return 0 != _pevtDone; }
  147. ICiCDocStore * GetDocStore() { return _xDocStore.GetPointer(); }
  148. private:
  149. static void WINAPI QuiesceAPCRoutine( DWORD_PTR dwParam );
  150. void Quiesce();
  151. enum PipeState { pipeStateNone = 10,
  152. pipeStateRead,
  153. pipeStateWrite,
  154. pipeStatePending };
  155. static void WINAPI APCRoutine( DWORD dwError,
  156. DWORD cbTransferred,
  157. LPOVERLAPPED pOverlapped );
  158. RequestState HandleRequestNoThrow( DWORD cbRequest,
  159. DWORD & cbToWrite );
  160. #ifdef _WIN64
  161. void FixColumns ( CTableColumnSet * pCols32 );
  162. void FixRows ( BYTE * pbReply,
  163. BYTE * pbResults,
  164. ULONG cbResults,
  165. ULONG_PTR ulpClientBase,
  166. ULONG cRows,
  167. ULONG cbRowWidth );
  168. void FixVariantPointers ( PROPVARIANT32 *pVar32,
  169. PROPVARIANT *pVar64,
  170. BYTE *pbResults,
  171. ULONG_PTR ulClientBase );
  172. #endif
  173. void DoAPC( DWORD dwError, DWORD cbTransferred );
  174. ~CRequestServer()
  175. {
  176. prxDebugOut(( DEB_ITRACE, "deleting server pipe 0x%x\n", GetPipe() ));
  177. Win4Assert( NoOutstandingAPCs() );
  178. Win4Assert( 0 == _cRefs );
  179. Win4Assert( 0 == _pQuery );
  180. Win4Assert( 0 == _pWorkThread );
  181. Win4Assert( INVALID_HANDLE_VALUE == _hWorkThread );
  182. Win4Assert( 0 == _pevtDone );
  183. }
  184. int GetClientVersion() { return pmCiVersion( _iClientVersion ); }
  185. BOOL IsClient64() { return IsCi64( _iClientVersion ); }
  186. BOOL IsClientRemote() { return _fClientIsRemote; }
  187. void * _Buffer() { return _abBuffer; }
  188. void * _ActiveBuffer()
  189. {
  190. if ( _xTempBuffer.IsNull() )
  191. return _abBuffer;
  192. return _xTempBuffer.Get();
  193. }
  194. DWORD _BufferSize() { return sizeof _abBuffer; }
  195. void FormScopeRestriction( CiMetaData & eType, XRestriction & rst );
  196. void FreeQuery()
  197. {
  198. // insures only one thread will delete the PQuery
  199. PQuery * pInitial = (PQuery *) InterlockedCompareExchangePointer(
  200. (void **) &_pQuery,
  201. NULL,
  202. _pQuery );
  203. delete pInitial; // may be 0
  204. #ifdef _WIN64
  205. // Free the column descriptions
  206. _xCols64.Free();
  207. _xCols32.Free();
  208. #endif
  209. }
  210. typedef RequestState (CRequestServer:: * ProxyMessageFunction)(
  211. DWORD cbRequest,
  212. DWORD & cbToWrite );
  213. static const ProxyMessageFunction _aMsgFunctions[ cProxyMessages ];
  214. static const BOOL _afImpersonate[ cProxyMessages ];
  215. RequestState DoObsolete( DWORD, DWORD & );
  216. RequestState DoConnect( DWORD, DWORD & );
  217. RequestState DoDisconnect( DWORD, DWORD & );
  218. RequestState DoCreateQuery( DWORD, DWORD & );
  219. RequestState DoFreeCursor( DWORD, DWORD & );
  220. RequestState DoGetRows( DWORD, DWORD & );
  221. RequestState DoRatioFinished( DWORD, DWORD & );
  222. RequestState DoCompareBmk( DWORD, DWORD & );
  223. RequestState DoGetApproximatePosition( DWORD, DWORD & );
  224. RequestState DoSetBindings( DWORD, DWORD & );
  225. RequestState DoGetNotify( DWORD, DWORD & );
  226. RequestState DoSendNotify( DWORD, DWORD & );
  227. RequestState DoSetWatchMode( DWORD, DWORD & );
  228. RequestState DoGetWatchInfo( DWORD, DWORD & );
  229. RequestState DoShrinkWatchRegion( DWORD, DWORD & );
  230. RequestState DoRefresh( DWORD, DWORD & );
  231. RequestState DoGetQueryStatus( DWORD, DWORD & );
  232. RequestState DoCiState( DWORD, DWORD & );
  233. RequestState DoBeginCacheTransaction( DWORD, DWORD & );
  234. RequestState DoSetupCache( DWORD, DWORD & );
  235. RequestState DoEndCacheTransaction( DWORD, DWORD & );
  236. RequestState DoForceMerge( DWORD, DWORD & );
  237. RequestState DoAbortMerge( DWORD, DWORD & );
  238. RequestState DoFetchValue( DWORD, DWORD & );
  239. RequestState DoWorkIdToPath( DWORD, DWORD & );
  240. RequestState DoUpdateDocuments( DWORD, DWORD & );
  241. RequestState DoGetQueryStatusEx( DWORD, DWORD & );
  242. RequestState DoRestartPosition( DWORD, DWORD & );
  243. RequestState DoStopAsynch( DWORD, DWORD & );
  244. RequestState DoStartWatching( DWORD, DWORD & );
  245. RequestState DoStopWatching( DWORD, DWORD & );
  246. RequestState DoSetCatState( DWORD, DWORD & );
  247. PipeState _state; // none, read, write, or pending
  248. long _cRefs; // refcount
  249. int _iClientVersion; // version of the client
  250. BOOL _fClientIsRemote; // TRUE if client is remote
  251. XInterface<ICiCDocStore> _xDocStore; // Set if a docstore is found
  252. PQuery * _pQuery; // set if a query is active
  253. CWorkThread * _pWorkThread; // worker thread for this server
  254. HANDLE _hWorkThread; // worker thread for this server
  255. XArray<BYTE> _xTempBuffer; // buffer for big reads/writes
  256. XArray<WCHAR> _xClientMachine; // name of the client's machine
  257. XArray<WCHAR> _xClientUser; // name of the client
  258. XArray<BYTE> _xFetchedValue; // state for pmFetchValue
  259. DWORD _cbFetchedValueSoFar; // state for pmFetchValue
  260. DWORD _cbPendingWrite; // bytes to write at completion
  261. SCODE _scPendingStatus; // status code for completed op
  262. CRequestQueue & _requestQueue; // the 1 and only request queue
  263. CWorkQueue & _workQueue; // the 1 and only work queue
  264. XInterface<IDBProperties> _xDbProperties; // properties from connect
  265. DWORD _dwLastTouched;
  266. CEventSem * _pevtDone; // set when the instance dies
  267. #ifdef _WIN64
  268. unsigned _cbRowWidth64;
  269. unsigned _cbRowWidth32;
  270. XPtr<CTableColumnSet> _xCols64;
  271. XPtr<CTableColumnSet> _xCols32;
  272. #endif
  273. // this buffer must be 8-byte aligned and large enough to read
  274. // any request except pmCreateQuery and pmSetBindings
  275. LONGLONG _abBuffer[ 2048 / sizeof LONGLONG ];
  276. };
  277. //+-------------------------------------------------------------------------
  278. //
  279. // Class: CServerItem
  280. //
  281. // Synopsis: Encapsulates a CRequestServer for use in the circular queue,
  282. // which requires many of the methods implemented below.
  283. //
  284. // History: 16-Sep-96 dlee Created.
  285. //
  286. //--------------------------------------------------------------------------
  287. class CServerItem
  288. {
  289. public:
  290. CServerItem() : _pServer( 0 ) {}
  291. CServerItem( CRequestServer *pServer ) : _pServer( pServer ) {}
  292. ~CServerItem()
  293. {
  294. Free();
  295. }
  296. void Create( const WCHAR * pwcName,
  297. ULONG cmsDefaultClientTimeout,
  298. CRequestQueue & requestQueue,
  299. CWorkQueue & workQueue )
  300. {
  301. Win4Assert( 0 == _pServer );
  302. _pServer = new CRequestServer( pwcName,
  303. cmsDefaultClientTimeout,
  304. requestQueue,
  305. workQueue );
  306. }
  307. void Acquire( CServerItem & item )
  308. {
  309. item = *this;
  310. _pServer = 0;
  311. }
  312. CServerItem & operator = (CServerItem & src )
  313. {
  314. Win4Assert( 0 == _pServer );
  315. _pServer = src._pServer;
  316. src._pServer = 0;
  317. return *this;
  318. }
  319. CRequestServer * Get()
  320. {
  321. return _pServer;
  322. }
  323. void Free()
  324. {
  325. if ( 0 != _pServer )
  326. {
  327. _pServer->Release();
  328. _pServer = 0;
  329. }
  330. }
  331. CRequestServer * Acquire()
  332. {
  333. CRequestServer *p = _pServer;
  334. _pServer = 0;
  335. return p;
  336. }
  337. private:
  338. CRequestServer * _pServer;
  339. };
  340. //+-------------------------------------------------------------------------
  341. //
  342. // Class: CRequestQueue
  343. //
  344. // Synopsis: Handles the main work of the service and the caching of
  345. // request servers.
  346. //
  347. // History: 16-Sep-96 dlee Created.
  348. // 30-Mar-98 kitmanh Added new flag _fNetPause
  349. // 14-Apr-98 kitmanh Renamed _evtStopWork to
  350. // _evtStateChange and StopWork() to
  351. // WakeForStateChange()
  352. // 14-Apr-98 kitmanh Added a DynArrayInPlace,
  353. // StateChangeArray for work items
  354. // related to state change
  355. //
  356. //--------------------------------------------------------------------------
  357. class CRequestQueue
  358. {
  359. public:
  360. CRequestQueue( unsigned cMaxCachedRequests,
  361. unsigned cMaxRequests,
  362. unsigned cmsDefaultClientTimeout,
  363. BOOL fMinimizeWorkingSet,
  364. unsigned cMinClientIdleTime,
  365. unsigned cmsStartupDelay,
  366. const GUID & guidDocStoreClient );
  367. ~CRequestQueue()
  368. {
  369. ClearSCArray();
  370. #if CI_PIPE_TESTING
  371. if ( 0 != _hTraceDll )
  372. {
  373. FreeLibrary( _hTraceDll );
  374. _hTraceDll = 0;
  375. }
  376. #endif // CI_PIPE_TESTING
  377. }
  378. void DoWork();
  379. void RecycleRequestServerNoThrow( CRequestServer *pServer );
  380. void WakeForStateChange() { _evtStateChange.Set(); }
  381. void IncrementPendingItems() { InterlockedIncrement( &_cPendingItems ); }
  382. void DecrementPendingItems() { InterlockedDecrement( &_cPendingItems ); }
  383. void AddToListNoThrow( CRequestServer * pServer )
  384. {
  385. CLock lock( _mutex );
  386. _tableActiveServers.AddEntry( pServer );
  387. }
  388. void RemoveFromListNoThrow( CRequestServer * pServer )
  389. {
  390. CLock lock( _mutex );
  391. BOOL fDeleted = _tableActiveServers.DeleteEntry( pServer );
  392. Win4Assert( fDeleted );
  393. }
  394. BOOL IsShutdown() const { return _fShutdown; }
  395. BOOL IsNetPause() const { return _fNetPause; }
  396. BOOL IsNetContinue() const { return _fNetContinue; }
  397. BOOL IsNetStop() const { return _fNetStop; }
  398. // Reset some member variables and reset the _evtStateChange event for restarting
  399. // up from NetPause or NetContinue
  400. void ReStart()
  401. {
  402. CLock lock( _mutex );
  403. _fShutdown = FALSE;
  404. _fNetPause = FALSE;
  405. _fNetContinue = FALSE;
  406. _fNetStop = FALSE;
  407. ClearSCArray();
  408. _evtStateChange.Reset();
  409. }
  410. void WrestReqServerFromIdleClient();
  411. CMutexSem & GetTheMutex() { return _mutex; }
  412. void SetNetPause()
  413. {
  414. CLock lock( _mutex );
  415. _fNetPause = TRUE;
  416. }
  417. void SetNetContinue()
  418. {
  419. CLock lock( _mutex );
  420. _fNetContinue = TRUE;
  421. }
  422. void SetNetStop()
  423. {
  424. CLock lock( _mutex );
  425. _fNetStop = TRUE;
  426. }
  427. SECURITY_DESCRIPTOR * GetSecurityDescriptor()
  428. {
  429. Win4Assert( !_xSecurityDescriptor.IsNull() );
  430. return (SECURITY_DESCRIPTOR *) _xSecurityDescriptor.GetPointer();
  431. }
  432. void AddSCItem( SCWorkItem * newItem, WCHAR const * wcStoppedCat )
  433. {
  434. XPtrST<WCHAR> xBuf;
  435. if ( wcStoppedCat )
  436. {
  437. // Validate it looks like a good path
  438. unsigned cwc = wcslen( wcStoppedCat );
  439. if ( cwc >= MAX_PATH )
  440. THROW( CException( E_INVALIDARG ) );
  441. xBuf.Set( new WCHAR[ cwc + 1 ] );
  442. newItem->StoppedCat = xBuf.GetPointer();
  443. RtlCopyMemory( newItem->StoppedCat, wcStoppedCat, sizeof WCHAR * ( cwc + 1 ) );
  444. }
  445. else
  446. newItem->StoppedCat = 0;
  447. CLock lockx( _mutex );
  448. _stateChangeArray.Add( *newItem, _stateChangeArray.Count() );
  449. xBuf.Acquire();
  450. }
  451. DWORD SCArrayCount()
  452. {
  453. CLock lockx( _mutex );
  454. return _stateChangeArray.Count();
  455. }
  456. SCWorkItem * GetSCItem( DWORD iSCArray )
  457. {
  458. return &(_stateChangeArray.Get( iSCArray ));
  459. }
  460. void ClearSCArray()
  461. {
  462. for ( unsigned i = 0; i < _stateChangeArray.Count(); i++ )
  463. {
  464. SCWorkItem * WorkItem = GetSCItem(i);
  465. if ( WorkItem->StoppedCat )
  466. {
  467. delete [] WorkItem->StoppedCat;
  468. }
  469. }
  470. _stateChangeArray.Clear();
  471. }
  472. BOOL AreDocStoresOpen() const { return _fDocStoresOpen; }
  473. ICiCDocStoreLocator * DocStoreLocator();
  474. #if CI_PIPE_TESTING
  475. typedef SCODE (* PipeTraceServerBeforeCall) ( HANDLE hPipe,
  476. ULONG cbWrite,
  477. void * pvWrite,
  478. ULONG & rcbWritten,
  479. void *& rpvWritten );
  480. typedef SCODE (* PipeTraceServerAfterCall) ( HANDLE hPipe,
  481. ULONG cbWrite,
  482. void * pvWrite,
  483. ULONG cbWritten,
  484. void * pvWritten );
  485. typedef SCODE (* PipeTraceServerReadCall) ( HANDLE hPipe,
  486. ULONG cbRead,
  487. void * pvRead );
  488. PipeTraceServerBeforeCall _pTraceBefore;
  489. PipeTraceServerAfterCall _pTraceAfter;
  490. PipeTraceServerReadCall _pTraceRead;
  491. HINSTANCE _hTraceDll;
  492. BOOL IsPipeTracingEnabled() { return 0 != _hTraceDll; }
  493. #endif // CI_PIPE_TESTING
  494. private:
  495. void ShutdownActiveServers( ICiCDocStore * pDocStore );
  496. void Shutdown();
  497. void OpenAllDocStores();
  498. void FreeCachedServers();
  499. BOOL _fShutdown;
  500. BOOL _fMinimizeWorkingSet;
  501. BOOL _fNetPause;
  502. BOOL _fNetContinue;
  503. BOOL _fNetStop;
  504. LONG _cBusyItems;
  505. LONG _cPendingItems;
  506. DWORD _cmsDefaultClientTimeout;
  507. DWORD _cMaxSimultaneousRequests;
  508. DWORD _cmsStartupDelay;
  509. CAutoEventSem _event;
  510. CEventSem _evtStateChange;
  511. CWorkQueue _workQueue;
  512. CDynArrayInPlace<SCWorkItem> _stateChangeArray;
  513. CMutexSem _mutex;
  514. THashTable<CRequestServer *> _tableActiveServers;
  515. TFifoCircularQueue<CServerItem> _queueCachedServers;
  516. DWORD _cMinClientIdleTime;
  517. XArray<BYTE> _xSecurityDescriptor;
  518. GUID _guidDocStoreClient;
  519. BOOL _fDocStoresOpen;
  520. };