Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1242 lines
40 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1996 - 2001
  5. //
  6. // File: crequest.cxx
  7. //
  8. // Contents: Client side of catalog/query requests
  9. //
  10. // Classes: CPipeClient
  11. // CRequestClient
  12. //
  13. // History: 16-Sep-96 dlee Created.
  14. //
  15. //--------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <query.hxx>
  19. #include <cidbprop.hxx>
  20. #include <sizeser.hxx>
  21. #include <memser.hxx>
  22. DECLARE_INFOLEVEL(prx);
  23. //+-------------------------------------------------------------------------
  24. //
  25. // Member: CPipeClient::CPipeClient, protected
  26. //
  27. // Synopsis: Simple constructor
  28. //
  29. // History: 16-Sep-96 dlee Created.
  30. //
  31. //--------------------------------------------------------------------------
  32. CPipeClient::CPipeClient() : _hPipe( INVALID_HANDLE_VALUE )
  33. {
  34. } //CPipeClient
  35. //+-------------------------------------------------------------------------
  36. //
  37. // Member: CPipeClient::Init, protected
  38. //
  39. // Synopsis: Second phase constructor for a client pipe. The pipe is
  40. // opened or an exception is thrown. This method may take
  41. // awhile to complete depending on the availability of a pipe
  42. // instance on the server and on the timeout for the pipe as
  43. // set on the server.
  44. //
  45. // Arguments: [pwcMachine] - Name of the server or "." for local machine
  46. // [pwcPipe] - Name of the pipe
  47. //
  48. // History: 16-Sep-96 dlee Created.
  49. //
  50. //--------------------------------------------------------------------------
  51. void CPipeClient::Init(
  52. WCHAR const * pwcMachine,
  53. WCHAR const * pwcPipe )
  54. {
  55. #if CI_PIPE_TESTING
  56. _pTraceBefore = 0;
  57. _pTraceAfter = 0;
  58. _hTraceDll = LoadLibraryEx( L"cipipetrace.dll", 0,
  59. LOAD_WITH_ALTERED_SEARCH_PATH );
  60. if ( 0 != _hTraceDll )
  61. {
  62. _pTraceBefore = (PipeTraceBeforeCall)
  63. GetProcAddress( _hTraceDll, "Before" );
  64. _pTraceAfter = (PipeTraceAfterCall)
  65. GetProcAddress( _hTraceDll, "After" );
  66. }
  67. #endif // CI_PIPE_TESTING
  68. RtlZeroMemory( &_overlapped, sizeof _overlapped );
  69. RtlZeroMemory( &_overlappedWrite, sizeof _overlappedWrite );
  70. _fServerIsRemote = ( L'.' != pwcMachine[0] );
  71. WCHAR awcName[ MAX_PATH ];
  72. unsigned cwc = wcslen( pwcMachine );
  73. cwc += wcslen( pwcPipe );
  74. cwc += 20;
  75. if ( cwc >= ( sizeof awcName / sizeof WCHAR ) )
  76. THROW( CException( E_INVALIDARG ) );
  77. wcscpy( awcName, L"\\\\" );
  78. wcscat( awcName, pwcMachine );
  79. wcscat( awcName, L"\\pipe\\" );
  80. wcscat( awcName, pwcPipe );
  81. #if CIDBG == 1
  82. WCHAR awcThisUser[ UNLEN ];
  83. DWORD cbThisUser = sizeof awcThisUser / sizeof WCHAR;
  84. GetUserName( awcThisUser, &cbThisUser );
  85. prxDebugOut(( DEB_ITRACE,
  86. "connecting tid %d to pipe '%ws' as user '%ws'\n",
  87. GetCurrentThreadId(),
  88. awcName,
  89. awcThisUser ));
  90. #endif // CIDBG == 1
  91. do
  92. {
  93. // Timeout based on what the server specified if a pipe exists
  94. // but no instances are available. Throw if no pipe exists.
  95. if ( ! WaitNamedPipe( awcName, NMPWAIT_USE_DEFAULT_WAIT ) )
  96. QUIETTHROW( CException() );
  97. // At least one instance was available. This CreateFile will fail
  98. // if some other app grabbed the instance before we could. If so,
  99. // wait and try again.
  100. _hPipe = CreateFile( awcName,
  101. GENERIC_READ | GENERIC_WRITE,
  102. FILE_SHARE_READ | FILE_SHARE_WRITE,
  103. 0, // security
  104. OPEN_EXISTING,
  105. FILE_ATTRIBUTE_NORMAL | FILE_FLAG_OVERLAPPED,
  106. 0 ); // template
  107. if ( INVALID_HANDLE_VALUE != _hPipe )
  108. {
  109. // Local client pipes are always created in byte mode, not
  110. // message mode, so set the mode to message.
  111. DWORD dwMode = PIPE_READMODE_MESSAGE | PIPE_WAIT;
  112. if ( ! SetNamedPipeHandleState( _hPipe, &dwMode, 0, 0 ) )
  113. {
  114. HRESULT hr = HRESULT_FROM_WIN32( GetLastError() );
  115. CloseHandle( _hPipe );
  116. _hPipe = INVALID_HANDLE_VALUE;
  117. THROW( CException( hr ) );
  118. }
  119. break;
  120. }
  121. else if ( ERROR_PIPE_BUSY != GetLastError() )
  122. {
  123. THROW( CException() );
  124. }
  125. } while ( TRUE );
  126. prxDebugOut(( DEB_ITRACE, "created pipe %#x\n", _hPipe ));
  127. } //Init
  128. //+-------------------------------------------------------------------------
  129. //
  130. // Member: CPipeClient::Close, protected
  131. //
  132. // Synopsis: Closes the pipe if it is open
  133. //
  134. // History: 16-Sep-96 dlee Created.
  135. //
  136. //--------------------------------------------------------------------------
  137. void CPipeClient::Close()
  138. {
  139. if ( INVALID_HANDLE_VALUE != _hPipe )
  140. {
  141. prxDebugOut(( DEB_ITRACE, "closing pipe: %#x\n", _hPipe ));
  142. BOOL fCloseOk = CloseHandle( _hPipe );
  143. Win4Assert( fCloseOk );
  144. _hPipe = INVALID_HANDLE_VALUE;
  145. }
  146. #if CI_PIPE_TESTING
  147. if ( 0 != _hTraceDll )
  148. {
  149. FreeLibrary( _hTraceDll );
  150. _hTraceDll = 0;
  151. }
  152. #endif // CI_PIPE_TESTING
  153. } //Close
  154. //+-------------------------------------------------------------------------
  155. //
  156. // Function: HandleClientWriteError
  157. //
  158. // Synopsis: Handles error case on pipe write commands
  159. //
  160. // Arguments: [hPipe] -- Pipe on which the operation failed
  161. //
  162. // Notes: When it looks like the connection has gone stale, throw
  163. // STATUS_CONNECTION_DISCONNECTED, so the caller knows to
  164. // open a new pipe to the server.
  165. //
  166. // History: 16-May-99 dlee Created.
  167. //
  168. //--------------------------------------------------------------------------
  169. void HandleClientWriteError( HANDLE hPipe )
  170. {
  171. //
  172. // This error state will happen for stale cached ICommands.
  173. // Alternatively, the handle will be set to INVALID_HANDLE_VALUE by
  174. // TerminateRudelyNoThrow(), and the pipe will no longer
  175. // be connected if cisvc went down.
  176. // Throw a well-known status so we can try to connect again.
  177. //
  178. DWORD dwError = GetLastError();
  179. if ( INVALID_HANDLE_VALUE == hPipe ||
  180. ERROR_PIPE_NOT_CONNECTED == dwError ||
  181. ERROR_BAD_PIPE == dwError ||
  182. ERROR_BAD_NET_RESP == dwError ) // rdr gives this sometimes
  183. THROW( CException( STATUS_CONNECTION_DISCONNECTED ) );
  184. THROW( CException() );
  185. } //HandleClientWriteError
  186. //+-------------------------------------------------------------------------
  187. //
  188. // Member: CPipeClient::TransactSync, protected
  189. //
  190. // Synopsis: Does a synchronous write/read transaction on the pipe.
  191. //
  192. // Arguments: [pvWrite] - Buffer to be written
  193. // [cbToWrite] - # of bytes to write
  194. // [pvRead] - Buffer for read result
  195. // [cbReadRequest] - Size of pvRead
  196. // [cbRead] - Returns # of bytes read
  197. //
  198. // History: 16-Sep-96 dlee Created.
  199. //
  200. //--------------------------------------------------------------------------
  201. void CPipeClient::TransactSync(
  202. void * pvWrite,
  203. DWORD cbToWrite,
  204. void * pvRead,
  205. DWORD cbReadRequest,
  206. DWORD & cbRead )
  207. {
  208. prxDebugOut(( DEB_ITRACE, "xact tid %d on pipe %#x\n",
  209. GetCurrentThreadId(),
  210. _hPipe ));
  211. //
  212. // Win32 named pipe operations require buffers < 64k. If you specify
  213. // a larger buffer it succeeds without a failure code, but the server
  214. // never sees the request. So do an explicit check here to validate
  215. // the buffer size.
  216. //
  217. if ( cbToWrite > 0xffff )
  218. THROW( CException( E_INVALIDARG ) );
  219. _overlapped.hEvent = _event.GetHandle();
  220. #if CI_PIPE_TESTING
  221. void * pvWriteOrg = pvWrite;
  222. DWORD cbToWriteOrg = cbToWrite;
  223. if ( 0 != _pTraceBefore )
  224. (*_pTraceBefore)( _hPipe,
  225. cbToWriteOrg,
  226. pvWriteOrg,
  227. cbToWrite,
  228. pvWrite );
  229. #endif // CI_PIPE_TESTING
  230. if ( ! TransactNamedPipe( _hPipe,
  231. pvWrite,
  232. cbToWrite,
  233. pvRead,
  234. cbReadRequest,
  235. &cbRead,
  236. &_overlapped ) )
  237. {
  238. if ( ERROR_IO_PENDING == GetLastError() )
  239. {
  240. if ( !GetOverlappedResult( _hPipe,
  241. &_overlapped,
  242. &cbRead,
  243. TRUE ) )
  244. HandleClientWriteError( _hPipe );
  245. }
  246. else
  247. HandleClientWriteError( _hPipe );
  248. }
  249. #if CI_PIPE_TESTING
  250. if ( 0 != _pTraceAfter )
  251. (*_pTraceAfter)( _hPipe,
  252. cbToWriteOrg,
  253. pvWriteOrg,
  254. cbToWrite,
  255. pvWrite,
  256. cbRead,
  257. pvRead );
  258. #endif // CI_PIPE_TESTING
  259. } //TransactSync
  260. //+-------------------------------------------------------------------------
  261. //
  262. // Member: CPipeClient::WriteSync, protected
  263. //
  264. // Synopsis: Does a synchronous write to the pipe.
  265. //
  266. // Arguments: [pvWrite] - Buffer to be written
  267. // [cbToWrite] - # of bytes to write
  268. //
  269. // Notes: When it looks like the connection has gone stale, throw
  270. // STATUS_CONNECTION_DISCONNECTED, so the caller knows to
  271. // open a new pipe to the server,.
  272. //
  273. // History: 16-Sep-96 dlee Created.
  274. //
  275. //--------------------------------------------------------------------------
  276. void CPipeClient::WriteSync(
  277. void * pvWrite,
  278. DWORD cbToWrite )
  279. {
  280. prxDebugOut(( DEB_ITRACE, "writesync tid %d on pipe %#x\n",
  281. GetCurrentThreadId(),
  282. _hPipe ));
  283. //
  284. // Win32 named pipe operations require buffers < 64k. If you specify
  285. // a larger buffer it succeeds without a failure code, but the server
  286. // never sees the request. So do an explicit check here to validate
  287. // the buffer size.
  288. //
  289. if ( cbToWrite > 0xffff )
  290. THROW( CException( E_INVALIDARG ) );
  291. _overlappedWrite.hEvent = _eventWrite.GetHandle();
  292. DWORD cbWritten;
  293. if ( ! WriteFile( _hPipe,
  294. pvWrite,
  295. cbToWrite,
  296. &cbWritten,
  297. &_overlappedWrite ) )
  298. {
  299. if ( ERROR_IO_PENDING == GetLastError() )
  300. {
  301. if ( !GetOverlappedResult( _hPipe,
  302. &_overlappedWrite,
  303. &cbWritten,
  304. TRUE ) )
  305. HandleClientWriteError( _hPipe );
  306. }
  307. else
  308. HandleClientWriteError( _hPipe );
  309. }
  310. } //WriteSync
  311. //+-------------------------------------------------------------------------
  312. //
  313. // Member: CPipeClient::ReadSync, protected
  314. //
  315. // Synopsis: Does a synchronous read from the pipe.
  316. //
  317. // Arguments: [pvRead] - Buffer for read result
  318. // [cbReadRequest] - Size of pvRead
  319. // [cbRead] - Returns # of bytes read
  320. //
  321. // History: 16-Sep-96 dlee Created.
  322. //
  323. //--------------------------------------------------------------------------
  324. void CPipeClient::ReadSync(
  325. void * pvRead,
  326. DWORD cbToRead,
  327. DWORD & cbRead )
  328. {
  329. prxDebugOut(( DEB_ITRACE, "readsync 1 tid %d on pipe %#x\n",
  330. GetCurrentThreadId(),
  331. _hPipe ));
  332. _overlapped.hEvent = _event.GetHandle();
  333. if ( ! ReadFile( _hPipe,
  334. pvRead,
  335. cbToRead,
  336. &cbRead,
  337. &_overlapped ) )
  338. {
  339. if ( ERROR_IO_PENDING == GetLastError() )
  340. {
  341. if ( !GetOverlappedResult( _hPipe,
  342. &_overlapped,
  343. &cbRead,
  344. TRUE ) )
  345. {
  346. // If this assert hits, you probably added large notify msg
  347. Win4Assert( ERROR_MORE_DATA != GetLastError() );
  348. THROW( CException() );
  349. }
  350. }
  351. else
  352. THROW( CException() );
  353. }
  354. } //ReadSync
  355. //+-------------------------------------------------------------------------
  356. //
  357. // Member: CPipeClient::ReadSync, protected
  358. //
  359. // Synopsis: Does a synchronous read from the pipe, aborting the read
  360. // if hEvent is signalled before the read is started or
  361. // completed.
  362. //
  363. // Arguments: [pvRead] - Buffer for read result
  364. // [cbReadRequest] - Size of pvRead
  365. // [cbRead] - Returns # of bytes read
  366. // [hEvent] - When signalled, the read is aborted
  367. //
  368. // Returns: TRUE if hEvent has been triggered
  369. //
  370. // History: 16-Sep-96 dlee Created.
  371. //
  372. //--------------------------------------------------------------------------
  373. BOOL CPipeClient::ReadSync(
  374. void * pvRead,
  375. DWORD cbToRead,
  376. DWORD & cbRead,
  377. HANDLE hEvent )
  378. {
  379. cbRead = 0;
  380. // Since the read below can complete without going pending,
  381. // check the terminate event here first.
  382. if ( 0 == WaitForSingleObject( hEvent, 0 ) )
  383. return TRUE;
  384. prxDebugOut(( DEB_ITRACE, "readsync 2 tid %d on pipe %#x\n",
  385. GetCurrentThreadId(),
  386. _hPipe ));
  387. _overlapped.hEvent = _event.GetHandle();
  388. if ( ! ReadFile( _hPipe,
  389. pvRead,
  390. cbToRead,
  391. &cbRead,
  392. &_overlapped ) )
  393. {
  394. if ( ERROR_IO_PENDING == GetLastError() )
  395. {
  396. HANDLE ah[2];
  397. ah[0] = _event.GetHandle();
  398. ah[1] = hEvent;
  399. DWORD dw = WaitForMultipleObjects( 2, ah, FALSE, INFINITE );
  400. Win4Assert( 0 == dw || 1 == dw );
  401. if ( 0 == dw )
  402. {
  403. if ( !GetOverlappedResult( _hPipe,
  404. &_overlapped,
  405. &cbRead,
  406. FALSE ) )
  407. THROW( CException() );
  408. }
  409. else if ( 1 == dw )
  410. {
  411. prxDebugOut(( DEB_ITRACE,
  412. "notify thread told to die, cancel i/o\n" ));
  413. // Cancel the io so that it won't complete on buffers that
  414. // have been freed. No check can be made of the return code
  415. // since the pipe may have been closed by now on the server.
  416. BOOL fOK = CancelIo( _hPipe );
  417. prxDebugOut(( DEB_ITRACE, "CancelIo: %d\n", fOK ));
  418. if ( !fOK ) {
  419. prxDebugOut(( DEB_ITRACE, "CancelIo error: %d\n",
  420. GetLastError() ));
  421. }
  422. if ( !GetOverlappedResult( _hPipe,
  423. &_overlapped,
  424. &cbRead,
  425. TRUE ) )
  426. {
  427. cbRead = 0;
  428. DWORD dw = GetLastError();
  429. prxDebugOut(( DEB_ITRACE,
  430. "i/o cancelled, result: %d\n", dw ));
  431. // benign assert if hit; I'm is just curious.
  432. Win4Assert( ERROR_OPERATION_ABORTED == dw ||
  433. ERROR_NO_DATA == dw );
  434. }
  435. return TRUE;
  436. }
  437. else THROW( CException() );
  438. }
  439. else THROW( CException() );
  440. }
  441. return FALSE;
  442. } //ReadSync
  443. //+-------------------------------------------------------------------------
  444. //
  445. // Function: TranslateNewPropsToOldProps
  446. //
  447. // Synopsis: Translates v 6+ client properties into version 5 props.
  448. // V5 props are used for IS 2.0.
  449. //
  450. // Arguments: [oldProps] - destination of translated values
  451. // [newProps] - source of translated values
  452. //
  453. // History: 31-May-97 dlee Created.
  454. //
  455. //--------------------------------------------------------------------------
  456. void TranslateNewPropsToOldProps(
  457. CDbProperties & oldProps,
  458. CDbProperties & newProps )
  459. {
  460. const GUID guidFsClientPropset = DBPROPSET_FSCIFRMWRK_EXT;
  461. const GUID guidQueryCorePropset = DBPROPSET_CIFRMWRKCORE_EXT;
  462. // pluck out the catalog and scope information from the new set
  463. BSTR bstrMachine = 0;
  464. BSTR bstrCatalog = 0;
  465. CDynArrayInPlace<LONG> aDepths(2);
  466. CDynArrayInPlace<BSTR> aScopes(2);
  467. LONG lQueryType = 0;
  468. for ( ULONG i = 0; i < newProps.Count(); i++ )
  469. {
  470. CDbPropSet & propSet = newProps.GetPropSet( i );
  471. DBPROPSET *pSet = propSet.CastToStruct();
  472. if ( guidQueryCorePropset == pSet->guidPropertySet )
  473. {
  474. ULONG cProp = pSet->cProperties;
  475. DBPROP * pProp = pSet->rgProperties;
  476. for ( ULONG p = 0; p < pSet->cProperties; p++, pProp++ )
  477. {
  478. VARIANT &v = pProp->vValue;
  479. switch ( pProp->dwPropertyID )
  480. {
  481. case DBPROP_MACHINE :
  482. {
  483. if ( VT_BSTR == v.vt )
  484. bstrMachine = v.bstrVal;
  485. else if ( ( VT_ARRAY | VT_BSTR ) == v.vt )
  486. {
  487. ULONG cElem = v.parray->rgsabound[0].cElements;
  488. WCHAR **ppMachines = (WCHAR **) v.parray->pvData;
  489. if ( 0 != cElem )
  490. {
  491. // if not 1, it's a bug in higher level code
  492. Win4Assert( 1 == cElem );
  493. bstrMachine = ppMachines[0];
  494. }
  495. }
  496. break;
  497. }
  498. }
  499. }
  500. }
  501. else if ( guidFsClientPropset == pSet->guidPropertySet )
  502. {
  503. ULONG cProp = pSet->cProperties;
  504. DBPROP * pProp = pSet->rgProperties;
  505. for ( ULONG p = 0; p < pSet->cProperties; p++, pProp++ )
  506. {
  507. VARIANT &v = pProp->vValue;
  508. prxDebugOut(( DEB_ITRACE, "converting from vt: %#x\n", v.vt ));
  509. switch ( pProp->dwPropertyID )
  510. {
  511. case DBPROP_CI_INCLUDE_SCOPES :
  512. {
  513. // can be either a BSTR or a safearray of BSTRs
  514. if ( VT_BSTR == v.vt )
  515. {
  516. aScopes[0] = v.bstrVal;
  517. }
  518. else if ( ( VT_ARRAY | VT_BSTR ) == v.vt )
  519. {
  520. ULONG cElem = v.parray->rgsabound[0].cElements;
  521. WCHAR **ppScopes = (WCHAR **) v.parray->pvData;
  522. for ( ULONG e = 0; e < cElem; e++ )
  523. aScopes[ e ] = ppScopes[ e ];
  524. }
  525. break;
  526. }
  527. case DBPROP_CI_DEPTHS :
  528. {
  529. // can be either an I4 or an array of I4s
  530. if ( VT_I4 == v.vt )
  531. {
  532. aDepths[0] = v.lVal;
  533. }
  534. else if ( ( VT_ARRAY | VT_I4 ) == v.vt )
  535. {
  536. ULONG cElem = v.parray->rgsabound[0].cElements;
  537. ULONG *pElem = (ULONG *) v.parray->pvData;
  538. for ( ULONG e = 0; e < cElem; e++ )
  539. aDepths[ e ] = pElem[ e ];
  540. }
  541. break;
  542. }
  543. case DBPROP_CI_CATALOG_NAME :
  544. {
  545. if ( VT_BSTR == v.vt )
  546. bstrCatalog = v.bstrVal;
  547. else if ( ( VT_ARRAY | VT_BSTR ) == v.vt )
  548. {
  549. ULONG cElem = v.parray->rgsabound[0].cElements;
  550. WCHAR **ppNames = (WCHAR **) v.parray->pvData;
  551. if ( 0 != cElem )
  552. {
  553. // if not 1, it's a bug in higher level code
  554. Win4Assert( 1 == cElem );
  555. bstrCatalog = ppNames[0];
  556. }
  557. }
  558. break;
  559. }
  560. case DBPROP_CI_QUERY_TYPE :
  561. {
  562. Win4Assert( VT_I4 == v.vt );
  563. lQueryType = v.lVal;
  564. break;
  565. }
  566. }
  567. }
  568. }
  569. }
  570. if ( 0 == bstrCatalog ||
  571. 0 == bstrMachine )
  572. THROW( CException( STATUS_INVALID_PARAMETER ) );
  573. prxDebugOut(( DEB_ITRACE,
  574. "Converting new props to old props, catalog '%ws'\n",
  575. bstrCatalog ));
  576. prxDebugOut(( DEB_ITRACE,
  577. "type %d, %d scopes, %d depths\n",
  578. lQueryType,
  579. aScopes.Count(),
  580. aDepths.Count() ));
  581. // create an old set of properties based on the info
  582. DBPROPSET aNewSet[2];
  583. DBPROP aFSProps[4];
  584. RtlZeroMemory( aFSProps, sizeof aFSProps );
  585. ULONG cNewSet = 2;
  586. aNewSet[0].cProperties = 2;
  587. aNewSet[0].guidPropertySet = guidFsClientPropset;
  588. aNewSet[0].rgProperties = aFSProps;
  589. aFSProps[0].dwPropertyID = DBPROP_CI_CATALOG_NAME;
  590. aFSProps[0].vValue.vt = VT_LPWSTR;
  591. aFSProps[0].vValue.bstrVal = bstrCatalog;
  592. aFSProps[0].colid.eKind = DBKIND_GUID_PROPID;
  593. aFSProps[1].dwPropertyID = DBPROP_CI_QUERY_TYPE;
  594. aFSProps[1].vValue.vt = VT_I4;
  595. aFSProps[1].vValue.lVal = lQueryType;
  596. aFSProps[1].colid.eKind = DBKIND_GUID_PROPID;
  597. if ( 0 != aDepths.Count() )
  598. {
  599. aFSProps[cNewSet].dwPropertyID = DBPROP_CI_DEPTHS;
  600. aFSProps[cNewSet].colid.eKind = DBKIND_GUID_PROPID;
  601. PROPVARIANT &vDepths = (PROPVARIANT &) aFSProps[cNewSet].vValue;
  602. cNewSet++;
  603. vDepths.vt = VT_VECTOR | VT_I4;
  604. vDepths.cal.cElems = aDepths.Count();
  605. vDepths.cal.pElems = (LONG *) aDepths.GetPointer();
  606. }
  607. if ( 0 != aScopes.Count() )
  608. {
  609. aFSProps[cNewSet].dwPropertyID = DBPROP_CI_INCLUDE_SCOPES;
  610. aFSProps[cNewSet].colid.eKind = DBKIND_GUID_PROPID;
  611. PROPVARIANT &vScopes = (PROPVARIANT &) aFSProps[cNewSet].vValue;
  612. cNewSet++;
  613. vScopes.vt = VT_VECTOR | VT_LPWSTR;
  614. vScopes.calpwstr.cElems = aScopes.Count();
  615. vScopes.calpwstr.pElems = (WCHAR **) aScopes.GetPointer();
  616. }
  617. aNewSet[0].cProperties = cNewSet;
  618. DBPROP aQueryProps[1];
  619. RtlZeroMemory( aQueryProps, sizeof aQueryProps );
  620. aNewSet[1].cProperties = 1;
  621. aNewSet[1].guidPropertySet = guidQueryCorePropset;
  622. aNewSet[1].rgProperties = aQueryProps;
  623. aQueryProps[0].dwPropertyID = DBPROP_MACHINE;
  624. aQueryProps[0].vValue.vt = VT_BSTR;
  625. aQueryProps[0].vValue.bstrVal = bstrMachine;
  626. aQueryProps[0].colid.eKind = DBKIND_GUID_PROPID;
  627. SCODE sc = oldProps.SetProperties( 2, aNewSet );
  628. if ( FAILED( sc ) )
  629. THROW( CException( sc ) );
  630. } //TranslateNewPropsToOldProps
  631. //+-------------------------------------------------------------------------
  632. //
  633. // Member: CRequestClient::CRequestClient, public
  634. //
  635. // Synopsis: Constructor for a client request
  636. //
  637. // Arguments: [pwcMachine] - Machine name of server
  638. // [pDbProperties] - Client version 6 set of properties
  639. //
  640. // History: 16-Sep-96 dlee Created.
  641. //
  642. //--------------------------------------------------------------------------
  643. CRequestClient::CRequestClient(
  644. WCHAR const * pwcMachine,
  645. IDBProperties * pDbProperties ) :
  646. _fNotifyOn( FALSE ),
  647. _fNotifyEverOn( FALSE ),
  648. _fReadPending( FALSE ),
  649. _pvDataTemp( 0 ),
  650. _cbDataTemp( 0 )
  651. {
  652. WCHAR const * pwcMach = pwcMachine;
  653. WCHAR const * pwcPipe = CI_PIPE_NAME;
  654. WCHAR awcMachine[ MAX_PATH + 1 ];
  655. WCHAR const * pwcColon = wcschr( pwcMachine, L':' );
  656. if ( 0 != pwcColon )
  657. {
  658. unsigned cwc = (unsigned) ( pwcColon - pwcMachine );
  659. if ( cwc >= MAX_PATH )
  660. THROW( CException( E_INVALIDARG ) );
  661. RtlCopyMemory( awcMachine, pwcMachine, sizeof( WCHAR ) * cwc );
  662. awcMachine[ cwc ] = 0;
  663. pwcMach = awcMachine;
  664. pwcPipe = pwcColon + 1;
  665. }
  666. Init( pwcMach, pwcPipe );
  667. // Send the pmConnect message to the server. For logging and
  668. // debugging, send the machine and username with the message.
  669. WCHAR awcThisMachine[ MAX_COMPUTERNAME_LENGTH + 1 ];
  670. DWORD cwcThisMachine = sizeof awcThisMachine / sizeof WCHAR;
  671. if ( !GetComputerName( awcThisMachine, &cwcThisMachine ) )
  672. THROW( CException() );
  673. WCHAR awcThisUser[ UNLEN + 1 ];
  674. DWORD cwcThisUser = sizeof awcThisUser / sizeof WCHAR;
  675. if ( !GetUserName( awcThisUser, &cwcThisUser ) )
  676. {
  677. //
  678. // For some configurations of asp.net the context in which the
  679. // thread runs doesn't have access to the user name. Fail this
  680. // case silently since the username is optional and only used for
  681. // logging.
  682. //
  683. if ( ERROR_ACCESS_DENIED == GetLastError() )
  684. {
  685. awcThisUser[0] = 0;
  686. cwcThisUser = 0;
  687. }
  688. else
  689. THROW( CException() );
  690. }
  691. Win4Assert( 0 != pDbProperties );
  692. //
  693. // We know that the IDbProperties is implemented by CDbProperties.
  694. //
  695. CDbProperties & dbp2 = *((CDbProperties *) pDbProperties);
  696. // Make and marshall v5 properties
  697. XInterface<CDbProperties> xdbp( new CDbProperties() );
  698. if ( xdbp.IsNull() )
  699. THROW( CException( E_OUTOFMEMORY ) );
  700. TranslateNewPropsToOldProps( xdbp.GetReference(), dbp2 );
  701. CSizeSerStream ssSize;
  702. xdbp->Marshall( ssSize );
  703. ULONG cbProps = ssSize.Size();
  704. //
  705. // Compute the size of the dbproperties to be sent.
  706. // The DBPROPSET_ROWSET properties aren't used on the server side in
  707. // this form -- it's a waste to marshall/unmarshall 0x27 properties
  708. // for no good reason. The rowset props we care about are sent in
  709. // a compressed form when a query is issued.
  710. //
  711. CSizeSerStream ssSize2;
  712. GUID guidRowsetProp = DBPROPSET_ROWSET;
  713. dbp2.Marshall( ssSize2, 1, &guidRowsetProp );
  714. ULONG cbProps2 = ssSize2.Size();
  715. prxDebugOut(( DEB_ITRACE, "cb old props %d, cb new props: %d\n",
  716. cbProps, cbProps2 ));
  717. DWORD cbRequest = CPMConnectIn::SizeOf( awcThisMachine,
  718. awcThisUser,
  719. cbProps,
  720. cbProps2 );
  721. XArray<BYTE> xRequest( cbRequest );
  722. CPMConnectIn *pRequest = new( xRequest.Get() )
  723. CPMConnectIn( awcThisMachine,
  724. awcThisUser,
  725. IsServerRemote(),
  726. cbProps,
  727. cbProps2 );
  728. //
  729. // Serialize the DbProperties.
  730. //
  731. BYTE * pb = pRequest->GetBlobStartAddr();
  732. CMemSerStream ss( pb, cbProps );
  733. xdbp->Marshall( ss );
  734. BYTE * pb2 = pRequest->GetBlob2StartAddr();
  735. CMemSerStream ss2( pb2, cbProps2 );
  736. dbp2.Marshall( ss2, 1, &guidRowsetProp );
  737. pRequest->SetCheckSum( cbRequest );
  738. CPMConnectOut reply;
  739. DWORD cbReply;
  740. DataWriteRead( pRequest,
  741. cbRequest,
  742. &reply,
  743. sizeof reply,
  744. cbReply );
  745. Win4Assert( sizeof reply == cbReply );
  746. _ServerVersion = reply.ServerVersion();
  747. } //CRequestClient
  748. //+-------------------------------------------------------------------------
  749. //
  750. // Member: CRequestClient::Disconnect, public
  751. //
  752. // Synopsis: Sends a disconnect message to the server, which will then
  753. // do a Win32 disconnect from the pipe. After this call, the
  754. // pipe handle can only be closed.
  755. //
  756. // History: 16-Sep-96 dlee Created.
  757. //
  758. //--------------------------------------------------------------------------
  759. void CRequestClient::Disconnect()
  760. {
  761. CProxyMessage request( pmDisconnect );
  762. DataWrite( &request, sizeof request );
  763. } //Disconnect
  764. //+-------------------------------------------------------------------------
  765. //
  766. // Member: CRequestClient::EnableNotify, public
  767. //
  768. // Synopsis: Tells the class that the notify thread will be doing reads
  769. // for data threads.
  770. //
  771. // History: 16-Sep-96 dlee Created.
  772. //
  773. //--------------------------------------------------------------------------
  774. void CRequestClient::EnableNotify()
  775. {
  776. CLock lock( _mutex );
  777. prxDebugOut(( DEB_ITRACE, "enable notify\n" ));
  778. Win4Assert( !_fNotifyOn );
  779. _fNotifyOn = TRUE;
  780. _fNotifyEverOn = TRUE;
  781. prxDebugOut(( DEB_ITRACE, "enabled notify\n" ));
  782. } //EnableNotify
  783. //+-------------------------------------------------------------------------
  784. //
  785. // Member: CRequestClient::DisableNotify, public
  786. //
  787. // Synopsis: Tells the class that the notify thread is busy so
  788. // data threads should wait for themselves.
  789. //
  790. // History: 16-Sep-96 dlee Created.
  791. //
  792. //--------------------------------------------------------------------------
  793. void CRequestClient::DisableNotify()
  794. {
  795. CReleasableLock lock( _mutex );
  796. prxDebugOut(( DEB_ITRACE, "disable notify\n" ));
  797. Win4Assert( _fNotifyOn );
  798. // If a read is pending for the notify thread to complete,
  799. // wake the data thread up so it can wait for itself.
  800. _fNotifyOn = FALSE;
  801. if ( _fReadPending )
  802. {
  803. _pvDataTemp = 0;
  804. _eventData.Set();
  805. lock.Release();
  806. _eventDataDone.Wait();
  807. }
  808. prxDebugOut(( DEB_ITRACE, "disabled notify\n" ));
  809. } //DisableNotify
  810. //+-------------------------------------------------------------------------
  811. //
  812. // Member: CRequestClient::DataWrite, public
  813. //
  814. // Synopsis: Writes data to the pipe
  815. //
  816. // Arguments: [pvWrite] - pointer to the buffer to be written
  817. // [cbWrite] - # of bytes to write
  818. //
  819. // History: 16-Sep-96 dlee Created.
  820. //
  821. //--------------------------------------------------------------------------
  822. void CRequestClient::DataWrite(
  823. void * pvWrite,
  824. DWORD cbWrite )
  825. {
  826. CLock lockData( _mutexData );
  827. CLock lock( _mutex );
  828. WriteSync( pvWrite, cbWrite );
  829. } //DataWrite
  830. //+-------------------------------------------------------------------------
  831. //
  832. // Member: CRequestClient::DataWriteRead, public
  833. //
  834. // Synopsis: Does a data (non-notification) write/read transaction with
  835. // the server.
  836. //
  837. // Arguments: [pvWrite] - Buffer to be written
  838. // [cbToWrite] - # of bytes to write
  839. // [pvRead] - Buffer for read result
  840. // [cbReadRequest] - Size of pvRead
  841. // [cbRead] - Returns # of bytes read
  842. //
  843. // History: 16-Sep-96 dlee Created.
  844. //
  845. //--------------------------------------------------------------------------
  846. void CRequestClient::DataWriteRead(
  847. void * pvWrite,
  848. DWORD cbWrite,
  849. void * pvRead,
  850. DWORD cbToRead,
  851. DWORD & cbRead )
  852. {
  853. int ExpectedMsg = ((CProxyMessage *)pvWrite)->GetMessage();
  854. prxDebugOut(( DEB_ITRACE, "DataWriteRead msg %d, cb %d\n",
  855. ExpectedMsg, cbWrite ));
  856. CLock lockData( _mutexData );
  857. CReleasableLock lock( _mutex );
  858. if ( _fNotifyOn )
  859. {
  860. WriteSync( pvWrite, cbWrite );
  861. _fReadPending = TRUE;
  862. lock.Release();
  863. _eventData.Wait();
  864. _fReadPending = FALSE;
  865. prxDebugOut(( DEB_ITRACE,
  866. "dwr eventdata triggered, _pvDataTemp: %p\n",
  867. _pvDataTemp ));
  868. // set this event when we fall out of scope
  869. CEventSetter setter( _eventDataDone );
  870. if ( 0 == _pvDataTemp )
  871. {
  872. // we can wait ourselves
  873. lock.Request();
  874. ReadSync( pvRead, cbToRead, cbRead );
  875. prxDebugOut(( DEB_ITRACE, "dwr done, this, cb: %d\n", cbRead ));
  876. }
  877. else
  878. {
  879. // notify thread completed the read for us
  880. Win4Assert( _cbDataTemp <= cbToRead );
  881. RtlCopyMemory( pvRead, _pvDataTemp, _cbDataTemp );
  882. cbRead = _cbDataTemp;
  883. prxDebugOut(( DEB_ITRACE, "dwr done, other, cb: %d\n", cbRead ));
  884. }
  885. }
  886. else
  887. {
  888. if ( _fNotifyEverOn )
  889. {
  890. // Spurious notify messages prohibit use of TransactSync. Use
  891. // an individual Write, then Read until the appropriate msg is
  892. // found, throwing away unwanted notification messages.
  893. WriteSync( pvWrite, cbWrite );
  894. do
  895. {
  896. // Some notification messages are larger than what we might
  897. // be reading here, so we may need to use a temporary buffer.
  898. void * pvReadBuffer = pvRead;
  899. DWORD cbReadBuffer = cbToRead;
  900. // CPMRatioFinishedOut is the largest notification msg.
  901. // Change this code if you add a larger notification message.
  902. Win4Assert( sizeof CPMRatioFinishedOut >=
  903. sizeof CPMSendNotifyOut );
  904. CPMRatioFinishedOut pmTmp;
  905. if ( cbToRead < sizeof pmTmp )
  906. {
  907. pvReadBuffer = &pmTmp;
  908. cbReadBuffer = sizeof pmTmp;
  909. }
  910. ReadSync( pvReadBuffer, cbReadBuffer, cbRead );
  911. int msg = ((CProxyMessage *) pvReadBuffer)->GetMessage();
  912. prxDebugOut(( DEB_ITRACE, "dwr done, msg %d cb: %d\n",
  913. msg, cbRead ));
  914. if ( ExpectedMsg == msg )
  915. {
  916. // Copy from the temporary buffer if it was used.
  917. if ( pvReadBuffer != pvRead )
  918. {
  919. // Normal case and error case...
  920. Win4Assert( cbToRead <= cbRead ||
  921. sizeof CProxyMessage == cbRead );
  922. RtlCopyMemory( pvRead, pvReadBuffer, cbRead );
  923. }
  924. break;
  925. }
  926. prxDebugOut(( DEB_WARN,
  927. "dwr tossing spurious notify msg %d cb: %d\n",
  928. msg, cbRead ));
  929. } while ( TRUE );
  930. }
  931. else
  932. {
  933. TransactSync( pvWrite, cbWrite, pvRead, cbToRead, cbRead );
  934. }
  935. }
  936. CProxyMessage &reply = * (CProxyMessage *) pvRead;
  937. // If the message returned a failure code, throw it.
  938. if ( ! SUCCEEDED( reply.GetStatus() ) )
  939. QUIETTHROW( CException( reply.GetStatus() ) );
  940. } //DataWriteRead
  941. //+-------------------------------------------------------------------------
  942. //
  943. // Member: CRequestClient::NotifyWriteRead, public
  944. //
  945. // Synopsis: Does a notification (non-data) write/read transaction with
  946. // the server. If the read is a message destined for another'
  947. // thread, notify the thread that data is available and wait
  948. // for another message.
  949. //
  950. // Arguments: [hStopNotify] - if signalled, read is cancelled
  951. // [pvWrite] - Buffer to be written
  952. // [cbWrite] - # of bytes to write
  953. // [pvRead] - Buffer for read result
  954. // [cbBuffer] - Size of pvRead
  955. // [cbRead] - Returns # of bytes read
  956. //
  957. // Returns: TRUE if hStopNotify was signalled, FALSE otherwise
  958. //
  959. // Notes: This function knows about pmGetNotify and pmSendNotify
  960. //
  961. // History: 16-Sep-96 dlee Created.
  962. //
  963. //--------------------------------------------------------------------------
  964. BOOL CRequestClient::NotifyWriteRead(
  965. HANDLE hStopNotify,
  966. void * pvWrite,
  967. DWORD cbWrite,
  968. void * pvRead,
  969. DWORD cbBuffer,
  970. DWORD & cbRead )
  971. {
  972. // First check if we are shutting down the query
  973. if ( 0 == WaitForSingleObject( hStopNotify, 0 ) )
  974. return TRUE;
  975. // ensure notifications are disabled by the time we exit scope
  976. Win4Assert( !_fNotifyOn );
  977. CEnableNotify enable( *this );
  978. Win4Assert( _fNotifyOn );
  979. // If a pmGetNotify is sent and the reply is pmGetNotify, it means that
  980. // notifications aren't available yet and a pmSendNotify will come later.
  981. // If a pmSendNotify is replied, notifications were available.
  982. int ExpectedMsg = ((CProxyMessage *)pvWrite)->GetMessage();
  983. if ( pmGetNotify == ExpectedMsg )
  984. ExpectedMsg = pmSendNotify;
  985. {
  986. CLock lock( _mutex );
  987. WriteSync( pvWrite, cbWrite );
  988. }
  989. do
  990. {
  991. BYTE abBuf[ cbMaxProxyBuffer ];
  992. cbRead = 0;
  993. BOOL fStopNotify = ReadSync( abBuf,
  994. sizeof abBuf,
  995. cbRead,
  996. hStopNotify );
  997. // If we got any data, process the data even if "stop notify" is
  998. // true, since we don't want to leave the data thread stranded.
  999. if ( 0 != cbRead )
  1000. {
  1001. CProxyMessage &msg = * (CProxyMessage *) abBuf;
  1002. prxDebugOut(( DEB_ITRACE,
  1003. "NotifyWriteRead complete cb %d, msg %d\n",
  1004. cbRead,
  1005. msg.GetMessage() ));
  1006. // If the pmGetNotify came back, loop around and wait for
  1007. // a real notification or a message intended for a data thread.
  1008. if ( pmGetNotify == msg.GetMessage() )
  1009. {
  1010. if ( ! SUCCEEDED( msg.GetStatus() ) )
  1011. THROW( CException( msg.GetStatus() ) );
  1012. }
  1013. else
  1014. {
  1015. // If this is a notification, return so the client can be
  1016. // advised, then this function will be re-entered.
  1017. if ( msg.GetMessage() == ExpectedMsg )
  1018. {
  1019. CProxyMessage &reply = * (CProxyMessage *) pvRead;
  1020. if ( ! SUCCEEDED( msg.GetStatus() ) )
  1021. THROW( CException( msg.GetStatus() ) );
  1022. Win4Assert( cbRead <= cbBuffer );
  1023. RtlCopyMemory( pvRead, abBuf, cbRead );
  1024. return fStopNotify;
  1025. }
  1026. // Tell the thread waiting for data that it's available.
  1027. // That thread can throw if the status is failure.
  1028. _pvDataTemp = abBuf;
  1029. _cbDataTemp = cbRead;
  1030. _eventData.Set();
  1031. _eventDataDone.Wait();
  1032. }
  1033. }
  1034. if ( fStopNotify )
  1035. return TRUE;
  1036. } while ( TRUE );
  1037. return FALSE;
  1038. } //NotifyWriteRead