Leaked source code of windows server 2003

1063 lines
27 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. StateSup.c
  5. Abstract:
  6. This module implements the Named Pipe State Support routines
  7. Author:
  8. Gary Kimura [GaryKi] 30-Aug-1990
  9. Revision History:
  10. --*/
  11. #include "NpProcs.h"
  12. //
  13. // The Bug check file id for this module
  14. //
  15. #define BugCheckFileId (NPFS_BUG_CHECK_STATESUP)
  16. //
  17. // The debug trace level
  18. //
  19. #define Dbg (DEBUG_TRACE_STATESUP)
  20. #ifdef ALLOC_PRAGMA
  21. #pragma alloc_text(PAGE, NpInitializePipeState)
  22. #pragma alloc_text(PAGE, NpUninitializePipeState)
  23. #pragma alloc_text(PAGE, NpSetListeningPipeState)
  24. #pragma alloc_text(PAGE, NpSetConnectedPipeState)
  25. #pragma alloc_text(PAGE, NpSetClosingPipeState)
  26. #pragma alloc_text(PAGE, NpSetDisconnectedPipeState)
  27. #endif
  28. VOID
  29. NpCancelListeningQueueIrp (
  30. IN PDEVICE_OBJECT DeviceObject,
  31. IN PIRP Irp
  32. );
  33. VOID
  34. NpInitializePipeState (
  35. IN PCCB Ccb,
  36. IN PFILE_OBJECT ServerFileObject
  37. )
  38. /*++
  39. Routine Description:
  40. This routine initialize a named pipe instance to the disconnected state.
  41. Arguments:
  42. Ccb - Supplies a pointer to the Ccb representing the pipe state
  43. ServerFileObject - Supplies a pointer to the server file object
  44. Return Value:
  45. None.
  46. --*/
  47. {
  48. PAGED_CODE();
  49. DebugTrace(+1, Dbg, "NpInitializePipeState, Ccb = %08lx\n", Ccb);
  50. //
  51. // Set the ccb and nonpaged ccb fields
  52. //
  53. Ccb->FileObject[ FILE_PIPE_SERVER_END ] = ServerFileObject;
  54. Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
  55. //
  56. // The file object contexts pointers.
  57. //
  58. NpSetFileObject (ServerFileObject,
  59. Ccb,
  60. Ccb->NonpagedCcb,
  61. FILE_PIPE_SERVER_END);
  62. //
  63. // and return to our caller
  64. //
  65. DebugTrace(-1, Dbg, "NpInitializePipeState -> VOID\n", 0);
  66. return;
  67. }
  68. VOID
  69. NpUninitializePipeState (
  70. IN PCCB Ccb
  71. )
  72. /*++
  73. Routine Description:
  74. This routine initialize a named pipe instance to the disconnected state.
  75. Arguments:
  76. Ccb - Supplies a pointer to the Ccb representing the pipe state
  77. Return Value:
  78. None.
  79. --*/
  80. {
  81. PAGED_CODE();
  82. DebugTrace(+1, Dbg, "NpUninitializePipeState, Ccb = %08lx\n", Ccb);
  83. //
  84. // The file object contexts pointers for our server to null
  85. //
  86. NpSetFileObject (Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  87. NULL,
  88. NULL,
  89. FILE_PIPE_SERVER_END);
  90. Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
  91. //
  92. // The file object contexts pointers for our client to null
  93. //
  94. NpSetFileObject (Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  95. NULL,
  96. NULL,
  97. FILE_PIPE_CLIENT_END);
  98. Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
  99. //
  100. // Set to null both pointers to file object.
  101. //
  102. Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
  103. Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
  104. //
  105. // and return to our caller
  106. //
  107. DebugTrace(-1, Dbg, "NpUninitializePipeState -> VOID\n", 0);
  108. return;
  109. }
  110. NTSTATUS
  111. NpSetListeningPipeState (
  112. IN PCCB Ccb,
  113. IN PIRP Irp,
  114. IN PLIST_ENTRY DeferredList
  115. )
  116. /*++
  117. Routine Description:
  118. This routine sets a named pipe to the listening state. This routine
  119. will either complete the IRP right away or put in the listening queue
  120. to be completed later.
  121. Arguments:
  122. Ccb - Supplies a pointer to the Ccb representing the pipe state
  123. Irp - Supplies the Irp doing the listening operation
  124. Return Value:
  125. NTSTATUS
  126. --*/
  127. {
  128. NTSTATUS Status;
  129. DebugTrace(+1, Dbg, "NpSetListeningPipeState, Ccb = %08lx\n", Ccb);
  130. //
  131. // Case on the current state of the named pipe
  132. //
  133. switch (Ccb->NamedPipeState) {
  134. case FILE_PIPE_DISCONNECTED_STATE:
  135. DebugTrace(0, Dbg, "Pipe was disconnected\n", 0);
  136. //
  137. // Set the state to listening and check for any wait for named
  138. // pipe requests.
  139. //
  140. Status = NpCancelWaiter (&NpVcb->WaitQueue,
  141. &Ccb->Fcb->FullFileName,
  142. STATUS_SUCCESS,
  143. DeferredList);
  144. if (!NT_SUCCESS (Status)) {
  145. break;
  146. }
  147. //
  148. // If the completion mode is complete operation then we can
  149. // complete this irp otherwise we need to enqueue the irp
  150. // into the listening queue, and mark it pending.
  151. //
  152. if (Ccb->ReadCompletionMode[FILE_PIPE_SERVER_END].CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
  153. Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
  154. Status = STATUS_PIPE_LISTENING;
  155. } else {
  156. //
  157. // Set the cancel routine and also check if the irp is already cancelled
  158. //
  159. IoSetCancelRoutine (Irp, NpCancelListeningQueueIrp);
  160. if (Irp->Cancel && IoSetCancelRoutine (Irp, NULL) != NULL) {
  161. Status = STATUS_CANCELLED;
  162. } else {
  163. Ccb->NamedPipeState = FILE_PIPE_LISTENING_STATE;
  164. IoMarkIrpPending (Irp);
  165. InsertTailList (&Ccb->ListeningQueue, &Irp->Tail.Overlay.ListEntry);
  166. Status = STATUS_PENDING;
  167. }
  168. }
  169. break;
  170. case FILE_PIPE_LISTENING_STATE:
  171. DebugTrace(0, Dbg, "Pipe was listening\n", 0);
  172. //
  173. // If the completion mode is complete operation then we can
  174. // complete this irp otherwise we need to enqueue the irp
  175. // into the listening queue, and mark it pending.
  176. //
  177. if (Ccb->ReadCompletionMode[FILE_PIPE_SERVER_END].CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
  178. Status = STATUS_PIPE_LISTENING;
  179. } else {
  180. //
  181. // Set the cancel routine and also check if the irp is already cancelled
  182. //
  183. IoSetCancelRoutine (Irp, NpCancelListeningQueueIrp);
  184. if (Irp->Cancel && IoSetCancelRoutine (Irp, NULL) != NULL) {
  185. Status = STATUS_CANCELLED;
  186. } else {
  187. IoMarkIrpPending (Irp);
  188. InsertTailList (&Ccb->ListeningQueue, &Irp->Tail.Overlay.ListEntry);
  189. Status = STATUS_PENDING;
  190. }
  191. }
  192. break;
  193. case FILE_PIPE_CONNECTED_STATE:
  194. DebugTrace(0, Dbg, "Pipe was connected\n", 0);
  195. Status = STATUS_PIPE_CONNECTED;
  196. break;
  197. case FILE_PIPE_CLOSING_STATE:
  198. DebugTrace(0, Dbg, "Pipe was closing\n", 0);
  199. Status = STATUS_PIPE_CLOSING;
  200. break;
  201. default:
  202. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  203. }
  204. //
  205. // and return to our caller
  206. //
  207. DebugTrace(-1, Dbg, "NpSetListeningPipeState -> %08lx\n", Status);
  208. return Status;
  209. }
  210. NTSTATUS
  211. NpSetConnectedPipeState (
  212. IN PCCB Ccb,
  213. IN PFILE_OBJECT ClientFileObject,
  214. IN PLIST_ENTRY DeferredList
  215. )
  216. /*++
  217. Routine Description:
  218. This routine sets the state of a named pipe to connected.
  219. Arguments:
  220. Ccb - Supplies a pointer to the Ccb representing the pipe state
  221. ClientFileObject - Supplies the file object for the client that is
  222. doing the connect.
  223. DeferredList - List of IRP's to complete after we drop locks
  224. Return Value:
  225. NTSTATUS
  226. --*/
  227. {
  228. NTSTATUS Status;
  229. PNONPAGED_CCB NonpagedCcb;
  230. PIRP LocalIrp;
  231. DebugTrace(+1, Dbg, "NpSetConnectedPipeState, Ccb = %08lx\n", Ccb);
  232. //
  233. // Save a pointer to the nonpaged ccb, we really need to do this now so when we
  234. // complete our listening waiters we won't touch paged pool
  235. //
  236. NonpagedCcb = Ccb->NonpagedCcb;
  237. ASSERT (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE);
  238. //
  239. // Set the state of the pipe to connected and adjust the
  240. // appropriate read mode and completion mode values
  241. //
  242. Ccb->NamedPipeState = FILE_PIPE_CONNECTED_STATE;
  243. Ccb->ReadCompletionMode[FILE_PIPE_CLIENT_END].ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
  244. Ccb->ReadCompletionMode[FILE_PIPE_CLIENT_END].CompletionMode = FILE_PIPE_QUEUE_OPERATION;
  245. //
  246. // Set our back pointer to the client file object and set the
  247. // client file object context pointers
  248. //
  249. Ccb->FileObject[FILE_PIPE_CLIENT_END] = ClientFileObject;
  250. NpSetFileObject (ClientFileObject,
  251. Ccb,
  252. NonpagedCcb,
  253. FILE_PIPE_CLIENT_END);
  254. //
  255. // And complete any listening waiters
  256. //
  257. while (!IsListEmpty (&Ccb->ListeningQueue)) {
  258. PLIST_ENTRY Links;
  259. Links = RemoveHeadList (&Ccb->ListeningQueue);
  260. LocalIrp = CONTAINING_RECORD (Links, IRP, Tail.Overlay.ListEntry);
  261. //
  262. // Remove the cancel routine and detect if cancel is active. If it is leave the IRP to the
  263. // cancel routine.
  264. if (IoSetCancelRoutine (LocalIrp, NULL) != NULL) {
  265. NpDeferredCompleteRequest (LocalIrp, STATUS_SUCCESS, DeferredList);
  266. } else {
  267. InitializeListHead (&LocalIrp->Tail.Overlay.ListEntry);
  268. }
  269. }
  270. Status = STATUS_SUCCESS;
  271. return Status;
  272. }
  273. NTSTATUS
  274. NpSetClosingPipeState (
  275. IN PCCB Ccb,
  276. IN PIRP Irp,
  277. IN NAMED_PIPE_END NamedPipeEnd,
  278. IN PLIST_ENTRY DeferredList
  279. )
  280. /*++
  281. Routine Description:
  282. This routine sets a pipe state to closing. This routine will
  283. either complete the irp right away or put in on the data queue
  284. to be completed later.
  285. Arguments:
  286. Ccb - Supplies a pointer to the Ccb representing the pipe state
  287. Irp - Supplies the Irp trying to do the close operation
  288. NamedPipeEnd - Indicates if the server or client is doing the transition
  289. Return Value:
  290. NTSTATUS -
  291. --*/
  292. {
  293. NTSTATUS Status;
  294. PNONPAGED_CCB NonpagedCcb;
  295. PFCB Fcb;
  296. PIRP LocalIrp;
  297. KIRQL CancelIrql;
  298. PDATA_QUEUE ReadQueue;
  299. PDATA_QUEUE WriteQueue;
  300. PEVENT_TABLE_ENTRY Event;
  301. DebugTrace(+1, Dbg, "NpSetClosingPipeState, Ccb = %08lx\n", Ccb);
  302. Fcb = Ccb->Fcb;
  303. //
  304. // Save a pointer to the nonpaged ccb, we really need to do this now so when we
  305. // complete our listening waiters we won't touch paged pool
  306. //
  307. NonpagedCcb = Ccb->NonpagedCcb;
  308. //
  309. // Case on the current state of the named pipe
  310. //
  311. switch (Ccb->NamedPipeState) {
  312. case FILE_PIPE_DISCONNECTED_STATE:
  313. DebugTrace(0, Dbg, "Pipe was disconnected\n", 0);
  314. ASSERT( NamedPipeEnd == FILE_PIPE_SERVER_END );
  315. //
  316. // Pipe is disconnected, for safety sake we'll zero out the
  317. // file objects context pointers to use
  318. //
  319. NpSetFileObject (Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  320. NULL,
  321. NULL,
  322. FILE_PIPE_SERVER_END);
  323. Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
  324. NpSetFileObject (Ccb->FileObject[FILE_PIPE_CLIENT_END],
  325. NULL,
  326. NULL,
  327. FILE_PIPE_CLIENT_END);
  328. Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
  329. //
  330. // Close it we delete the instance, and possibly the Fcb if its
  331. // open count is now zero.
  332. //
  333. NpDeleteCcb (Ccb, DeferredList);
  334. if (Fcb->OpenCount == 0) {
  335. NpDeleteFcb (Fcb, DeferredList);
  336. }
  337. Status = STATUS_SUCCESS;
  338. break;
  339. case FILE_PIPE_LISTENING_STATE:
  340. DebugTrace(0, Dbg, "Pipe was listening\n", 0);
  341. ASSERT( NamedPipeEnd == FILE_PIPE_SERVER_END );
  342. //
  343. // Pipe in listening state, so complete all IRPs that are in the
  344. // listening queue with a closing status, and then delete the
  345. // instance and possibly the Fcb if its open count is now zero
  346. //
  347. //
  348. // And complete any listening waiters
  349. //
  350. while (!IsListEmpty (&Ccb->ListeningQueue)) {
  351. PLIST_ENTRY Links;
  352. Links = RemoveHeadList (&Ccb->ListeningQueue);
  353. LocalIrp = CONTAINING_RECORD (Links, IRP, Tail.Overlay.ListEntry);
  354. //
  355. // Remove the cancel routine and detect if cancel is active. If it is leave the IRP to the
  356. // cancel routine.
  357. if (IoSetCancelRoutine (LocalIrp, NULL) != NULL) {
  358. NpDeferredCompleteRequest (LocalIrp, STATUS_PIPE_BROKEN, DeferredList);
  359. } else {
  360. InitializeListHead (&LocalIrp->Tail.Overlay.ListEntry);
  361. }
  362. }
  363. //
  364. // For safety sake we'll zero out the file objects context
  365. // pointers to use
  366. //
  367. NpSetFileObject (Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  368. NULL,
  369. NULL,
  370. FILE_PIPE_SERVER_END);
  371. Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
  372. NpSetFileObject (Ccb->FileObject[FILE_PIPE_CLIENT_END],
  373. NULL,
  374. NULL,
  375. FILE_PIPE_CLIENT_END);
  376. Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
  377. //
  378. // Remove the ccb and possibly the Fcb
  379. //
  380. NpDeleteCcb (Ccb, DeferredList);
  381. if (Fcb->OpenCount == 0) {
  382. NpDeleteFcb (Fcb, DeferredList);
  383. }
  384. //
  385. // And now complete the irp
  386. //
  387. Status = STATUS_SUCCESS;
  388. break;
  389. case FILE_PIPE_CONNECTED_STATE:
  390. //
  391. // The pipe is connected so decide who is trying to do the close
  392. // and then fall into common code
  393. //
  394. if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
  395. DebugTrace(0, Dbg, "Pipe was connected, server doing close\n", 0);
  396. ReadQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
  397. WriteQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
  398. Event = NonpagedCcb->EventTableEntry[FILE_PIPE_CLIENT_END];
  399. //
  400. // For safety sake we'll zero out the file objects context
  401. // pointers to use
  402. //
  403. NpSetFileObject (Ccb->FileObject[ FILE_PIPE_SERVER_END],
  404. NULL,
  405. NULL,
  406. FILE_PIPE_SERVER_END);
  407. Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
  408. } else {
  409. DebugTrace(0, Dbg, "Pipe was connected, client doing close\n", 0);
  410. ReadQueue = &Ccb->DataQueue[FILE_PIPE_OUTBOUND];
  411. WriteQueue = &Ccb->DataQueue[FILE_PIPE_INBOUND];
  412. Event = NonpagedCcb->EventTableEntry[FILE_PIPE_SERVER_END];
  413. //
  414. // For safety sake we'll zero out the file objects context
  415. // pointers to use
  416. //
  417. NpSetFileObject (Ccb->FileObject[ FILE_PIPE_CLIENT_END],
  418. NULL,
  419. NULL,
  420. FILE_PIPE_CLIENT_END);
  421. Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
  422. }
  423. //
  424. // To do a close on a connected pipe we set its state to closing
  425. // drain the read queue and drain reads on the write queue.
  426. //
  427. //
  428. // Closing <---ReadQueue---- [ Remove all entries ]
  429. // End
  430. // ---WriteQueue---> [ Remove only read entries ]
  431. //
  432. Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE;
  433. while (!NpIsDataQueueEmpty (ReadQueue)) {
  434. if ((LocalIrp = NpRemoveDataQueueEntry (ReadQueue, FALSE, DeferredList)) != NULL) {
  435. NpDeferredCompleteRequest (LocalIrp, STATUS_PIPE_BROKEN, DeferredList);
  436. }
  437. }
  438. while (!NpIsDataQueueEmpty (WriteQueue) &&
  439. (WriteQueue->QueueState == ReadEntries)) {
  440. if ((LocalIrp = NpRemoveDataQueueEntry (WriteQueue, FALSE, DeferredList)) != NULL) {
  441. NpDeferredCompleteRequest (LocalIrp, STATUS_PIPE_BROKEN, DeferredList);
  442. }
  443. }
  444. Status = STATUS_SUCCESS;
  445. //
  446. // Now signal the other sides event to show that something has
  447. // happened
  448. //
  449. NpSignalEventTableEntry( Event );
  450. break;
  451. case FILE_PIPE_CLOSING_STATE:
  452. //
  453. // The pipe is closing so decide who is trying to complete the close
  454. // and then fall into common code
  455. //
  456. if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
  457. DebugTrace(0, Dbg, "Pipe was closing, server doing close\n", 0);
  458. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  459. //
  460. // For safety sake we'll zero out the file objects context
  461. // pointers to use
  462. //
  463. NpSetFileObject (Ccb->FileObject[FILE_PIPE_SERVER_END],
  464. NULL,
  465. NULL,
  466. FILE_PIPE_SERVER_END);
  467. Ccb->FileObject[FILE_PIPE_SERVER_END] = NULL;
  468. NpSetFileObject (Ccb->FileObject[FILE_PIPE_CLIENT_END],
  469. NULL,
  470. NULL,
  471. FILE_PIPE_CLIENT_END);
  472. Ccb->FileObject[FILE_PIPE_CLIENT_END] = NULL;
  473. } else {
  474. DebugTrace(0, Dbg, "Pipe was closing, client doing close\n", 0);
  475. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  476. //
  477. // For safety sake we'll zero out the file objects context
  478. // pointers to use
  479. //
  480. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  481. NULL,
  482. NULL,
  483. FILE_PIPE_SERVER_END );
  484. Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
  485. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  486. NULL,
  487. NULL,
  488. FILE_PIPE_CLIENT_END );
  489. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  490. }
  491. //
  492. // To do a close on a closing pipe we drain the read queue of
  493. // all its entries, delete the instance, and possibly delete the
  494. // Fcb if its open count is now zero.
  495. //
  496. //
  497. // Previously <-----Closed----- Closing
  498. // Closed End
  499. // End ----ReadQueue--->
  500. //
  501. while (!NpIsDataQueueEmpty( ReadQueue )) {
  502. if ((LocalIrp = NpRemoveDataQueueEntry( ReadQueue, FALSE, DeferredList )) != NULL) {
  503. NpDeferredCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN, DeferredList );
  504. }
  505. }
  506. NpUninitializeSecurity (Ccb);
  507. if (Ccb->ClientInfo != NULL) {
  508. NpFreePool (Ccb->ClientInfo);
  509. Ccb->ClientInfo = NULL;
  510. }
  511. NpDeleteCcb( Ccb, DeferredList );
  512. if (Fcb->OpenCount == 0) {
  513. NpDeleteFcb( Fcb, DeferredList );
  514. }
  515. Status = STATUS_SUCCESS;
  516. break;
  517. default:
  518. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  519. }
  520. //
  521. // and return to our caller
  522. //
  523. DebugTrace(-1, Dbg, "NpSetClosingPipeState -> %08lx\n", Status);
  524. return Status;
  525. }
  526. NTSTATUS
  527. NpSetDisconnectedPipeState (
  528. IN PCCB Ccb,
  529. IN PLIST_ENTRY DeferredList
  530. )
  531. /*++
  532. Routine Description:
  533. This routine sets a pipe state to disconnected, only the server is
  534. allowed to do this transition
  535. Arguments:
  536. Ccb - Supplies a pointer to the Ccb representing the pipe instance
  537. DeferredList - List of IRPs to complete later after we drop the locks
  538. Return Value:
  539. NTSTATUS
  540. --*/
  541. {
  542. NTSTATUS Status;
  543. PNONPAGED_CCB NonpagedCcb;
  544. PIRP Irp;
  545. PDATA_QUEUE Inbound;
  546. PDATA_QUEUE Outbound;
  547. PEVENT_TABLE_ENTRY ClientEvent;
  548. DebugTrace(+1, Dbg, "NpSetDisconnectedPipeState, Ccb = %08lx\n", Ccb);
  549. //
  550. // Save a pointer to the nonpaged ccb, we really need to do this now so when we
  551. // complete our listening waiters we won't touch paged pool
  552. //
  553. NonpagedCcb = Ccb->NonpagedCcb;
  554. //
  555. // Case on the current state of the named pipe
  556. //
  557. switch (Ccb->NamedPipeState) {
  558. case FILE_PIPE_DISCONNECTED_STATE:
  559. DebugTrace(0, Dbg, "Pipe already disconnected\n", 0);
  560. //
  561. // pipe already disconnected so there is no work for us to do
  562. //
  563. Status = STATUS_PIPE_DISCONNECTED;
  564. break;
  565. case FILE_PIPE_LISTENING_STATE:
  566. DebugTrace(0, Dbg, "Pipe was listening\n", 0);
  567. //
  568. // Pipe in listening state, so complete all IRPs that are in the
  569. // listening queue with a disconnected status
  570. //
  571. while (!IsListEmpty( &Ccb->ListeningQueue )) {
  572. PLIST_ENTRY Links;
  573. Links = RemoveHeadList( &Ccb->ListeningQueue );
  574. Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  575. //
  576. // Remove the cancel routine and detect if cancel is active. If it is leave the IRP to the
  577. // cancel routine.
  578. if (IoSetCancelRoutine( Irp, NULL ) != NULL) {
  579. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  580. } else {
  581. InitializeListHead (&Irp->Tail.Overlay.ListEntry);
  582. }
  583. }
  584. Status = STATUS_SUCCESS;
  585. break;
  586. case FILE_PIPE_CONNECTED_STATE:
  587. DebugTrace(0, Dbg, "Pipe was connected\n", 0);
  588. Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  589. Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  590. ClientEvent = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  591. //
  592. // Pipe is connected so we need to discard all of the data queues
  593. // and complete any of their IRPs with status disconnected.
  594. //
  595. while (!NpIsDataQueueEmpty( Inbound )) {
  596. if ((Irp = NpRemoveDataQueueEntry( Inbound, FALSE, DeferredList )) != NULL) {
  597. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  598. }
  599. }
  600. while (!NpIsDataQueueEmpty( Outbound )) {
  601. if ((Irp = NpRemoveDataQueueEntry( Outbound, FALSE, DeferredList )) != NULL) {
  602. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  603. }
  604. }
  605. //
  606. // Signal the client event and then remove it from the pipe
  607. //
  608. NpSignalEventTableEntry( ClientEvent );
  609. NpDeleteEventTableEntry( &NpVcb->EventTable, ClientEvent );
  610. NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ] = NULL;
  611. //
  612. // Disable the client's file object
  613. //
  614. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  615. NULL,
  616. NULL,
  617. FILE_PIPE_CLIENT_END );
  618. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  619. NpUninitializeSecurity (Ccb);
  620. if (Ccb->ClientInfo != NULL) {
  621. NpFreePool (Ccb->ClientInfo);
  622. Ccb->ClientInfo = NULL;
  623. }
  624. Status = STATUS_SUCCESS;
  625. break;
  626. case FILE_PIPE_CLOSING_STATE:
  627. DebugTrace(0, Dbg, "Pipe was closing\n", 0);
  628. Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  629. Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  630. ClientEvent = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  631. //
  632. // Pipe is closing (this had to have been done by the client) we
  633. // need to discard all of the data queues (only the inbound can have
  634. // entries) and complete any of their IRPs with status disconnected.
  635. //
  636. //
  637. // Server <----Inbound---- Client
  638. // End End
  639. // ----Closed----->
  640. //
  641. while (!NpIsDataQueueEmpty( Inbound )) {
  642. if ((Irp = NpRemoveDataQueueEntry( Inbound, FALSE, DeferredList )) != NULL) {
  643. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  644. }
  645. }
  646. ASSERT( NpIsDataQueueEmpty( Outbound ) );
  647. //
  648. // The client event should already be gone but for safety sake
  649. // we'll make sure its gone.
  650. //
  651. NpDeleteEventTableEntry( &NpVcb->EventTable, ClientEvent );
  652. NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ] = NULL;
  653. //
  654. // Also if it's still connected, disable the client's file object
  655. //
  656. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  657. NULL,
  658. NULL,
  659. FILE_PIPE_CLIENT_END );
  660. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  661. NpUninitializeSecurity (Ccb);
  662. if (Ccb->ClientInfo != NULL) {
  663. NpFreePool (Ccb->ClientInfo);
  664. Ccb->ClientInfo = NULL;
  665. }
  666. Status = STATUS_SUCCESS;
  667. break;
  668. default:
  669. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  670. }
  671. //
  672. // Set the state to disconnected
  673. //
  674. Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
  675. //
  676. // and return to our caller
  677. //
  678. DebugTrace(-1, Dbg, "NpSetDisconnectedPipeState -> %08lx\n", Status);
  679. return Status;
  680. }
  681. //
  682. // Local support routine
  683. //
  684. VOID
  685. NpCancelListeningQueueIrp (
  686. IN PDEVICE_OBJECT DeviceObject,
  687. IN PIRP Irp
  688. )
  689. /*++
  690. Routine Description:
  691. This routine implements the cancel function for an IRP saved in a listening
  692. queue
  693. Arguments:
  694. DeviceObject - ignored
  695. Irp - Supplies the Irp being cancelled. A pointer to the ccb
  696. structure is stored in the information field of the Irp Iosb
  697. field.
  698. Return Value:
  699. None.
  700. --*/
  701. {
  702. UNREFERENCED_PARAMETER( DeviceObject );
  703. IoReleaseCancelSpinLock( Irp->CancelIrql );
  704. //
  705. // Get exclusive access to the named pipe vcb so we can now do our work
  706. //
  707. FsRtlEnterFileSystem();
  708. NpAcquireExclusiveVcb();
  709. RemoveEntryList (&Irp->Tail.Overlay.ListEntry);
  710. NpReleaseVcb();
  711. FsRtlExitFileSystem();
  712. NpCompleteRequest (Irp, STATUS_CANCELLED);
  713. //
  714. // And return to our caller
  715. //
  716. return;
  717. }