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.

1876 lines
42 KiB

  1. /*++
  2. Copyright (c) 1999-2000 Microsoft Corporation
  3. Module Name:
  4. chanmgr.c
  5. Abstract:
  6. Routines for managing channels in the sac.
  7. Author:
  8. Brian Guarraci (briangu) March, 2001.
  9. Revision History:
  10. --*/
  11. #include "sac.h"
  12. /////////////////////////////////////////////////////////
  13. //
  14. // Begin global data
  15. //
  16. //
  17. // The max number of times we attempt to reap a channel
  18. // when shutting down the channel manager
  19. //
  20. #define SHUTDOWN_MAX_ATTEMPT_COUNT 100
  21. //
  22. // Delay between channel each reap attempt (ms)
  23. //
  24. #define SHUTDOWN_REAP_ATTEMP_DELAY 500
  25. //
  26. // This is where the channel objects are stored
  27. //
  28. PSAC_CHANNEL ChannelArray[MAX_CHANNEL_COUNT];
  29. //
  30. // Macros for managing the different channel locks
  31. //
  32. #if DBG
  33. #define MAX_REF_COUNT 100
  34. #endif
  35. #define INIT_CHANMGR_LOCKS(_i) \
  36. INITIALIZE_LOCK(ChannelSlotLock[_i]); \
  37. InterlockedExchange((volatile long *)&ChannelRefCount[_i], 0);\
  38. InterlockedExchange((volatile long *)&ChannelReaped[_i], 1);
  39. //
  40. // This macro increments the ref count of a channel
  41. // if the ref count was already non-zero (in use).
  42. //
  43. #define CHANNEL_REF_COUNT_INCREMENT_IN_USE(_i)\
  44. if (CHANNEL_SLOT_IS_IN_USE(_i)) { \
  45. CHANNEL_REF_COUNT_INCREMENT(_i); \
  46. ASSERT(ChannelRefCount[_i] >= 2); \
  47. } \
  48. #define CHANNEL_REF_COUNT_INCREMENT(_i)\
  49. ASSERT(ChannelRefCount[_i] <= MAX_REF_COUNT); \
  50. ASSERT(ChannelRefCount[_i] >= 1); \
  51. InterlockedIncrement((volatile long *)&ChannelRefCount[_i]); \
  52. ASSERT(ChannelRefCount[_i] <= MAX_REF_COUNT);
  53. #define CHANNEL_REF_COUNT_DECREMENT(_i)\
  54. ASSERT(ChannelRefCount[_i] <= MAX_REF_COUNT); \
  55. ASSERT(ChannelRefCount[_i] > 1); \
  56. InterlockedDecrement((volatile long *)&ChannelRefCount[_i]); \
  57. ASSERT(ChannelRefCount[_i] >= 1);
  58. #define CHANNEL_REF_COUNT_ZERO(_i)\
  59. ASSERT(ChannelRefCount[_i] == 1); \
  60. ASSERT(!ChannelIsActive(ChannelArray[_i])); \
  61. InterlockedExchange((volatile long *)&ChannelRefCount[_i], 0);
  62. #define CHANNEL_REF_COUNT_ONE(_i)\
  63. ASSERT(ChannelRefCount[_i] == 0); \
  64. InterlockedExchange((volatile long *)&ChannelRefCount[_i], 1);
  65. #define CHANNEL_REF_COUNT_DECREMENT_WITH_LOCK(_i)\
  66. LOCK_CHANNEL_SLOT(_i); \
  67. CHANNEL_REF_COUNT_DECREMENT(_i); \
  68. UNLOCK_CHANNEL_SLOT(_i);
  69. #define CHANNEL_SLOT_IS_IN_USE(_i)\
  70. (ChannelRefCount[_i] > 0)
  71. #define CHANNEL_SLOT_IS_REAPED(_i)\
  72. (ChannelReaped[_i])
  73. #define CHANNEL_SLOT_IS_REAPED_SET(_i)\
  74. InterlockedExchange((volatile long *)&ChannelReaped[_i], 1);
  75. #define CHANNEL_SLOT_IS_REAPED_CLEAR(_i)\
  76. ASSERT(ChannelReaped[_i] == 1); \
  77. InterlockedExchange((volatile long *)&ChannelReaped[_i], 0);
  78. #define CHANNEL_SLOT_IS_IN_USE(_i)\
  79. (ChannelRefCount[_i] > 0)
  80. #define LOCK_CHANNEL_SLOT(_i) \
  81. ACQUIRE_LOCK(ChannelSlotLock[_i])
  82. #define UNLOCK_CHANNEL_SLOT(_i) \
  83. RELEASE_LOCK(ChannelSlotLock[_i])
  84. //
  85. // Corresponding array of mutex's for each channel
  86. //
  87. ULONG ChannelRefCount[MAX_CHANNEL_COUNT];
  88. ULONG ChannelReaped[MAX_CHANNEL_COUNT];
  89. SAC_LOCK ChannelSlotLock[MAX_CHANNEL_COUNT];
  90. //
  91. // This lock is used to prevent >= 2 threads from
  92. // creating a channel at the same time. By holding this
  93. // lock while we create a channel, we can ensure that
  94. // when we check for name uniqueness, that there isn't
  95. // another thread creating a channel with the same name.
  96. //
  97. SAC_LOCK ChannelCreateLock;
  98. //
  99. // Flag indicating if the channel manager is allowed to
  100. // create new channels. This is used, for instance,
  101. // when we shutdown the channel manager to prevent
  102. // new channels from being created after we shutdown.
  103. //
  104. BOOLEAN ChannelCreateEnabled;
  105. #define IsChannelCreateEnabled() (ChannelCreateEnabled)
  106. //
  107. // prototypes
  108. //
  109. NTSTATUS
  110. ChanMgrReapChannels(
  111. VOID
  112. );
  113. NTSTATUS
  114. ChanMgrReapChannel(
  115. IN ULONG ChannelIndex
  116. );
  117. //
  118. // End global data
  119. //
  120. /////////////////////////////////////////////////////////
  121. NTSTATUS
  122. ChanMgrInitialize(
  123. VOID
  124. )
  125. /*++
  126. Routine Description:
  127. This routine allocates and initializes the channel manager structures
  128. Arguments:
  129. NONE
  130. Return Value:
  131. STATUS_SUCCESS if successful, else the appropriate error code.
  132. --*/
  133. {
  134. ULONG i;
  135. //
  136. // Initialize the channel create lock
  137. //
  138. INITIALIZE_LOCK(ChannelCreateLock);
  139. //
  140. // Channel creation is enabled
  141. //
  142. ChannelCreateEnabled = TRUE;
  143. //
  144. // initialize each channel slot
  145. //
  146. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  147. //
  148. // initialize the channel as available
  149. //
  150. ChannelArray[i] = NULL;
  151. //
  152. // initialize the locks for this channel
  153. //
  154. INIT_CHANMGR_LOCKS(i);
  155. }
  156. return STATUS_SUCCESS;
  157. }
  158. NTSTATUS
  159. ChanMgrShutdown(
  160. VOID
  161. )
  162. /*++
  163. Routine Description:
  164. This routine allocates and initializes the channel manager structures
  165. Arguments:
  166. NONE
  167. Return Value:
  168. STATUS_SUCCESS if successful, else the appropriate error code.
  169. --*/
  170. {
  171. NTSTATUS Status;
  172. ULONG i;
  173. ULONG AttemptCount;
  174. PSAC_CHANNEL Channel;
  175. //
  176. // NOT YET TESTED
  177. //
  178. //
  179. // Hold the channel create lock and prevent any new channels from
  180. // being created while we shutdown
  181. //
  182. ACQUIRE_LOCK(ChannelCreateLock);
  183. //
  184. // Channel creation is disabled
  185. //
  186. ChannelCreateEnabled = TRUE;
  187. //
  188. // Close each channel
  189. //
  190. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  191. //
  192. // Get the ith channel
  193. //
  194. Status = ChanMgrGetByIndex(
  195. i,
  196. &Channel
  197. );
  198. //
  199. // skip empty channel slots
  200. //
  201. if (Status == STATUS_NOT_FOUND) {
  202. //
  203. // advance to the next channel slot
  204. //
  205. continue;
  206. }
  207. //
  208. // break if we hit an error...
  209. //
  210. if (! NT_SUCCESS(Status)) {
  211. break;
  212. }
  213. //
  214. // Close the channel
  215. //
  216. Status = ChannelClose(Channel);
  217. //
  218. // break if we hit an error...
  219. //
  220. if (! NT_SUCCESS(Status)) {
  221. break;
  222. }
  223. //
  224. // Release the channel
  225. //
  226. Status = ChanMgrReleaseChannel(Channel);
  227. //
  228. // break if we hit an error...
  229. //
  230. if (! NT_SUCCESS(Status)) {
  231. break;
  232. }
  233. }
  234. //
  235. // At this point, all the channels are closed.
  236. // However, it is possible that a channel is still
  237. // being used - the ref count of the channel is > 1.
  238. // We need to attempt to reap the channels until
  239. // all are reaped, or we give up.
  240. //
  241. //
  242. // Attempt to reap each channel
  243. //
  244. AttemptCount = 0;
  245. while(AttemptCount < SHUTDOWN_MAX_ATTEMPT_COUNT) {
  246. BOOLEAN bContinue;
  247. //
  248. // Attempt to reap all unreaped channels
  249. //
  250. Status = ChanMgrReapChannels();
  251. if (!NT_SUCCESS(Status)) {
  252. break;
  253. }
  254. //
  255. // See if any channels are not reaped
  256. //
  257. bContinue = FALSE;
  258. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  259. //
  260. // If the channel is not reaped, delay before attempting again
  261. //
  262. if (! CHANNEL_SLOT_IS_REAPED(i)) {
  263. //
  264. // We need to continue reaping
  265. //
  266. bContinue = TRUE;
  267. break;
  268. }
  269. }
  270. //
  271. // if we need to continue reaping,
  272. // then increment our attempt count and delay
  273. // otherwise, we are done.
  274. //
  275. if (bContinue) {
  276. LARGE_INTEGER WaitTime;
  277. //
  278. // When attempting to reap a channel, this is the delay we use
  279. // between each reap attempt.
  280. //
  281. WaitTime.QuadPart = Int32x32To64((LONG)SHUTDOWN_REAP_ATTEMP_DELAY, -1000);
  282. //
  283. // Keep track of how many times we have tried
  284. //
  285. AttemptCount++;
  286. //
  287. // Wait...
  288. //
  289. KeDelayExecutionThread(KernelMode, FALSE, &WaitTime);
  290. } else {
  291. //
  292. // all channels are reaped
  293. //
  294. break;
  295. }
  296. }
  297. //
  298. // Release the channel create lock and let the create threads
  299. // unblock. They will fail their creation attempt because creation
  300. // is now disabled.
  301. //
  302. RELEASE_LOCK(ChannelCreateLock);
  303. return STATUS_SUCCESS;
  304. }
  305. NTSTATUS
  306. ChanMgrGetChannelIndex(
  307. IN PSAC_CHANNEL Channel,
  308. OUT PULONG ChannelIndex
  309. )
  310. /*++
  311. Routine Description:
  312. This routine determines a channel's index in teh channel array.
  313. Arguments:
  314. Channel - the channel to get the index of
  315. ChannelIndex - the index of the channel
  316. Return Value:
  317. STATUS_SUCCESS - if the mapping was successful
  318. otherwise, error status
  319. --*/
  320. {
  321. ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER_1);
  322. ASSERT_STATUS(ChannelIndex, STATUS_INVALID_PARAMETER_2);
  323. *ChannelIndex = ChannelGetIndex(Channel);
  324. return STATUS_SUCCESS;
  325. }
  326. BOOLEAN
  327. ChanMgrIsUniqueName(
  328. IN PCWSTR Name
  329. )
  330. /*++
  331. Routine Description:
  332. This routine determines if a channel name already is used
  333. Arguments:
  334. Name - the name to search for
  335. Return Value:
  336. TRUE - if the channel name is unique
  337. otherwise, FALSE
  338. --*/
  339. {
  340. BOOLEAN IsUnique;
  341. NTSTATUS Status;
  342. PSAC_CHANNEL Channel;
  343. IsUnique = FALSE;
  344. //
  345. // see if a channel already has the name
  346. //
  347. Status = ChanMgrGetChannelByName(
  348. Name,
  349. &Channel
  350. );
  351. //
  352. // if we get a not found status,
  353. // then we know the name is unique
  354. //
  355. if (Status == STATUS_NOT_FOUND) {
  356. IsUnique = TRUE;
  357. }
  358. //
  359. // we are done with the channel
  360. //
  361. if (NT_SUCCESS(Status)) {
  362. ChanMgrReleaseChannel(Channel);
  363. }
  364. return IsUnique;
  365. }
  366. NTSTATUS
  367. ChanMgrGenerateUniqueCmdName(
  368. OUT PWSTR ChannelName
  369. )
  370. /*++
  371. Routine Description:
  372. This routine generates a unique channel name for the cmd console channels
  373. Arguments:
  374. ChannelName - destination buffer for the new channel name
  375. Return Value:
  376. STATUS_SUCCESS - if the mapping was successful
  377. otherwise, error status
  378. --*/
  379. {
  380. //
  381. // Counter for generating unique cmd names
  382. //
  383. static ULONG CmdConsoleChannelIndex = 0;
  384. ASSERT_STATUS(ChannelName, STATUS_INVALID_PARAMETER);
  385. //
  386. // Keep constructing a new name unti it is unique
  387. //
  388. do {
  389. //
  390. // restrict the channel enumeration to 0-9999
  391. //
  392. CmdConsoleChannelIndex = (CmdConsoleChannelIndex + 1) % 10000;
  393. //
  394. // construct the channel name
  395. //
  396. swprintf(ChannelName, L"Cmd%04d", CmdConsoleChannelIndex);
  397. } while ( !ChanMgrIsUniqueName(ChannelName) );
  398. return STATUS_SUCCESS;
  399. }
  400. NTSTATUS
  401. ChanMgrReleaseChannel(
  402. IN PSAC_CHANNEL Channel
  403. )
  404. /*++
  405. Routine Description:
  406. This routine is the counterpart for the GetChannelByXXX routines.
  407. These routines hold the mutex for the channel if it is found;
  408. This routine release the mutex.
  409. Arguments:
  410. ChannelIndex - The index of the channel to release
  411. Return Value:
  412. Status
  413. --*/
  414. {
  415. ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
  416. LOCK_CHANNEL_SLOT(ChannelGetIndex(Channel));
  417. CHANNEL_REF_COUNT_DECREMENT(ChannelGetIndex(Channel));
  418. //
  419. // the reference count should never be 0 at this point
  420. //
  421. ASSERT(ChannelRefCount[ChannelGetIndex(Channel)] > 0);
  422. if (ChannelRefCount[ChannelGetIndex(Channel)] == 1) {
  423. do {
  424. if (! ChannelIsActive(Channel)) {
  425. //
  426. // If the channel doesn't have the preserve bit set, dereference the channel
  427. //
  428. if (! (ChannelArray[ChannelGetIndex(Channel)]->Flags & SAC_CHANNEL_FLAG_PRESERVE)) {
  429. //
  430. // Channel is officially closed
  431. //
  432. CHANNEL_REF_COUNT_ZERO(ChannelGetIndex(Channel));
  433. break;
  434. }
  435. //
  436. // if the channel is not active and
  437. // the channel has the preserve bit set but no longer has new data in
  438. // the obuffer, then the channel is now completely closed and the reference
  439. // can be removed.
  440. //
  441. if (! ((ChannelArray[ChannelGetIndex(Channel)]->Flags & SAC_CHANNEL_FLAG_PRESERVE) &&
  442. ChannelHasNewOBufferData(ChannelArray[ChannelGetIndex(Channel)]))) {
  443. //
  444. // Channel is officially closed
  445. //
  446. CHANNEL_REF_COUNT_ZERO(ChannelGetIndex(Channel));
  447. break;
  448. }
  449. }
  450. } while ( FALSE );
  451. }
  452. UNLOCK_CHANNEL_SLOT(ChannelGetIndex(Channel));
  453. return STATUS_SUCCESS;
  454. }
  455. NTSTATUS
  456. ChanMgrGetByHandle(
  457. IN SAC_CHANNEL_HANDLE TargetChannelHandle,
  458. OUT PSAC_CHANNEL* TargetChannel
  459. )
  460. /*++
  461. Routine Description:
  462. This routine provides the means to map the Channel Handle which is
  463. owned by the user mode code to the Channel structure which is owned
  464. by the driver.
  465. The mapping is done simply by scanning the existing Channels for one with
  466. a matching Handle.
  467. Note: if we successfully find the channel,
  468. then the mutex is held for this channel and the caller is
  469. responsible for releasing it
  470. Arguments:
  471. TargetChannelHandle - the handle to the channel to look for
  472. TargetChannel - if the search is successful, this contains the
  473. a pointer to the SAC_CHANNEL structure of the
  474. channel we want
  475. Return Value:
  476. STATUS_SUCCESS - if the mapping was successful
  477. otherwise, error status
  478. --*/
  479. {
  480. NTSTATUS Status;
  481. PSAC_CHANNEL Channel;
  482. ULONG i;
  483. ASSERT_STATUS(TargetChannel, STATUS_INVALID_PARAMETER_2);
  484. //
  485. // initialize our response
  486. //
  487. *TargetChannel = NULL;
  488. //
  489. // default: we didn't find the channel
  490. //
  491. Status = STATUS_NOT_FOUND;
  492. //
  493. // search
  494. //
  495. // Note: Since the channel handles are really GUIDs, we can use normal
  496. // GUID comparison tools
  497. //
  498. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  499. //
  500. // Increment the ref count of channels that are in use,
  501. // otherwise skip empty channel slots
  502. //
  503. LOCK_CHANNEL_SLOT(i);
  504. CHANNEL_REF_COUNT_INCREMENT_IN_USE(i);
  505. if (! CHANNEL_SLOT_IS_IN_USE(i)) {
  506. UNLOCK_CHANNEL_SLOT(i);
  507. continue;
  508. }
  509. UNLOCK_CHANNEL_SLOT(i);
  510. //
  511. // get the ith channel
  512. //
  513. Channel = ChannelArray[i];
  514. //
  515. // The channel slot should not be null since the channel is present
  516. //
  517. ASSERT(Channel != NULL);
  518. //
  519. // compare the handles
  520. //
  521. if (ChannelIsEqual(Channel, &TargetChannelHandle)) {
  522. //
  523. // we have a match
  524. //
  525. Status = STATUS_SUCCESS;
  526. //
  527. // Send back the channel
  528. //
  529. *TargetChannel = Channel;
  530. break;
  531. }
  532. CHANNEL_REF_COUNT_DECREMENT_WITH_LOCK(i);
  533. }
  534. return Status;
  535. }
  536. NTSTATUS
  537. ChanMgrGetByHandleAndFileObject(
  538. IN SAC_CHANNEL_HANDLE TargetChannelHandle,
  539. IN PFILE_OBJECT FileObject,
  540. OUT PSAC_CHANNEL* TargetChannel
  541. )
  542. /*++
  543. Routine Description:
  544. This routine provides the same functionality as GetByHandle with the
  545. added bonus of comparing a channel against the file object that was
  546. used to create the channel.
  547. A successful match implies that the caller specified a valid channel
  548. handle, and is indeed the process that created the channel.
  549. Note: if we successfully find the channel,
  550. then the mutex is held for this channel and the caller is
  551. responsible for releasing it
  552. Arguments:
  553. TargetChannelHandle - the handle to the channel to look for
  554. FileObject - the file object to compare against after we have
  555. found the channel by its handle
  556. TargetChannel - if the search is successful, this contains the
  557. a pointer to the SAC_CHANNEL structure of the
  558. channel we want
  559. Return Value:
  560. STATUS_SUCCESS - if the mapping was successful
  561. otherwise, error status
  562. --*/
  563. {
  564. NTSTATUS Status;
  565. PSAC_CHANNEL Channel;
  566. //
  567. // Get the channel by its handle
  568. //
  569. Status = ChanMgrGetByHandle(
  570. TargetChannelHandle,
  571. &Channel
  572. );
  573. if (NT_SUCCESS(Status)) {
  574. //
  575. // Compare the channel's file object with the specified object
  576. //
  577. if (ChannelGetFileObject(Channel) == FileObject) {
  578. //
  579. // They are equal, so send the channel back
  580. //
  581. *TargetChannel = Channel;
  582. } else {
  583. //
  584. // we are done with the channel
  585. //
  586. ChanMgrReleaseChannel(Channel);
  587. //
  588. // They are not equal, so dont send it back
  589. //
  590. *TargetChannel = NULL;
  591. //
  592. // tell the caller we didnt find the channel
  593. //
  594. Status = STATUS_NOT_FOUND;
  595. }
  596. }
  597. return Status;
  598. }
  599. NTSTATUS
  600. ChanMgrGetChannelByName(
  601. IN PCWSTR Name,
  602. OUT PSAC_CHANNEL* pChannel
  603. )
  604. /*++
  605. Routine Description:
  606. This is a convenience routine to fetch a channel by its name
  607. Note: if we successfully find the channel,
  608. then the mutex is held for this channel and the caller is
  609. responsible for releasing it
  610. Arguments:
  611. Name - channel name to key on
  612. pChannel - if successful, contains the channel
  613. Return Value:
  614. STATUS_SUCCESS - channel was found
  615. otherwise, error status
  616. --*/
  617. {
  618. NTSTATUS Status;
  619. NTSTATUS tmpStatus;
  620. PSAC_CHANNEL Channel;
  621. ULONG i;
  622. PWSTR ChannelName;
  623. ULONG l;
  624. ASSERT_STATUS(Name, STATUS_INVALID_PARAMETER_1);
  625. ASSERT_STATUS(pChannel, STATUS_INVALID_PARAMETER_2);
  626. //
  627. // initialize our response
  628. //
  629. *pChannel = NULL;
  630. //
  631. // default: we didn't find the channel
  632. //
  633. Status = STATUS_NOT_FOUND;
  634. //
  635. // Find the channel
  636. //
  637. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  638. //
  639. // Increment the ref count of channels that are in use,
  640. // otherwise skip empty channel slots
  641. //
  642. LOCK_CHANNEL_SLOT(i);
  643. CHANNEL_REF_COUNT_INCREMENT_IN_USE(i);
  644. if (! CHANNEL_SLOT_IS_IN_USE(i)) {
  645. UNLOCK_CHANNEL_SLOT(i);
  646. continue;
  647. }
  648. UNLOCK_CHANNEL_SLOT(i);
  649. //
  650. // get the ith channel
  651. //
  652. Channel = ChannelArray[i];
  653. //
  654. // The channel slot should not be null since the channel is present
  655. //
  656. ASSERT(Channel != NULL);
  657. //
  658. // compare the name
  659. //
  660. tmpStatus = ChannelGetName(
  661. Channel,
  662. &ChannelName
  663. );
  664. ASSERT(NT_SUCCESS(tmpStatus));
  665. if (NT_SUCCESS(tmpStatus)) {
  666. //
  667. // Compare the names
  668. //
  669. l = _wcsicmp(Name, ChannelName);
  670. //
  671. // Release the name
  672. //
  673. FREE_POOL(&ChannelName);
  674. //
  675. // If the names are equal, then we are done
  676. //
  677. if (l == 0) {
  678. //
  679. // we have a match
  680. //
  681. Status = STATUS_SUCCESS;
  682. //
  683. // Send back the channel
  684. //
  685. *pChannel = Channel;
  686. break;
  687. }
  688. }
  689. CHANNEL_REF_COUNT_DECREMENT_WITH_LOCK(i);
  690. }
  691. return Status;
  692. }
  693. NTSTATUS
  694. ChanMgrGetByIndex(
  695. IN ULONG TargetIndex,
  696. OUT PSAC_CHANNEL* TargetChannel
  697. )
  698. /*++
  699. Routine Description:
  700. This routine provides the means to retrieve a channel by its index
  701. in the global channel array.
  702. Note: if we successfully find the channel,
  703. then the mutex is held for this channel and the caller is
  704. responsible for releasing it
  705. Arguments:
  706. TargetIndex - the index of the channel to find
  707. TargetChannel - if the search is successful, this contains the
  708. a pointer to the SAC_CHANNEL structure of the
  709. channel we want
  710. Return Value:
  711. STATUS_SUCCESS - if the mapping was successful
  712. otherwise, error status
  713. --*/
  714. {
  715. NTSTATUS Status;
  716. ASSERT_STATUS(TargetIndex < MAX_CHANNEL_COUNT, STATUS_INVALID_PARAMETER_1);
  717. ASSERT_STATUS(TargetChannel, STATUS_INVALID_PARAMETER_2);
  718. //
  719. // default: the channel slot is empty
  720. //
  721. *TargetChannel = NULL;
  722. Status = STATUS_NOT_FOUND;
  723. //
  724. // attempt to get a reference to the specified channel
  725. //
  726. LOCK_CHANNEL_SLOT(TargetIndex);
  727. CHANNEL_REF_COUNT_INCREMENT_IN_USE(TargetIndex);
  728. if (CHANNEL_SLOT_IS_IN_USE(TargetIndex)) {
  729. //
  730. // directly access the channel from teh array
  731. //
  732. *TargetChannel = ChannelArray[TargetIndex];
  733. //
  734. // We have succeeded
  735. //
  736. Status = STATUS_SUCCESS;
  737. }
  738. UNLOCK_CHANNEL_SLOT(TargetIndex);
  739. return Status;
  740. }
  741. NTSTATUS
  742. ChanMgrGetNextActiveChannel(
  743. IN PSAC_CHANNEL CurrentChannel,
  744. OUT PULONG TargetIndex,
  745. OUT PSAC_CHANNEL* TargetChannel
  746. )
  747. /*++
  748. Routine Description:
  749. Search the channel array for the next active channel.
  750. Note: if we successfully find the channel,
  751. then the mutex is held for this channel and the caller is
  752. responsible for releasing it
  753. Arguments:
  754. CurrentChannel - Start the search at the entry after this one
  755. TargetIndex - If found, this contains the index of the channel
  756. TargetChannel - if found, this contains the channel
  757. Return Value:
  758. Status
  759. --*/
  760. {
  761. BOOLEAN Found;
  762. NTSTATUS Status;
  763. ULONG ScanIndex;
  764. PSAC_CHANNEL Channel;
  765. ULONG StartIndex;
  766. ULONG CurrentIndex;
  767. ASSERT_STATUS(CurrentChannel, STATUS_INVALID_PARAMETER_1);
  768. ASSERT_STATUS(TargetIndex, STATUS_INVALID_PARAMETER_2);
  769. ASSERT_STATUS(TargetChannel, STATUS_INVALID_PARAMETER_3);
  770. //
  771. // get the index of the current channel
  772. //
  773. Status = ChanMgrGetChannelIndex(
  774. CurrentChannel,
  775. &CurrentIndex
  776. );
  777. if (! NT_SUCCESS(Status)) {
  778. return Status;
  779. }
  780. //
  781. // default: we didn't find any active channels
  782. //
  783. Found = FALSE;
  784. //
  785. // start searching from the next entry after the current index
  786. //
  787. StartIndex = (CurrentIndex + 1) % MAX_CHANNEL_COUNT;
  788. ScanIndex = StartIndex;
  789. //
  790. // scan until we find an active channel, or end up where we started
  791. //
  792. // Note: we have a halting condition at the SAC channel, since it
  793. // is always active and present.
  794. //
  795. do {
  796. //
  797. // get the ith channel
  798. //
  799. Status = ChanMgrGetByIndex(
  800. ScanIndex,
  801. &Channel
  802. );
  803. //
  804. // skip empty channel slots
  805. //
  806. if (Status == STATUS_NOT_FOUND) {
  807. //
  808. // advance to the next channel slot
  809. //
  810. ScanIndex = (ScanIndex + 1) % MAX_CHANNEL_COUNT;
  811. continue;
  812. }
  813. //
  814. // break if we hit an error...
  815. //
  816. if (! NT_SUCCESS(Status)) {
  817. break;
  818. }
  819. //
  820. // A channel is active if:
  821. // 1. The state is Active or
  822. // 2. The state is Inactive AND the channel has new data
  823. //
  824. if (ChannelIsActive(Channel) ||
  825. (!ChannelIsActive(Channel) && ChannelHasNewOBufferData(Channel))
  826. ) {
  827. Found = TRUE;
  828. break;
  829. }
  830. //
  831. // we are done with the channel slot
  832. //
  833. Status = ChanMgrReleaseChannel(Channel);
  834. if (! NT_SUCCESS(Status)) {
  835. break;
  836. }
  837. //
  838. // advance to the next channel slot
  839. //
  840. ScanIndex = (ScanIndex + 1) % MAX_CHANNEL_COUNT;
  841. } while ( ScanIndex != StartIndex );
  842. //
  843. // If we were successful, send back the results
  844. //
  845. if (NT_SUCCESS(Status) && Found) {
  846. *TargetIndex = ScanIndex;
  847. *TargetChannel = Channel;
  848. }
  849. return Status;
  850. }
  851. NTSTATUS
  852. ChanMgrCreateChannel(
  853. OUT PSAC_CHANNEL* Channel,
  854. IN PSAC_CHANNEL_OPEN_ATTRIBUTES Attributes
  855. )
  856. /*++
  857. Routine Description:
  858. This adds a channel to the Global Channel List.
  859. Note: if we successfully create the channel,
  860. then the mutex is held for this channel and the caller is
  861. responsible for releasing it
  862. Arguments:
  863. Channel - the channel to add
  864. Attributes - the new channel's attributes
  865. Return Value:
  866. STATUS_SUCCESS - if the mapping was successful
  867. otherwise, error status
  868. Security:
  869. interface:
  870. external -> internal (when using the IOCTL path)
  871. event HANDLES have not yet been validated as referencing
  872. valid event objects
  873. everything else has been validated
  874. --*/
  875. {
  876. NTSTATUS Status;
  877. ULONG i;
  878. SAC_CHANNEL_HANDLE Handle;
  879. PSAC_CHANNEL NewChannel;
  880. ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
  881. ASSERT_STATUS(Attributes, STATUS_INVALID_PARAMETER_2);
  882. //
  883. // Hold the channel create lock while we attempt to create a channel
  884. //
  885. ACQUIRE_LOCK(ChannelCreateLock);
  886. do {
  887. //
  888. // If channel creation is disabled, then bail
  889. //
  890. // Note: we do this check here so that if we
  891. // were blocked on the ChannelCreateLock
  892. // while the chanmgr was shutting down,
  893. // we will notice that channel creation
  894. // is disabled.
  895. //
  896. if (! IsChannelCreateEnabled()) {
  897. Status = STATUS_UNSUCCESSFUL;
  898. break;
  899. }
  900. //
  901. // Do lazy garbage collection on closed channels
  902. //
  903. Status = ChanMgrReapChannels();
  904. if (! NT_SUCCESS(Status)) {
  905. break;
  906. }
  907. //
  908. // verify that there isn't another channel by the same name
  909. //
  910. if (! ChanMgrIsUniqueName(Attributes->Name)) {
  911. Status = STATUS_DUPLICATE_NAME;
  912. break;
  913. }
  914. //
  915. // default: we assume there are no vacant channels
  916. //
  917. Status = STATUS_INSUFFICIENT_RESOURCES;
  918. //
  919. // Allocate memory for the channel
  920. //
  921. NewChannel = ALLOCATE_POOL(sizeof(SAC_CHANNEL), CHANNEL_POOL_TAG);
  922. ASSERT_STATUS(NewChannel, STATUS_NO_MEMORY);
  923. //
  924. // Initialize the channel memory region
  925. //
  926. RtlZeroMemory(NewChannel, sizeof(SAC_CHANNEL));
  927. //
  928. // attempt to add the channel to the channel list
  929. //
  930. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  931. //
  932. // find reaped channel slots
  933. //
  934. if (! CHANNEL_SLOT_IS_REAPED(i)) {
  935. continue;
  936. }
  937. //
  938. // Make sure this slot should be available
  939. //
  940. ASSERT(! CHANNEL_SLOT_IS_IN_USE(i));
  941. //
  942. // Attempt to find an open slot in the channel array
  943. //
  944. InterlockedCompareExchangePointer(
  945. &ChannelArray[i],
  946. NewChannel,
  947. NULL
  948. );
  949. //
  950. // did we get the slot?
  951. //
  952. if (ChannelArray[i] != NewChannel) {
  953. continue;
  954. }
  955. //
  956. // Initialize the SAC_CHANNEL_HANDLE structure
  957. //
  958. RtlZeroMemory(&Handle, sizeof(SAC_CHANNEL_HANDLE));
  959. Status = ExUuidCreate(&Handle.ChannelHandle);
  960. if (! NT_SUCCESS(Status)) {
  961. IF_SAC_DEBUG(
  962. SAC_DEBUG_FAILS,
  963. KdPrint(("SAC Create Channel :: Failed to get GUID\n"))
  964. );
  965. break;
  966. }
  967. //
  968. // Instantiate the new channel
  969. //
  970. Status = ChannelCreate(
  971. NewChannel,
  972. Attributes,
  973. Handle
  974. );
  975. if (! NT_SUCCESS(Status)) {
  976. break;
  977. }
  978. //
  979. // Set the channel array index for this channel
  980. //
  981. ChannelSetIndex(NewChannel, i);
  982. //
  983. // This channel slot is now in use
  984. //
  985. LOCK_CHANNEL_SLOT(i);
  986. CHANNEL_REF_COUNT_ONE(i);
  987. UNLOCK_CHANNEL_SLOT(i);
  988. //
  989. // send back the new channel
  990. //
  991. *Channel = NewChannel;
  992. //
  993. // this channel slot is no longer reaped
  994. // that is, it contains a live channel
  995. //
  996. CHANNEL_SLOT_IS_REAPED_CLEAR(i);
  997. break;
  998. }
  999. //
  1000. // free the channel memory
  1001. //
  1002. if (!NT_SUCCESS(Status)) {
  1003. FREE_POOL(&NewChannel);
  1004. }
  1005. } while ( FALSE );
  1006. //
  1007. // We are done attempting to create a channel
  1008. //
  1009. RELEASE_LOCK(ChannelCreateLock);
  1010. return Status;
  1011. }
  1012. NTSTATUS
  1013. ChanMgrChannelDestroy(
  1014. PSAC_CHANNEL Channel
  1015. )
  1016. /*++
  1017. Routine Description:
  1018. This routine destroys the given channel
  1019. Note: caller must hold channel mutex
  1020. Arguments:
  1021. Channel - the channel to remove
  1022. Return Value:
  1023. STATUS_SUCCESS - if the mapping was successful
  1024. otherwise, error status
  1025. --*/
  1026. {
  1027. NTSTATUS Status;
  1028. ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
  1029. //
  1030. // Make sure the caller isn't trying to destroy an active channel
  1031. //
  1032. ASSERT_STATUS(!CHANNEL_SLOT_IS_IN_USE(ChannelGetIndex(Channel)), STATUS_INVALID_PARAMETER);
  1033. //
  1034. // Do channel specific destruction
  1035. //
  1036. Status = Channel->Destroy(Channel);
  1037. //
  1038. // Decrement the # of
  1039. //
  1040. return Status;
  1041. }
  1042. NTSTATUS
  1043. ChanMgrCloseChannelsWithFileObject(
  1044. IN PFILE_OBJECT FileObject
  1045. )
  1046. /*++
  1047. Routine Description:
  1048. This routine closes all channels that have the specified FileObject
  1049. Arguments:
  1050. FileObject - the file object to search for
  1051. Return Value:
  1052. STATUS_SUCCESS
  1053. otherwise, error status
  1054. --*/
  1055. {
  1056. NTSTATUS Status;
  1057. PSAC_CHANNEL Channel;
  1058. ULONG i;
  1059. ASSERT_STATUS(FileObject, STATUS_INVALID_PARAMETER_1);
  1060. //
  1061. // default: we didn't find the channel
  1062. //
  1063. Status = STATUS_NOT_FOUND;
  1064. //
  1065. // Find the channels with equal File Objects
  1066. //
  1067. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  1068. //
  1069. // get the ith channel
  1070. //
  1071. Status = ChanMgrGetByIndex(i, &Channel);
  1072. //
  1073. // skip empty channel slots
  1074. //
  1075. if (Status == STATUS_NOT_FOUND) {
  1076. //
  1077. // advance to the next channel slot
  1078. //
  1079. continue;
  1080. }
  1081. //
  1082. // break if we hit an error...
  1083. //
  1084. if (! NT_SUCCESS(Status)) {
  1085. break;
  1086. }
  1087. //
  1088. // if the file objects are equal,
  1089. // then close the channel
  1090. //
  1091. if (ChannelGetFileObject(Channel) == FileObject) {
  1092. //
  1093. // They are equal, so close the channel
  1094. //
  1095. Status = ChanMgrCloseChannel(Channel);
  1096. }
  1097. //
  1098. // Release the channel
  1099. //
  1100. Status = ChanMgrReleaseChannel(Channel);
  1101. //
  1102. // break if we hit an error...
  1103. //
  1104. if (! NT_SUCCESS(Status)) {
  1105. break;
  1106. }
  1107. }
  1108. return Status;
  1109. }
  1110. NTSTATUS
  1111. ChanMgrCloseChannel(
  1112. IN PSAC_CHANNEL Channel
  1113. )
  1114. /*++
  1115. Routine Description:
  1116. This routine closes the given channel
  1117. Arguments:
  1118. Channel - the channel to close
  1119. Return Value:
  1120. Status
  1121. --*/
  1122. {
  1123. NTSTATUS Status;
  1124. ASSERT_STATUS(Channel, STATUS_INVALID_PARAMETER);
  1125. do {
  1126. //
  1127. // Make sure the channel is not already inactive
  1128. //
  1129. if (! ChannelIsActive(Channel)) {
  1130. Status = STATUS_ALREADY_DISCONNECTED;
  1131. break;
  1132. }
  1133. //
  1134. // Call the channel's close routine first
  1135. //
  1136. Status = ChannelClose(Channel);
  1137. } while ( FALSE );
  1138. //
  1139. // notify the io mgr that we made an attempt to
  1140. // close the channel.
  1141. //
  1142. IoMgrHandleEvent(
  1143. IO_MGR_EVENT_CHANNEL_CLOSE,
  1144. Channel,
  1145. (PVOID)&Status
  1146. );
  1147. return Status;
  1148. }
  1149. NTSTATUS
  1150. ChanMgrReapChannel(
  1151. IN ULONG ChannelIndex
  1152. )
  1153. /*++
  1154. Routine Description:
  1155. This routine serves as a garbage collector by scanning
  1156. all channels for those that are ready to be removed. A
  1157. channel is ready to be removed when its state is both
  1158. inactive and it has no new data in its buffer - i.e.,
  1159. the stored data has been viewed.
  1160. Note: caller must hold channel mutex
  1161. Arguments:
  1162. ChannelIndex - index of the channel to reap
  1163. Return Value:
  1164. STATUS_SUCCESS if there were no problems,
  1165. NOTE: Success doesn't imply that any channels were removed, it
  1166. only means there were no errors during the process.
  1167. otherwise, failure status
  1168. --*/
  1169. {
  1170. NTSTATUS Status;
  1171. ASSERT_STATUS(ChannelArray[ChannelIndex], STATUS_INVALID_PARAMETER);
  1172. ASSERT_STATUS(ChannelIsClosed(ChannelArray[ChannelIndex]), STATUS_INVALID_PARAMETER);
  1173. //
  1174. // Destroy and free the channel from the channel manager's pool
  1175. //
  1176. do {
  1177. //
  1178. // Make sure all the channel locks are signaled
  1179. //
  1180. ASSERT_CHANNEL_LOCKS_SIGNALED(ChannelArray[ChannelIndex]);
  1181. //
  1182. // destroy the channel
  1183. //
  1184. Status = ChanMgrChannelDestroy(ChannelArray[ChannelIndex]);
  1185. ASSERT(NT_SUCCESS(Status));
  1186. if (!NT_SUCCESS(Status)) {
  1187. break;
  1188. }
  1189. //
  1190. // free the channel memory
  1191. //
  1192. FREE_POOL(&ChannelArray[ChannelIndex]);
  1193. //
  1194. // indicate that this channel slot is available for reuse
  1195. //
  1196. InterlockedExchangePointer(
  1197. &ChannelArray[ChannelIndex],
  1198. NULL
  1199. );
  1200. //
  1201. // mark this channel slot as reaped
  1202. //
  1203. // Note: this keeps the reaper from re-reaping
  1204. // a channel while we are creating a new one
  1205. // in a slot that looks like it can be reaped
  1206. // that is, the ref count == 0, etc.
  1207. //
  1208. CHANNEL_SLOT_IS_REAPED_SET(ChannelIndex);
  1209. } while ( FALSE );
  1210. return Status;
  1211. }
  1212. NTSTATUS
  1213. ChanMgrReapChannels(
  1214. VOID
  1215. )
  1216. /*++
  1217. Routine Description:
  1218. This routine serves as a garbage collector by scanning
  1219. all channels for those that are ready to be removed. A
  1220. channel is ready to be removed when its state is both
  1221. inactive and it has no new data in its buffer - i.e.,
  1222. the stored data has been viewed.
  1223. Arguments:
  1224. Channel - the channel to add
  1225. Return Value:
  1226. Status
  1227. --*/
  1228. {
  1229. NTSTATUS Status;
  1230. ULONG i;
  1231. //
  1232. // default: reap pass was successful
  1233. //
  1234. Status = STATUS_SUCCESS;
  1235. //
  1236. // add the channel to the global channel list
  1237. //
  1238. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  1239. //
  1240. // Lock this channel slot
  1241. //
  1242. LOCK_CHANNEL_SLOT(i);
  1243. do {
  1244. //
  1245. // skip reaped channels
  1246. //
  1247. if (CHANNEL_SLOT_IS_REAPED(i)) {
  1248. break;
  1249. }
  1250. ASSERT(ChannelArray[i] != NULL);
  1251. //
  1252. // Skip active channel slots
  1253. //
  1254. if (CHANNEL_SLOT_IS_IN_USE(i)) {
  1255. break;
  1256. }
  1257. //
  1258. // Force channels that don't have the preserve bit set into a closed state.
  1259. // That is, status is inactive and the channel has no new data
  1260. //
  1261. ChannelSetIBufferHasNewData(ChannelArray[i], FALSE);
  1262. ChannelSetOBufferHasNewData(ChannelArray[i], FALSE);
  1263. //
  1264. // Do "lazy" garbage collection by only removing channels
  1265. // when we want to create a new one
  1266. //
  1267. Status = ChanMgrReapChannel(i);
  1268. if (! NT_SUCCESS(Status)) {
  1269. break;
  1270. }
  1271. } while ( FALSE );
  1272. //
  1273. // We are done with this channel
  1274. //
  1275. UNLOCK_CHANNEL_SLOT(i);
  1276. if (! NT_SUCCESS(Status)) {
  1277. break;
  1278. }
  1279. }
  1280. return Status;
  1281. }
  1282. NTSTATUS
  1283. ChanMgrGetChannelCount(
  1284. OUT PULONG ChannelCount
  1285. )
  1286. /*++
  1287. Routine Description:
  1288. This routine determines the current # of channel slots that
  1289. are currently occupied by either an active channel
  1290. or an inactive channel that has it's preserve bit set
  1291. and the data has not been seen (quasi-active state).
  1292. Arguments:
  1293. ChannelCount
  1294. Return Value:
  1295. Status
  1296. --*/
  1297. {
  1298. ULONG i;
  1299. NTSTATUS Status;
  1300. PSAC_CHANNEL Channel;
  1301. ASSERT_STATUS(ChannelCount, STATUS_INVALID_PARAMETER);
  1302. //
  1303. // default
  1304. //
  1305. Status = STATUS_SUCCESS;
  1306. //
  1307. // Initialize
  1308. //
  1309. *ChannelCount = 0;
  1310. //
  1311. // Iterate through the channels count the # of channel slots that
  1312. // are currently occupied by either an active channel
  1313. // or an inactive channel that has it's preserve bit set
  1314. // and the data has not been seen (quasi-active state).
  1315. //
  1316. for (i = 0; i < MAX_CHANNEL_COUNT; i++) {
  1317. //
  1318. // Query the channel manager for a list of all currently active channels
  1319. //
  1320. Status = ChanMgrGetByIndex(
  1321. i,
  1322. &Channel
  1323. );
  1324. //
  1325. // skip empty slots
  1326. //
  1327. if (Status == STATUS_NOT_FOUND) {
  1328. //
  1329. // revert to Success since this isn't an error condition
  1330. //
  1331. Status = STATUS_SUCCESS;
  1332. continue;
  1333. }
  1334. ASSERT(NT_SUCCESS(Status));
  1335. if (! NT_SUCCESS(Status)) {
  1336. break;
  1337. }
  1338. ASSERT(Channel != NULL);
  1339. //
  1340. // A channel is active if:
  1341. // 1. The state is Active or
  1342. // 2. The state is Inactive AND the channel has new data
  1343. //
  1344. if (ChannelIsActive(Channel) ||
  1345. (!ChannelIsActive(Channel) && ChannelHasNewOBufferData(Channel))
  1346. ) {
  1347. *ChannelCount += 1;
  1348. }
  1349. //
  1350. // We are done with the channel
  1351. //
  1352. Status = ChanMgrReleaseChannel(Channel);
  1353. if (! NT_SUCCESS(Status)) {
  1354. break;
  1355. }
  1356. }
  1357. ASSERT(NT_SUCCESS(Status));
  1358. return Status;
  1359. }
  1360. NTSTATUS
  1361. ChanMgrIsFull(
  1362. OUT PBOOLEAN bStatus
  1363. )
  1364. /*++
  1365. Routine Description:
  1366. Determine if it is possible to add another channel
  1367. Arguments:
  1368. bSuccess - the channel count status
  1369. Return Value:
  1370. TRUE - the max channel count has been reached
  1371. FALSE - otherwise
  1372. --*/
  1373. {
  1374. NTSTATUS Status;
  1375. ULONG ChannelCount;
  1376. //
  1377. // Get the current channel count
  1378. //
  1379. Status = ChanMgrGetChannelCount(&ChannelCount);
  1380. //
  1381. // This operation should be successful
  1382. //
  1383. ASSERT(Status == STATUS_SUCCESS);
  1384. if (!NT_SUCCESS(Status)) {
  1385. *bStatus = FALSE;
  1386. } else {
  1387. *bStatus = (ChannelCount == MAX_CHANNEL_COUNT ? TRUE : FALSE);
  1388. }
  1389. return Status;
  1390. }