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.

4453 lines
151 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2000
  5. //
  6. // File: srequest.cxx
  7. //
  8. // Contents: Server side of catalog/query requests
  9. //
  10. // Classes: CPipeServer
  11. // CRequestServer
  12. // CRequestQueue
  13. //
  14. // Functions: StartCiSvcWork
  15. // StopCiSvcWork
  16. //
  17. // History: 16-Sep-96 dlee Created.
  18. //
  19. //--------------------------------------------------------------------------
  20. #include <pch.cxx>
  21. #pragma hdrstop
  22. #include <cci.hxx>
  23. #include <query.hxx>
  24. #include <rstprop.hxx>
  25. #include <pickle.hxx>
  26. #include <worker.hxx>
  27. #include <propspec.hxx>
  28. #include <seqquery.hxx>
  29. #include <rowseek.hxx>
  30. #include <srequest.hxx>
  31. #include <propvar.h>
  32. #include <ciregkey.hxx>
  33. #include <regacc.hxx>
  34. #include <imprsnat.hxx>
  35. #include <driveinf.hxx>
  36. #include <qparse.hxx>
  37. #include <dbprputl.hxx>
  38. #include <cidbprop.hxx>
  39. #include <ciframe.hxx>
  40. #include <cisvcfrm.hxx>
  41. #include <lang.hxx>
  42. #include <fsciexps.hxx>
  43. #include <pidcvt.hxx>
  44. #include <cisvcex.hxx>
  45. #include <fsciclnt.h>
  46. #include "secutil.hxx"
  47. extern CLocateDocStore g_svcDocStoreLocator;
  48. extern CStaticMutexSem g_mtxStartStop;
  49. CRequestQueue * g_pRequestQueue = 0;
  50. const CRequestServer::ProxyMessageFunction CRequestServer::_aMsgFunctions[] =
  51. {
  52. DoConnect,
  53. DoDisconnect,
  54. DoCreateQuery,
  55. DoFreeCursor,
  56. DoGetRows,
  57. DoRatioFinished,
  58. DoCompareBmk,
  59. DoGetApproximatePosition,
  60. DoSetBindings,
  61. DoGetNotify,
  62. DoSendNotify,
  63. DoSetWatchMode,
  64. DoGetWatchInfo,
  65. DoShrinkWatchRegion,
  66. DoRefresh,
  67. DoGetQueryStatus,
  68. DoObsolete, //WidToPath
  69. DoCiState,
  70. DoObsolete, //BeginCacheTransaction
  71. DoObsolete, //SetupCache
  72. DoObsolete, //EndCacheTransaction
  73. DoObsolete, //AddScope
  74. DoObsolete, //RemoveScope
  75. DoObsolete, //AddVirtualScope
  76. DoObsolete, //RemoveVirtualScope
  77. DoForceMerge,
  78. DoAbortMerge,
  79. DoObsolete, //SetPartition
  80. DoFetchValue,
  81. DoWorkIdToPath,
  82. DoUpdateDocuments,
  83. DoGetQueryStatusEx,
  84. DoRestartPosition,
  85. DoStopAsynch,
  86. DoStartWatching,
  87. DoStopWatching,
  88. DoSetCatState
  89. };
  90. const BOOL CRequestServer::_afImpersonate[] =
  91. {
  92. TRUE, // DoConnect,
  93. FALSE, // DoDisconnect,
  94. TRUE, // DoCreateQuery,
  95. FALSE, // DoFreeCursor,
  96. TRUE, // DoGetRows,
  97. FALSE, // DoRatioFinished,
  98. FALSE, // DoCompareBmk,
  99. FALSE, // DoGetApproximatePosition,
  100. FALSE, // DoSetBindings,
  101. FALSE, // DoGetNotify,
  102. FALSE, // DoSendNotify,
  103. FALSE, // DoSetWatchMode,
  104. FALSE, // DoGetWatchInfo,
  105. FALSE, // DoShrinkWatchRegion,
  106. FALSE, // DoRefresh,
  107. FALSE, // DoGetQueryStatus,
  108. FALSE, // DoObsolete, //DoWidToPath,
  109. FALSE, // DoCiState,
  110. TRUE, // DoBeginCacheTransaction,
  111. TRUE, // DoSetupCache,
  112. TRUE, // DoEndCacheTransaction,
  113. FALSE, // DoObsolete, //AddScope
  114. FALSE, // DoObsolete, //RemoveScope
  115. FALSE, // DoObsolete, //AddVirtualScope
  116. FALSE, // DoObsolete, //RemoveVirtualScope
  117. TRUE, // DoForceMerge,
  118. TRUE, // DoAbortMerge,
  119. FALSE, // DoObsolete, //SetPartition
  120. TRUE, // DoFetchValue,
  121. TRUE, // DoWorkIdToPath,
  122. TRUE, // DoUpdateDocuments,
  123. FALSE, // DoGetQueryStatusEx,
  124. FALSE, // DoRestartPosition,
  125. FALSE, // DoStopAsynch,
  126. FALSE, // DoStartWatching,
  127. FALSE, // DoStopWatching,
  128. TRUE, // DoSetCatState
  129. };
  130. //+-------------------------------------------------------------------------
  131. //
  132. // Member: CPipeServer::CPipeServer, public
  133. //
  134. // Synopsis: Constructor for a server pipe. The pipe is created such
  135. // that any client can connect.
  136. //
  137. // Arguments: [pwcName] - Name for the pipe
  138. // [cmsDefaultClientTimeout] - Default timeout for clients
  139. // trying to get a pipe instance
  140. // [pSecurityDescriptor] - Security for the pipe
  141. //
  142. // History: 16-Sep-96 dlee Created.
  143. //
  144. //--------------------------------------------------------------------------
  145. CPipeServer::CPipeServer(
  146. const WCHAR * pwcName,
  147. ULONG cmsDefaultClientTimeout,
  148. SECURITY_DESCRIPTOR * pSecurityDescriptor ) :
  149. _eventWrite( (HANDLE) 0 ) // defer creation of the notification event
  150. {
  151. RtlZeroMemory( &_overlapped, sizeof _overlapped );
  152. SECURITY_ATTRIBUTES saPipeSecurity;
  153. saPipeSecurity.nLength = sizeof SECURITY_ATTRIBUTES;
  154. saPipeSecurity.bInheritHandle = FALSE;
  155. saPipeSecurity.lpSecurityDescriptor = pSecurityDescriptor;
  156. // note: the read/write buffers are allocated from non-paged pool,
  157. // and are grown if too small to reflect usage
  158. _hPipe = CreateNamedPipe( pwcName,
  159. PIPE_ACCESS_DUPLEX |
  160. FILE_FLAG_OVERLAPPED,
  161. PIPE_TYPE_MESSAGE |
  162. PIPE_READMODE_MESSAGE |
  163. PIPE_WAIT,
  164. PIPE_UNLIMITED_INSTANCES,
  165. 1024, // read buffer size
  166. 2048, // write buffer size
  167. cmsDefaultClientTimeout,
  168. &saPipeSecurity );
  169. if ( INVALID_HANDLE_VALUE == _hPipe )
  170. THROW( CException() );
  171. prxDebugOut(( DEB_ITRACE, "created pipe 0x%x\n", _hPipe ));
  172. } //CPipeServer
  173. //+-------------------------------------------------------------------------
  174. //
  175. // Member: CPipeServer::Connect, public
  176. //
  177. // Synopsis: Enables a client to connect to the pipe.
  178. //
  179. // Returns: TRUE if connected, FALSE if GetEvent() will be signalled
  180. // on connection, or throws on error.
  181. //
  182. // History: 16-Sep-96 dlee Created.
  183. //
  184. //--------------------------------------------------------------------------
  185. BOOL CPipeServer::Connect()
  186. {
  187. prxDebugOut(( DEB_ITRACE, "connecting from pipe 0x%x\n", _hPipe ));
  188. _overlapped.hEvent = _event.GetHandle();
  189. BOOL fEventWait = ConnectNamedPipe( _hPipe, &_overlapped );
  190. if ( !fEventWait )
  191. {
  192. DWORD dwError = GetLastError();
  193. prxDebugOut(( DEB_ITRACE, "CPipeServer::Connect.. GetLastError() == %d\n", dwError ));
  194. if ( ERROR_PIPE_CONNECTED == dwError )
  195. return TRUE;
  196. else if ( ERROR_IO_PENDING != dwError )
  197. THROW( CException() );
  198. }
  199. return FALSE;
  200. } //Connect
  201. //+-------------------------------------------------------------------------
  202. //
  203. // Member: CPipeServer::ReadRemainingSync, public
  204. //
  205. // Synopsis: Reads the remainder of a message from the pipe (if any)
  206. //
  207. // Arguments: [pvSoFar] - Part of the message read so far
  208. // [cbSoFar] - in: # of bytes read so far for the message
  209. // out: # bytes total in message
  210. //
  211. // Returns: Pointer to memory containing entire message or 0 if
  212. // there really wasn't anything more to read
  213. //
  214. // History: 16-Sep-96 dlee Created.
  215. //
  216. //--------------------------------------------------------------------------
  217. BYTE * CPipeServer::ReadRemainingSync(
  218. void * pvSoFar,
  219. DWORD & cbSoFar )
  220. {
  221. DWORD cbLeft;
  222. if ( ! PeekNamedPipe( _hPipe, 0, 0, 0, 0, &cbLeft ) )
  223. THROW( CException() );
  224. if ( 0 == cbLeft )
  225. {
  226. prxDebugOut(( DEB_WARN, "peek says no more to read\n" ));
  227. return 0;
  228. }
  229. XArray<BYTE> xMsg( cbSoFar + cbLeft );
  230. RtlCopyMemory( xMsg.Get(), pvSoFar, cbSoFar );
  231. CEventSem evt;
  232. OVERLAPPED o;
  233. RtlZeroMemory( &o, sizeof o );
  234. o.hEvent = evt.GetHandle();
  235. DWORD cbRead;
  236. if ( ! ReadFile( _hPipe,
  237. xMsg.Get() + cbSoFar,
  238. cbLeft,
  239. &cbRead,
  240. &o ) )
  241. {
  242. if ( ERROR_IO_PENDING == GetLastError() )
  243. {
  244. if ( !GetOverlappedResult( _hPipe,
  245. &o,
  246. &cbRead,
  247. TRUE ) )
  248. THROW( CException() );
  249. }
  250. else
  251. THROW( CException() );
  252. }
  253. Win4Assert( cbRead == cbLeft );
  254. cbSoFar += cbLeft;
  255. return xMsg.Acquire();
  256. } //ReadRemainingSync
  257. //+-------------------------------------------------------------------------
  258. //
  259. // Member: CPipeServer::WriteSync, public
  260. //
  261. // Synopsis: Does a synchronous write to a pipe. There can be at most
  262. // one caller at a time to this method.
  263. //
  264. // Arguments: [pv] - Buffer to write
  265. // [cb] - # of bytes to write
  266. //
  267. // History: 16-Sep-96 dlee Created.
  268. //
  269. //--------------------------------------------------------------------------
  270. void CPipeServer::WriteSync(
  271. void * pv,
  272. DWORD cb )
  273. {
  274. prxDebugOut(( DEB_ITRACE, "WriteSync on this 0x%x, pipe 0x%x\n",
  275. this, _hPipe ));
  276. OVERLAPPED o;
  277. RtlZeroMemory( &o, sizeof o );
  278. // Create and keep the event, since if we do it once (for notifications)
  279. // we'll likely do it again soon.
  280. if ( 0 == _eventWrite.GetHandle() )
  281. _eventWrite.Create();
  282. o.hEvent = _eventWrite.GetHandle();
  283. if ( ! WriteFile( _hPipe, pv, cb, 0, &o ) )
  284. {
  285. if ( ERROR_IO_PENDING == GetLastError() )
  286. {
  287. DWORD cbWritten;
  288. if ( !GetOverlappedResult( _hPipe,
  289. &o,
  290. &cbWritten,
  291. TRUE ) )
  292. THROW( CException() );
  293. Win4Assert( cbWritten == cb );
  294. }
  295. else
  296. THROW( CException() );
  297. }
  298. prxDebugOut(( DEB_ITRACE, "WriteSync completed on this 0x%x, pipe 0x%x\n",
  299. this, _hPipe ));
  300. } //WriteSync
  301. //+-------------------------------------------------------------------------
  302. //
  303. // Member: CRequestServer::CRequestServer, public
  304. //
  305. // Synopsis: Constructor for the request server
  306. //
  307. // Arguments: [pwcPipe] - Name of the pipe to use
  308. // [cmsDefaultClientTimeout] - Timeout for clients waiting for
  309. // and instance
  310. // [requestQueue] - The 1 and only request queue
  311. // [workQueue] - The work queue
  312. //
  313. // History: 16-Sep-96 dlee Created.
  314. //
  315. //--------------------------------------------------------------------------
  316. CRequestServer::CRequestServer(
  317. const WCHAR * pwcPipe,
  318. ULONG cmsDefaultClientTimeout,
  319. CRequestQueue & requestQueue,
  320. CWorkQueue & workQueue ) :
  321. CPipeServer( pwcPipe,
  322. cmsDefaultClientTimeout,
  323. requestQueue.GetSecurityDescriptor() ),
  324. PWorkItem( sigCRequestServer ),
  325. _state( pipeStateNone ),
  326. _cRefs( 1 ),
  327. _iClientVersion( 0 ),
  328. _pQuery( 0 ),
  329. _fClientIsRemote( FALSE ),
  330. _pWorkThread( 0 ),
  331. _hWorkThread( INVALID_HANDLE_VALUE ),
  332. _cbFetchedValueSoFar( 0 ),
  333. _cbPendingWrite( 0 ),
  334. _scPendingStatus( S_OK ),
  335. _requestQueue( requestQueue ),
  336. _workQueue( workQueue ),
  337. _pevtDone( 0 ),
  338. _dwLastTouched( GetTickCount() )
  339. {
  340. requestQueue.AddToListNoThrow( this );
  341. } //CRequestServer
  342. //+-------------------------------------------------------------------------
  343. //
  344. // Member: CRequestServer::Release, public
  345. //
  346. // Synopsis: Releases and if approprate deletes the object
  347. //
  348. // History: 16-Sep-96 dlee Created.
  349. //
  350. //--------------------------------------------------------------------------
  351. void CRequestServer::Release()
  352. {
  353. Win4Assert( 0 != _cRefs );
  354. CLock lock( _requestQueue.GetTheMutex() );
  355. // Since the AddRef() is not done under lock (and we don't want to)
  356. // InterlockedDecrement is used even though we're under lock.
  357. if ( 0 == InterlockedDecrement( & _cRefs ) )
  358. {
  359. _requestQueue.RemoveFromListNoThrow( this );
  360. // If someone is waiting for this to go out of the list,
  361. // tell them now.
  362. if ( 0 != _pevtDone )
  363. {
  364. _pevtDone->Set();
  365. _pevtDone = 0;
  366. }
  367. delete this;
  368. }
  369. } //Release
  370. //+-------------------------------------------------------------------------
  371. //
  372. // Member: CRequestServer::DoIt, public
  373. //
  374. // Synopsis: Implements the work queue DoIt method by scheduling
  375. // the first read from the client of the pipe. The work queue
  376. // is needed since apc completion routines must be run by
  377. // the thread that submitted the i/o.
  378. //
  379. // Arguments: [pThread] - Thread being used (for refcounting)
  380. //
  381. // History: 16-Sep-96 dlee Created.
  382. //
  383. //--------------------------------------------------------------------------
  384. void CRequestServer::DoIt(
  385. CWorkThread *pThread )
  386. {
  387. TRY
  388. {
  389. Win4Assert( pipeStateNone == _state );
  390. Win4Assert( 0 == _pWorkThread );
  391. Win4Assert( INVALID_HANDLE_VALUE == _hWorkThread );
  392. prxDebugOut(( DEB_ITRACE, "doit CRequestServer %p\n", this ));
  393. _pWorkThread = pThread;
  394. _hWorkThread = pThread->GetThreadHandle();
  395. _workQueue.AddRef( pThread );
  396. _state = pipeStateRead;
  397. Read( _Buffer(), _BufferSize(), APCRoutine );
  398. if ( IsBeingRemoved() )
  399. CancelIO();
  400. }
  401. CATCH( CException, ex )
  402. {
  403. prxDebugOut(( DEB_ITRACE,
  404. "failed initial read error 0x%x, pipe %p\n",
  405. ex.GetErrorCode(),
  406. GetPipe() ));
  407. _state = pipeStateNone;
  408. _requestQueue.RecycleRequestServerNoThrow( this );
  409. }
  410. END_CATCH;
  411. } //DoIt
  412. //+-------------------------------------------------------------------------
  413. //
  414. // Member: CRequestServer::DeferredAPC, public
  415. //
  416. // Synopsis: Performs an APC that was earlier deferred.
  417. //
  418. // History: 16-Sep-96 dlee Created.
  419. //
  420. //--------------------------------------------------------------------------
  421. void CRequestServer::DeferredAPC()
  422. {
  423. DoAPC( _dwDeferredAPCError, _cbDeferredAPCTransferred );
  424. } //DeferredAPC
  425. //+-------------------------------------------------------------------------
  426. //
  427. // Function: TranslateOldPropsToNewProps
  428. //
  429. // Synopsis: Translates ver 5 client properties into version 6+ props
  430. //
  431. // Arguments: [oldProps] - source of translated values
  432. // [newProps] - destination of translated values
  433. //
  434. // History: 31-May-97 dlee Created.
  435. //
  436. //--------------------------------------------------------------------------
  437. void TranslateOldPropsToNewProps(
  438. CDbProperties & oldProps,
  439. CDbProperties & newProps )
  440. {
  441. const GUID guidFsClientPropset = DBPROPSET_FSCIFRMWRK_EXT;
  442. const GUID guidQueryCorePropset = DBPROPSET_CIFRMWRKCORE_EXT;
  443. // pluck out the catalog and scope information from the old set
  444. WCHAR *pwcCatalog = 0;
  445. BSTR bstrMachine = 0;
  446. CDynArrayInPlace<ULONG> aDepths(2);
  447. CDynArrayInPlace<WCHAR *> aScopes(2);
  448. LONG lQueryType = 0;
  449. for ( ULONG i = 0; i < oldProps.Count(); i++ )
  450. {
  451. CDbPropSet & propSet = oldProps.GetPropSet( i );
  452. DBPROPSET *pSet = propSet.CastToStruct();
  453. if ( guidQueryCorePropset == pSet->guidPropertySet )
  454. {
  455. ULONG cProp = pSet->cProperties;
  456. DBPROP * pProp = pSet->rgProperties;
  457. for ( ULONG p = 0; p < pSet->cProperties; p++, pProp++ )
  458. {
  459. PROPVARIANT &v = (PROPVARIANT &) pProp->vValue;
  460. switch ( pProp->dwPropertyID )
  461. {
  462. case DBPROP_MACHINE :
  463. {
  464. Win4Assert( VT_BSTR == v.vt );
  465. if ( VT_BSTR == v.vt )
  466. bstrMachine = v.bstrVal;
  467. break;
  468. }
  469. }
  470. }
  471. }
  472. else if ( guidFsClientPropset == pSet->guidPropertySet )
  473. {
  474. ULONG cProp = pSet->cProperties;
  475. DBPROP * pProp = pSet->rgProperties;
  476. for ( ULONG p = 0; p < pSet->cProperties; p++, pProp++ )
  477. {
  478. PROPVARIANT &v = (PROPVARIANT &) pProp->vValue;
  479. switch ( pProp->dwPropertyID )
  480. {
  481. case DBPROP_CI_INCLUDE_SCOPES :
  482. {
  483. Win4Assert( (VT_VECTOR|VT_LPWSTR) == v.vt );
  484. if ( (VT_VECTOR|VT_LPWSTR) == v.vt )
  485. for ( ULONG s = 0; s < v.calpwstr.cElems; s++ )
  486. aScopes[s] = v.calpwstr.pElems[s];
  487. break;
  488. }
  489. case DBPROP_CI_DEPTHS :
  490. {
  491. Win4Assert( (VT_VECTOR|VT_I4) == v.vt );
  492. if ( (VT_VECTOR|VT_I4) == v.vt )
  493. for ( ULONG s = 0; s < v.cal.cElems; s++ )
  494. aDepths[s] = v.cal.pElems[s];
  495. break;
  496. }
  497. case DBPROP_CI_CATALOG_NAME :
  498. {
  499. Win4Assert( VT_LPWSTR == v.vt );
  500. if ( VT_LPWSTR == v.vt )
  501. pwcCatalog = v.pwszVal;
  502. break;
  503. }
  504. case DBPROP_CI_QUERY_TYPE :
  505. {
  506. Win4Assert( VT_I4 == v.vt );
  507. lQueryType = v.lVal;
  508. break;
  509. }
  510. }
  511. }
  512. }
  513. }
  514. if ( 0 == pwcCatalog ||
  515. 0 == bstrMachine )
  516. THROW( CException( STATUS_INVALID_PARAMETER_MIX ) );
  517. prxDebugOut(( DEB_ITRACE,
  518. "Converting old props to new props, catalog '%ws'",
  519. pwcCatalog ));
  520. prxDebugOut(( DEB_ITRACE,
  521. "type %d, %d scopes, %d depths\n",
  522. lQueryType,
  523. aScopes.Count(),
  524. aDepths.Count() ));
  525. // create a new set of properties based on the old info
  526. CDynArrayInPlace<BSTR> aBSTR( aScopes.Count() + 2 );
  527. DBPROPSET aNewSet[2];
  528. DBPROP aFSProps[4];
  529. RtlZeroMemory( aFSProps, sizeof aFSProps );
  530. aNewSet[0].cProperties = 0;
  531. aNewSet[0].guidPropertySet = guidFsClientPropset;
  532. aNewSet[0].rgProperties = aFSProps;
  533. aFSProps[0].dwPropertyID = DBPROP_CI_CATALOG_NAME;
  534. aFSProps[0].vValue.vt = VT_BSTR;
  535. aFSProps[0].vValue.bstrVal = SysAllocString( pwcCatalog );
  536. aBSTR[ aBSTR.Count() ] = aFSProps[0].vValue.bstrVal;
  537. aNewSet[0].cProperties++;
  538. aFSProps[1].dwPropertyID = DBPROP_CI_QUERY_TYPE;
  539. aFSProps[1].vValue.vt = VT_I4;
  540. aFSProps[1].vValue.lVal = lQueryType;
  541. aNewSet[0].cProperties++;
  542. DBPROP & propDepth = aFSProps[ aNewSet[0].cProperties ];
  543. propDepth.dwPropertyID = DBPROP_CI_DEPTHS;
  544. SAFEARRAY saDepth = { 1, // Dimension
  545. FADF_AUTO, // Flags: on stack
  546. sizeof(LONG), // Size of an element
  547. 1, // Lock count. 1 for safety.
  548. (void *)aDepths.GetPointer(), // The data
  549. { aDepths.Count(), 0 } }; // Bounds (element count, low bound)
  550. if ( 1 == aDepths.Count() )
  551. {
  552. propDepth.vValue.vt = VT_I4;
  553. propDepth.vValue.lVal = aDepths[0];
  554. aNewSet[0].cProperties++;
  555. }
  556. else if ( aDepths.Count() > 1 )
  557. {
  558. propDepth.vValue.vt = ( VT_ARRAY | VT_I4 );
  559. propDepth.vValue.parray = & saDepth;
  560. aNewSet[0].cProperties++;
  561. }
  562. DBPROP & propScope = aFSProps[ aNewSet[0].cProperties ];
  563. propScope.dwPropertyID = DBPROP_CI_INCLUDE_SCOPES;
  564. SAFEARRAY saScope = { 1, // Dimension
  565. FADF_AUTO | FADF_BSTR, // Flags: on stack, contains BSTRs
  566. sizeof(BSTR), // Size of an element
  567. 1, // Lock count. 1 for safety.
  568. (void *)0, // The data
  569. { aScopes.Count(), 0 } }; // Bounds (element count, low bound)
  570. if ( 1 == aScopes.Count() )
  571. {
  572. propScope.vValue.vt = VT_BSTR;
  573. BSTR bstr = SysAllocString( aScopes[ 0 ] );
  574. aBSTR[ aBSTR.Count() ] = bstr;
  575. propScope.vValue.bstrVal = bstr;
  576. aNewSet[0].cProperties++;
  577. }
  578. else if ( aScopes.Count() > 1 )
  579. {
  580. propScope.vValue.vt = ( VT_ARRAY | VT_BSTR );
  581. propScope.vValue.parray = & saScope;
  582. BSTR * pBSTR = (BSTR *) aBSTR.GetPointer();
  583. pBSTR += aBSTR.Count();
  584. for ( ULONG x = 0; x < aScopes.Count(); x++ )
  585. aBSTR[ aBSTR.Count() ] = SysAllocString( aScopes[ x ] );
  586. saScope.pvData = (void *) pBSTR;
  587. aNewSet[0].cProperties++;
  588. }
  589. DBPROP aQueryProps[1];
  590. RtlZeroMemory( aQueryProps, sizeof aQueryProps );
  591. aNewSet[1].cProperties = 1;
  592. aNewSet[1].guidPropertySet = guidQueryCorePropset;
  593. aNewSet[1].rgProperties = aQueryProps;
  594. aQueryProps[0].dwPropertyID = DBPROP_MACHINE;
  595. aQueryProps[0].vValue.vt = VT_BSTR;
  596. aQueryProps[0].vValue.bstrVal = bstrMachine;
  597. // Verify all the bstrs were allocated
  598. for ( ULONG iBstr = 0; iBstr < aBSTR.Count(); iBstr++ )
  599. {
  600. if ( 0 == aBSTR[ iBstr ] )
  601. {
  602. for ( ULONG i = 0; i < aBSTR.Count(); i++ )
  603. {
  604. if ( 0 != aBSTR[ i ] )
  605. SysFreeString( aBSTR[ i ] );
  606. }
  607. THROW( CException( E_OUTOFMEMORY ) );
  608. }
  609. }
  610. SCODE sc = newProps.SetProperties( 2, aNewSet );
  611. for ( ULONG ibstr = 0; ibstr < aBSTR.Count(); ibstr++ )
  612. SysFreeString( aBSTR[ ibstr ] );
  613. if ( FAILED( sc ) )
  614. THROW( CException( sc ) );
  615. } //TranslateOldPropsToNewProps
  616. //+-------------------------------------------------------------------------
  617. //
  618. // Member: CRequestServer::DoConnect, private
  619. //
  620. // Synopsis: Handles a connect message.
  621. //
  622. // Arguments: [cbRequest] - Size of the request in _Buffer()
  623. // [cbToWrite] - On output, set to the # of bytes to write if
  624. // other than sizeof CProxyMessage.
  625. //
  626. // History: 16-Sep-96 dlee Created.
  627. //
  628. //--------------------------------------------------------------------------
  629. RequestState CRequestServer::DoConnect(
  630. DWORD cbRequest,
  631. DWORD & cbToWrite )
  632. {
  633. CPMConnectIn &request = * (CPMConnectIn *) _ActiveBuffer();
  634. XPtrST<BYTE> xTemp( _xTempBuffer.Acquire() );
  635. Win4Assert( pmConnect == request.GetMessage() );
  636. // guard against attack
  637. Win4Assert( 0 == _pQuery );
  638. Win4Assert( _xDocStore.IsNull() );
  639. if ( !_xDocStore.IsNull() )
  640. THROW( CException( STATUS_INVALID_PARAMETER ) );
  641. // save the client version, isRemote, machine name, and user name
  642. _iClientVersion = request.GetClientVersion();
  643. // don't support old clients
  644. if ( GetClientVersion() < 5 )
  645. THROW( CException( STATUS_INVALID_PARAMETER_MIX ) );
  646. request.ValidateCheckSum( GetClientVersion(), cbRequest );
  647. _fClientIsRemote = request.IsClientRemote();
  648. WCHAR *pwcMachine = request.GetClientMachineName();
  649. ULONG cwcMachine = 1 + wcslen( pwcMachine );
  650. // Check if the machine name looks mal-formed
  651. if ( ( cwcMachine * sizeof WCHAR ) >= __min( 1024, cbRequest ) )
  652. THROW( CException( STATUS_INVALID_PARAMETER ) );
  653. WCHAR *pwcUser = request.GetClientUserName();
  654. ULONG cwcUser = 1 + wcslen( pwcUser );
  655. // Check if the user name looks mal-formed
  656. if ( ( ( cwcMachine + cwcUser ) * sizeof WCHAR ) >= __min( 1024, cbRequest ) )
  657. THROW( CException( STATUS_INVALID_PARAMETER ) );
  658. _xClientMachine.Init( cwcMachine );
  659. RtlCopyMemory( _xClientMachine.Get(),
  660. pwcMachine,
  661. _xClientMachine.SizeOf() );
  662. _xClientUser.Init( cwcUser );
  663. RtlCopyMemory( _xClientUser.Get(),
  664. pwcUser,
  665. _xClientUser.SizeOf() );
  666. //
  667. // Retreive the db properties.
  668. //
  669. if ( 5 == GetClientVersion() )
  670. {
  671. // unmarshall the old-style properties, and translate into
  672. // the new-style properties
  673. if ( request.GetBlobSize() > 0 )
  674. {
  675. if ( request.GetBlobSize() >= cbRequest )
  676. THROW( CException( STATUS_INVALID_PARAMETER ) );
  677. CMemDeSerStream stmDeser( request.GetBlobStartAddr(),
  678. request.GetBlobSize() );
  679. XInterface<CDbProperties> xOldDbP( new CDbProperties );
  680. if ( xOldDbP.IsNull() || ! xOldDbP->UnMarshall( stmDeser ) )
  681. THROW( CException( E_OUTOFMEMORY ) );
  682. XInterface<CDbProperties> xNewDbP( new CDbProperties );
  683. if ( xNewDbP.IsNull() )
  684. THROW( CException( E_OUTOFMEMORY ) );
  685. TranslateOldPropsToNewProps( xOldDbP.GetReference(),
  686. xNewDbP.GetReference() );
  687. _xDbProperties.Set( xNewDbP.Acquire() );
  688. }
  689. }
  690. else
  691. {
  692. Win4Assert( GetClientVersion() >= 6 );
  693. if ( GetClientVersion() < 5 )
  694. THROW( CException( STATUS_INVALID_PARAMETER ) );
  695. if ( request.GetBlob2Size() > 0 )
  696. {
  697. if ( ( 0 == request.GetBlob2StartAddr() ) ||
  698. ( ( request.GetBlobSize() + request.GetBlob2Size() ) >= cbRequest ) )
  699. THROW( CException( STATUS_INVALID_PARAMETER ) );
  700. CMemDeSerStream stmDeser( request.GetBlob2StartAddr(),
  701. request.GetBlob2Size() );
  702. XInterface<CDbProperties> xDbP( new CDbProperties );
  703. if ( xDbP.IsNull() || !xDbP->UnMarshall( stmDeser ) )
  704. THROW( CException( E_OUTOFMEMORY ) );
  705. _xDbProperties.Set( xDbP.Acquire() );
  706. }
  707. }
  708. prxDebugOut(( DEB_ITRACE|DEB_PRX_LOG,
  709. "connect clientver %d, remote %d, machine '%ws', user '%ws'\n",
  710. _iClientVersion,
  711. _fClientIsRemote,
  712. pwcMachine,
  713. pwcUser ));
  714. XInterface<ICiCDocStoreLocator> xLocator( _requestQueue.DocStoreLocator() );
  715. Win4Assert( !xLocator.IsNull() );
  716. CPMConnectOut & reply = *(CPMConnectOut *) _Buffer();
  717. cbToWrite = sizeof reply;
  718. reply.ServerVersion() = pmServerVersion;
  719. //
  720. // Never fault in the docstore since docstores have been opened by now.
  721. //
  722. Win4Assert( _requestQueue.AreDocStoresOpen() );
  723. ICiCDocStore * pDocStore = 0;
  724. SCODE sc = xLocator->LookUpDocStore( _xDbProperties.GetPointer(),
  725. &pDocStore,
  726. TRUE );
  727. if ( SUCCEEDED(sc) )
  728. {
  729. // sc will be CI_S_NO_DOCSTORE if this is the CIADMIN catalog
  730. if ( 0 != pDocStore )
  731. {
  732. _xDocStore.Set( pDocStore );
  733. // This QI is just about guaranteed to work.
  734. XInterface<ICiCAdviseStatus> xAdviseStatus;
  735. sc = pDocStore->QueryInterface( IID_ICiCAdviseStatus,
  736. xAdviseStatus.GetQIPointer() );
  737. if ( S_OK != sc )
  738. THROW( CException(sc) );
  739. xAdviseStatus->IncrementPerfCounterValue( CI_PERF_RUNNING_QUERIES );
  740. }
  741. }
  742. else
  743. reply.SetStatus( CI_E_NO_CATALOG );
  744. return stateContinue;
  745. } //DoConnect
  746. //+-------------------------------------------------------------------------
  747. //
  748. // Member: CRequestServer::DoDisconnect, private
  749. //
  750. // Synopsis: Handles a disconnect message.
  751. //
  752. // Arguments: [cbRequest] - Size of the request in _Buffer()
  753. // [cbToWrite] - On output, set to the # of bytes to write if
  754. // other than sizeof CProxyMessage.
  755. //
  756. // Returns: stateDisconnect -- the connection will be closed
  757. //
  758. // History: 16-Sep-96 dlee Created.
  759. //
  760. //--------------------------------------------------------------------------
  761. RequestState CRequestServer::DoDisconnect(
  762. DWORD cbRequest,
  763. DWORD & cbToWrite )
  764. {
  765. CProxyMessage &msg = * (CProxyMessage *) _Buffer();
  766. Win4Assert( pmDisconnect == msg.GetMessage() );
  767. return stateDisconnect;
  768. } //DoDisconnect
  769. //+-------------------------------------------------------------------------
  770. //
  771. // Member: CRequestServer::DoCreateQuery, private
  772. //
  773. // Synopsis: Handles a create query message.
  774. //
  775. // Arguments: [cbRequest] - Size of the request in _Buffer()
  776. // [cbToWrite] - On output, set to the # of bytes to write if
  777. // other than sizeof CProxyMessage.
  778. //
  779. // History: 16-Sep-96 dlee Created.
  780. //
  781. //--------------------------------------------------------------------------
  782. RequestState CRequestServer::DoCreateQuery(
  783. DWORD cbRequest,
  784. DWORD & cbToWrite )
  785. {
  786. // if this hits, there is probably a cursor refcounting bug
  787. Win4Assert( 0 == _pQuery );
  788. if ( _xDocStore.IsNull() ||
  789. ( 0 != _pQuery ) )
  790. THROW( CException( STATUS_INVALID_PARAMETER ) );
  791. XInterface<ICiCDocStoreEx> xDocStoreEx;
  792. SCODE sc = _xDocStore->QueryInterface( IID_ICiCDocStoreEx,
  793. xDocStoreEx.GetQIPointer() );
  794. if ( SUCCEEDED(sc) )
  795. {
  796. BOOL fNoQuery = FALSE;
  797. sc = xDocStoreEx->IsNoQuery( &fNoQuery );
  798. if ( S_OK == sc )
  799. {
  800. if ( fNoQuery )
  801. THROW( CException( QUERY_S_NO_QUERY ) );
  802. }
  803. else
  804. THROW ( CException( sc ) );
  805. }
  806. else
  807. THROW ( CException( sc ) );
  808. RequestState state = stateContinue;
  809. // The request is either in the standard buffer or the temp buffer.
  810. // Take ownership of the temp buffer.
  811. CPMCreateQueryIn &request = * (CPMCreateQueryIn *) _ActiveBuffer();
  812. XPtrST<BYTE> xTemp( _xTempBuffer.Acquire() );
  813. // marshalling / unmarshalling is inconsistent if alignment is different
  814. Win4Assert( isQWordAligned( &request ) );
  815. Win4Assert( isQWordAligned( request.Data() ) );
  816. request.ValidateCheckSum( GetClientVersion(), cbRequest );
  817. // unpickle the query
  818. XColumnSet cols;
  819. XRestriction rst;
  820. XSortSet sort;
  821. XCategorizationSet categ;
  822. CRowsetProperties Props;
  823. XPidMapper pidmap;
  824. UnPickle( GetClientVersion(),
  825. cols,
  826. rst,
  827. sort,
  828. categ,
  829. Props,
  830. pidmap,
  831. (BYTE *) request.Data(),
  832. cbRequest - sizeof CProxyMessage );
  833. if ( Props.GetMaxResults() > 0 && Props.GetFirstRows() > 0 )
  834. THROW( CException( E_INVALIDARG ) );
  835. // Compute # of cursors to create and where to put them
  836. unsigned cCursors = 1;
  837. if ( 0 != categ.GetPointer() )
  838. cCursors += categ->Size();
  839. // verify the output buffer is large enough
  840. if ( _BufferSize() <
  841. ( cCursors * sizeof ULONG + sizeof CPMCreateQueryOut ) )
  842. THROW( CException( STATUS_INVALID_PARAMETER ) );
  843. // get reference to CLangList to pass to CQParse objects...
  844. XInterface<ICiManager> xICiManager;
  845. sc = _xDocStore->GetContentIndex( xICiManager.GetPPointer() );
  846. if ( FAILED(sc) )
  847. THROW( CException(sc) );
  848. XInterface<ICiFrameworkQuery> xICiFrameworkQuery;
  849. sc = xICiManager->QueryInterface( IID_ICiFrameworkQuery,
  850. xICiFrameworkQuery.GetQIPointer() );
  851. if ( FAILED(sc) )
  852. THROW( CException(sc) );
  853. CLangList * pLangList = 0;
  854. sc = xICiFrameworkQuery->GetLangList((void**)&pLangList);
  855. if ( FAILED(sc) )
  856. THROW( CException(sc) );
  857. //
  858. // Set up a property mapper. Used for restriction parsing and sort/output
  859. // column translation.
  860. //
  861. XInterface<IPropertyMapper> xPropMapper;
  862. sc = _xDocStore->GetPropertyMapper( xPropMapper.GetPPointer() );
  863. if ( FAILED( sc ) )
  864. {
  865. vqDebugOut(( DEB_ERROR, "CRequestServer::DoCreateQuery, GetPropertyMapper failed\n" ));
  866. THROW( CException( sc ) );
  867. }
  868. //
  869. // Adjust pidmap to translate properties.
  870. //
  871. CPidConverter PidConverter( xPropMapper.GetPointer() );
  872. pidmap->SetPidConverter( &PidConverter );
  873. // parse the query -- expand phrases, etc.
  874. XRestriction rstParsed;
  875. DWORD dwQueryStatus = 0;
  876. if ( !rst.IsNull() )
  877. {
  878. CQParse qparse( pidmap.GetReference(), *pLangList );
  879. rstParsed.Set( qparse.Parse( rst.GetPointer() ) );
  880. DWORD dwParseStatus = qparse.GetStatus();
  881. if ( ( 0 != ( dwParseStatus & CI_NOISE_PHRASE ) ) &&
  882. ( rst->Type() != RTVector ) &&
  883. ( rst->Type() != RTOr ) )
  884. {
  885. vqDebugOut(( DEB_WARN, "Query contains phrase composed "
  886. "entirely of noise words.\n" ));
  887. THROW( CException( QUERY_E_ALLNOISE ) );
  888. }
  889. const DWORD dwCiNoise = CI_NOISE_IN_PHRASE | CI_NOISE_PHRASE;
  890. if ( 0 != ( dwCiNoise & dwParseStatus ) )
  891. dwQueryStatus |= STAT_NOISE_WORDS;
  892. }
  893. //
  894. // Re-map property ids.
  895. //
  896. //
  897. // TODO: Get rid of this whole pid remap thing. We should
  898. // really be able to do it earlier now that the pidmap
  899. // can be set up to convert fake to real pids.
  900. //
  901. XInterface<CPidRemapper> pidremap( new CPidRemapper( pidmap.GetReference(),
  902. xPropMapper,
  903. 0, // rstParsed.GetPointer(),
  904. cols.GetPointer(),
  905. sort.GetPointer() ) );
  906. //
  907. // WorkID may be added to the columns requested in SetBindings.
  908. // Be sure it's in the pidremap from the beginning.
  909. //
  910. CFullPropSpec psWorkId( guidQuery, DISPID_QUERY_WORKID );
  911. pidremap->NameToReal( &psWorkId );
  912. XInterface<ICiQueryPropertyMapper> xQueryPropMapper;
  913. sc = pidremap->QueryInterface( IID_ICiQueryPropertyMapper,
  914. xQueryPropMapper.GetQIPointer() );
  915. if ( FAILED(sc) )
  916. {
  917. vqDebugOut(( DEB_ERROR, "DoCreateQuery - QI for property mapper failed 0x%x\n", sc ));
  918. THROW ( CException( sc ) ) ;
  919. }
  920. XInterface<ICiCQuerySession> xQuerySession;
  921. sc = _xDocStore->GetQuerySession( xQuerySession.GetPPointer() );
  922. if ( FAILED(sc) )
  923. {
  924. vqDebugOut(( DEB_ERROR, "DoCreateQuery - GetQuerySession failed 0x%x\n", sc ));
  925. THROW ( CException( sc ) ) ;
  926. }
  927. //
  928. // Initialize the query session
  929. //
  930. sc = xQuerySession->Init( 0,
  931. 0,
  932. _xDbProperties.GetPointer(),
  933. xQueryPropMapper.GetPointer() );
  934. if ( FAILED( sc ) )
  935. THROW( CException( sc ) );
  936. //
  937. // Optimize the query
  938. //
  939. XQueryOptimizer xqopt( new CQueryOptimizer( xQuerySession,
  940. _xDocStore.GetPointer(),
  941. rstParsed,
  942. cols.GetReference(),
  943. sort.GetPointer(),
  944. pidremap.GetReference(),
  945. Props,
  946. dwQueryStatus ) );
  947. prxDebugOut(( DEB_ITRACE, "Query has %s1 component%s\n",
  948. xqopt->IsMultiCursor() ? "> " : "",
  949. xqopt->IsMultiCursor() ? "s" : "" ));
  950. prxDebugOut(( DEB_ITRACE, "Current component of query %s fully sorted\n",
  951. xqopt->IsFullySorted() ? "is" : "is not" ));
  952. prxDebugOut(( DEB_ITRACE, "Current component of query %s positionable\n",
  953. xqopt->IsPositionable() ? "is" : "is not" ));
  954. prxDebugOut(( DEB_ITRACE, "Rowset props flags: 0x%x\n",
  955. Props.GetPropertyFlags() ));
  956. prxDebugOut(( DEB_ITRACE, "Rowset props maxresults: %d\n",
  957. Props.GetMaxResults() ));
  958. prxDebugOut(( DEB_ITRACE, "Rowset props cmdtimeout: %d\n",
  959. Props.GetCommandTimeout() ));
  960. CPMCreateQueryOut &reply = * (CPMCreateQueryOut *) _Buffer();
  961. ULONG *aCursors = reply.GetCursors();
  962. reply.IsWorkIdUnique() = xqopt->IsWorkidUnique();
  963. reply.SetServerCookie( (ULONG_PTR) this );
  964. // create either a true sequential or bigtable query
  965. if ( ( (Props.GetPropertyFlags() & eLocatable) == 0) &&
  966. ( !xqopt->IsMultiCursor() ) &&
  967. ( xqopt->IsFullySorted() ) &&
  968. ( 0 == categ.GetPointer() ) )
  969. {
  970. _pQuery = new CSeqQuery( xqopt,
  971. cols,
  972. aCursors,
  973. pidremap,
  974. _xDocStore.GetPointer() );
  975. reply.IsTrueSequential() = TRUE;
  976. }
  977. else
  978. {
  979. reply.IsTrueSequential() = FALSE;
  980. // If we've been instructed to create a synchronous cursor,
  981. // put the request into a pending state
  982. BOOL fSync = ( 0 == ( Props.GetPropertyFlags() & eAsynchronous ) );
  983. XInterface<CRequestServer> xMe;
  984. if ( fSync )
  985. {
  986. // Refcount ourselves in case the async write fails and
  987. // the request server is recycled before this thread returns.
  988. AddRef();
  989. xMe.Set( this );
  990. state = statePending;
  991. _state = pipeStatePending;
  992. _scPendingStatus = S_OK;
  993. _cbPendingWrite = sizeof CPMCreateQueryOut +
  994. ( sizeof ULONG * cCursors );
  995. }
  996. TRY
  997. {
  998. CRequestQueue & requestQueue = _requestQueue;
  999. PQuery *pQ = new CAsyncQuery( xqopt,
  1000. cols,
  1001. sort,
  1002. categ,
  1003. cCursors,
  1004. aCursors,
  1005. pidremap,
  1006. (Props.GetPropertyFlags() & eWatchable) != 0,
  1007. _xDocStore.GetPointer(),
  1008. fSync ? this : 0 );
  1009. // If synchronous, the query may be done and freed
  1010. // by the client app by now. the CRequestServer is still
  1011. // valid due to the AddRef above.
  1012. if ( fSync )
  1013. requestQueue.IncrementPendingItems();
  1014. else
  1015. _pQuery = pQ;
  1016. }
  1017. CATCH( CException, e )
  1018. {
  1019. _pQuery = 0;
  1020. _state = pipeStateRead;
  1021. RETHROW();
  1022. }
  1023. END_CATCH
  1024. }
  1025. cbToWrite = sizeof CPMCreateQueryOut + ( sizeof ULONG * cCursors );
  1026. return state;
  1027. } //DoCreateQuery
  1028. //+-------------------------------------------------------------------------
  1029. //
  1030. // Member: CRequestServer::DoFreeCursor, private
  1031. //
  1032. // Synopsis: Handles a free cursor message.
  1033. //
  1034. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1035. // [cbToWrite] - On output, set to the # of bytes to write if
  1036. // other than sizeof CProxyMessage.
  1037. //
  1038. // History: 16-Sep-96 dlee Created.
  1039. //
  1040. //--------------------------------------------------------------------------
  1041. RequestState CRequestServer::DoFreeCursor(
  1042. DWORD cbRequest,
  1043. DWORD & cbToWrite )
  1044. {
  1045. if ( 0 == _pQuery )
  1046. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1047. CPMFreeCursorIn &request = * (CPMFreeCursorIn *) _Buffer();
  1048. CPMFreeCursorOut &reply = * (CPMFreeCursorOut *) _Buffer();
  1049. reply.CursorsRemaining() = _pQuery->FreeCursor( request.GetCursor() );
  1050. // The client is allowed to serially do multiple queries on 1 connection.
  1051. // The way a query is released is by freeing all of its cursors.
  1052. // If this is the last cursor reference to the query, delete the query.
  1053. if ( 0 == reply.CursorsRemaining() )
  1054. FreeQuery();
  1055. cbToWrite = sizeof reply;
  1056. return stateContinue;
  1057. } //DoFreeCursor
  1058. //+-------------------------------------------------------------------------
  1059. //
  1060. // Member: CRequestServer::DoGetRows, private
  1061. //
  1062. // Synopsis: Handles a get rows message.
  1063. //
  1064. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1065. // [cbToWrite] - On output, set to the # of bytes to write if
  1066. // other than sizeof CProxyMessage.
  1067. //
  1068. // History: 16-Sep-96 dlee Created.
  1069. // 12-Nov-99 KLam Adjust results for Win64 server to
  1070. // Win32 client.
  1071. //
  1072. //--------------------------------------------------------------------------
  1073. RequestState CRequestServer::DoGetRows(
  1074. DWORD cbRequest,
  1075. DWORD & cbToWrite )
  1076. {
  1077. if ( 0 == _pQuery )
  1078. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1079. CPMGetRowsIn & request = * (CPMGetRowsIn *) _Buffer();
  1080. request.ValidateCheckSum( GetClientVersion(), cbRequest );
  1081. // The input buffer must be as large as the parameter buffer
  1082. // plus the size of the serialized seek description.
  1083. Win4Assert( _BufferSize() >= sizeof CPMGetRowsOut + request.GetSeekSize() );
  1084. if ( _BufferSize() < sizeof CPMGetRowsOut + request.GetSeekSize() )
  1085. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1086. unsigned cbReserved = request.GetReservedSize();
  1087. unsigned cbRowWidth = request.GetRowWidth();
  1088. unsigned cbClientRead = request.GetReadBufferSize();
  1089. unsigned cRowsToTransfer = request.GetRowsToTransfer();
  1090. BOOL fFwdFetch = request.GetFwdFetch();
  1091. ULONG_PTR ulClientBase = request.GetClientBase();
  1092. ULONG hCursor = request.GetCursor();
  1093. // validate params agains attack
  1094. if ( 0 == cbRowWidth ||
  1095. cbRowWidth > cbClientRead ||
  1096. cbReserved >= cbClientRead )
  1097. {
  1098. Win4Assert( 0 != cbRowWidth );
  1099. Win4Assert( cbRowWidth <= cbClientRead );
  1100. Win4Assert( cbReserved < cbClientRead );
  1101. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1102. }
  1103. // Deserialize the row seek description
  1104. Win4Assert( isQWordAligned( (void*) UIntToPtr( cbReserved ) ) );
  1105. Win4Assert( isQWordAligned( request.GetDesc() ) );
  1106. CMemDeSerStream stmDeser( request.GetDesc(), request.GetSeekSize() );
  1107. XPtr<CRowSeekDescription> pRowSeek;
  1108. UnmarshallRowSeekDescription( stmDeser, GetClientVersion(), pRowSeek, FALSE );
  1109. CPMGetRowsOut *pReply;
  1110. // use a temporary buffer if the client is doing a large read
  1111. if ( cbClientRead <= _BufferSize() )
  1112. {
  1113. pReply = (CPMGetRowsOut *) _Buffer();
  1114. }
  1115. else
  1116. {
  1117. _xTempBuffer.Init( cbClientRead );
  1118. pReply = new( _xTempBuffer.Get() ) CPMGetRowsOut;
  1119. }
  1120. #if CIDBG == 1
  1121. RtlFillMemory( ( (BYTE *) pReply ) + sizeof CPMGetRowsOut,
  1122. cbClientRead - sizeof CPMGetRowsOut,
  1123. 0xca );
  1124. #endif // CIDBG == 1
  1125. // cbReserved includes room for the the CPMGetRowsOut and the marshalled
  1126. // seek description. All other space in the buffer is for row data.
  1127. unsigned cbRealRowWidth = cbRowWidth;
  1128. #ifdef _WIN64
  1129. if ( !IsClient64() ) // replying to a 32 bit client
  1130. cbRealRowWidth = _cbRowWidth64;
  1131. #endif
  1132. CFixedVarBufferAllocator Alloc( pReply,
  1133. ulClientBase,
  1134. cbClientRead,
  1135. cbRealRowWidth,
  1136. cbReserved );
  1137. CGetRowsParams Fetch( cRowsToTransfer,
  1138. fFwdFetch,
  1139. cbRealRowWidth,
  1140. Alloc );
  1141. XPtr<CRowSeekDescription> xRowSeekOut;
  1142. SCODE scRet = _pQuery->GetRows( hCursor,
  1143. pRowSeek.GetReference(),
  1144. Fetch,
  1145. xRowSeekOut );
  1146. if ( ( SUCCEEDED( scRet ) ) ||
  1147. ( ( STATUS_BUFFER_TOO_SMALL == scRet ) && ( Fetch.RowsTransferred() > 0 ) ) )
  1148. {
  1149. if ( STATUS_BUFFER_TOO_SMALL == scRet )
  1150. pReply->SetStatus( DB_S_BLOCKLIMITEDROWS );
  1151. else
  1152. pReply->SetStatus( scRet );
  1153. pReply->RowsReturned() = Fetch.RowsTransferred();
  1154. #ifdef _WIN64
  1155. if ( !IsClient64() ) // replying to a 32 bit client
  1156. {
  1157. // Reply + CPMGetRowsOut + seek info => table info
  1158. BYTE *pbResults = ((BYTE *)pReply) + cbReserved;
  1159. unsigned cbResults = cbClientRead - cbReserved;
  1160. unsigned cRows = Fetch.RowsTransferred();
  1161. //
  1162. // Adjust the sizes of the results to fit for a Win32 client
  1163. //
  1164. FixRows ( (BYTE *)pReply, pbResults, cbResults,
  1165. ulClientBase, cRows, cbRowWidth );
  1166. }
  1167. #endif
  1168. //
  1169. // We can't say everything is ok and fetch 0 rows. This assert was
  1170. // added because we hit this situation on the client side during
  1171. // stress.
  1172. //
  1173. Win4Assert( ! ( ( S_OK == scRet ) &&
  1174. ( 0 == Fetch.RowsTransferred() ) ) );
  1175. if ( xRowSeekOut.IsNull() )
  1176. {
  1177. ULONG *pul = (ULONG *) pReply->GetSeekDesc();
  1178. *pul = 0;
  1179. }
  1180. else
  1181. {
  1182. Win4Assert( ( xRowSeekOut->MarshalledSize() +
  1183. sizeof CPMGetRowsOut ) <= cbReserved );
  1184. CMemSerStream stmMem( pReply->GetSeekDesc(),
  1185. xRowSeekOut->MarshalledSize() );
  1186. xRowSeekOut->Marshall( stmMem );
  1187. }
  1188. // Have to transfer the entire buffer since variable data is
  1189. // written from the top of the buffer down, and fixed data from
  1190. // the bottom of the buffer up.
  1191. cbToWrite = cbClientRead;
  1192. }
  1193. else
  1194. {
  1195. // This exception is too commmon in testing...
  1196. QUIETTHROW( CException( scRet ) );
  1197. }
  1198. prxDebugOut(( DEB_ITRACE, "status at end of getrows: 0x%x\n",
  1199. pReply->GetStatus() ));
  1200. return stateContinue;
  1201. } //DoGetRows
  1202. #ifdef _WIN64
  1203. //+-------------------------------------------------------------------------
  1204. //
  1205. // Member: CRequestServer::FixRows, private
  1206. //
  1207. // Synopsis: Adjusts Win64 rows into Win32 rows.
  1208. //
  1209. // Arguments: [pbReply] - Reply buffer
  1210. // [pbResults] - Buffer containting result data
  1211. // [cbResults] - Number of bytes in results buffer
  1212. // [ulpClientBase] - Offset of buffer on the client
  1213. // [cRows] - Count of rows
  1214. // [cbRowWidth] - Bytes in a row
  1215. //
  1216. // History: 12-Nov-99 KLam created
  1217. //
  1218. //--------------------------------------------------------------------------
  1219. void CRequestServer::FixRows ( BYTE * pbReply,
  1220. BYTE * pbResults,
  1221. ULONG cbResults,
  1222. ULONG_PTR ulpClientBase,
  1223. ULONG cRows,
  1224. ULONG cbRowWidth )
  1225. {
  1226. prxDebugOut(( DEB_ITRACE,
  1227. "64bit server replying to 32bit client, fixing rows!\n" ));
  1228. Win4Assert( !IsClient64() );
  1229. unsigned cCols = _xCols64->Count();
  1230. // Save the result buffer
  1231. BYTE *pbCurrentResults = new BYTE[cbResults];
  1232. XPtrST<BYTE> xbCurrentResults( pbCurrentResults );
  1233. prxDebugOut(( DEB_ITRACE,
  1234. "\tCopying %d bytes from 0x%I64x to 0x%I64x\n",
  1235. cbResults, pbResults, pbCurrentResults ));
  1236. memcpy( pbCurrentResults, pbResults, cbResults );
  1237. #if CIDBG == 1
  1238. RtlFillMemory( pbResults,
  1239. cRows * _cbRowWidth64,
  1240. 0xba );
  1241. #endif // CIDBG == 1
  1242. prxDebugOut(( DEB_ITRACE,
  1243. "\tReturning %d rows and %d cols each row being %d bytes (32bit: %d) for a total of %d in a %d bytes buffer\n",
  1244. cRows, cCols, _cbRowWidth64, cbRowWidth, cRows * _cbRowWidth64, cbResults ));
  1245. prxDebugOut(( DEB_ITRACE,
  1246. "\t64bit results are at: 0x%I64x 32bit results will be at: 0x%I64x\n",
  1247. pbCurrentResults, pbResults ));
  1248. // Fix the results
  1249. for ( unsigned iRow = 0; iRow < cRows; iRow++ )
  1250. {
  1251. prxDebugOut(( DEB_ITRACE, "\n\tRow: %d Reply Buffer: 0x%I64x Data Buffer: 0x%I64x\n",
  1252. iRow, pbCurrentResults, pbResults ));
  1253. for ( unsigned iCol = 0; iCol < cCols; iCol++ )
  1254. {
  1255. prxDebugOut(( DEB_ITRACE, "\n\t\tColumn: %d\n", iCol ));
  1256. prxDebugOut(( DEB_ITRACE, "\t\t_xCols64 0x%I64x\t_xCols32 0x%I64x\n",
  1257. _xCols64.GetPointer(), _xCols32.GetPointer() ));
  1258. CTableColumn *pCol64 = _xCols64->Get(iCol);
  1259. CTableColumn *pCol32 = _xCols32->Get(iCol);
  1260. if ( pCol64->IsValueStored() )
  1261. {
  1262. ULONG cbSize32 = 0;
  1263. if ( pCol64->GetStoredType() == VT_VARIANT )
  1264. {
  1265. PROPVARIANT *pVar64 = (PROPVARIANT *) (pbCurrentResults + pCol64->GetValueOffset());
  1266. PROPVARIANT32 *pVar32 = (PROPVARIANT32 *) (pbResults + pCol32->GetValueOffset());
  1267. prxDebugOut(( DEB_ITRACE,
  1268. "\t\t Col64 Data: 0x%I64x Offset: %d Col32 Data: 0x%I64x Offset: %d\n",
  1269. pVar64, pCol64->GetValueOffset(), pVar32, pCol32->GetValueOffset() ));
  1270. cbSize32 = sizeof( PROPVARIANT32 ) +
  1271. ((CTableVariant *)pVar64)->VarDataSize32( pbReply, ulpClientBase );
  1272. pVar32->wReserved2 = (WORD) cbSize32;
  1273. FixVariantPointers ( pVar32, pVar64, pbReply, ulpClientBase );
  1274. }
  1275. else if ( pCol64->GetStoredType() == VT_I4 )
  1276. {
  1277. ULONG *pul64 = (ULONG *) (pbCurrentResults + pCol64->GetValueOffset());
  1278. ULONG *pul32 = (ULONG *) (pbResults + pCol32->GetValueOffset());
  1279. prxDebugOut(( DEB_ITRACE,
  1280. "\t\t VT_I4: %d Col64 Data: 0x%I64x Offset: %d Col32 Data: 0x%I64x Offset: %d\n",
  1281. *pul64, pul64, pCol64->GetValueOffset(), pul32, pCol32->GetValueOffset() ));
  1282. cbSize32 = 4;
  1283. *pul32 = *pul64;
  1284. }
  1285. else
  1286. {
  1287. // Unhandled type
  1288. Win4Assert ( pCol64->GetStoredType() == VT_I4 ||
  1289. pCol64->GetStoredType() == VT_VARIANT );
  1290. }
  1291. if ( pCol64->IsStatusStored() )
  1292. {
  1293. BYTE *pbStatus64 = (BYTE *) (pbCurrentResults + pCol64->GetStatusOffset());
  1294. BYTE *pbStatus32 = (BYTE *) (pbResults + pCol32->GetStatusOffset());
  1295. *pbStatus32 = *pbStatus64;
  1296. prxDebugOut (( DEB_ITRACE, "\t\tStatus = 0x%x\n", *pbStatus32 ));
  1297. }
  1298. if ( pCol64->IsLengthStored() )
  1299. {
  1300. LONG *plLength64 = (LONG *) (pbCurrentResults + pCol64->GetLengthOffset());
  1301. LONG *plLength32 = (LONG *) (pbResults + pCol32->GetLengthOffset());
  1302. prxDebugOut (( DEB_ITRACE, "\t\tSize32 = %d Size64 = %d\n", cbSize32, *plLength64 ));
  1303. *plLength32 = cbSize32;
  1304. prxDebugOut (( DEB_ITRACE, "\t\tLength = %d\n", *plLength32 ));
  1305. }
  1306. }
  1307. }
  1308. // Move to the next row
  1309. pbResults += cbRowWidth;
  1310. pbCurrentResults += _cbRowWidth64;
  1311. }
  1312. } // FixRows
  1313. //+-------------------------------------------------------------------------
  1314. //
  1315. // Member: CRequestServer::FixVariantPointers, private
  1316. //
  1317. // Synopsis: Adjusts Win64 variants to fit into Win32 variants.
  1318. //
  1319. // Arguments: [pVar32] - Pointer to 32 bit variant
  1320. // [pVar64] - Pointer to 64 bit variant
  1321. // [pbResults] - Buffer containing variant data
  1322. // [ulClientBase] - Offset of buffer on the client
  1323. //
  1324. // History: 21-Oct-99 KLam created
  1325. // 13-Feb-2000 KLam assert needed to check element not pointer
  1326. // 15-Feb-2000 DLee DECIMAL is special case (16 bits)
  1327. //
  1328. //--------------------------------------------------------------------------
  1329. void CRequestServer::FixVariantPointers ( PROPVARIANT32 *pVar32,
  1330. PROPVARIANT *pVar64,
  1331. BYTE *pbResults,
  1332. ULONG_PTR ulClientBase )
  1333. {
  1334. pVar32->vt = pVar64->vt;
  1335. // reference or a vector or an array
  1336. if ( CTableVariant::IsByRef ( pVar64->vt ) || 0 != (pVar64->vt & (VT_VECTOR | VT_ARRAY)) )
  1337. {
  1338. // blob used here as a generic holder for a size and pointer
  1339. pVar32->blob.cbSize = pVar64->blob.cbSize;
  1340. pVar32->blob.pBlob = (PTR32)(UINT_PTR) (pVar64->blob.pBlobData);
  1341. prxDebugOut(( DEB_ITRACE,
  1342. "\t\t Fixing reference. ClientBase: 0x%I64x Buffer: 0x%I64x at 0x%x\n",
  1343. ulClientBase, pbResults, pVar32->blob.pBlob ));
  1344. if ( VT_LPWSTR == pVar64->vt ||
  1345. VT_LPSTR == pVar64->vt ||
  1346. VT_BSTR == pVar64->vt )
  1347. prxDebugOut(( DEB_ITRACE, "\t\tvt: %d pStr: 0x%I64x\n",
  1348. pVar64->vt,
  1349. ((UINT_PTR)pVar64->calpwstr.pElems - ulClientBase) + pbResults ));
  1350. else
  1351. prxDebugOut(( DEB_ITRACE, "\t\tvt: %d size: 0x%I64x pBlob: 0x%I64x\n",
  1352. pVar64->vt, pVar64->blob.cbSize, pVar64->blob.pBlobData ));
  1353. // Vector of strings
  1354. if ( (VT_VECTOR|VT_LPWSTR) == pVar64->vt ||
  1355. (VT_VECTOR|VT_LPSTR) == pVar64->vt ||
  1356. (VT_VECTOR|VT_BSTR) == pVar64->vt )
  1357. {
  1358. // Get a pointer to the vector in the variable section of the return buffer
  1359. void ** ppvVector = (void **)( ((UINT_PTR)pVar64->calpwstr.pElems - ulClientBase ) + pbResults );
  1360. ULONG * pulVector = (ULONG *) ppvVector;
  1361. prxDebugOut(( DEB_ITRACE, "\t\t Fixing vector 0x%I64x\n", ppvVector ));
  1362. for ( unsigned iElement = 0; iElement < pVar64->calpwstr.cElems; ++iElement )
  1363. pulVector[iElement] = (ULONG) (UINT_PTR) (ppvVector[iElement]);
  1364. }
  1365. // Vector of variants
  1366. else if ( (VT_VARIANT|VT_VECTOR) == pVar64->vt ) // not currently supported
  1367. {
  1368. PROPVARIANT * pVarVector64 = (PROPVARIANT *)( ((UINT_PTR)pVar64->capropvar.pElems - ulClientBase ) + pbResults );
  1369. PROPVARIANT32 * pVarVector32 = (PROPVARIANT32 *) pVarVector64;
  1370. // Recursively fix each variant in the vector
  1371. for ( unsigned iVarElement = 0; iVarElement < pVar64->capropvar.cElems; ++iVarElement )
  1372. FixVariantPointers ( &pVarVector32[iVarElement],
  1373. &pVarVector64[iVarElement],
  1374. pbResults,
  1375. ulClientBase );
  1376. }
  1377. // Arrays (Safearrays)
  1378. else if ( ( 0 != (VT_ARRAY & pVar64->vt) ) ||
  1379. ( VT_SAFEARRAY == (pVar64->vt & VT_TYPEMASK) ) )
  1380. {
  1381. // Get a pointer to the vector in the variable section of the return buffer
  1382. SAFEARRAY * psa = (SAFEARRAY *)(( (UINT_PTR)pVar64->pparray - ulClientBase ) + pbResults );
  1383. SAFEARRAY32 * psa32 = (SAFEARRAY32 *) psa;
  1384. psa32->pvData = (PTR32) (UINT_PTR) psa->pvData;
  1385. // memmove is smart enough to move the overlapping bytes first
  1386. memmove ( psa32->rgsabound,
  1387. psa->rgsabound,
  1388. psa32->cDims * sizeof (SAFEARRAYBOUND) );
  1389. if ( VT_BSTR == (pVar64->vt & VT_TYPEMASK) )
  1390. {
  1391. // Pointing to an array of 32bit pointers so adjust the size
  1392. psa32->cbElements = sizeof ( PTR32 );
  1393. // Get the number of elements in the safe array
  1394. unsigned cBstrElements = psa32->rgsabound[0].cElements;
  1395. for ( unsigned j = 1; j < psa32->cDims; j++ )
  1396. cBstrElements *= psa32->rgsabound[j].cElements;
  1397. ULONG *pulBstr = (ULONG *) ((psa32->pvData - ulClientBase) + pbResults );
  1398. void **ppvBstr = (void **) pulBstr;
  1399. for ( j = 0; j < cBstrElements; j++ )
  1400. {
  1401. // Make sure Win64 isn't passing to big of a pointer
  1402. if ( 0 != (((ULONG_PTR)ppvBstr[j]) & 0xFFFFFFFF00000000) )
  1403. {
  1404. prxDebugOut(( DEB_ERROR, "Non 32 bit pointer 0x%I64x !!!\n",
  1405. (ULONG_PTR)ppvBstr[j] ));
  1406. Win4Assert( 0 == (((ULONG_PTR)ppvBstr[j]) & 0xFFFFFFFF00000000) );
  1407. }
  1408. pulBstr[j] = (ULONG) (ULONG_PTR) ppvBstr[j];
  1409. }
  1410. }
  1411. else if ( VT_VARIANT == (pVar64->vt & VT_TYPEMASK) )
  1412. {
  1413. // Pointing to an array of 32bit variants so adjust the size
  1414. psa32->cbElements = sizeof ( PROPVARIANT32 );
  1415. // Get the number of elements in the safe array
  1416. unsigned cVariants = psa32->rgsabound[0].cElements;
  1417. for ( unsigned j = 1; j < psa32->cDims; j++ )
  1418. cVariants *= psa32->rgsabound[j].cElements;
  1419. PROPVARIANT * avar64 = (PROPVARIANT *) ((psa32->pvData - ulClientBase) + pbResults );
  1420. PROPVARIANT32 * avar32 = (PROPVARIANT32 *) avar64;
  1421. prxDebugOut(( DEB_ITRACE, "\t\t Found %d Variants at 0x%I64x\n", cVariants, avar64 ));
  1422. // Recursively fix each variant in the array
  1423. for ( unsigned v = 0; v < cVariants; v++ )
  1424. FixVariantPointers ( &avar32[v],
  1425. &avar64[v],
  1426. pbResults,
  1427. ulClientBase );
  1428. }
  1429. }
  1430. }
  1431. else if ( VT_DECIMAL == pVar64->vt )
  1432. {
  1433. RtlCopyMemory ( pVar32, pVar64, sizeof PROPVARIANT32 );
  1434. }
  1435. else
  1436. {
  1437. pVar32->uhVal = (ULONGLONG)(UINT_PTR) pVar64->pulVal;
  1438. prxDebugOut(( DEB_ITRACE, "\t\tvt: %d value: 0x%I64x\n\n",
  1439. pVar64->vt, pVar64->uhVal ));
  1440. }
  1441. } //FixVariantPointers
  1442. #endif // _WIN64
  1443. //+-------------------------------------------------------------------------
  1444. //
  1445. // Member: CRequestServer::DoRestartPosition, private
  1446. //
  1447. // Synopsis: Handles a restart position message.
  1448. //
  1449. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1450. // [cbToWrite] - On output, set to the # of bytes to write if
  1451. // other than sizeof CProxyMessage.
  1452. //
  1453. // History: 17-Apr-97 emilyb created
  1454. //
  1455. //--------------------------------------------------------------------------
  1456. RequestState CRequestServer::DoRestartPosition(
  1457. DWORD cbRequest,
  1458. DWORD & cbToWrite )
  1459. {
  1460. if ( 0 == _pQuery )
  1461. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1462. CPMRestartPositionIn & request = * (CPMRestartPositionIn *) _Buffer();
  1463. _pQuery->RestartPosition( request.GetCursor(),
  1464. request.GetChapter() );
  1465. return stateContinue;
  1466. } //DoRestartPosition
  1467. //+-------------------------------------------------------------------------
  1468. //
  1469. // Member: CRequestServer::DoStopAsynch, private
  1470. //
  1471. // Synopsis: Handles a stop processing of async rowset message.
  1472. //
  1473. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1474. // [cbToWrite] - On output, set to the # of bytes to write if
  1475. // other than sizeof CProxyMessage.
  1476. //
  1477. // History: 17-Apr-97 emilyb created
  1478. //
  1479. //--------------------------------------------------------------------------
  1480. RequestState CRequestServer::DoStopAsynch(
  1481. DWORD cbRequest,
  1482. DWORD & cbToWrite )
  1483. {
  1484. if ( 0 == _pQuery )
  1485. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1486. CPMStopAsynchIn & request = * (CPMStopAsynchIn *) _Buffer();
  1487. _pQuery->StopAsynch( request.GetCursor() );
  1488. return stateContinue;
  1489. } //DoStopAsynch
  1490. //+-------------------------------------------------------------------------
  1491. //
  1492. // Member: CRequestServer::DoStartWatching, private
  1493. //
  1494. // Synopsis: Handles a start watch all behavior for rowset message.
  1495. //
  1496. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1497. // [cbToWrite] - On output, set to the # of bytes to write if
  1498. // other than sizeof CProxyMessage.
  1499. //
  1500. // History: 17-Apr-97 emilyb created
  1501. //
  1502. //--------------------------------------------------------------------------
  1503. RequestState CRequestServer::DoStartWatching(
  1504. DWORD cbRequest,
  1505. DWORD & cbToWrite )
  1506. {
  1507. if ( 0 == _pQuery )
  1508. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1509. CPMStartWatchingIn & request = * (CPMStartWatchingIn *) _Buffer();
  1510. _pQuery->StartWatching( request.GetCursor() );
  1511. return stateContinue;
  1512. } //DoStartWatching
  1513. //+-------------------------------------------------------------------------
  1514. //
  1515. // Member: CRequestServer::DoStopWatching, private
  1516. //
  1517. // Synopsis: Handles a stop watch all behavior for rowset message.
  1518. //
  1519. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1520. // [cbToWrite] - On output, set to the # of bytes to write if
  1521. // other than sizeof CProxyMessage.
  1522. //
  1523. // History: 17-Apr-97 emilyb created
  1524. //
  1525. //--------------------------------------------------------------------------
  1526. RequestState CRequestServer::DoStopWatching(
  1527. DWORD cbRequest,
  1528. DWORD & cbToWrite )
  1529. {
  1530. if ( 0 == _pQuery )
  1531. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1532. CPMStopWatchingIn & request = * (CPMStopWatchingIn *) _Buffer();
  1533. _pQuery->StopWatching( request.GetCursor() );
  1534. return stateContinue;
  1535. } //DoStopWatching
  1536. //+-------------------------------------------------------------------------
  1537. //
  1538. // Member: CRequestServer::DoRatioFinished, private
  1539. //
  1540. // Synopsis: Handles a ratio finished message.
  1541. //
  1542. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1543. // [cbToWrite] - On output, set to the # of bytes to write if
  1544. // other than sizeof CProxyMessage.
  1545. //
  1546. // History: 16-Sep-96 dlee Created.
  1547. //
  1548. //--------------------------------------------------------------------------
  1549. RequestState CRequestServer::DoRatioFinished(
  1550. DWORD cbRequest,
  1551. DWORD & cbToWrite )
  1552. {
  1553. if ( 0 == _pQuery )
  1554. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1555. CPMRatioFinishedIn &request = * (CPMRatioFinishedIn *) _Buffer();
  1556. CPMRatioFinishedOut &reply = * (CPMRatioFinishedOut *) _Buffer();
  1557. DBCOUNTITEM den, num, rows;
  1558. _pQuery->RatioFinished( request.GetCursor(),
  1559. den,
  1560. num,
  1561. rows,
  1562. reply.NewRows() );
  1563. reply.Denominator() = (ULONG) den;
  1564. reply.Numerator() = (ULONG) num;
  1565. reply.RowCount() = (ULONG) rows;
  1566. cbToWrite = sizeof reply;
  1567. return stateContinue;
  1568. } //DoRatioFinished
  1569. //+-------------------------------------------------------------------------
  1570. //
  1571. // Member: CRequestServer::DoCompareBmk, private
  1572. //
  1573. // Synopsis: Handles a compare bookmark message.
  1574. //
  1575. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1576. // [cbToWrite] - On output, set to the # of bytes to write if
  1577. // other than sizeof CProxyMessage.
  1578. //
  1579. // History: 16-Sep-96 dlee Created.
  1580. //
  1581. //--------------------------------------------------------------------------
  1582. RequestState CRequestServer::DoCompareBmk(
  1583. DWORD cbRequest,
  1584. DWORD & cbToWrite )
  1585. {
  1586. if ( 0 == _pQuery )
  1587. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1588. CPMCompareBmkIn &request = * (CPMCompareBmkIn *) _Buffer();
  1589. CPMCompareBmkOut &reply = * (CPMCompareBmkOut *) _Buffer();
  1590. _pQuery->Compare( request.GetCursor(),
  1591. request.GetChapter(),
  1592. request.GetBmkFirst(),
  1593. request.GetBmkSecond(),
  1594. reply.Comparison() );
  1595. cbToWrite = sizeof reply;
  1596. return stateContinue;
  1597. } //DoCompareBmk
  1598. //+-------------------------------------------------------------------------
  1599. //
  1600. // Member: CRequestServer::DoGetApproximatePosition, private
  1601. //
  1602. // Synopsis: Handles a get approximate position message.
  1603. //
  1604. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1605. // [cbToWrite] - On output, set to the # of bytes to write if
  1606. // other than sizeof CProxyMessage.
  1607. //
  1608. // History: 16-Sep-96 dlee Created.
  1609. //
  1610. //--------------------------------------------------------------------------
  1611. RequestState CRequestServer::DoGetApproximatePosition(
  1612. DWORD cbRequest,
  1613. DWORD & cbToWrite )
  1614. {
  1615. if ( 0 == _pQuery )
  1616. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1617. CPMGetApproximatePositionIn &request = * (CPMGetApproximatePositionIn *)_Buffer();
  1618. CPMGetApproximatePositionOut &reply = * (CPMGetApproximatePositionOut *)_Buffer();
  1619. DBCOUNTITEM cNum,cDen;
  1620. _pQuery->GetApproximatePosition( request.GetCursor(),
  1621. request.GetChapter(),
  1622. request.GetBmk(),
  1623. & cNum,
  1624. & cDen );
  1625. reply.Numerator() = (ULONG) cNum;
  1626. reply.Denominator() = (ULONG) cDen;
  1627. cbToWrite = sizeof reply;
  1628. return stateContinue;
  1629. } //DoGetApproximatePosition
  1630. //+-------------------------------------------------------------------------
  1631. //
  1632. // Member: CRequestServer::DoSetBindings, private
  1633. //
  1634. // Synopsis: Handles a set bindings message.
  1635. //
  1636. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1637. // [cbToWrite] - On output, set to the # of bytes to write if
  1638. // other than sizeof CProxyMessage.
  1639. //
  1640. // History: 16-Sep-96 dlee Created.
  1641. // 05-Oct-99 KLam Handle Win32 client to Win64 server
  1642. //
  1643. //--------------------------------------------------------------------------
  1644. RequestState CRequestServer::DoSetBindings(
  1645. DWORD cbRequest,
  1646. DWORD & cbToWrite )
  1647. {
  1648. Win4Assert( 0 != _pQuery || IsBeingRemoved() );
  1649. if ( 0 == _pQuery )
  1650. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1651. // The request is either in the standard buffer or the temp buffer.
  1652. // Take ownership of the temp buffer.
  1653. CPMSetBindingsIn &request = * (CPMSetBindingsIn *) _ActiveBuffer();
  1654. XPtrST<BYTE> xTemp( _xTempBuffer.Acquire() );
  1655. Win4Assert( isQWordAligned( request.GetDescription() ) );
  1656. request.ValidateCheckSum( GetClientVersion(), cbRequest );
  1657. CMemDeSerStream stmDeser( request.GetDescription(),
  1658. request.GetBindingDescLength() );
  1659. XPtr<CPidMapper> Pidmap( new CPidMapper() );
  1660. XPtr<CTableColumnSet> Cols( new CTableColumnSet ( stmDeser,
  1661. Pidmap.GetReference() ) );
  1662. #ifdef _WIN64
  1663. // Create a new TableColumnSet with 64-bit sizes
  1664. if ( !IsClient64() )
  1665. {
  1666. prxDebugOut(( DEB_ITRACE, "32bit client querying 64bit server, fixing columns!\n" ));
  1667. //
  1668. // The client gave us a 32-bit column description
  1669. // Fix the column descriptions to work on Win64
  1670. //
  1671. FixColumns ( Cols.Acquire() );
  1672. _cbRowWidth32 = request.GetRowLength();
  1673. // SetBindings with the 64 bit table
  1674. _pQuery->SetBindings( request.GetCursor(),
  1675. _cbRowWidth64,
  1676. _xCols64.GetReference(),
  1677. Pidmap.GetReference() );
  1678. prxDebugOut(( DEB_ITRACE, "\tRow Length: Win32 %d Win64 %d\n", _cbRowWidth32, _cbRowWidth64 ));
  1679. prxDebugOut(( DEB_ITRACE, "\t\t_xCols64 0x%I64x\n\t\t_xCols32 0x%I64x\n",
  1680. _xCols64.GetPointer(), _xCols32.GetPointer() ));
  1681. }
  1682. else
  1683. {
  1684. #endif
  1685. _pQuery->SetBindings( request.GetCursor(),
  1686. request.GetRowLength(),
  1687. Cols.GetReference(),
  1688. Pidmap.GetReference() );
  1689. #ifdef _WIN64
  1690. }
  1691. #endif
  1692. return stateContinue;
  1693. } //DoSetBindings
  1694. #ifdef _WIN64
  1695. //+-------------------------------------------------------------------------
  1696. //
  1697. // Member: CRequestServer::FixColumns, private
  1698. //
  1699. // Synopsis: Adjusts a Win32 column description to a Win64 column description
  1700. // and saves both descriptions
  1701. //
  1702. // Arguments: [pCols32] - 32 bit table column set description
  1703. //
  1704. // History: 12-Nov-99 KLam Created.
  1705. //
  1706. //--------------------------------------------------------------------------
  1707. void CRequestServer::FixColumns ( CTableColumnSet * pCols32 )
  1708. {
  1709. USHORT iEnd = 0;
  1710. USHORT iAlignment;
  1711. // Make sure these were freed from FreeQuery
  1712. if ( !_xCols64.IsNull() && !_xCols32.IsNull() )
  1713. THROW ( CException( STATUS_INVALID_PARAMETER ) );
  1714. // Create a 64 bit column description
  1715. _xCols64.Set( new CTableColumnSet ( pCols32->Count() ) );
  1716. _xCols32.Set( pCols32 );
  1717. for (unsigned iCol = 0; iCol < _xCols32->Count(); iCol++)
  1718. {
  1719. CTableColumn *pColumn = _xCols32->Get(iCol);
  1720. VARTYPE vt = pColumn->GetStoredType();
  1721. Win4Assert ( VT_VARIANT == vt|| VT_I4 == vt );
  1722. XPtr<CTableColumn> xColumn64 (new CTableColumn( iCol ));
  1723. if ( pColumn->IsValueStored() )
  1724. {
  1725. prxDebugOut(( DEB_ITRACE,
  1726. "\n\tFound value type: %d width: %d offset: %d\n",
  1727. pColumn->GetStoredType(), pColumn->GetValueSize(), pColumn->GetValueOffset() ));
  1728. if ( VT_VARIANT == vt )
  1729. {
  1730. iAlignment = (USHORT)AlignBlock ( iEnd, sizeof(LONGLONG) );
  1731. iEnd = iAlignment + sizeof (PROPVARIANT);
  1732. xColumn64->SetValueField( VT_VARIANT,
  1733. iAlignment,
  1734. sizeof (PROPVARIANT) );
  1735. }
  1736. else if ( VT_I4 == vt )
  1737. {
  1738. iAlignment = (USHORT)AlignBlock ( iEnd, sizeof(ULONG) );
  1739. iEnd = iAlignment + sizeof (ULONG);
  1740. xColumn64->SetValueField( VT_I4,
  1741. iAlignment,
  1742. sizeof (ULONG) );
  1743. }
  1744. prxDebugOut(( DEB_ITRACE,
  1745. "\t Replacing with width: %d offset: %d\n",
  1746. xColumn64->GetValueSize(), xColumn64->GetValueOffset() ));
  1747. }
  1748. if ( pColumn->IsStatusStored() )
  1749. {
  1750. prxDebugOut(( DEB_ITRACE,
  1751. "\tFound status width: %d offset: %d\n",
  1752. pColumn->GetStatusSize(), pColumn->GetStatusOffset() ));
  1753. iAlignment = (USHORT)AlignBlock ( iEnd, sizeof (BYTE) );
  1754. iEnd = iAlignment + sizeof (BYTE);
  1755. xColumn64->SetStatusField( iAlignment, sizeof (BYTE) );
  1756. prxDebugOut(( DEB_ITRACE,
  1757. "\t Replacing with width: %d offset: %d\n",
  1758. xColumn64->GetStatusSize(), xColumn64->GetStatusOffset() ));
  1759. }
  1760. if ( pColumn->IsLengthStored() )
  1761. {
  1762. prxDebugOut(( DEB_ITRACE,
  1763. "\tFound length width: %d offset: %d\n",
  1764. pColumn->GetLengthSize(), pColumn->GetLengthOffset() ));
  1765. iAlignment = (USHORT)AlignBlock ( iEnd, sizeof (ULONG) );
  1766. iEnd = iAlignment + sizeof (ULONG);
  1767. xColumn64->SetLengthField( iAlignment, sizeof (ULONG) );
  1768. prxDebugOut(( DEB_ITRACE,
  1769. "\t Replacing with width: %d offset: %d\n",
  1770. xColumn64->GetLengthSize(), xColumn64->GetLengthOffset() ));
  1771. }
  1772. // Store the column in the column set
  1773. _xCols64->Add( xColumn64.GetPointer(), iCol );
  1774. xColumn64.Acquire();
  1775. }
  1776. _cbRowWidth64 = AlignBlock( iEnd, sizeof(ULONGLONG) );
  1777. } // FixColumns
  1778. #endif // _WIN64
  1779. //+-------------------------------------------------------------------------
  1780. //
  1781. // Member: CRequestServer::DoGetNotify, private
  1782. //
  1783. // Synopsis: Handles a get notify message.
  1784. //
  1785. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1786. // [cbToWrite] - On output, set to the # of bytes to write if
  1787. // other than sizeof CProxyMessage.
  1788. //
  1789. // History: 16-Sep-96 dlee Created.
  1790. //
  1791. //--------------------------------------------------------------------------
  1792. RequestState CRequestServer::DoGetNotify(
  1793. DWORD cbRequest,
  1794. DWORD & cbToWrite )
  1795. {
  1796. // _pQuery will be zero if the notify thread comes in after the last
  1797. // FreeCursor. This is a rare non-fatal condition and it is ok to
  1798. // throw an error.
  1799. if ( 0 == _pQuery )
  1800. QUIETTHROW( CException( STATUS_INVALID_PARAMETER ) );
  1801. CProxyMessage &msg = * (CProxyMessage *) _Buffer();
  1802. Win4Assert( pmGetNotify == msg.GetMessage() );
  1803. CNotificationSync sync( this );
  1804. DBWATCHNOTIFY wn;
  1805. SCODE sc = _pQuery->GetNotifications( sync, wn );
  1806. // If STATUS_PENDING, just return the pmGetNotify and the client will
  1807. // be expecting 0 or 1 pmSendNotify messages at some later time.
  1808. // Otherwise, the notification is available and it is returned here.
  1809. if ( STATUS_PENDING != sc )
  1810. {
  1811. Win4Assert( S_OK == sc ); // GetNotifications throws on failure
  1812. CPMSendNotifyOut *pReply = new( _Buffer() ) CPMSendNotifyOut( wn );
  1813. cbToWrite = sizeof CPMSendNotifyOut;
  1814. }
  1815. return stateContinue;
  1816. } //DoGetNotify
  1817. //+-------------------------------------------------------------------------
  1818. //
  1819. // Member: CRequestServer::DoSendNotify, private
  1820. //
  1821. // Synopsis: Handles a send notify message.
  1822. //
  1823. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1824. // [cbToWrite] - On output, set to the # of bytes to write if
  1825. // other than sizeof CProxyMessage.
  1826. //
  1827. // History: 16-Sep-96 dlee Created.
  1828. //
  1829. //--------------------------------------------------------------------------
  1830. RequestState CRequestServer::DoSendNotify(
  1831. DWORD cbRequest,
  1832. DWORD & cbToWrite )
  1833. {
  1834. Win4Assert( FALSE && !"pmSendNotify is server to client only!" );
  1835. return stateDisconnect;
  1836. } //DoSendNotify
  1837. //+-------------------------------------------------------------------------
  1838. //
  1839. // Member: CRequestServer::DoSetWatchMode, private
  1840. //
  1841. // Synopsis: Handles a set watch mode message.
  1842. //
  1843. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1844. // [cbToWrite] - On output, set to the # of bytes to write if
  1845. // other than sizeof CProxyMessage.
  1846. //
  1847. // History: 16-Sep-96 dlee Created.
  1848. //
  1849. //--------------------------------------------------------------------------
  1850. RequestState CRequestServer::DoSetWatchMode(
  1851. DWORD cbRequest,
  1852. DWORD & cbToWrite )
  1853. {
  1854. if ( 0 == _pQuery )
  1855. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1856. CPMSetWatchModeIn &request = * (CPMSetWatchModeIn *) _Buffer();
  1857. HWATCHREGION hRegion = request.GetRegion();
  1858. _pQuery->SetWatchMode( &hRegion, request.GetMode() );
  1859. CPMSetWatchModeOut &reply = * (CPMSetWatchModeOut *) _Buffer();
  1860. reply.Region() = hRegion;
  1861. cbToWrite = sizeof reply;
  1862. return stateContinue;
  1863. } //DoSetWatchMode
  1864. //+-------------------------------------------------------------------------
  1865. //
  1866. // Member: CRequestServer::DoGetWatchInfo, private
  1867. //
  1868. // Synopsis: Handles a get watch info message.
  1869. //
  1870. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1871. // [cbToWrite] - On output, set to the # of bytes to write if
  1872. // other than sizeof CProxyMessage.
  1873. //
  1874. // History: 16-Sep-96 dlee Created.
  1875. //
  1876. //--------------------------------------------------------------------------
  1877. RequestState CRequestServer::DoGetWatchInfo(
  1878. DWORD cbRequest,
  1879. DWORD & cbToWrite )
  1880. {
  1881. if ( 0 == _pQuery )
  1882. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1883. CPMGetWatchInfoIn &request = * (CPMGetWatchInfoIn *) _Buffer();
  1884. CPMGetWatchInfoOut &reply = * (CPMGetWatchInfoOut *) _Buffer();
  1885. DBCOUNTITEM cRows;
  1886. _pQuery->GetWatchInfo( request.GetRegion(),
  1887. & reply.Mode(),
  1888. & reply.Chapter(),
  1889. & reply.Bookmark(),
  1890. & cRows );
  1891. reply.RowCount() = (ULONG) cRows;
  1892. cbToWrite = sizeof reply;
  1893. return stateContinue;
  1894. } //DoGetWatchInfo
  1895. //+-------------------------------------------------------------------------
  1896. //
  1897. // Member: CRequestServer::DoShrinkWatchRegion, private
  1898. //
  1899. // Synopsis: Handles a shrink watch region message.
  1900. //
  1901. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1902. // [cbToWrite] - On output, set to the # of bytes to write if
  1903. // other than sizeof CProxyMessage.
  1904. //
  1905. // History: 16-Sep-96 dlee Created.
  1906. //
  1907. //--------------------------------------------------------------------------
  1908. RequestState CRequestServer::DoShrinkWatchRegion(
  1909. DWORD cbRequest,
  1910. DWORD & cbToWrite )
  1911. {
  1912. if ( 0 == _pQuery )
  1913. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1914. CPMShrinkWatchRegionIn &request = * (CPMShrinkWatchRegionIn *) _Buffer();
  1915. _pQuery->ShrinkWatchRegion( request.GetRegion(),
  1916. request.GetChapter(),
  1917. request.GetBookmark(),
  1918. request.GetRowCount() );
  1919. return stateContinue;
  1920. } //DoShrinkWatchRegion
  1921. //+-------------------------------------------------------------------------
  1922. //
  1923. // Member: CRequestServer::DoRefresh, private
  1924. //
  1925. // Synopsis: Handles a refresh message.
  1926. //
  1927. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1928. // [cbToWrite] - On output, set to the # of bytes to write if
  1929. // other than sizeof CProxyMessage.
  1930. //
  1931. // History: 16-Sep-96 dlee Created.
  1932. //
  1933. //--------------------------------------------------------------------------
  1934. RequestState CRequestServer::DoRefresh(
  1935. DWORD cbRequest,
  1936. DWORD & cbToWrite )
  1937. {
  1938. if ( 0 == _pQuery )
  1939. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1940. _pQuery->Refresh();
  1941. return stateContinue;
  1942. } //DoRefresh
  1943. //+-------------------------------------------------------------------------
  1944. //
  1945. // Member: CRequestServer::DoGetQueryStatus, private
  1946. //
  1947. // Synopsis: Handles a get query status message.
  1948. //
  1949. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1950. // [cbToWrite] - On output, set to the # of bytes to write if
  1951. // other than sizeof CProxyMessage.
  1952. //
  1953. // History: 16-Sep-96 dlee Created.
  1954. //
  1955. //--------------------------------------------------------------------------
  1956. RequestState CRequestServer::DoGetQueryStatus(
  1957. DWORD cbRequest,
  1958. DWORD & cbToWrite )
  1959. {
  1960. if ( 0 == _pQuery )
  1961. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1962. CPMGetQueryStatusIn &request = * (CPMGetQueryStatusIn *) _Buffer();
  1963. CPMGetQueryStatusOut &reply = * (CPMGetQueryStatusOut *) _Buffer();
  1964. _pQuery->GetQueryStatus( request.GetCursor(),
  1965. reply.QueryStatus() );
  1966. cbToWrite = sizeof reply;
  1967. return stateContinue;
  1968. } //DoGetQueryStatus
  1969. //+-------------------------------------------------------------------------
  1970. //
  1971. // Member: CRequestServer::DoGetQueryStatusEx, private
  1972. //
  1973. // Synopsis: Handles a get query status message.
  1974. //
  1975. // Arguments: [cbRequest] - Size of the request in _Buffer()
  1976. // [cbToWrite] - On output, set to the # of bytes to write if
  1977. // other than sizeof CProxyMessage.
  1978. //
  1979. // History: 16-Sep-96 dlee Created.
  1980. //
  1981. //--------------------------------------------------------------------------
  1982. RequestState CRequestServer::DoGetQueryStatusEx(
  1983. DWORD cbRequest,
  1984. DWORD & cbToWrite )
  1985. {
  1986. if ( 0 == _pQuery )
  1987. THROW( CException( STATUS_INVALID_PARAMETER ) );
  1988. CPMGetQueryStatusExIn &request = * (CPMGetQueryStatusExIn *) _Buffer();
  1989. CPMGetQueryStatusExOut &reply = * (CPMGetQueryStatusExOut *) _Buffer();
  1990. DBCOUNTITEM den, num, iBmk, cRows;
  1991. _pQuery->GetQueryStatusEx( request.GetCursor(),
  1992. reply.QueryStatus(),
  1993. reply.FilteredDocuments(),
  1994. reply.DocumentsToFilter(),
  1995. den,
  1996. num,
  1997. request.GetBookmark(),
  1998. iBmk,
  1999. cRows );
  2000. reply.RatioFinishedDenominator() = (ULONG) den;
  2001. reply.RatioFinishedNumerator() = (ULONG) num;
  2002. reply.RowBmk() = (ULONG) iBmk;
  2003. reply.RowsTotal() = (ULONG) cRows;
  2004. cbToWrite = sizeof reply;
  2005. return stateContinue;
  2006. } //DoGetQueryStatusEx
  2007. //+-------------------------------------------------------------------------
  2008. //
  2009. // Member: CRequestServer::DoCiState, private
  2010. //
  2011. // Synopsis: Handles a ci state message.
  2012. //
  2013. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2014. // [cbToWrite] - On output, set to the # of bytes to write if
  2015. // other than sizeof CProxyMessage.
  2016. //
  2017. // History: 16-Sep-96 dlee Created.
  2018. //
  2019. //--------------------------------------------------------------------------
  2020. RequestState CRequestServer::DoCiState(
  2021. DWORD cbRequest,
  2022. DWORD & cbToWrite )
  2023. {
  2024. CPMCiStateInOut &request = * (CPMCiStateInOut *) _Buffer();
  2025. if ( _xDocStore.IsNull() )
  2026. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2027. XInterface<IFsCiAdmin> xFsCiAdmin;
  2028. SCODE sc = _xDocStore->QueryInterface( IID_IFsCiAdmin,
  2029. xFsCiAdmin.GetQIPointer() );
  2030. if ( S_OK == sc )
  2031. {
  2032. sc = xFsCiAdmin->CiState( &(request.GetState()) );
  2033. request.SetStatus( sc );
  2034. }
  2035. cbToWrite = sizeof CProxyMessage + request.GetState().cbStruct;
  2036. return stateContinue;
  2037. } //DoCiState
  2038. //+-------------------------------------------------------------------------
  2039. //
  2040. // Member: CRequestServer::DoObsolete, private
  2041. //
  2042. // Synopsis: Handles an obsolete message
  2043. //
  2044. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2045. // [cbToWrite] - On output, set to the # of bytes to write if
  2046. // other than sizeof CProxyMessage.
  2047. //
  2048. // History: 16-Sep-96 dlee Created.
  2049. //
  2050. //--------------------------------------------------------------------------
  2051. RequestState CRequestServer::DoObsolete(
  2052. DWORD cbRequest,
  2053. DWORD & cbToWrite )
  2054. {
  2055. // This request is obsolete
  2056. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2057. return stateDisconnect;
  2058. } //DoObsolete
  2059. //+-------------------------------------------------------------------------
  2060. //
  2061. // Member: CRequestServer::DoForceMerge, private
  2062. //
  2063. // Synopsis: Handles a force merge message.
  2064. //
  2065. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2066. // [cbToWrite] - On output, set to the # of bytes to write if
  2067. // other than sizeof CProxyMessage.
  2068. //
  2069. // History: 16-Sep-96 dlee Created.
  2070. //
  2071. //--------------------------------------------------------------------------
  2072. RequestState CRequestServer::DoForceMerge(
  2073. DWORD cbRequest,
  2074. DWORD & cbToWrite )
  2075. {
  2076. VerifyThreadHasAdminPrivilege();
  2077. if ( _xDocStore.IsNull() )
  2078. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2079. CPMForceMergeIn &request = * (CPMForceMergeIn *) _Buffer();
  2080. XInterface<IFsCiAdmin> xFsCiAdmin;
  2081. SCODE sc = _xDocStore->QueryInterface( IID_IFsCiAdmin,
  2082. xFsCiAdmin.GetQIPointer() );
  2083. if ( SUCCEEDED(sc) )
  2084. sc = xFsCiAdmin->ForceMerge( request.GetPartID() );
  2085. if ( !SUCCEEDED(sc) )
  2086. THROW( CException(sc) );
  2087. return stateContinue;
  2088. } //DoForceMerge
  2089. //+-------------------------------------------------------------------------
  2090. //
  2091. // Member: CRequestServer::DoAbortMerge, private
  2092. //
  2093. // Synopsis: Handles an abort merge message.
  2094. //
  2095. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2096. // [cbToWrite] - On output, set to the # of bytes to write if
  2097. // other than sizeof CProxyMessage.
  2098. //
  2099. // History: 16-Sep-96 dlee Created.
  2100. //
  2101. //--------------------------------------------------------------------------
  2102. RequestState CRequestServer::DoAbortMerge(
  2103. DWORD cbRequest,
  2104. DWORD & cbToWrite )
  2105. {
  2106. VerifyThreadHasAdminPrivilege();
  2107. if ( _xDocStore.IsNull() )
  2108. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2109. CPMAbortMergeIn &request = * (CPMAbortMergeIn *) _Buffer();
  2110. XInterface<IFsCiAdmin> xFsCiAdmin;
  2111. SCODE sc = _xDocStore->QueryInterface( IID_IFsCiAdmin,
  2112. xFsCiAdmin.GetQIPointer() );
  2113. if ( SUCCEEDED(sc) )
  2114. sc = xFsCiAdmin->AbortMerge( request.GetPartID() );
  2115. if ( !SUCCEEDED(sc) )
  2116. THROW( CException(sc) );
  2117. return stateContinue;
  2118. } //DoAbortMerge
  2119. //+-------------------------------------------------------------------------
  2120. //
  2121. // Member: CRequestServer::DoSetCatState, private
  2122. //
  2123. // Synopsis: Handles a SetCiCatState message.
  2124. //
  2125. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2126. // [cbToWrite] - On output, set to the # of bytes to write if
  2127. // other than sizeof CProxyMessage.
  2128. //
  2129. // History: 14-Apr-98 kitmanh Created.
  2130. //
  2131. //--------------------------------------------------------------------------
  2132. RequestState CRequestServer::DoSetCatState(
  2133. DWORD cbRequest,
  2134. DWORD & cbToWrite )
  2135. {
  2136. ciDebugOut(( DEB_ITRACE, "DoSetCatState is called\n" ));
  2137. VerifyThreadHasAdminPrivilege();
  2138. CPMSetCatStateIn &request = * (CPMSetCatStateIn *) _Buffer();
  2139. CPMSetCatStateOut &reply = * (CPMSetCatStateOut *) _Buffer();
  2140. XInterface<ICiCDocStoreLocator> xLocator( _requestQueue.DocStoreLocator() );
  2141. Win4Assert( !xLocator.IsNull() );
  2142. BOOL fAbsUnWritable = FALSE; //temp value
  2143. DWORD dwOldState;
  2144. // hack to check if all catalogs are up, catalog name is ignored
  2145. if ( CICAT_ALL_OPENED == request.GetNewState() )
  2146. {
  2147. reply.GetOldState() = _requestQueue.AreDocStoresOpen(); // make a constant
  2148. cbToWrite = sizeof reply;
  2149. return stateContinue;
  2150. }
  2151. // end of hack
  2152. ICiCDocStore * pDocStore = 0;
  2153. // Make sure we have a valid catalog name
  2154. WCHAR *szCatalog = request.GetCatName();
  2155. if ( 0 == szCatalog )
  2156. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2157. unsigned cwc = wcslen( szCatalog );
  2158. if ( ( 0 == cwc) || ( cwc >= ( MAX_PATH-1 ) ) )
  2159. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2160. // check old state of docstore
  2161. SCODE sc = xLocator->GetDocStoreState( szCatalog,
  2162. &pDocStore,
  2163. &dwOldState );
  2164. reply.GetOldState() = dwOldState;
  2165. if ( SUCCEEDED(sc) )
  2166. {
  2167. _xDocStore.Set( pDocStore );
  2168. if ( 0 != pDocStore )
  2169. {
  2170. // This QI is just about guaranteed to work.
  2171. XInterface<ICiCAdviseStatus> xAdviseStatus;
  2172. sc = pDocStore->QueryInterface( IID_ICiCAdviseStatus,
  2173. xAdviseStatus.GetQIPointer() );
  2174. if ( S_OK != sc )
  2175. THROW( CException(sc) );
  2176. xAdviseStatus->IncrementPerfCounterValue( CI_PERF_RUNNING_QUERIES );
  2177. }
  2178. //Push an item onto the _stateChangeArray for the (make this a function name DoDisConnect
  2179. SCWorkItem newItem;
  2180. ciDebugOut(( DEB_ITRACE, "request.GetNewState == %d\n", request.GetNewState() ));
  2181. switch ( request.GetNewState() )
  2182. {
  2183. case CICAT_GET_STATE:
  2184. break;
  2185. case CICAT_STOPPED:
  2186. if ( 0 == (CICAT_STOPPED & dwOldState) )
  2187. {
  2188. newItem.type = eStopCat;
  2189. newItem.pDocStore = _xDocStore.GetPointer();
  2190. _requestQueue.AddSCItem( &newItem , 0 );
  2191. xLocator->AddStoppedCat( dwOldState, request.GetCatName() );
  2192. CLock lock( g_mtxStartStop );
  2193. sc = StopFWCiSvcWork( eStopCat );
  2194. }
  2195. break;
  2196. case CICAT_READONLY:
  2197. ciDebugOut(( DEB_ITRACE, "New state is CICAT_READONLY\n" ));
  2198. if ( 0 == (CICAT_READONLY & dwOldState) )
  2199. {
  2200. newItem.type = eCatRO;
  2201. newItem.pDocStore = _xDocStore.GetPointer();
  2202. if ( 0 != (CICAT_STOPPED & dwOldState) )
  2203. {
  2204. ciDebugOut(( DEB_ITRACE, "DoSetCatState, restarting a stopped cat\n" ));
  2205. ciDebugOut(( DEB_ITRACE, "DoSetCatState.. newItem.StoppedCat is %ws\n", request.GetCatName() ));
  2206. _requestQueue.AddSCItem( &newItem, request.GetCatName() );
  2207. }
  2208. else
  2209. _requestQueue.AddSCItem( &newItem , 0 );
  2210. CLock lock( g_mtxStartStop );
  2211. sc = StopFWCiSvcWork( eCatRO );
  2212. }
  2213. ciDebugOut(( DEB_ITRACE, "Done setting CICAT_READONLY\n" ));
  2214. break;
  2215. case CICAT_WRITABLE:
  2216. if ( 0 == (CICAT_WRITABLE & dwOldState) )
  2217. {
  2218. sc = xLocator->IsMarkedReadOnly( request.GetCatName(), &fAbsUnWritable );
  2219. if ( FAILED(sc) )
  2220. THROW( CException(sc) );
  2221. ciDebugOut(( DEB_ITRACE, "DoSetCatState.. IsMarkedReadOnly is %d\n", fAbsUnWritable ));
  2222. if ( CICAT_STOPPED == dwOldState )
  2223. {
  2224. if ( !fAbsUnWritable )
  2225. {
  2226. sc = xLocator->IsVolumeOrDirRO( request.GetCatName(), &fAbsUnWritable );
  2227. if ( FAILED(sc) )
  2228. THROW( CException(sc) );
  2229. }
  2230. ciDebugOut(( DEB_ITRACE, "DoSetCatState.. fAbsUnWritable is %d\n", fAbsUnWritable ));
  2231. }
  2232. if ( fAbsUnWritable )
  2233. {
  2234. //Catalog cannot be open for r/w, open as r/o instead
  2235. //can't throw, must finish work
  2236. newItem.type = eCatRO;
  2237. }
  2238. else
  2239. newItem.type = eCatW;
  2240. newItem.pDocStore = _xDocStore.GetPointer();
  2241. if ( CICAT_STOPPED == dwOldState )
  2242. {
  2243. ciDebugOut(( DEB_ITRACE, "DoSetCatState, restarting a stopped cat\n" ));
  2244. ciDebugOut(( DEB_ITRACE, "DoSetCatState.. newItem.StoppedCat is %ws\n", request.GetCatName() ));
  2245. _requestQueue.AddSCItem( &newItem, request.GetCatName() );
  2246. }
  2247. else
  2248. _requestQueue.AddSCItem( &newItem, 0 );
  2249. CLock lock( g_mtxStartStop );
  2250. sc = StopFWCiSvcWork( newItem.type );
  2251. }
  2252. break;
  2253. case CICAT_NO_QUERY:
  2254. if ( 0 == (CICAT_NO_QUERY & dwOldState) )
  2255. {
  2256. newItem.type = eNoQuery;
  2257. sc = xLocator->IsMarkedReadOnly( request.GetCatName(), &fAbsUnWritable );
  2258. if ( FAILED(sc) )
  2259. THROW( CException(sc) );
  2260. ciDebugOut(( DEB_ITRACE, "DoSetCatState.. IsMarkedReadOnly is %d\n", fAbsUnWritable ));
  2261. if ( 0 != (CICAT_STOPPED & dwOldState) )
  2262. {
  2263. if ( !fAbsUnWritable )
  2264. {
  2265. sc = xLocator->IsVolumeOrDirRO( request.GetCatName(), &fAbsUnWritable );
  2266. if ( FAILED(sc) )
  2267. THROW( CException(sc) );
  2268. }
  2269. ciDebugOut(( DEB_ITRACE, "DoSetCatState(NoQuery).. fAbsUnWritable is %d\n", fAbsUnWritable ));
  2270. }
  2271. if ( fAbsUnWritable )
  2272. {
  2273. //The catalog is absolutely unwritable, opening for ReadOnly instead
  2274. //can't throw here, since work needs to be done.
  2275. newItem.fNoQueryRW = FALSE;
  2276. }
  2277. else
  2278. newItem.fNoQueryRW = TRUE;
  2279. newItem.pDocStore = _xDocStore.GetPointer();
  2280. if ( 0 != (CICAT_STOPPED & dwOldState) )
  2281. _requestQueue.AddSCItem( &newItem, request.GetCatName() );
  2282. else
  2283. _requestQueue.AddSCItem( &newItem, 0 );
  2284. CLock lock( g_mtxStartStop );
  2285. sc = StopFWCiSvcWork( newItem.type );
  2286. }
  2287. break;
  2288. default:
  2289. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2290. }
  2291. }
  2292. ciDebugOut(( DEB_ITRACE, "DoSetCatState sc is %d or %#x\n", sc ));
  2293. if ( !SUCCEEDED(sc) )
  2294. THROW( CException(sc) );
  2295. cbToWrite = sizeof reply;
  2296. return stateContinue;
  2297. } //DoSetCatState
  2298. //+-------------------------------------------------------------------------
  2299. //
  2300. // Member: CRequestServer::DoFetchValue, private
  2301. //
  2302. // Synopsis: Retrieves a value from the property cache
  2303. //
  2304. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2305. // [cbToWrite] - On output, set to the # of bytes to write if
  2306. // other than sizeof CProxyMessage.
  2307. //
  2308. // History: 16-Sep-96 dlee Created.
  2309. //
  2310. //--------------------------------------------------------------------------
  2311. RequestState CRequestServer::DoFetchValue(
  2312. DWORD cbRequest,
  2313. DWORD & cbToWrite )
  2314. {
  2315. if ( 0 == _pQuery )
  2316. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2317. CPMFetchValueIn &request = * (CPMFetchValueIn *) _Buffer();
  2318. request.ValidateCheckSum( GetClientVersion(), cbRequest );
  2319. WORKID wid = request.GetWID();
  2320. DWORD cbSoFar = request.GetSoFar();
  2321. DWORD cbPropSpec = request.GetPSSize();
  2322. DWORD cbChunk = request.GetChunkSize();
  2323. // if this is the first request for the value, fetch the value
  2324. if ( 0 == cbSoFar )
  2325. {
  2326. _xFetchedValue.Free();
  2327. _cbFetchedValueSoFar = 0;
  2328. Win4Assert( isQWordAligned( request.GetPS() ) );
  2329. CMemDeSerStream stmDeser( request.GetPS(), cbPropSpec );
  2330. CFullPropSpec ps( stmDeser );
  2331. if ( !ps.IsValid() )
  2332. THROW( CException( E_OUTOFMEMORY ) );
  2333. PROPVARIANT var;
  2334. if ( !_pQuery->FetchDeferredValue( wid, ps, var ) || var.vt == VT_EMPTY )
  2335. {
  2336. //
  2337. // FetchDeferredValue does a security check to make sure the client has access
  2338. // to this wid. A hacker could pass in a wid not returned in a query.
  2339. //
  2340. CPMFetchValueOut &reply = * (CPMFetchValueOut *) _Buffer();
  2341. reply.ValueExists() = FALSE;
  2342. cbToWrite = sizeof reply;
  2343. return stateContinue;
  2344. }
  2345. // marshall the property value and save it in _xFetchedValue
  2346. SPropVariant xvar( &var );
  2347. ULONG cb = 0;
  2348. StgConvertVariantToProperty( &var,
  2349. CP_WINUNICODE,
  2350. 0,
  2351. &cb,
  2352. pidInvalid,
  2353. FALSE,
  2354. 0 );
  2355. _xFetchedValue.Init( cb );
  2356. StgConvertVariantToProperty( &var,
  2357. CP_WINUNICODE,
  2358. (SERIALIZEDPROPERTYVALUE *)_xFetchedValue.Get(),
  2359. &cb,
  2360. pidInvalid,
  2361. FALSE,
  2362. 0 );
  2363. }
  2364. // send a chunk (or all) of the marshalled property value
  2365. Win4Assert( cbSoFar == _cbFetchedValueSoFar );
  2366. Win4Assert( 0 != _xFetchedValue.Get() );
  2367. DWORD cbToGo = _xFetchedValue.SizeOf() - _cbFetchedValueSoFar;
  2368. Win4Assert( sizeof CPMFetchValueOut < cbChunk );
  2369. DWORD cbValToWrite = __min( cbChunk - sizeof CPMFetchValueOut, cbToGo );
  2370. cbToWrite = sizeof CPMFetchValueOut + cbValToWrite;
  2371. CPMFetchValueOut *pReply;
  2372. if ( cbToWrite <= _BufferSize() )
  2373. {
  2374. pReply = (CPMFetchValueOut *) _Buffer();
  2375. }
  2376. else
  2377. {
  2378. _xTempBuffer.Init( cbToWrite );
  2379. pReply = new( _xTempBuffer.Get() ) CPMFetchValueOut;
  2380. }
  2381. pReply->ValueExists() = TRUE;
  2382. pReply->ValueSize() = cbValToWrite;
  2383. pReply->MoreExists() = ( cbValToWrite != cbToGo );
  2384. RtlCopyMemory( pReply->Value(),
  2385. _xFetchedValue.Get() + _cbFetchedValueSoFar,
  2386. cbValToWrite );
  2387. _cbFetchedValueSoFar += cbValToWrite;
  2388. if ( !pReply->MoreExists() )
  2389. {
  2390. _xFetchedValue.Free();
  2391. _cbFetchedValueSoFar = 0;
  2392. }
  2393. return stateContinue;
  2394. } //DoFetchValue
  2395. //+-------------------------------------------------------------------------
  2396. //
  2397. // Member: CRequestServer::DoWorkIdToPath, private
  2398. //
  2399. // Synopsis: Converts a wid to a path.
  2400. //
  2401. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2402. // [cbToWrite] - On output, set to the # of bytes to write if
  2403. // other than sizeof CProxyMessage.
  2404. //
  2405. // History: 16-Sep-96 dlee Created.
  2406. //
  2407. //--------------------------------------------------------------------------
  2408. RequestState CRequestServer::DoWorkIdToPath(
  2409. DWORD cbRequest,
  2410. DWORD & cbToWrite )
  2411. {
  2412. if ( 0 == _pQuery )
  2413. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2414. CPMWorkIdToPathIn &request = * (CPMWorkIdToPathIn *) _Buffer();
  2415. CFunnyPath funnyPath;
  2416. _pQuery->WorkIdToPath( request.GetWorkId(), funnyPath );
  2417. CPMWorkIdToPathOut &reply = * (CPMWorkIdToPathOut *) _Buffer();
  2418. cbToWrite = sizeof reply;
  2419. if ( 0 != funnyPath.GetActualLength() )
  2420. {
  2421. reply.Any() = TRUE;
  2422. ULONG cbPath = (funnyPath.GetActualLength()+1) * sizeof(WCHAR);
  2423. RtlCopyMemory( reply.Path(), funnyPath.GetActualPath(), cbPath );
  2424. cbToWrite += cbPath;
  2425. }
  2426. else
  2427. {
  2428. reply.Any() = FALSE;
  2429. }
  2430. return stateContinue;
  2431. } //DoWorkIdToPath
  2432. //+-------------------------------------------------------------------------
  2433. //
  2434. // Member: CRequestServer::DoUpdateDocuments, private
  2435. //
  2436. // Synopsis: Handles an update documents message.
  2437. //
  2438. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2439. // [cbToWrite] - On output, set to the # of bytes to write if
  2440. // other than sizeof CProxyMessage.
  2441. //
  2442. // History: 16-Sep-96 dlee Created.
  2443. //
  2444. //--------------------------------------------------------------------------
  2445. RequestState CRequestServer::DoUpdateDocuments(
  2446. DWORD cbRequest,
  2447. DWORD & cbToWrite )
  2448. {
  2449. VerifyThreadHasAdminPrivilege();
  2450. if ( _xDocStore.IsNull() )
  2451. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2452. CPMUpdateDocumentsIn &request = * (CPMUpdateDocumentsIn *) _Buffer();
  2453. XInterface<IFsCiAdmin> xFsCiAdmin;
  2454. SCODE sc = _xDocStore->QueryInterface( IID_IFsCiAdmin,
  2455. xFsCiAdmin.GetQIPointer() );
  2456. if ( wcslen( request.GetRootPath() ) >= MAX_PATH )
  2457. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2458. if ( SUCCEEDED(sc) )
  2459. sc = xFsCiAdmin->UpdateDocuments( request.GetRootPath(),
  2460. request.GetFlag() );
  2461. if ( !SUCCEEDED(sc) )
  2462. THROW( CException(sc) );
  2463. return stateContinue;
  2464. } //DoUpdateDocuments
  2465. //+-------------------------------------------------------------------------
  2466. //
  2467. // Member: CRequestServer::HandleRequestNoThrow, private
  2468. //
  2469. // Synopsis: Processes a request. This method can't throw. If there
  2470. // is any problem with the request, set the status code
  2471. // in the message to reflect the problem.
  2472. //
  2473. // Arguments: [cbRequest] - Size of the request in _Buffer()
  2474. // [cbToWrite] - On output, set to the # of bytes to write if
  2475. // other than sizeof CProxyMessage.
  2476. //
  2477. // Returns: FALSE if the connection with the client should be terminated,
  2478. // TRUE otherwise.
  2479. //
  2480. // History: 16-Sep-96 dlee Created.
  2481. //
  2482. //--------------------------------------------------------------------------
  2483. RequestState CRequestServer::HandleRequestNoThrow(
  2484. DWORD cbRequest,
  2485. DWORD & cbToWrite )
  2486. {
  2487. // buffers must be 8-byte aligned on both sides of the proxy or the
  2488. // marshalling/unmarshalling will be inconsistent.
  2489. Win4Assert( isQWordAligned( _Buffer() ) );
  2490. CProxyMessage &msg = * (CProxyMessage *) _Buffer();
  2491. // Require that messages sent from clients have status set to S_OK,
  2492. // as the reply message is in the same buffer and there is no need
  2493. // to re-write the S_OK.
  2494. Win4Assert( S_OK == msg.GetStatus() );
  2495. RequestState state = stateContinue;
  2496. TRY
  2497. {
  2498. Win4Assert( _xTempBuffer.SizeOf() > _BufferSize() ||
  2499. _xTempBuffer.IsNull() );
  2500. int iMsg = msg.GetMessage() - pmConnect;
  2501. if ( ( iMsg < 0 ) || ( iMsg >= cProxyMessages ) )
  2502. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2503. // Don't impersonate when not necessary -- it's slow
  2504. XPipeImpersonation impersonate;
  2505. if ( _afImpersonate[ iMsg ] )
  2506. impersonate.Impersonate( GetPipe() );
  2507. SetLastTouchedTime( GetTickCount() );
  2508. state = ( this->*( _aMsgFunctions[ iMsg ] ) )( cbRequest,
  2509. cbToWrite );
  2510. prxDebugOut(( DEB_ITRACE,
  2511. "finish msg %d, cb %d, sc 0x%x, to pipe 0x%x\n",
  2512. msg.GetMessage(),
  2513. cbToWrite,
  2514. msg.GetStatus(),
  2515. GetPipe() ));
  2516. }
  2517. CATCH( CException, ex )
  2518. {
  2519. prxDebugOut(( DEB_ITRACE,
  2520. "HandleRequestNoThrow rs 0x%x msg %d caught 0x%x\n",
  2521. this,
  2522. msg.GetMessage(),
  2523. ex.GetErrorCode() ));
  2524. msg.SetStatus( ex.GetErrorCode() );
  2525. cbToWrite = sizeof CProxyMessage;
  2526. _xTempBuffer.Free();
  2527. }
  2528. END_CATCH;
  2529. return state;
  2530. } //HandleRequestNoThrow
  2531. //+-------------------------------------------------------------------------
  2532. //
  2533. // Member: CRequestServer::DoAPC, private
  2534. //
  2535. // Synopsis: This method is called when an i/o operation is completed,
  2536. // whether successfully or not. If there was an error,
  2537. // this method terminates the connection.
  2538. //
  2539. // Arguments: [dwError] - Win32 error code for i/o operation
  2540. // [cbTransferred] - # of bytes read or written
  2541. //
  2542. // History: 16-Sep-96 dlee Created.
  2543. //
  2544. //--------------------------------------------------------------------------
  2545. void CRequestServer::DoAPC(
  2546. DWORD dwError,
  2547. DWORD cbTransferred )
  2548. {
  2549. prxDebugOut(( DEB_ITRACE, "apc %s t 0x%x p 0x%x msg %d cb %d err %d\n",
  2550. pipeStateRead == _state ? "read" :
  2551. pipeStateWrite == _state ? "write" : "none",
  2552. GetCurrentThreadId(),
  2553. GetPipe(),
  2554. * (int *) _Buffer(),
  2555. cbTransferred,
  2556. dwError ));
  2557. // Ownership of the item is with the apc: either issue another i/o
  2558. // or recycle the request server.
  2559. TRY
  2560. {
  2561. //
  2562. // If we are recursing processing APCs, defer this APC.
  2563. // Why would we be processing APCs? Someone in the query path
  2564. // probably used RPC, and due to a bug in RPC we hit this.
  2565. //
  2566. if ( _pWorkThread->IsProcessingAPC() )
  2567. {
  2568. _dwDeferredAPCError = dwError;
  2569. _cbDeferredAPCTransferred = cbTransferred;
  2570. _pWorkThread->DeferAPC( this );
  2571. return;
  2572. }
  2573. //
  2574. // Mark the thread as busy processing an APC and addref it so the
  2575. // destructor can unmark it.
  2576. //
  2577. XAPCWorkerThread apcWorker( _workQueue, _pWorkThread );
  2578. // if the apc operation completed with an error, abort the connection
  2579. if ( 0 != dwError )
  2580. QUIETTHROW( CException( HRESULT_FROM_WIN32( dwError ) ) );
  2581. if ( IsBeingRemoved() )
  2582. THROW( CException( STATUS_TOO_LATE ) );
  2583. if ( pipeStateRead == _state )
  2584. {
  2585. // if the entire message didn't fit in the buffer (eg, there was
  2586. // a large restriction) read the rest of the message.
  2587. if ( _BufferSize() == cbTransferred )
  2588. {
  2589. prxDebugOut(( DEB_ITRACE, "more data available\n" ));
  2590. BYTE *p = ReadRemainingSync( _Buffer(), cbTransferred );
  2591. //
  2592. // ReadRemainingSync returns 0 if there was an exact fit
  2593. // into _Buffer, so there was nothing left to read.
  2594. //
  2595. if ( 0 != p )
  2596. {
  2597. _xTempBuffer.Set( cbTransferred, p );
  2598. prxDebugOut(( DEB_ITRACE, "total msg cb: %d\n",
  2599. cbTransferred ));
  2600. // Only certain msgs expect the input buffer to be in
  2601. // _xTempBuffer. Fail if it's not one of these msgs.
  2602. int pm = * (int *) _xTempBuffer.Get();
  2603. Win4Assert( ( pmCreateQuery == pm ) ||
  2604. ( pmConnect == pm ) ||
  2605. ( pmSetBindings == pm ) );
  2606. if ( pmCreateQuery != pm &&
  2607. pmConnect != pm &&
  2608. pmSetBindings != pm )
  2609. THROW( CException( STATUS_INVALID_PARAMETER ) );
  2610. }
  2611. }
  2612. #if CIDBG == 1
  2613. prxDebugOut(( DEB_PRX_MSGS,
  2614. "proxy read %d bytes at %p\n",
  2615. cbTransferred, _ActiveBuffer() ));
  2616. #endif // CIDBG == 1
  2617. #if CI_PIPE_TESTING
  2618. if ( 0 != _requestQueue._pTraceRead )
  2619. (*_requestQueue._pTraceRead)( GetPipe(),
  2620. cbTransferred,
  2621. _ActiveBuffer() );
  2622. #endif // CI_PIPE_TESTING
  2623. // The read completed, process the request
  2624. DWORD cbToWrite = sizeof CProxyMessage;
  2625. RequestState state = HandleRequestNoThrow( cbTransferred, cbToWrite );
  2626. if ( stateContinue == state )
  2627. {
  2628. Win4Assert( cbToWrite >= sizeof CProxyMessage );
  2629. Win4Assert( ( cbToWrite <= _BufferSize() ) ||
  2630. ( !_xTempBuffer.IsNull() ) );
  2631. Win4Assert( ( cbToWrite > _BufferSize() ) ||
  2632. ( _xTempBuffer.IsNull() ) );
  2633. Win4Assert( ( _xTempBuffer.IsNull() ) ||
  2634. ( cbToWrite == _xTempBuffer.SizeOf() ) );
  2635. _state = pipeStateWrite;
  2636. #if CIDBG == 1
  2637. prxDebugOut(( DEB_PRX_MSGS,
  2638. "proxy writing %d bytes at %p\n",
  2639. cbToWrite, _ActiveBuffer() ));
  2640. #endif // CIDBG == 1
  2641. void * pvToWrite = _ActiveBuffer();
  2642. #if CI_PIPE_TESTING
  2643. void * pvToWriteOrg = pvToWrite;
  2644. DWORD cbToWriteOrg = cbToWrite;
  2645. if ( 0 != _requestQueue._pTraceBefore )
  2646. (*_requestQueue._pTraceBefore)( GetPipe(),
  2647. cbToWriteOrg,
  2648. pvToWriteOrg,
  2649. cbToWrite,
  2650. pvToWrite );
  2651. #endif // CI_PIPE_TESTING
  2652. Write( pvToWrite, cbToWrite, APCRoutine );
  2653. #if CI_PIPE_TESTING
  2654. if ( 0 != _requestQueue._pTraceAfter )
  2655. (*_requestQueue._pTraceAfter)( GetPipe(),
  2656. cbToWriteOrg,
  2657. pvToWriteOrg,
  2658. cbToWrite,
  2659. pvToWrite );
  2660. #endif // CI_PIPE_TESTING
  2661. if ( IsBeingRemoved() )
  2662. CancelIO();
  2663. }
  2664. else if ( stateDisconnect == state )
  2665. {
  2666. Win4Assert( _xTempBuffer.IsNull() );
  2667. _state = pipeStateNone;
  2668. _requestQueue.RecycleRequestServerNoThrow( this );
  2669. }
  2670. else
  2671. {
  2672. Win4Assert( statePending == state );
  2673. }
  2674. }
  2675. else
  2676. {
  2677. Win4Assert( pipeStateWrite == _state );
  2678. // cleanup temp buffer if allocated for the write
  2679. _xTempBuffer.Free();
  2680. // the write completed, so schedule another read
  2681. _state = pipeStateRead;
  2682. Read( _Buffer(), _BufferSize(), APCRoutine );
  2683. if ( IsBeingRemoved() )
  2684. CancelIO();
  2685. }
  2686. }
  2687. CATCH( CException, ex )
  2688. {
  2689. prxDebugOut(( DEB_WARN,
  2690. "exception in APC error %#x, this %#x, pipe %#x\n",
  2691. ex.GetErrorCode(),
  2692. this,
  2693. GetPipe() ));
  2694. // disconnect the pipe (and the query if it exists)
  2695. _state = pipeStateNone;
  2696. _requestQueue.RecycleRequestServerNoThrow( this );
  2697. }
  2698. END_CATCH;
  2699. } //DoAPC
  2700. //+-------------------------------------------------------------------------
  2701. //
  2702. // Member: CRequestServer::APCRoutine, private, static
  2703. //
  2704. // Synopsis: This method is called when an i/o operation is completed.
  2705. //
  2706. // Arguments: [dwError] - Win32 error code for i/o operation
  2707. // [cbTransferred] - # of bytes read or written
  2708. // [pOverlapped] - Points to the overlapped for the i/o
  2709. //
  2710. // History: 16-Sep-96 dlee Created.
  2711. //
  2712. //--------------------------------------------------------------------------
  2713. void WINAPI CRequestServer::APCRoutine(
  2714. DWORD dwError,
  2715. DWORD cbTransferred,
  2716. LPOVERLAPPED pOverlapped )
  2717. {
  2718. // It would be a programming error to take an exception here, and it
  2719. // has never been hit. Leave the check in for checked builds.
  2720. #if CIDBG == 1
  2721. TRY
  2722. {
  2723. #endif
  2724. // The request server was saved in the hEvent field, which the
  2725. // Win32 doc says is a good place for a user's APC data
  2726. CRequestServer &serv = * (CRequestServer *) (CPipeServer *)
  2727. ( pOverlapped->hEvent );
  2728. serv.DoAPC( dwError, cbTransferred );
  2729. #if CIDBG == 1
  2730. }
  2731. CATCH( CException, e )
  2732. {
  2733. prxDebugOut(( DEB_ERROR, "exception in APCRoutine: 0x%x\n",
  2734. e.GetErrorCode() ));
  2735. Win4Assert( !"caught an unexpected exception in an apc" );
  2736. }
  2737. END_CATCH;
  2738. #endif
  2739. } //APCRoutine
  2740. //+-------------------------------------------------------------------------
  2741. //
  2742. // Member: CRequestServer::CancelAPCRoutine, private/static
  2743. //
  2744. // Synopsis: Called in an APC when a connection should be cancelled
  2745. //
  2746. // Arguments: [dwParam] - The request server
  2747. //
  2748. // History: 16-Sep-96 dlee Created.
  2749. //
  2750. //--------------------------------------------------------------------------
  2751. void WINAPI CRequestServer::CancelAPCRoutine(
  2752. DWORD_PTR dwParam )
  2753. {
  2754. TRY
  2755. {
  2756. CRequestServer * pServer = (CRequestServer *) dwParam;
  2757. XInterface<CRequestServer> xServer( pServer );
  2758. prxDebugOut(( DEB_ITRACE,
  2759. "Canceling server 0x%x io pipe 0x%x\n",
  2760. pServer, pServer->GetPipe() ));
  2761. // Freeing a pending query will result in the request server
  2762. // being cleaned up, since _fShutdown/BeingRemoved is TRUE.
  2763. // Cancelling pending IO will cause the IO APC routine to be
  2764. // called with an error completion status, which will clean up
  2765. // the request server.
  2766. if ( pipeStatePending == pServer->_state )
  2767. pServer->FreeQuery();
  2768. else if ( pipeStateNone != pServer->_state )
  2769. pServer->CancelIO();
  2770. }
  2771. CATCH( CException, e )
  2772. {
  2773. prxDebugOut(( DEB_ERROR, "cancelapc caught 0x%x\n",
  2774. e.GetErrorCode() ));
  2775. Win4Assert( !"CancelAPC caught an exception" );
  2776. }
  2777. END_CATCH
  2778. } //CancelAPCRoutine
  2779. //+-------------------------------------------------------------------------
  2780. //
  2781. // Member: CRequestServer::Quiesce, private
  2782. //
  2783. // Synopsis: Called by the APC when a query with notifications quiesces
  2784. //
  2785. // History: 16-Sep-96 dlee Created.
  2786. //
  2787. //--------------------------------------------------------------------------
  2788. void CRequestServer::Quiesce()
  2789. {
  2790. TRY
  2791. {
  2792. prxDebugOut(( DEB_ITRACE,
  2793. "Quiescing server 0x%x io pipe 0x%x\n",
  2794. this, GetPipe() ));
  2795. Win4Assert( pipeStatePending == _state );
  2796. // If we're shutting down or the server is disconnecting the client
  2797. // for being idle for too long, abort now.
  2798. if ( _requestQueue.IsShutdown() || IsBeingRemoved() )
  2799. THROW( CException( STATUS_TOO_LATE ) );
  2800. // the long-running operation completed, so do the write
  2801. _xTempBuffer.Free();
  2802. Win4Assert( 0 != _pQuery );
  2803. _state = pipeStateWrite;
  2804. //
  2805. // If the first call to Quiesce is to tell us that the asynch
  2806. // query execution failed, free the query.
  2807. //
  2808. if ( FAILED ( _scPendingStatus ) )
  2809. FreeQuery();
  2810. CProxyMessage &msg = * (CProxyMessage *) _Buffer();
  2811. msg.SetStatus( _scPendingStatus );
  2812. Write( (BYTE *) _Buffer(), _cbPendingWrite, APCRoutine );
  2813. // Note that the state of these may have changed after the check above
  2814. if ( IsBeingRemoved() )
  2815. CancelIO();
  2816. }
  2817. CATCH( CException, ex )
  2818. {
  2819. prxDebugOut(( DEB_ITRACE,
  2820. "quiesce write error 0x%x, pipe 0x%x\n",
  2821. ex.GetErrorCode(),
  2822. GetPipe() ));
  2823. _state = pipeStateNone;
  2824. _requestQueue.RecycleRequestServerNoThrow( this );
  2825. }
  2826. END_CATCH;
  2827. } //Quiesce
  2828. //+-------------------------------------------------------------------------
  2829. //
  2830. // Member: CRequestServer::QuiesceAPCRoutine, private/static
  2831. //
  2832. // Synopsis: Called in an APC when a query with notifications quiesces
  2833. //
  2834. // Arguments: [dwParam] - The request server
  2835. //
  2836. // History: 16-Sep-96 dlee Created.
  2837. //
  2838. //--------------------------------------------------------------------------
  2839. void WINAPI CRequestServer::QuiesceAPCRoutine(
  2840. ULONG_PTR dwParam )
  2841. {
  2842. CRequestServer & Server = * (CRequestServer *) dwParam;
  2843. Server.Quiesce();
  2844. } //QuiesceAPCRoutine
  2845. //+-------------------------------------------------------------------------
  2846. //
  2847. // Member: CRequestServer::QueryQuiesced, public
  2848. //
  2849. // Synopsis: Called when a synchronous query is quiesced, so the pending
  2850. // request can be completed by the thread that created the query.
  2851. //
  2852. // History: 16-Feb-97 dlee Created.
  2853. //
  2854. //--------------------------------------------------------------------------
  2855. void CRequestServer::QueryQuiesced(
  2856. BOOL fSuccess,
  2857. SCODE sc )
  2858. {
  2859. // only complete the work if the query is truly quiesced
  2860. if ( fSuccess || _requestQueue.IsShutdown() || IsBeingRemoved() )
  2861. {
  2862. Win4Assert( IsBeingRemoved() || 0 != _pQuery || _requestQueue.IsShutdown() );
  2863. Win4Assert( pipeStatePending == _state );
  2864. _scPendingStatus = sc;
  2865. _requestQueue.DecrementPendingItems();
  2866. QueueUserAPC( CRequestServer::QuiesceAPCRoutine,
  2867. GetWorkerThreadHandle(),
  2868. (ULONG_PTR) this );
  2869. }
  2870. } //QueryQuiesced
  2871. //+-------------------------------------------------------------------------
  2872. //
  2873. // Member: CRequestServer::CompleteNotification, public
  2874. //
  2875. // Synopsis: This is called by a query worker thread when a notification
  2876. // should be delivered to the client.
  2877. //
  2878. // Arguments: [dwChangeType] - The notification
  2879. //
  2880. // History: 16-Sep-96 dlee Created.
  2881. //
  2882. //--------------------------------------------------------------------------
  2883. void CRequestServer::CompleteNotification(
  2884. DWORD dwChangeType )
  2885. {
  2886. // _pQuery can be 0 if the query is in the process of being deleted,
  2887. // since _pQuery is set to 0 before it's actually deleted in FreeQuery(),
  2888. // and queries that haven't quiesced yet always quiesce on destruction.
  2889. if ( 0 != _pQuery )
  2890. {
  2891. CPMSendNotifyOut notify( dwChangeType );
  2892. WriteSync( &notify, sizeof notify );
  2893. }
  2894. } //CompleteNotification
  2895. //+-------------------------------------------------------------------------
  2896. //
  2897. // Member: CRequestServer::Cleanup, public
  2898. //
  2899. // Synopsis: Frees data and refcounts associated with the request server.
  2900. //
  2901. // History: 16-Sep-96 dlee Created.
  2902. //
  2903. //--------------------------------------------------------------------------
  2904. void CRequestServer::Cleanup()
  2905. {
  2906. FreeQuery();
  2907. _xTempBuffer.Free();
  2908. _fClientIsRemote = FALSE;
  2909. _state = pipeStateNone;
  2910. _cbPendingWrite = 0;
  2911. _scPendingStatus = S_OK;
  2912. _xClientMachine.Free();
  2913. _xClientUser.Free();
  2914. // Remove the refcount on the thread since it no longer has to process
  2915. // APCs on behalf of this request server.
  2916. if ( 0 != _pWorkThread )
  2917. {
  2918. _hWorkThread = INVALID_HANDLE_VALUE;
  2919. _workQueue.Release( _pWorkThread );
  2920. _pWorkThread = 0;
  2921. }
  2922. _xDbProperties.Free();
  2923. if ( !_xDocStore.IsNull() )
  2924. {
  2925. XInterface<ICiCAdviseStatus> xAdviseStatus;
  2926. SCODE sc = _xDocStore->QueryInterface( IID_ICiCAdviseStatus,
  2927. xAdviseStatus.GetQIPointer() );
  2928. // It would be a bug if this QI actually failed.
  2929. if ( S_OK == sc )
  2930. xAdviseStatus->DecrementPerfCounterValue( CI_PERF_RUNNING_QUERIES );
  2931. _xDocStore.Free();
  2932. }
  2933. } //Cleanup
  2934. //+-------------------------------------------------------------------------
  2935. //
  2936. // Member: CRequestQueue::CRequestQueue, public
  2937. //
  2938. // Synopsis: Constructs a request queue
  2939. //
  2940. // Arguments: [cMaxCachedServerItems] -- max # of cached pipe objects
  2941. // [cMaxSimultaneousRequests] -- max # of simultaneous pipes
  2942. //
  2943. // History: 16-Sep-96 dlee Created.
  2944. // 30-Mar-98 kitmanh Initialized _fNetPause
  2945. // and _fNetContinue to FALSE
  2946. //
  2947. //--------------------------------------------------------------------------
  2948. CRequestQueue::CRequestQueue(
  2949. unsigned cMaxCachedServerItems,
  2950. unsigned cMaxSimultaneousRequests,
  2951. unsigned cmsDefaultClientTimeout,
  2952. BOOL fMinimizeWorkingSet,
  2953. unsigned cMinClientIdleTime,
  2954. unsigned cmsStartupDelay,
  2955. const GUID & guidDocStoreClient ) :
  2956. _guidDocStoreClient( guidDocStoreClient ),
  2957. _cMaxSimultaneousRequests( cMaxSimultaneousRequests ),
  2958. _cmsDefaultClientTimeout( cmsDefaultClientTimeout ),
  2959. _fMinimizeWorkingSet( fMinimizeWorkingSet ),
  2960. _cMinClientIdleTime( cMinClientIdleTime ),
  2961. _cmsStartupDelay( cmsStartupDelay ),
  2962. _fDocStoresOpen( FALSE ),
  2963. _fShutdown( FALSE ),
  2964. _cBusyItems( 0 ),
  2965. _cPendingItems( 0 ),
  2966. _workQueue( 1, CWorkQueue::workQueueRequest ),
  2967. _tableActiveServers( cMaxSimultaneousRequests ),
  2968. _queueCachedServers( cMaxCachedServerItems ),
  2969. _fNetPause( FALSE ),
  2970. _fNetContinue( FALSE ),
  2971. _fNetStop( FALSE )
  2972. {
  2973. #if CI_PIPE_TESTING
  2974. _pTraceBefore = 0;
  2975. _pTraceAfter = 0;
  2976. _pTraceRead = 0;
  2977. _hTraceDll = LoadLibraryEx( L"cipipetrace.dll", 0,
  2978. LOAD_WITH_ALTERED_SEARCH_PATH );
  2979. if ( 0 != _hTraceDll )
  2980. {
  2981. _pTraceBefore = (PipeTraceServerBeforeCall)
  2982. GetProcAddress( _hTraceDll, "ServerBefore" );
  2983. _pTraceAfter = (PipeTraceServerAfterCall)
  2984. GetProcAddress( _hTraceDll, "ServerAfter" );
  2985. _pTraceRead = (PipeTraceServerReadCall)
  2986. GetProcAddress( _hTraceDll, "ServerRead" );
  2987. }
  2988. #endif // CI_PIPE_TESTING
  2989. _workQueue.Init();
  2990. //
  2991. // Read the worker queue registry settings in the SYSTEM context
  2992. // and initialize the parameters.
  2993. //
  2994. ULONG cMaxActiveThreads, cMinIdleThreads;
  2995. _workQueue.GetWorkQueueRegParams( cMaxActiveThreads,
  2996. cMinIdleThreads );
  2997. _workQueue.RefreshParams( cMaxActiveThreads, cMinIdleThreads );
  2998. //
  2999. // The security checks for the pipe are done in this order:
  3000. // The system account can create instances of this pipe.
  3001. // No-one can write DAC or OWNER, or create pipe instances.
  3002. // Everyone can read, write, and synchronize around this pipe.
  3003. //
  3004. // Actual query result and admin security checking is done when the
  3005. // requests are made, and are based on the pipe impersonation.
  3006. //
  3007. // This data really is const, but the Win32 security APIs don't do const.
  3008. //
  3009. static SID sidLocalSystem = { SID_REVISION,
  3010. 1,
  3011. SECURITY_NT_AUTHORITY,
  3012. SECURITY_LOCAL_SYSTEM_RID };
  3013. static SID sidWorld = { SID_REVISION,
  3014. 1,
  3015. SECURITY_WORLD_SID_AUTHORITY,
  3016. SECURITY_WORLD_RID };
  3017. // NTRAID#DB-NTBUG9-83834-2000/07/31-dlee No way to protect Indexing Service named pipes.
  3018. // FILE_CREATE_PIPE_INSTANCE no longer works, so we can't include
  3019. // it in the AceData. There is no good way to secure the pipe.
  3020. ACE_DATA AceData[] =
  3021. {
  3022. //{ ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  3023. // FILE_CREATE_PIPE_INSTANCE,
  3024. // &sidLocalSystem },
  3025. { ACCESS_DENIED_ACE_TYPE, 0, 0,
  3026. WRITE_DAC | WRITE_OWNER /*| FILE_CREATE_PIPE_INSTANCE */,
  3027. &sidWorld },
  3028. { ACCESS_ALLOWED_ACE_TYPE, 0, 0,
  3029. GENERIC_READ | GENERIC_WRITE | SYNCHRONIZE,
  3030. &sidWorld },
  3031. };
  3032. const ULONG cAces = sizeof AceData / sizeof ACE_DATA;
  3033. CiCreateSecurityDescriptor( AceData,
  3034. cAces,
  3035. &sidLocalSystem,
  3036. &sidLocalSystem,
  3037. _xSecurityDescriptor );
  3038. } //CRequestQueue
  3039. //+-------------------------------------------------------------------------
  3040. //
  3041. // Member: CRequestQueue::RecycleRequestServerNoThrow, public
  3042. //
  3043. // Synopsis: A request server has become available. Either delete it
  3044. // or cache it for use later. There is a transfer of ownership.
  3045. //
  3046. // Arguments: [pServer] - The request server to be reused or deleted
  3047. //
  3048. // History: 16-Sep-96 dlee Created.
  3049. //
  3050. // Notes: This method must not throw.
  3051. //
  3052. //--------------------------------------------------------------------------
  3053. void CRequestQueue::RecycleRequestServerNoThrow(
  3054. CRequestServer * pServer )
  3055. {
  3056. Win4Assert( pServer->NoOutstandingAPCs() );
  3057. CServerItem item( pServer );
  3058. BOOL fDisconnectOk = pServer->Disconnect();
  3059. if ( !fDisconnectOk )
  3060. {
  3061. prxDebugOut(( DEB_WARN, "Disconnect of server 0x%x failed %d\n",
  3062. pServer, GetLastError() ));
  3063. }
  3064. pServer->Cleanup();
  3065. // Only try to reuse the server if the refcount is 1 (it's available).
  3066. // The only reason the refcount might not be 1 is if we took an exception
  3067. // in DoIt(). Wake up the main thread if a request server is available.
  3068. if ( pServer->IsAvailable() )
  3069. {
  3070. // The Add will fail if the cache is full or there is an admin
  3071. // operation like shutdown going on.
  3072. if ( _queueCachedServers.Add( item ) )
  3073. _event.Set();
  3074. }
  3075. long cCurrent = InterlockedDecrement( &_cBusyItems );
  3076. // If no request servers are to be cached and we've fallen just
  3077. // under the ceiling on the # of items, set the event so the main
  3078. // thread can wake up and create another request server.
  3079. if ( ( !_fShutdown ) &&
  3080. ( 0 == _queueCachedServers.MaxRequests() ) &&
  3081. ( cCurrent == (long) ( _cMaxSimultaneousRequests - 1 ) ) )
  3082. _event.Set();
  3083. } //RecycleRequestServerNoThrow
  3084. //+-------------------------------------------------------------------------
  3085. //
  3086. // Member: CRequestQueue::OpenAllDocStores, private
  3087. //
  3088. // Synopsis: Tells the DocStore admin to open all docstores if they
  3089. // aren't open yet.
  3090. //
  3091. // History: 19-Jun-98 dlee Created.
  3092. //
  3093. //--------------------------------------------------------------------------
  3094. void CRequestQueue::OpenAllDocStores()
  3095. {
  3096. if ( !_fDocStoresOpen )
  3097. {
  3098. XInterface<ICiCDocStoreLocator> xLocator( DocStoreLocator() );
  3099. Win4Assert( !xLocator.IsNull() );
  3100. // Ignore failures to open docstores -- the docstore is responsible
  3101. xLocator->OpenAllDocStores();
  3102. _fDocStoresOpen = TRUE;
  3103. }
  3104. } //OpenAllDocStores
  3105. //+-------------------------------------------------------------------------
  3106. //
  3107. // Member: CRequestQueue::DocStoreLocator, public
  3108. //
  3109. // Synopsis: Retrieves the Doc Store Locator for the client
  3110. //
  3111. // History: 19-Jun-98 dlee Created.
  3112. //
  3113. //--------------------------------------------------------------------------
  3114. ICiCDocStoreLocator * CRequestQueue::DocStoreLocator()
  3115. {
  3116. return g_svcDocStoreLocator.Get( _guidDocStoreClient );
  3117. } //DocStoreLocator
  3118. //+-------------------------------------------------------------------------
  3119. //
  3120. // Member: CRequestQueue::DoWork, public
  3121. //
  3122. // Synopsis: This is the main loop for the CI service. It makes
  3123. // available pipes to which clients can connect. When the
  3124. // _evtStateChange event is triggered, the method exits.
  3125. //
  3126. // History: 16-Sep-96 dlee Created.
  3127. //
  3128. //--------------------------------------------------------------------------
  3129. void CRequestQueue::DoWork()
  3130. {
  3131. // Throw away all that startup code
  3132. SetProcessWorkingSetSize( GetCurrentProcess(), ~0, ~0 );
  3133. HANDLE ah[2];
  3134. ah[0] = _evtStateChange.GetHandle();
  3135. do
  3136. {
  3137. CServerItem item;
  3138. TRY
  3139. {
  3140. // If a cached server item is available, use it. Otherwise,
  3141. // create a non-cached item if we are under the limit.
  3142. prxDebugOut(( DEB_ITRACE, "cached/busy items: %d / %d\n",
  3143. _queueCachedServers.Count(), _cBusyItems ));
  3144. if ( ( !_queueCachedServers.AcquireTop( item ) ) &&
  3145. ( _cBusyItems < (LONG) _cMaxSimultaneousRequests ) )
  3146. item.Create( CI_SERVER_PIPE_NAME,
  3147. _cmsDefaultClientTimeout,
  3148. *this,
  3149. _workQueue );
  3150. if ( 0 != item.Get() )
  3151. {
  3152. // make sure it doesn't get thrown away right away
  3153. item.Get()->SetLastTouchedTime( GetTickCount() );
  3154. InterlockedIncrement( & _cBusyItems );
  3155. BOOL fConnected = item.Get()->Connect();
  3156. // if it's not connected yet, we have to wait on an event
  3157. if ( !fConnected )
  3158. {
  3159. prxDebugOut(( DEB_ITRACE,
  3160. "waiting for connect of pipe 0x%x\n",
  3161. item.Get()->GetPipe() ));
  3162. ah[1] = item.Get()->GetEvent();
  3163. DWORD dwTimeout = _fMinimizeWorkingSet ? 30000 : INFINITE;
  3164. DWORD dw;
  3165. do
  3166. {
  3167. //
  3168. // If catalogs haven't been opened yet due to the
  3169. // startup delay and it's a good time, open them.
  3170. //
  3171. if ( !_fDocStoresOpen )
  3172. {
  3173. if ( GetTickCount() >= _cmsStartupDelay )
  3174. {
  3175. OpenAllDocStores();
  3176. }
  3177. else
  3178. {
  3179. dwTimeout = 0;
  3180. DWORD dwTC = GetTickCount();
  3181. if ( _cmsStartupDelay > dwTC )
  3182. dwTimeout += ( _cmsStartupDelay - dwTC );
  3183. }
  3184. }
  3185. // event 0 -- shutdown
  3186. // event 1 -- a client connected
  3187. dw = WaitForMultipleObjectsEx( 2,
  3188. ah,
  3189. FALSE,
  3190. dwTimeout,
  3191. FALSE );
  3192. // if an event triggered, handle it
  3193. if ( WAIT_TIMEOUT != dw )
  3194. break;
  3195. // If there isn't anything else going on, trim our
  3196. // working set, and back off on the next time
  3197. if ( 1 == _cBusyItems )
  3198. {
  3199. dwTimeout = 120000; // 2 minutes
  3200. SetProcessWorkingSetSize( GetCurrentProcess(), ~0, ~0 );
  3201. }
  3202. } while ( TRUE );
  3203. Win4Assert( ( 0 == dw ) || ( 1 == dw ) );
  3204. if ( 0 == dw )
  3205. {
  3206. item.Free();
  3207. InterlockedDecrement( & _cBusyItems );
  3208. break; // out of the do loop
  3209. }
  3210. else if ( 1 != dw )
  3211. THROW( CException() );
  3212. item.Get()->ResetEvent();
  3213. }
  3214. //
  3215. // Open the docstores now since the connection will not
  3216. // force in a catalog if it's for administration.
  3217. //
  3218. OpenAllDocStores();
  3219. _workQueue.Add( item.Get() );
  3220. item.Acquire();
  3221. //
  3222. // Fix for 123796. If we have no more request servers left
  3223. // we should attempt to free one from an idle client.
  3224. //
  3225. if ( _cBusyItems == (LONG) _cMaxSimultaneousRequests )
  3226. WrestReqServerFromIdleClient();
  3227. }
  3228. else
  3229. {
  3230. //
  3231. // Wait for a request server to become available, either
  3232. // in the cache or under the max ceiling.
  3233. // event 0 -- shutdown
  3234. // event 1 -- request server is available
  3235. // timeout: look for an idle connection to destroy
  3236. //
  3237. prxDebugOut(( DEB_ITRACE, "wait for RequestServer\n" ));
  3238. DWORD dwTimeout = ( _cBusyItems == (LONG) _cMaxSimultaneousRequests ) ?
  3239. 10000 : INFINITE;
  3240. ah[1] = _event.GetHandle();
  3241. DWORD dw = WaitForMultipleObjectsEx( 2,
  3242. ah,
  3243. FALSE,
  3244. dwTimeout,
  3245. FALSE );
  3246. prxDebugOut(( DEB_ITRACE, "wfsoex wakeup: %d\n", dw ));
  3247. Win4Assert(( 0 == dw || 1 == dw || WAIT_TIMEOUT == dw));
  3248. if ( WAIT_TIMEOUT == dw )
  3249. WrestReqServerFromIdleClient();
  3250. else if ( 0 == dw )
  3251. break; // out of the do loop
  3252. else if ( 1 != dw )
  3253. THROW( CException() );
  3254. }
  3255. }
  3256. CATCH( CException, ex )
  3257. {
  3258. prxDebugOut(( DEB_WARN, "DoWork exception error 0x%x\n",
  3259. ex.GetErrorCode() ));
  3260. if ( 0 != item.Get() )
  3261. {
  3262. item.Free();
  3263. InterlockedDecrement( & _cBusyItems );
  3264. }
  3265. }
  3266. END_CATCH;
  3267. } while ( TRUE );
  3268. Shutdown();
  3269. } //DoWork
  3270. //+-------------------------------------------------------------------------
  3271. //
  3272. // Member: CRequestQueue::WrestReqServerFromIdleClient, private
  3273. //
  3274. // Synopsis: Looks for connection that have been idle for more than
  3275. // a predetermined amt of time. Flags the worst offender
  3276. // and kicks it off to pave way for a new connection.
  3277. //
  3278. // History: 03-Feb-98 KrishnaN Created.
  3279. //
  3280. //--------------------------------------------------------------------------
  3281. void CRequestQueue::WrestReqServerFromIdleClient()
  3282. {
  3283. // look for the most idle connection that crossed the threshold
  3284. //
  3285. // We could be a little more efficient if we kick out the
  3286. // first eligible idle client instead of looking for the most
  3287. // idle one. But this is infrequent enough and not a big enough
  3288. // problem that it's worth fixing.
  3289. //
  3290. XInterface<CRequestServer> xIdle;
  3291. {
  3292. CRequestServer * pMostIdleServer = 0;
  3293. DWORD dwCurrentTick = GetTickCount();
  3294. DWORD dwMaxIdleTime = 0;
  3295. CLock lock( _mutex );
  3296. for ( ULONG i = 0; i < _tableActiveServers.Size(); i++ )
  3297. {
  3298. CRequestServer *pServer = _tableActiveServers.GetEntry( i );
  3299. if ( !_tableActiveServers.IsFree( pServer ) &&
  3300. INVALID_HANDLE_VALUE != pServer->GetWorkerThreadHandle() )
  3301. {
  3302. DWORD dwLast = pServer->GetLastTouchedTime();
  3303. // The windows tick count wraps around every 50 days.
  3304. // Unsigned arithmetic accounts for that, so we don't have to.
  3305. DWORD dwIdleTime = dwCurrentTick - dwLast;
  3306. if ( dwIdleTime > _cMinClientIdleTime &&
  3307. dwIdleTime > dwMaxIdleTime )
  3308. {
  3309. dwMaxIdleTime = dwIdleTime;
  3310. pMostIdleServer = pServer;
  3311. }
  3312. }
  3313. }
  3314. if ( 0 != pMostIdleServer )
  3315. {
  3316. pMostIdleServer->AddRef();
  3317. xIdle.Set( pMostIdleServer );
  3318. }
  3319. }
  3320. if ( !xIdle.IsNull() )
  3321. {
  3322. // Make sure this isn't in the cache or it won't get deleted
  3323. _queueCachedServers.DisableAdditions();
  3324. FreeCachedServers();
  3325. // Disconnect this most-idle connection
  3326. CEventSem evt;
  3327. xIdle->BeingRemoved( &evt );
  3328. // Attempt to cancel it if it's still associated with a worker thread
  3329. HANDLE hThrd = xIdle->GetWorkerThreadHandle();
  3330. if ( INVALID_HANDLE_VALUE != hThrd )
  3331. {
  3332. DWORD dwRet = QueueUserAPC( CRequestServer::CancelAPCRoutine,
  3333. hThrd,
  3334. (ULONG_PTR) xIdle.GetPointer() );
  3335. Win4Assert( 0 != dwRet );
  3336. xIdle.Acquire();
  3337. }
  3338. // Wait for the connection to completely go away
  3339. xIdle.Free();
  3340. evt.Wait();
  3341. _queueCachedServers.EnableAdditions();
  3342. prxDebugOut(( DEB_ITRACE, "Successfully disconnected an idle client.\n" ));
  3343. }
  3344. } //WrestReqServerFromIdleClient
  3345. //+-------------------------------------------------------------------------
  3346. //
  3347. // Member: CRequestQueue::FreeCachedServers, private
  3348. //
  3349. // Synopsis: Removes all cached request servers
  3350. //
  3351. // History: 01-July-99 dlee Created from existing code
  3352. //
  3353. //--------------------------------------------------------------------------
  3354. void CRequestQueue::FreeCachedServers()
  3355. {
  3356. CServerItem item;
  3357. while ( _queueCachedServers.AcquireTop( item ) )
  3358. item.Free();
  3359. } //FreeCachedServers
  3360. //+-------------------------------------------------------------------------
  3361. //
  3362. // Member: CRequestQueue::ShutdownActiveServers, private
  3363. //
  3364. // Synopsis: Cancels pending IO on each active request server. It may
  3365. // be that a given request server has no IO pending, and
  3366. // that will be taken care of when the IO is requested.
  3367. //
  3368. // Arguments: [pDocStore] - pointer to a docstore
  3369. // if pDocStore == NULL, shutdown all active servers
  3370. //
  3371. // History: 19-May-97 dlee Created.
  3372. // 24-Apr-98 kitmanh Shut down active servers associated
  3373. // with the specified docstore
  3374. //
  3375. // Note: Always addref to everyone in the first loop, since the
  3376. // in the 2nd loop, the smart pointer xServer will release
  3377. // the pServer when it's out of scope, whether the docstore
  3378. // matches or not.
  3379. //
  3380. //--------------------------------------------------------------------------
  3381. void CRequestQueue::ShutdownActiveServers( ICiCDocStore * pDocStore )
  3382. {
  3383. ciDebugOut(( DEB_ITRACE, "ShutdownActiveServers is called\n" ));
  3384. // AddRef all outstanding request servers so they won't go away
  3385. {
  3386. CLock lock( _mutex );
  3387. for ( ULONG i = 0; i < _tableActiveServers.Size(); i++ )
  3388. {
  3389. CRequestServer *pServer = _tableActiveServers.GetEntry( i );
  3390. if ( !_tableActiveServers.IsFree( pServer ) )
  3391. pServer->AddRef();
  3392. }
  3393. }
  3394. // Make sure whatever request servers are freed aren't in the cache
  3395. _queueCachedServers.DisableAdditions();
  3396. FreeCachedServers();
  3397. //
  3398. // For each of the active request servers, file an APC so that the io
  3399. // for that thread will be canceled by that thread, and so that
  3400. // pending queries are cancelled. No items will be added to
  3401. // _tableActiveServers during this loop, but items may be deleted.
  3402. //
  3403. for ( ULONG i = 0; i < _tableActiveServers.Size(); i++ )
  3404. {
  3405. CRequestServer *pServer = _tableActiveServers.GetEntry( i );
  3406. if ( !_tableActiveServers.IsFree( pServer ) )
  3407. {
  3408. XInterface<CRequestServer> xServer( pServer );
  3409. // The thread handle will be invalid if no worker thread is yet
  3410. // associated or the association has been terminated. In either
  3411. // case by definition there can be no outstanding APCs.
  3412. // Note that the thread can't go away from under us since all
  3413. // threads in the worker pool were addref'ed earlier
  3414. // Disconnect it even if it has no docstore since it may be
  3415. // processing a connect and be about to get a docstore.
  3416. if ( ( 0 == pDocStore ) ||
  3417. ( pServer->GetDocStore() == 0 ) ||
  3418. ( pServer->GetDocStore() == pDocStore ) )
  3419. {
  3420. CEventSem evt;
  3421. pServer->BeingRemoved( &evt );
  3422. HANDLE hThread = pServer->GetWorkerThreadHandle();
  3423. if ( INVALID_HANDLE_VALUE != hThread &&
  3424. QueueUserAPC( CRequestServer::CancelAPCRoutine,
  3425. hThread,
  3426. (ULONG_PTR) pServer ) )
  3427. xServer.Acquire();
  3428. // Wait for the client to stop using the docstore
  3429. xServer.Free();
  3430. evt.Wait();
  3431. }
  3432. }
  3433. }
  3434. _queueCachedServers.EnableAdditions();
  3435. } //ShutdownActiveServers
  3436. //+-------------------------------------------------------------------------
  3437. //
  3438. // Method: CRequestQueue::Shutdown
  3439. //
  3440. // Synopsis: Cleans up after the request queue. Can't throw.
  3441. // handles both net stop and net pause
  3442. //
  3443. // History: 16-Sep-96 dlee Created.
  3444. // 30-Mar-98 kitmanh Don't shutdown workqueue if we're
  3445. // doing a net pause or a net continue
  3446. // 06-25-98 kitmanh Update
  3447. //
  3448. //--------------------------------------------------------------------------
  3449. void CRequestQueue::Shutdown()
  3450. {
  3451. prxDebugOut(( DEB_ITRACE, "Shutdown\n" ));
  3452. // Make sure the worker threads don't go away
  3453. _workQueue.AddRefWorkThreads();
  3454. unsigned i = 0;
  3455. SCWorkItem WorkItem;
  3456. {
  3457. CLock lock( _mutex );
  3458. if ( _fNetStop )
  3459. _fShutdown = TRUE;
  3460. if ( _stateChangeArray.Count() > 0 )
  3461. WorkItem = _stateChangeArray.Get(i);
  3462. else
  3463. {
  3464. ciDebugOut(( DEB_ITRACE, "Shutdown:: eNetStop\n" ));
  3465. // No workitems exist, must be net stop, pause or continue
  3466. // create a stop work item with NULL docstore
  3467. WorkItem.type = eNetStop; // note: workitem.type is not really
  3468. // important here
  3469. ciDebugOut(( DEB_ITRACE, "WorkItem.type is %d\n", WorkItem.type ));
  3470. WorkItem.pDocStore = 0;
  3471. WorkItem.StoppedCat = 0;
  3472. }
  3473. }
  3474. ciDebugOut(( DEB_ITRACE, "WorkItem.Count is %d\n", _stateChangeArray.Count() ));
  3475. do
  3476. {
  3477. ciDebugOut(( DEB_ITRACE, "i is %d\n", i ));
  3478. // now loop thru the workitem list and do the work
  3479. i++;
  3480. if ( 0 == WorkItem.StoppedCat )
  3481. ShutdownActiveServers( WorkItem.pDocStore );
  3482. {
  3483. CLock lock( _mutex );
  3484. if ( i < _stateChangeArray.Count() )
  3485. WorkItem = _stateChangeArray.Get(i);
  3486. }
  3487. } while ( i < _stateChangeArray.Count() );
  3488. if ( _fNetStop || _fNetPause || _fNetContinue )
  3489. {
  3490. if ( _stateChangeArray.Count() > 0 )
  3491. {
  3492. // No workitem has been created at the top of the function,
  3493. // thus need to run ShutdownActiveServers here
  3494. ShutdownActiveServers( 0 );
  3495. }
  3496. Win4Assert( !_queueCachedServers.Any() );
  3497. Win4Assert( !_tableActiveServers.Any() );
  3498. Win4Assert( 0 == _cBusyItems );
  3499. Win4Assert( 0 == _cPendingItems );
  3500. }
  3501. _workQueue.ReleaseWorkThreads();
  3502. if ( _fNetStop )
  3503. _workQueue.Shutdown();
  3504. } //Shutdown
  3505. //+---------------------------------------------------------------------------
  3506. //
  3507. // Function: StartFWCiSvcWork
  3508. //
  3509. // Synopsis: Is the main server loop. Is called by the cisvc to receive
  3510. // requests and demultiplex on them.
  3511. //
  3512. // Arguments: [lock] -- to be released when it's ok to call StopFWCiSvcWork
  3513. //
  3514. // History: 1-30-97 srikants Created
  3515. // 4-13-98 kitmanh Moved the creation of CRequestQueue to
  3516. // StartCisvcWork and passed the pointer
  3517. // in from StartCisvcWork to initialize
  3518. // g_pRequestQueue
  3519. //
  3520. // Notes: Must be called in the SYSTEM context without any impersonation.
  3521. //
  3522. //----------------------------------------------------------------------------
  3523. SCODE StartFWCiSvcWork( CReleasableLock & lock,
  3524. CRequestQueue * pRequestQueue,
  3525. CEventSem & evt )
  3526. {
  3527. ciDebugOut(( DEB_ITRACE, "StartFWCiSvcWork is called\n" ));
  3528. SCODE sc = S_OK;
  3529. TRY
  3530. {
  3531. ciDebugOut(( DEB_ITRACE, "NetPaused == %d and NetContinued == %d\n",
  3532. pRequestQueue->IsNetPause(), pRequestQueue->IsNetContinue() ));
  3533. g_pRequestQueue = pRequestQueue;
  3534. evt.Set();
  3535. lock.Release();
  3536. ciDebugOut(( DEB_ITRACE, "evtPauseContinue is set\n" ));
  3537. ciDebugOut(( DEB_ITRACE, "StartFWCisvcWork.. About to DoWork()\n" ));
  3538. g_pRequestQueue->DoWork();
  3539. ciDebugOut(( DEB_ITRACE, "StartFWCisvcWork.. Just fell out from DoWork\n" ));
  3540. ciDebugOut(( DEB_ITRACE, "g_pRequestQueue->IsShutdown() is %d\n",
  3541. g_pRequestQueue->IsShutdown() ));
  3542. // Check if a netpause or netcontinue is requested during DoWork()
  3543. if ( g_pRequestQueue->IsShutdown() &&
  3544. ! ( g_pRequestQueue->IsNetPause() || g_pRequestQueue->IsNetContinue() ) )
  3545. {
  3546. g_svcDocStoreLocator.Shutdown();
  3547. //
  3548. // Shutdown the Content Index work queue.
  3549. //
  3550. TheWorkQueue.Shutdown();
  3551. }
  3552. }
  3553. CATCH( CException,e )
  3554. {
  3555. ciDebugOut(( DEB_ERROR,
  3556. "Terminating - DoCiSvcServerWork(). Error 0x%X\n",
  3557. e.GetErrorCode() ));
  3558. sc = e.GetErrorCode();
  3559. }
  3560. END_CATCH
  3561. ciDebugOut(( DEB_ITRACE, "Request lock for resetting g_pRequestQueue to 0\n" ));
  3562. lock.Request();
  3563. ciDebugOut(( DEB_ITRACE, "Got lock\n" ));
  3564. g_pRequestQueue = 0;
  3565. ciDebugOut(( DEB_ITRACE, "About to release lock\n" ));
  3566. lock.Release();
  3567. return sc;
  3568. } //StartFWCiSvcWork
  3569. //+---------------------------------------------------------------------------
  3570. //
  3571. // Function: StopFWCiSvcWork
  3572. //
  3573. // Synopsis: Stops the server work. It is the Shutdown method called by
  3574. // cisvc to stop the work.
  3575. //
  3576. // Arguments: [type] -- type of work to do
  3577. // [wcVol] -- volume letter (for eLockVol only)
  3578. //
  3579. // History: 1-30-97 srikants Created
  3580. // 3-30-98 kitmanh If we're doing a net pause, set
  3581. // _fNetPause member in the CRequestQueue
  3582. //
  3583. //----------------------------------------------------------------------------
  3584. SCODE StopFWCiSvcWork( ECiSvcActionType type,
  3585. CReleasableLock * pLock,
  3586. CEventSem * pEvt,
  3587. WCHAR wcVol )
  3588. {
  3589. ciDebugOut(( DEB_ITRACE, "StopFWCiSvcWork.. type == %d\n", type ));
  3590. SCODE sc = S_OK;
  3591. // for the case where a shutdown occurs while the service is restarting
  3592. // for pausing, continuing, stopping a catalog
  3593. if ( eNetStop == type && 0 == g_pRequestQueue )
  3594. {
  3595. //block until g_pRequestQueue is non-zero
  3596. ciDebugOut(( DEB_ITRACE, "0 == g_pRequestQueue\n" ));
  3597. ciDebugOut(( DEB_ITRACE, "StopFWCiSvcWork: Release the lock\n" ));
  3598. ciDebugOut(( DEB_ITRACE, "Block on g_pevtPauseContinue for eNetStop\n" ));
  3599. //this lock need to be released, so the lock can be grabbed by the
  3600. //thread just done shutting down to finish restarting (calling
  3601. //StartFWCiSvcWork)
  3602. pLock->Release();
  3603. pEvt->Wait();
  3604. ciDebugOut(( DEB_ITRACE, "Done waiting on g_pevtPauseContinue\n" ));
  3605. pLock->Request();
  3606. ciDebugOut(( DEB_ITRACE, "StopFWCiSvcWork requested the lock\n" ));
  3607. }
  3608. if ( 0 != g_pRequestQueue )
  3609. {
  3610. ciDebugOut(( DEB_ITRACE, "0 != g_pRequestQueue\n" ));
  3611. ciDebugOut(( DEB_ITRACE, "g_pRequestQueue->IsShutdown() is %d\n", g_pRequestQueue->IsShutdown() ));
  3612. // Ignore all events if shutdown is initialized
  3613. if ( g_pRequestQueue->IsShutdown() )
  3614. return STATUS_TOO_LATE;
  3615. XInterface<ICiCDocStoreLocator> xLocator( g_pRequestQueue->DocStoreLocator() );
  3616. Win4Assert( !xLocator.IsNull() );
  3617. switch ( type )
  3618. {
  3619. case eNetPause:
  3620. g_pRequestQueue->SetNetPause();
  3621. break;
  3622. case eNetContinue:
  3623. g_pRequestQueue->SetNetContinue();
  3624. break;
  3625. case eNetStop:
  3626. g_pRequestQueue->SetNetStop();
  3627. break;
  3628. case eCatRO:
  3629. case eCatW:
  3630. case eStopCat:
  3631. case eNoQuery:
  3632. break;
  3633. case eLockVol:
  3634. sc = xLocator->StopCatalogsOnVol( wcVol, g_pRequestQueue );
  3635. ciDebugOut(( DEB_ITRACE, "After StopCatalogsOnVol\n" ));
  3636. break;
  3637. case eUnLockVol:
  3638. sc = xLocator->StartCatalogsOnVol( wcVol, g_pRequestQueue );
  3639. ciDebugOut(( DEB_ITRACE, "After StartCatalogsOnVol\n" ));
  3640. break;
  3641. default:
  3642. Win4Assert( !"StopFWCiSvcWork is called with invalid ECisvcActionType" );
  3643. }
  3644. ciDebugOut(( DEB_ITRACE, "Time to WakeForStateChange; type = %d\n", type ));
  3645. g_pRequestQueue->WakeForStateChange();
  3646. }
  3647. else
  3648. {
  3649. ciDebugOut(( DEB_ITRACE, "g_pRequestQueue->IsShutdown() is 0\n" ));
  3650. }
  3651. return sc;
  3652. } //StopFWCiSvcWork