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.

1580 lines
37 KiB

  1. /*++
  2. Copyright (c) 1998-2000 Microsoft Corporation
  3. Module Name:
  4. w32proc.cpp
  5. Abstract:
  6. Contains the parent of the Win32 IO processing class hierarchy
  7. for TS Device Redirection, W32ProcObj.
  8. Author:
  9. madan appiah (madana) 16-Sep-1998
  10. Revision History:
  11. --*/
  12. #include <precom.h>
  13. #define TRC_FILE "w32proc"
  14. #include "rdpdrcom.h"
  15. #include <winsock.h>
  16. #include "dbt.h"
  17. #include "w32proc.h"
  18. #include "w32drprn.h"
  19. #include "w32drman.h"
  20. #include "w32drlpt.h"
  21. #include "w32drcom.h"
  22. #include "w32drive.h"
  23. #include "drconfig.h"
  24. #include "drdbg.h"
  25. #include "thrpool.h"
  26. W32ProcObj::W32ProcObj( VCManager *pVCM ) : ProcObj(pVCM)
  27. /*++
  28. Routine Description:
  29. Constructor
  30. Arguments:
  31. pVCM - Virtual Channel IO Manager
  32. Return Value:
  33. NA
  34. --*/
  35. {
  36. DC_BEGIN_FN("W32ProcObj::W32ProcObj");
  37. //
  38. // Initialize the member variables.
  39. //
  40. _pWorkerThread = NULL;
  41. _bWin9xFlag = FALSE;
  42. _hRdpDrModuleHandle = NULL;
  43. _bLocalDevicesScanned = FALSE;
  44. _isShuttingDown = FALSE;
  45. //
  46. // Unit-Test Functions that Tests Thread Pools in the Background
  47. //
  48. #if DBG
  49. //ThreadPoolTestInit();
  50. #endif
  51. DC_END_FN();
  52. }
  53. W32ProcObj::~W32ProcObj(
  54. VOID
  55. )
  56. /*++
  57. Routine Description:
  58. Destructor for the W32ProcObj object.
  59. Arguments:
  60. none.
  61. Return Value:
  62. None
  63. --*/
  64. {
  65. DC_BEGIN_FN("W32ProcObj::~W32ProcObj");
  66. //
  67. // Shutdown the worker thread and cleanup if we are not already shut down.
  68. //
  69. if ((_pWorkerThread != NULL) && (_pWorkerThread->shutDownFlag == FALSE)) {
  70. Shutdown();
  71. }
  72. DC_END_FN();
  73. return;
  74. }
  75. ULONG
  76. W32ProcObj::GetDWordParameter(
  77. LPTSTR pszValueName,
  78. PULONG pulValue
  79. )
  80. /*++
  81. Routine Description:
  82. Reads a parameter ULONG value from the registry.
  83. Arguments:
  84. pszValueName - pointer to the value name string.
  85. pulValue - pointer to an ULONG parameter location.
  86. Return Value:
  87. Windows Error Code.
  88. --*/
  89. {
  90. ULONG ulError;
  91. HKEY hRootKey = HKEY_CURRENT_USER;
  92. HKEY hKey = NULL;
  93. ULONG ulType;
  94. ULONG ulValueDataSize;
  95. DC_BEGIN_FN("W32ProcObj::GetDWordParameter");
  96. TryAgain:
  97. ulError =
  98. RegOpenKeyEx(
  99. hRootKey,
  100. REG_RDPDR_PARAMETER_PATH,
  101. 0L,
  102. KEY_READ,
  103. &hKey);
  104. if (ulError != ERROR_SUCCESS) {
  105. TRC_ALT((TB, _T("RegOpenKeyEx() failed, %ld."), ulError));
  106. if( hRootKey == HKEY_CURRENT_USER ) {
  107. //
  108. // try with HKEY_LOCAL_MACHINE.
  109. //
  110. hRootKey = HKEY_LOCAL_MACHINE;
  111. goto TryAgain;
  112. }
  113. goto Cleanup;
  114. }
  115. ulValueDataSize = sizeof(ULONG);
  116. ulError =
  117. RegQueryValueEx(
  118. hKey,
  119. pszValueName,
  120. NULL,
  121. &ulType,
  122. (PBYTE)pulValue,
  123. &ulValueDataSize);
  124. if (ulError != ERROR_SUCCESS) {
  125. TRC_ALT((TB, _T("RegQueryValueEx() failed, %ld."), ulError));
  126. if( hRootKey == HKEY_CURRENT_USER ) {
  127. //
  128. // try with HKEY_LOCAL_MACHINE.
  129. //
  130. hRootKey = HKEY_LOCAL_MACHINE;
  131. RegCloseKey( hKey );
  132. hKey = NULL;
  133. goto TryAgain;
  134. }
  135. goto Cleanup;
  136. }
  137. ASSERT(ulType == REG_DWORD);
  138. ASSERT(ulValueDataSize == sizeof(ULONG));
  139. TRC_NRM((TB, _T("Parameter Value, %lx."), *pulValue));
  140. //
  141. // successfully done.
  142. //
  143. Cleanup:
  144. if( hKey != NULL ) {
  145. RegCloseKey( hKey );
  146. }
  147. DC_END_FN();
  148. return( ulError );
  149. }
  150. ULONG W32ProcObj::GetStringParameter(
  151. IN LPTSTR valueName,
  152. OUT DRSTRING value,
  153. IN ULONG maxSize
  154. )
  155. /*++
  156. Routine Description:
  157. Return Configurable string parameter.
  158. Arguments:
  159. valueName - Name of value to retrieve.
  160. value - Storage location for retrieved value.
  161. maxSize - Number of bytes available in the "value" data
  162. area.
  163. Return Value:
  164. Windows Error Code.
  165. --*/
  166. {
  167. ULONG ulError;
  168. HKEY hRootKey;
  169. HKEY hKey = NULL;
  170. ULONG ulType;
  171. DC_BEGIN_FN("W32ProcObj::GetStringParameter");
  172. //
  173. // Start with HKCU.
  174. //
  175. hRootKey = HKEY_CURRENT_USER;
  176. TryAgain:
  177. //
  178. // Open the reg key.
  179. //
  180. ulError =
  181. RegOpenKeyEx(
  182. hRootKey,
  183. REG_RDPDR_PARAMETER_PATH,
  184. 0L,
  185. KEY_READ,
  186. &hKey);
  187. if (ulError != ERROR_SUCCESS) {
  188. TRC_ERR((TB, _T("RegOpenKeyEx %ld."), ulError));
  189. //
  190. // Try with HKEY_LOCAL_MACHINE.
  191. //
  192. if( hRootKey == HKEY_CURRENT_USER ) {
  193. hRootKey = HKEY_LOCAL_MACHINE;
  194. goto TryAgain;
  195. }
  196. goto Cleanup;
  197. }
  198. //
  199. // Query the value.
  200. //
  201. ulError =
  202. RegQueryValueEx(
  203. hKey,
  204. valueName,
  205. NULL,
  206. &ulType,
  207. (PBYTE)value,
  208. &maxSize);
  209. if (ulError != ERROR_SUCCESS) {
  210. TRC_ERR((TB, _T("RegQueryValueEx %ld."), ulError));
  211. //
  212. // Try with HKEY_LOCAL_MACHINE.
  213. //
  214. if( hRootKey == HKEY_CURRENT_USER ) {
  215. hRootKey = HKEY_LOCAL_MACHINE;
  216. RegCloseKey( hKey );
  217. hKey = NULL;
  218. goto TryAgain;
  219. }
  220. goto Cleanup;
  221. }
  222. ASSERT(ulType == REG_SZ);
  223. TRC_NRM((TB, _T("Returning %s"), value));
  224. //
  225. // Successfully done.
  226. //
  227. Cleanup:
  228. if( hKey != NULL ) {
  229. RegCloseKey( hKey );
  230. }
  231. DC_END_FN();
  232. return ulError;
  233. }
  234. ULONG W32ProcObj::Initialize()
  235. /*++
  236. Routine Description:
  237. Initialize an instance of this class.
  238. Arguments:
  239. Return Value:
  240. ERROR_SUCCESS on success. Windows error status, otherwise.
  241. --*/
  242. {
  243. ULONG status = ERROR_SUCCESS;
  244. DC_BEGIN_FN("W32ProcObj::Initialize");
  245. //
  246. // We are not shutting down.
  247. //
  248. _isShuttingDown = FALSE;
  249. //
  250. // Find out which version of the OS is being run.
  251. //
  252. OSVERSIONINFO osVersion;;
  253. osVersion.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
  254. if (!GetVersionEx(&osVersion)) {
  255. status = GetLastError();
  256. TRC_ERR((TB, _T("GetVersionEx: %08X"), status));
  257. SetValid(FALSE);
  258. goto CLEANUPANDEXIT;
  259. }
  260. //
  261. // Are we a 9x OS?
  262. //
  263. if (osVersion.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS) {
  264. _bWin9xFlag = TRUE;
  265. }
  266. //
  267. // Get the background thread timeout value from the registry,
  268. // if it is defined.
  269. //
  270. if (GetDWordParameter(
  271. REGISTRY_BACKGROUNDTHREAD_TIMEOUT_NAME,
  272. &_threadTimeout
  273. ) != ERROR_SUCCESS) {
  274. _threadTimeout = REGISTRY_BACKGROUNDTHREAD_TIMEOUT_DEFAULT;
  275. }
  276. TRC_NRM((TB, _T("Thread timeout is %08X"), _threadTimeout));
  277. //
  278. // Instantiate the thread pool.
  279. //
  280. _threadPool = new ThreadPool(THRPOOL_DEFAULTMINTHREADS,
  281. THRPOOL_DEFAULTMAXTHREADS, _threadTimeout);
  282. if (_threadPool == NULL) {
  283. status = ERROR_NOT_ENOUGH_MEMORY;
  284. TRC_ERR((TB, L"Error allocating thread pool."));
  285. SetValid(FALSE);
  286. goto CLEANUPANDEXIT;
  287. }
  288. status = _threadPool->Initialize();
  289. if (status != ERROR_SUCCESS) {
  290. delete _threadPool;
  291. _threadPool = NULL;
  292. SetValid(FALSE);
  293. goto CLEANUPANDEXIT;
  294. }
  295. //
  296. // Create and resume the worker thread.
  297. //
  298. status = CreateWorkerThreadEntry(&_pWorkerThread);
  299. if (status != ERROR_SUCCESS) {
  300. SetValid(FALSE);
  301. goto CLEANUPANDEXIT;
  302. }
  303. if (ResumeThread(_pWorkerThread->hWorkerThread) == 0xFFFFFFFF ) {
  304. SetValid(FALSE);
  305. status = GetLastError();
  306. TRC_ERR((TB, _T("ResumeThread: %08X"), status));
  307. goto CLEANUPANDEXIT;
  308. }
  309. //
  310. // Call the parent's init function.
  311. //
  312. status = ProcObj::Initialize();
  313. if (status != ERROR_SUCCESS) {
  314. goto CLEANUPANDEXIT;
  315. }
  316. CLEANUPANDEXIT:
  317. DC_END_FN();
  318. return status;
  319. }
  320. VOID
  321. W32ProcObj::Shutdown()
  322. /*++
  323. Routine Description:
  324. Triggers the _hShutdownEvent event to terminate the worker thread and
  325. cleans up all resources.
  326. Arguments:
  327. Return Value:
  328. None
  329. --*/
  330. {
  331. ULONG i;
  332. DWORD waitResult;
  333. DC_BEGIN_FN("W32ProcObj::Shutdown");
  334. #if DBG
  335. //ThreadPoolTestShutdown();
  336. #endif
  337. //
  338. // Indicate that the object is in a shutdown state.
  339. //
  340. _isShuttingDown = TRUE;
  341. //
  342. // Wait for the worker thread to shut down.
  343. //
  344. if (_pWorkerThread != NULL) {
  345. //
  346. // Trigger worker thread shutdown and record that we are shutting down.
  347. //
  348. _pWorkerThread->shutDownFlag = TRUE;
  349. SetEvent(_pWorkerThread->controlEvent);
  350. //
  351. // Wait for it to shut down. DebugBreak if we hit the timeout, even in
  352. // free builds. By default, the timeout is infinite.
  353. //
  354. if (_pWorkerThread->hWorkerThread != NULL) {
  355. TRC_NRM((TB, _T("Waiting for worker thread to shut down.")));
  356. waitResult = WaitForSingleObject(
  357. _pWorkerThread->hWorkerThread,
  358. _threadTimeout
  359. );
  360. if (waitResult == WAIT_TIMEOUT) {
  361. TRC_ERR((TB, _T("Thread timeout")));
  362. DebugBreak();
  363. }
  364. else if (waitResult != WAIT_OBJECT_0) {
  365. TRC_ERR((TB, _T("WaitForSingleObject: %08X"), waitResult));
  366. ASSERT(FALSE);
  367. }
  368. }
  369. //
  370. // Remove all the threads in the thread pool.
  371. //
  372. if (_threadPool != NULL) {
  373. _threadPool->RemoveAllThreads();
  374. }
  375. //
  376. // Finish all outstanding IO requests and clean up respective
  377. // request contexts. First object is the control event. Second
  378. // object is the operation dispatch queue data ready event.
  379. //
  380. for (i=2; i<_pWorkerThread->waitableObjectCount; i++) {
  381. PASYNCIOREQCONTEXT reqContext = _pWorkerThread->waitingReqs[i];
  382. ASSERT(reqContext != NULL);
  383. if (reqContext->ioCompleteFunc != NULL) {
  384. reqContext->ioCompleteFunc(reqContext->clientContext,
  385. ERROR_CANCELLED);
  386. }
  387. delete reqContext;
  388. }
  389. //
  390. // Finish any pending operations in the worker thread's opearation
  391. // dispatch queue.
  392. //
  393. //
  394. // Clean up the control event and release the worker thread info. struct.
  395. //
  396. ASSERT(_pWorkerThread->controlEvent != NULL);
  397. CloseHandle(_pWorkerThread->controlEvent);
  398. if (_pWorkerThread->dispatchQueue != NULL) {
  399. delete _pWorkerThread->dispatchQueue;
  400. }
  401. delete _pWorkerThread;
  402. _pWorkerThread = NULL;
  403. }
  404. //
  405. // Let go of the thread pool.
  406. //
  407. if (_threadPool != NULL) {
  408. delete _threadPool;
  409. _threadPool = NULL;
  410. }
  411. //
  412. // Release attached DLL's
  413. //
  414. if (_hRdpDrModuleHandle != NULL) {
  415. FreeLibrary( _hRdpDrModuleHandle );
  416. _hRdpDrModuleHandle = NULL;
  417. }
  418. DC_END_FN();
  419. return;
  420. }
  421. VOID
  422. W32ProcObj::AnnounceDevicesToServer()
  423. /*++
  424. Routine Description:
  425. Enumerate devices and announce them to the server.
  426. Arguments:
  427. Return Value:
  428. --*/
  429. {
  430. DC_BEGIN_FN("W32ProcObj::AnnounceDevicesToServer");
  431. DispatchAsyncIORequest(
  432. (RDPAsyncFunc_StartIO)W32ProcObj::_AnnounceDevicesToServerFunc,
  433. NULL,
  434. NULL,
  435. this
  436. );
  437. }
  438. HANDLE W32ProcObj::_AnnounceDevicesToServerFunc(
  439. W32ProcObj *obj,
  440. DWORD *status
  441. )
  442. /*++
  443. Routine Description:
  444. Enumerate devices and announce them to the server from the
  445. worker thread.
  446. Arguments:
  447. obj - Relevant W32ProcObj instance.
  448. status - Return status.
  449. Return Value:
  450. NULL
  451. --*/
  452. {
  453. obj->AnnounceDevicesToServerFunc(status);
  454. return NULL;
  455. }
  456. VOID W32ProcObj::AnnounceDevicesToServerFunc(
  457. DWORD *status
  458. )
  459. {
  460. DC_BEGIN_FN("W32ProcObj::AnnounceDevicesToServerFunc");
  461. ULONG count, i;
  462. PRDPDR_HEADER pPacketHeader = NULL;
  463. INT sz;
  464. ASSERT(_initialized);
  465. *status = ERROR_SUCCESS;
  466. //
  467. // If we haven't already scanned for local devices.
  468. //
  469. if (!_bLocalDevicesScanned) {
  470. _bLocalDevicesScanned = TRUE;
  471. //
  472. // Invoke the enum functions.
  473. //
  474. count = DeviceEnumFunctionsCount();
  475. for (i=0; i<count; i++) {
  476. // Bail out if the shutdown flag is set.
  477. if (_pWorkerThread->shutDownFlag == TRUE) {
  478. TRC_NRM((TB, _T("Bailing out because shutdown flag is set.")));
  479. *status = WAIT_TIMEOUT;
  480. goto CLEANUPANDEXIT;
  481. }
  482. ASSERT(_DeviceEnumFunctions[i] != NULL);
  483. _DeviceEnumFunctions[i](this, _deviceMgr);
  484. }
  485. }
  486. //
  487. // Send the announce packet to the server. _pVCMgr cleans
  488. // up the packet on failure and on success.
  489. //
  490. pPacketHeader = GenerateAnnouncePacket(&sz, FALSE);
  491. if (pPacketHeader) {
  492. pPacketHeader->Component = RDPDR_CTYP_CORE;
  493. pPacketHeader->PacketId = DR_CORE_DEVICELIST_ANNOUNCE;
  494. _pVCMgr->ChannelWriteEx(pPacketHeader, sz);
  495. }
  496. CLEANUPANDEXIT:
  497. DC_END_FN();
  498. }
  499. DWORD W32ProcObj::DispatchAsyncIORequest(
  500. IN RDPAsyncFunc_StartIO ioStartFunc,
  501. IN OPTIONAL RDPAsyncFunc_IOComplete ioCompleteFunc,
  502. IN OPTIONAL RDPAsyncFunc_IOCancel ioCancelFunc,
  503. IN OPTIONAL PVOID clientContext
  504. )
  505. /*++
  506. Routine Description:
  507. Dispatch an asynchronous IO function.
  508. Arguments:
  509. startFunc - Points to the function that will be called to initiate the IO.
  510. finishFunc - Optionally, points to the function that will be called once
  511. the IO has completed.
  512. clientContext - Optional client information to be associated with the
  513. IO request.
  514. Return Value:
  515. ERROR_SUCCESS or Windows error code.
  516. --*/
  517. {
  518. PASYNCIOREQCONTEXT reqContext;
  519. DWORD result;
  520. DC_BEGIN_FN("W32ProcObj::DispatchAsyncIORequest");
  521. //
  522. // Assert that we are valid.
  523. //
  524. ASSERT(IsValid());
  525. if (!IsValid()) {
  526. DC_END_FN();
  527. return ERROR_INVALID_FUNCTION;
  528. }
  529. //
  530. // Instantiate the IO request context.
  531. //
  532. result = ERROR_SUCCESS;
  533. reqContext = new ASYNCIOREQCONTEXT();
  534. if (reqContext == NULL) {
  535. TRC_ERR((TB, _T("Alloc failed.")));
  536. result = ERROR_NOT_ENOUGH_MEMORY;
  537. }
  538. //
  539. // Fill it in.
  540. //
  541. if (result == ERROR_SUCCESS) {
  542. reqContext->ioStartFunc = ioStartFunc;
  543. reqContext->ioCompleteFunc = ioCompleteFunc;
  544. reqContext->ioCancelFunc = ioCancelFunc;
  545. reqContext->clientContext = clientContext;
  546. reqContext->instance = this;
  547. }
  548. //
  549. // Shove it into the worker thread's operation dispatch queue.
  550. //
  551. if (result == ERROR_SUCCESS) {
  552. if (!_pWorkerThread->dispatchQueue->Enqueue(
  553. (W32DispatchQueueFunc)_DispatchAsyncIORequest_Private,
  554. reqContext
  555. )) {
  556. result = GetLastError();
  557. delete reqContext;
  558. }
  559. }
  560. DC_END_FN();
  561. return result;
  562. }
  563. VOID W32ProcObj::DispatchAsyncIORequest_Private(
  564. IN PASYNCIOREQCONTEXT reqContext,
  565. IN BOOL cancelled
  566. )
  567. /*++
  568. Routine Description:
  569. Handler for asynchronous IO request dispatching.
  570. Arguments:
  571. reqContext - Request context for this function.
  572. cancelled - True if the queued request was cancelled and we need
  573. to clean up.
  574. Return Value:
  575. --*/
  576. {
  577. HANDLE waitableObject;
  578. DWORD result;
  579. DC_BEGIN_FN("W32ProcObj::DispatchAsyncIORequest_Private");
  580. //
  581. // If we are being cancelled, call the cancel function. Otherwise, start the
  582. // IO transaction.
  583. //
  584. if (!cancelled) {
  585. waitableObject = reqContext->ioStartFunc(reqContext->clientContext, &result);
  586. }
  587. else {
  588. TRC_NRM((TB, _T("Cancelling.")));
  589. if (reqContext->ioCancelFunc != NULL) {
  590. reqContext->ioCancelFunc(reqContext->clientContext);
  591. }
  592. waitableObject = NULL;
  593. result = ERROR_CANCELLED;
  594. }
  595. //
  596. // If we have a waitable object then add it to our list.
  597. //
  598. if (waitableObject != NULL) {
  599. result = AddWaitableObjectToWorkerThread(
  600. _pWorkerThread,
  601. waitableObject,
  602. reqContext
  603. );
  604. //
  605. // If we couldn't add the waitable object because we have
  606. // exceeded our max, then requeue the request, but do not
  607. // signal new data in the queue. We will check for new
  608. // data as soon as the waitable object count goes below the
  609. // max.
  610. //
  611. if (result == ERROR_INVALID_INDEX) {
  612. if (!_pWorkerThread->dispatchQueue->Requeue(
  613. (W32DispatchQueueFunc)_DispatchAsyncIORequest_Private,
  614. reqContext, FALSE)) {
  615. result = GetLastError();
  616. }
  617. else {
  618. result = ERROR_SUCCESS;
  619. }
  620. }
  621. }
  622. //
  623. // Complete if IO is not pending and clean up the request context.
  624. //
  625. if (waitableObject == NULL) {
  626. if (!cancelled) {
  627. if (reqContext->ioCompleteFunc != NULL) {
  628. reqContext->ioCompleteFunc(reqContext->clientContext, result);
  629. }
  630. }
  631. delete reqContext;
  632. }
  633. DC_END_FN();
  634. }
  635. ULONG
  636. W32ProcObj::CreateWorkerThreadEntry(
  637. PTHREAD_INFO *ppThreadInfo
  638. )
  639. /*++
  640. Routine Description:
  641. Create a worker thread entry and start the worker thread.
  642. Arguments:
  643. ppThreadInfo - pointer a location where the newly created thread info is
  644. returned.
  645. Return Value:
  646. Windows Status Code.
  647. --*/
  648. {
  649. ULONG ulRetCode;
  650. PTHREAD_INFO pThreadInfo = NULL;
  651. DC_BEGIN_FN("W32ProcObj::CreateWorkerThreadEntry");
  652. //
  653. // Initialize return value.
  654. //
  655. *ppThreadInfo = NULL;
  656. //
  657. // Create the associated thread data structure.
  658. //
  659. pThreadInfo = new THREAD_INFO();
  660. if (pThreadInfo == NULL) {
  661. TRC_ERR((TB, _T("Failed to alloc thread chain info structure.")));
  662. ulRetCode = ERROR_NOT_ENOUGH_MEMORY;
  663. goto Cleanup;
  664. }
  665. //
  666. // Instantiate the dispatch queue.
  667. //
  668. pThreadInfo->dispatchQueue = new W32DispatchQueue();
  669. if (pThreadInfo->dispatchQueue == NULL) {
  670. TRC_ERR((TB, _T("Failed to alloc thread chain info structure.")));
  671. ulRetCode = ERROR_NOT_ENOUGH_MEMORY;
  672. goto Cleanup;
  673. }
  674. ulRetCode = pThreadInfo->dispatchQueue->Initialize();
  675. if (ulRetCode != ERROR_SUCCESS) {
  676. delete pThreadInfo->dispatchQueue;
  677. delete pThreadInfo;
  678. pThreadInfo = NULL;
  679. goto Cleanup;
  680. }
  681. //
  682. // Create the control event and zero out the shutdown flag.
  683. //
  684. pThreadInfo->shutDownFlag = FALSE;
  685. pThreadInfo->controlEvent = CreateEvent(NULL, TRUE, FALSE, NULL);
  686. if (pThreadInfo->controlEvent == NULL) {
  687. TRC_ERR((TB, _T("CreateEvent %ld."), GetLastError()));
  688. delete pThreadInfo->dispatchQueue;
  689. delete pThreadInfo;
  690. pThreadInfo = NULL;
  691. ulRetCode = GetLastError();
  692. goto Cleanup;
  693. }
  694. //
  695. // Init waiting object info array.
  696. //
  697. memset(pThreadInfo->waitableObjects, 0, sizeof(pThreadInfo->waitableObjects));
  698. memset(pThreadInfo->waitingReqs, 0, sizeof(pThreadInfo->waitingReqs));
  699. //
  700. // Set the first waitable object as the controller event object for
  701. // worker thread shutdown.
  702. //
  703. pThreadInfo->waitableObjects[0] = pThreadInfo->controlEvent;
  704. pThreadInfo->waitableObjectCount = 1;
  705. //
  706. // Set the second waitable object as the waitable event for the operation
  707. // dispatch queue.
  708. //
  709. pThreadInfo->waitableObjects[1] = pThreadInfo->dispatchQueue->GetWaitableObject();
  710. pThreadInfo->waitableObjectCount++;
  711. //
  712. // Create the worker thread.
  713. //
  714. pThreadInfo->hWorkerThread = CreateThread(
  715. NULL, 0, _ObjectWorkerThread,
  716. this, CREATE_SUSPENDED,
  717. &pThreadInfo->ulThreadId
  718. );
  719. //
  720. // If failure.
  721. //
  722. if (pThreadInfo->hWorkerThread == NULL) {
  723. ulRetCode = GetLastError();
  724. TRC_ERR((TB, _T("CreateThread failed, %d."), ulRetCode));
  725. goto Cleanup;
  726. }
  727. //
  728. // Success!
  729. //
  730. ulRetCode = ERROR_SUCCESS;
  731. //
  732. // Set the return value.
  733. //
  734. *ppThreadInfo = pThreadInfo;
  735. //
  736. // Set the thread pointer to NULL so we don't clean up.
  737. //
  738. pThreadInfo = NULL;
  739. Cleanup:
  740. //
  741. // Clean up on error.
  742. //
  743. if (pThreadInfo != NULL) {
  744. if (pThreadInfo->dispatchQueue != NULL) {
  745. delete pThreadInfo->dispatchQueue;
  746. }
  747. ASSERT(ulRetCode != ERROR_SUCCESS);
  748. ASSERT(pThreadInfo->controlEvent != NULL);
  749. CloseHandle(pThreadInfo->controlEvent);
  750. delete pThreadInfo;
  751. }
  752. DC_END_FN();
  753. return ulRetCode;
  754. }
  755. VOID
  756. W32ProcObj::ProcessWorkerThreadObject(
  757. PTHREAD_INFO pThreadInfo,
  758. ULONG offset
  759. )
  760. /*++
  761. Routine Description:
  762. Process a signalled worker thread waitable object.
  763. Arguments:
  764. pThreadInfo - pointer to the thread info structure that triggered this even.
  765. offset - offset of object that is signaled.
  766. Return Value:
  767. None
  768. --*/
  769. {
  770. HANDLE hWaitableObject;
  771. PASYNCIOREQCONTEXT reqContext;
  772. DC_BEGIN_FN("W32ProcObj::ProcessWorkerThreadObject");
  773. //
  774. // Check the validity of the waitable object.
  775. //
  776. if (offset >= pThreadInfo->waitableObjectCount) {
  777. ASSERT(FALSE);
  778. goto Cleanup;
  779. }
  780. //
  781. // Get the parms for this waitable object.
  782. //
  783. hWaitableObject = pThreadInfo->waitableObjects[offset];
  784. reqContext = pThreadInfo->waitingReqs[offset];
  785. //
  786. // Invoke the completion function and clean up the request context.
  787. //
  788. if (reqContext->ioCompleteFunc != NULL) {
  789. reqContext->ioCompleteFunc(reqContext->clientContext, ERROR_SUCCESS);
  790. }
  791. delete reqContext;
  792. //
  793. // Move the last items to the now vacant spot and decrement the count.
  794. //
  795. pThreadInfo->waitableObjects[offset] =
  796. pThreadInfo->waitableObjects[pThreadInfo->waitableObjectCount - 1];
  797. pThreadInfo->waitingReqs[offset] =
  798. pThreadInfo->waitingReqs[pThreadInfo->waitableObjectCount - 1];
  799. //
  800. // Clear the unused spot.
  801. //
  802. memset(&pThreadInfo->waitingReqs[pThreadInfo->waitableObjectCount - 1],
  803. 0,sizeof(pThreadInfo->waitingReqs[pThreadInfo->waitableObjectCount - 1]));
  804. memset(&pThreadInfo->waitableObjects[pThreadInfo->waitableObjectCount - 1],
  805. 0,sizeof(pThreadInfo->waitableObjects[pThreadInfo->waitableObjectCount - 1]));
  806. pThreadInfo->waitableObjectCount--;
  807. //
  808. // Check to see if there are any operations in the queue that are pending
  809. // dispatch. This can happen if an operation was requeued because we
  810. // exceeded the maximum number of waitable objects.
  811. //
  812. CheckForQueuedOperations(pThreadInfo);
  813. Cleanup:
  814. DC_END_FN();
  815. return;
  816. }
  817. ULONG
  818. W32ProcObj::ObjectWorkerThread(
  819. VOID
  820. )
  821. /*++
  822. Routine Description:
  823. Worker Thread that manages waitable objects and their associated
  824. callbacks. This function allows us to do the bulk of the work for
  825. this module in the background so our impact on the client is minimal.
  826. Arguments:
  827. None.
  828. Return Value:
  829. None
  830. --*/
  831. {
  832. ULONG waitResult;
  833. ULONG objectOffset;
  834. W32DispatchQueueFunc func;
  835. PVOID clientData;
  836. DC_BEGIN_FN("W32ProcObj::ObjectWorkerThread");
  837. //
  838. // Loop Forever.
  839. //
  840. for (;;) {
  841. TRC_NRM((TB, _T("Entering wait with %d objects."),
  842. _pWorkerThread->waitableObjectCount));
  843. //
  844. // Wait for all the waitable objects.
  845. //
  846. #ifndef OS_WINCE
  847. waitResult = WaitForMultipleObjectsEx(
  848. _pWorkerThread->waitableObjectCount,
  849. _pWorkerThread->waitableObjects,
  850. FALSE,
  851. INFINITE,
  852. FALSE
  853. );
  854. #else
  855. waitResult = WaitForMultipleObjects(
  856. _pWorkerThread->waitableObjectCount,
  857. _pWorkerThread->waitableObjects,
  858. FALSE,
  859. INFINITE
  860. );
  861. #endif
  862. //
  863. // If the signalled object is the control object or the queue dispatch queue
  864. // data ready object then we need to check for shutdown and for data in the
  865. // dispatch queue.
  866. //
  867. objectOffset = waitResult - WAIT_OBJECT_0;
  868. if ((waitResult == WAIT_FAILED) ||
  869. (objectOffset == 0) ||
  870. (objectOffset == 1)) {
  871. if (_pWorkerThread->shutDownFlag) {
  872. TRC_NRM((TB, _T("Shutting down.")));
  873. break;
  874. }
  875. else {
  876. CheckForQueuedOperations(_pWorkerThread);
  877. }
  878. }
  879. else {
  880. if (objectOffset < _pWorkerThread->waitableObjectCount) {
  881. ProcessWorkerThreadObject(_pWorkerThread, objectOffset);
  882. }
  883. else {
  884. ASSERT(FALSE);
  885. }
  886. }
  887. }
  888. //
  889. // Cancel any outstanding IO requests.
  890. //
  891. TRC_NRM((TB, _T("Canceling outstanding IO.")));
  892. while (_pWorkerThread->dispatchQueue->Dequeue(&func, &clientData)) {
  893. func(clientData, TRUE);
  894. }
  895. DC_END_FN();
  896. return 0;
  897. }
  898. DWORD WINAPI
  899. W32ProcObj::_ObjectWorkerThread(
  900. LPVOID lpParam
  901. )
  902. {
  903. return ((W32ProcObj *)lpParam)->ObjectWorkerThread();
  904. }
  905. VOID W32ProcObj::_DispatchAsyncIORequest_Private(
  906. IN PASYNCIOREQCONTEXT reqContext,
  907. IN BOOL cancelled
  908. )
  909. {
  910. reqContext->instance->DispatchAsyncIORequest_Private(
  911. reqContext,
  912. cancelled);
  913. }
  914. DWORD W32ProcObj::AddWaitableObjectToWorkerThread(
  915. IN PTHREAD_INFO threadInfo,
  916. IN HANDLE waitableObject,
  917. IN PASYNCIOREQCONTEXT reqContext
  918. )
  919. /*++
  920. Routine Description:
  921. Add a waitable object to a worker thread.
  922. Arguments:
  923. threadInfo - Worker thread context.
  924. waitableObject - Waitable object.
  925. reqContext - Context for the IO request.
  926. Return Value:
  927. Returns ERROR_SUCCESS on success. Returns ERROR_INVALID_INDEX if there
  928. isn't currently room for another waitable object in the specified
  929. thread. Otherwise, windows error code is returned.
  930. --*/
  931. {
  932. ULONG waitableObjectCount = threadInfo->waitableObjectCount;
  933. DC_BEGIN_FN("W32ProcObj::AddWaitableObjectToWorkerThread");
  934. //
  935. // Make sure we don't run out of waitable objects.
  936. //
  937. if (waitableObjectCount < MAXIMUM_WAIT_OBJECTS) {
  938. ASSERT(threadInfo->waitableObjects[waitableObjectCount] == NULL);
  939. threadInfo->waitableObjects[waitableObjectCount] = waitableObject;
  940. threadInfo->waitingReqs[waitableObjectCount] = reqContext;
  941. threadInfo->waitableObjectCount++;
  942. DC_END_FN();
  943. return ERROR_SUCCESS;
  944. }
  945. else {
  946. DC_END_FN();
  947. return ERROR_INVALID_INDEX;
  948. }
  949. }
  950. VOID
  951. W32ProcObj::GetClientComputerName(
  952. PBYTE pbBuffer,
  953. PULONG pulBufferLen,
  954. PBOOL pbUnicodeFlag,
  955. PULONG pulCodePage
  956. )
  957. /*++
  958. Routine Description:
  959. Get Client Computer Name.
  960. Arguments:
  961. pbBuffer - pointer to a buffer where the computer name is returned.
  962. pulBufferLen - length of the above buffer.
  963. pbUnicodeFlag - pointer a BOOL location which is SET if the unicode returned
  964. computer name is returned.
  965. pulCodePage - pointer to a ULONG where the codepage value is returned if
  966. ansi computer.
  967. Return Value:
  968. Window Error Code.
  969. --*/
  970. {
  971. ULONG ulLen;
  972. DC_BEGIN_FN("W32ProcObj::GetClientComputerName");
  973. //
  974. // check to see we have sufficient buffer.
  975. //
  976. ASSERT(*pulBufferLen >= ((MAX_COMPUTERNAME_LENGTH + 1) * sizeof(WCHAR)));
  977. #ifndef OS_WINCE
  978. if( _bWin9xFlag == TRUE ) {
  979. //
  980. // get ansi computer name.
  981. //
  982. CHAR achAnsiComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  983. ulLen = sizeof(achAnsiComputerName);
  984. ulLen = GetComputerNameA( (LPSTR)achAnsiComputerName, &ulLen);
  985. if( ulLen != 0 ) {
  986. //
  987. // Convert the string to unicode.
  988. //
  989. RDPConvertToUnicode(
  990. (LPSTR)achAnsiComputerName,
  991. (LPWSTR)pbBuffer,
  992. *pulBufferLen );
  993. }
  994. }
  995. else {
  996. //
  997. // get unicode computer name.
  998. //
  999. ULONG numChars = *pulBufferLen / sizeof(TCHAR);
  1000. ulLen = GetComputerNameW( (LPWSTR)pbBuffer, &numChars );
  1001. *pulBufferLen = numChars * sizeof(TCHAR);
  1002. }
  1003. #else
  1004. //
  1005. // get ansi computer name.
  1006. //
  1007. CHAR achAnsiComputerName[MAX_COMPUTERNAME_LENGTH + 1];
  1008. if (gethostname(achAnsiComputerName, sizeof(achAnsiComputerName)) == 0)
  1009. {
  1010. ulLen = strlen(achAnsiComputerName);
  1011. }
  1012. else {
  1013. ulLen = 0;
  1014. }
  1015. if( ulLen != 0 ) {
  1016. //
  1017. // Convert the string to unicode.
  1018. //
  1019. RDPConvertToUnicode(
  1020. (LPSTR)achAnsiComputerName,
  1021. (LPWSTR)pbBuffer,
  1022. *pulBufferLen );
  1023. }
  1024. #endif
  1025. if( ulLen == 0 ) {
  1026. ULONG ulError;
  1027. ulError = GetLastError();
  1028. ASSERT(ulError != ERROR_BUFFER_OVERFLOW);
  1029. TRC_ERR((TB, _T("GetComputerNameA() failed, %ld."), ulError));
  1030. *(LPWSTR)pbBuffer = L'\0';
  1031. }
  1032. //
  1033. // set return parameters.
  1034. //
  1035. *pbUnicodeFlag = TRUE;
  1036. *pulCodePage = 0;
  1037. *pulBufferLen = ((wcslen((LPWSTR)pbBuffer) + 1) * sizeof(WCHAR));
  1038. Cleanup:
  1039. DC_END_FN();
  1040. return;
  1041. }
  1042. VOID
  1043. W32ProcObj::CheckForQueuedOperations(
  1044. IN PTHREAD_INFO thread
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. Check the operation dispatch queue for queued operations.
  1049. Arguments:
  1050. thread - Is the thread form which to dequeue the next operation.
  1051. Return Value:
  1052. ERROR_SUCCESS on success. Otherwise, Windows error code is returned.
  1053. --*/
  1054. {
  1055. W32DispatchQueueFunc func;
  1056. PVOID clientData;
  1057. DC_BEGIN_FN("W32ProcObj::CheckForQueuedOperations");
  1058. while (thread->dispatchQueue->Dequeue(&func, &clientData)) {
  1059. func(clientData, FALSE);
  1060. }
  1061. DC_END_FN();
  1062. }
  1063. void
  1064. W32ProcObj::OnDeviceChange(
  1065. IN WPARAM wParam,
  1066. IN LPARAM lParam)
  1067. /*++
  1068. Routine Description:
  1069. On Device Change notification
  1070. Arguments:
  1071. wParam device change notification type
  1072. lParam device change info
  1073. Return Value:
  1074. N/A
  1075. --*/
  1076. {
  1077. W32DeviceChangeParam *param = NULL;
  1078. BYTE *devBuffer = NULL;
  1079. DEV_BROADCAST_HDR *pDBHdr;
  1080. DWORD status = ERROR_OUTOFMEMORY;
  1081. DC_BEGIN_FN("W32ProcObj::OnDeviceChange");
  1082. //
  1083. // We only care about device arrival and removal.
  1084. //
  1085. if (wParam == DBT_DEVICEARRIVAL || wParam == DBT_DEVICEREMOVECOMPLETE) {
  1086. pDBHdr = (DEV_BROADCAST_HDR *)lParam;
  1087. if (pDBHdr != NULL && pDBHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
  1088. DEV_BROADCAST_VOLUME * pDBVol = (DEV_BROADCAST_VOLUME *)lParam;
  1089. if (!(pDBVol->dbcv_flags & DBTF_MEDIA)) {
  1090. devBuffer = new BYTE[pDBHdr->dbch_size];
  1091. if (devBuffer != NULL) {
  1092. memcpy(devBuffer, (void*)lParam, pDBHdr->dbch_size);
  1093. param = new W32DeviceChangeParam(this, wParam, (LPARAM)devBuffer);
  1094. if (param != NULL) {
  1095. status = DispatchAsyncIORequest(
  1096. (RDPAsyncFunc_StartIO)W32ProcObj::_OnDeviceChangeFunc,
  1097. NULL,
  1098. NULL,
  1099. param
  1100. );
  1101. }
  1102. else {
  1103. status = GetLastError();
  1104. }
  1105. }
  1106. //
  1107. // Clean up
  1108. //
  1109. if (status != ERROR_SUCCESS) {
  1110. if (param != NULL) {
  1111. delete param;
  1112. }
  1113. if (devBuffer != NULL) {
  1114. delete devBuffer;
  1115. }
  1116. }
  1117. }
  1118. }
  1119. }
  1120. DC_END_FN();
  1121. }
  1122. HANDLE W32ProcObj::_OnDeviceChangeFunc(
  1123. W32DeviceChangeParam *param,
  1124. DWORD *status
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. Handle device change notification from the worker thread.
  1129. Arguments:
  1130. param - Relevant W32DeviceChangeParam
  1131. status - Return status.
  1132. Return Value:
  1133. NULL
  1134. --*/
  1135. {
  1136. DC_BEGIN_FN("_OnDeviceChangeFunc");
  1137. ASSERT(param != NULL);
  1138. param->_instance->OnDeviceChangeFunc(status, param->_wParam, param->_lParam);
  1139. DC_END_FN();
  1140. delete ((void *)(param->_lParam));
  1141. delete param;
  1142. return NULL;
  1143. }
  1144. void
  1145. W32ProcObj::OnDeviceChangeFunc(
  1146. DWORD *status,
  1147. IN WPARAM wParam,
  1148. IN LPARAM lParam)
  1149. /*++
  1150. Routine Description:
  1151. On Device Change notification
  1152. Arguments:
  1153. status return status
  1154. wParam device change notification type
  1155. lParam device change info
  1156. Return Value:
  1157. N/A
  1158. --*/
  1159. {
  1160. DEV_BROADCAST_HDR *pDBHdr;
  1161. PRDPDR_HEADER pPacketHeader = NULL;
  1162. INT sz;
  1163. DC_BEGIN_FN("OnDeviceChangeFunc");
  1164. ASSERT(_initialized);
  1165. *status = ERROR_SUCCESS;
  1166. pDBHdr = (DEV_BROADCAST_HDR *)lParam;
  1167. switch (wParam) {
  1168. //
  1169. // Device arrival
  1170. //
  1171. case DBT_DEVICEARRIVAL:
  1172. //
  1173. // This is a volume device arrival message
  1174. //
  1175. if (pDBHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
  1176. DEV_BROADCAST_VOLUME * pDBVol = (DEV_BROADCAST_VOLUME *)lParam;
  1177. if (!(pDBVol->dbcv_flags & DBTF_MEDIA)) {
  1178. DWORD unitMask = pDBVol->dbcv_unitmask;
  1179. W32Drive::EnumerateDrives(this, _deviceMgr, unitMask);
  1180. pPacketHeader = GenerateAnnouncePacket(&sz, TRUE);
  1181. if (pPacketHeader) {
  1182. pPacketHeader->Component = RDPDR_CTYP_CORE;
  1183. pPacketHeader->PacketId = DR_CORE_DEVICELIST_ANNOUNCE;
  1184. _pVCMgr->ChannelWrite(pPacketHeader, sz);
  1185. }
  1186. }
  1187. }
  1188. break;
  1189. //
  1190. // Device removal
  1191. //
  1192. case DBT_DEVICEREMOVECOMPLETE:
  1193. //
  1194. // This is a volume device removal message
  1195. //
  1196. if (pDBHdr->dbch_devicetype == DBT_DEVTYP_VOLUME) {
  1197. DEV_BROADCAST_VOLUME * pDBVol = (DEV_BROADCAST_VOLUME *)lParam;
  1198. if (!(pDBVol->dbcv_flags & DBTF_MEDIA)) {
  1199. DWORD unitMask = pDBVol->dbcv_unitmask;
  1200. W32Drive::RemoveDrives(this, _deviceMgr, unitMask);
  1201. pPacketHeader = GenerateDeviceRemovePacket(&sz);
  1202. if (pPacketHeader) {
  1203. pPacketHeader->Component = RDPDR_CTYP_CORE;
  1204. pPacketHeader->PacketId = DR_CORE_DEVICELIST_REMOVE;
  1205. _pVCMgr->ChannelWrite(pPacketHeader, sz);
  1206. }
  1207. }
  1208. }
  1209. break;
  1210. default:
  1211. return;
  1212. }
  1213. DC_END_FN();
  1214. }