Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

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