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

1101 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. //
  238. // Case on the current state of the named pipe
  239. //
  240. switch (Ccb->NamedPipeState) {
  241. case FILE_PIPE_DISCONNECTED_STATE:
  242. DebugTrace(0, Dbg, "Pipe was disconnected\n", 0);
  243. NpBugCheck( 0, 0, 0 );
  244. case FILE_PIPE_LISTENING_STATE:
  245. DebugTrace(0, Dbg, "Pipe was listening\n", 0);
  246. //
  247. // Set the state of the pipe to connected and adjust the
  248. // appropriate read mode and completion mode values
  249. //
  250. Ccb->NamedPipeState = FILE_PIPE_CONNECTED_STATE;
  251. Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
  252. Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].CompletionMode = FILE_PIPE_QUEUE_OPERATION;
  253. //
  254. // Set our back pointer to the client file object and set the
  255. // client file object context pointers
  256. //
  257. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = ClientFileObject;
  258. NpSetFileObject( ClientFileObject,
  259. Ccb,
  260. NonpagedCcb,
  261. FILE_PIPE_CLIENT_END );
  262. //
  263. // And complete any listening waiters
  264. //
  265. while (!IsListEmpty( &Ccb->ListeningQueue )) {
  266. PLIST_ENTRY Links;
  267. Links = RemoveHeadList( &Ccb->ListeningQueue );
  268. LocalIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  269. //
  270. // Remove the cancel routine and detect if cancel is active. If it is leave the IRP to the
  271. // cancel routine.
  272. if (IoSetCancelRoutine( LocalIrp, NULL ) != NULL) {
  273. NpDeferredCompleteRequest( LocalIrp, STATUS_SUCCESS, DeferredList );
  274. } else {
  275. InitializeListHead (&LocalIrp->Tail.Overlay.ListEntry);
  276. }
  277. }
  278. Status = STATUS_SUCCESS;
  279. break;
  280. case FILE_PIPE_CONNECTED_STATE:
  281. DebugTrace(0, Dbg, "Pipe was connected\n", 0);
  282. NpBugCheck( 0, 0, 0 );
  283. case FILE_PIPE_CLOSING_STATE:
  284. DebugTrace(0, Dbg, "Pipe was closing\n", 0);
  285. NpBugCheck( 0, 0, 0 );
  286. default:
  287. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  288. }
  289. //
  290. // and return to our caller
  291. //
  292. DebugTrace(-1, Dbg, "NpSetConnectedPipeState -> %08lx\n", Status);
  293. return Status;
  294. }
  295. NTSTATUS
  296. NpSetClosingPipeState (
  297. IN PCCB Ccb,
  298. IN PIRP Irp,
  299. IN NAMED_PIPE_END NamedPipeEnd,
  300. IN PLIST_ENTRY DeferredList
  301. )
  302. /*++
  303. Routine Description:
  304. This routine sets a pipe state to closing. This routine will
  305. either complete the irp right away or put in on the data queue
  306. to be completed later.
  307. Arguments:
  308. Ccb - Supplies a pointer to the Ccb representing the pipe state
  309. Irp - Supplies the Irp trying to do the close operation
  310. NamedPipeEnd - Indicates if the server or client is doing the transition
  311. Return Value:
  312. NTSTATUS -
  313. --*/
  314. {
  315. NTSTATUS Status;
  316. PNONPAGED_CCB NonpagedCcb;
  317. PFCB Fcb;
  318. PIRP LocalIrp;
  319. KIRQL CancelIrql;
  320. PDATA_QUEUE ReadQueue;
  321. PDATA_QUEUE WriteQueue;
  322. PEVENT_TABLE_ENTRY Event;
  323. DebugTrace(+1, Dbg, "NpSetClosingPipeState, Ccb = %08lx\n", Ccb);
  324. Fcb = Ccb->Fcb;
  325. //
  326. // Save a pointer to the nonpaged ccb, we really need to do this now so when we
  327. // complete our listening waiters we won't touch paged pool
  328. //
  329. NonpagedCcb = Ccb->NonpagedCcb;
  330. //
  331. // Case on the current state of the named pipe
  332. //
  333. switch (Ccb->NamedPipeState) {
  334. case FILE_PIPE_DISCONNECTED_STATE:
  335. DebugTrace(0, Dbg, "Pipe was disconnected\n", 0);
  336. ASSERT( NamedPipeEnd == FILE_PIPE_SERVER_END );
  337. //
  338. // Pipe is disconnected, for safety sake we'll zero out the
  339. // file objects context pointers to use
  340. //
  341. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  342. NULL,
  343. NULL,
  344. FILE_PIPE_SERVER_END );
  345. Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
  346. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  347. NULL,
  348. NULL,
  349. FILE_PIPE_CLIENT_END );
  350. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  351. //
  352. // Close it we delete the instance, and possibly the Fcb if its
  353. // open count is now zero.
  354. //
  355. NpDeleteCcb( Ccb, DeferredList );
  356. if (Fcb->OpenCount == 0) {
  357. NpDeleteFcb( Fcb, DeferredList );
  358. }
  359. Status = STATUS_SUCCESS;
  360. break;
  361. case FILE_PIPE_LISTENING_STATE:
  362. DebugTrace(0, Dbg, "Pipe was listening\n", 0);
  363. ASSERT( NamedPipeEnd == FILE_PIPE_SERVER_END );
  364. //
  365. // Pipe in listening state, so complete all IRPs that are in the
  366. // listening queue with a closing status, and then delete the
  367. // instance and possibly the Fcb if its open count is now zero
  368. //
  369. //
  370. // And complete any listening waiters
  371. //
  372. while (!IsListEmpty( &Ccb->ListeningQueue )) {
  373. PLIST_ENTRY Links;
  374. Links = RemoveHeadList( &Ccb->ListeningQueue );
  375. LocalIrp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  376. //
  377. // Remove the cancel routine and detect if cancel is active. If it is leave the IRP to the
  378. // cancel routine.
  379. if (IoSetCancelRoutine( LocalIrp, NULL ) != NULL) {
  380. NpDeferredCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN, DeferredList );
  381. } else {
  382. InitializeListHead (&LocalIrp->Tail.Overlay.ListEntry);
  383. }
  384. }
  385. //
  386. // For safety sake we'll zero out the file objects context
  387. // pointers to use
  388. //
  389. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  390. NULL,
  391. NULL,
  392. FILE_PIPE_SERVER_END );
  393. Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
  394. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  395. NULL,
  396. NULL,
  397. FILE_PIPE_CLIENT_END );
  398. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  399. //
  400. // Remove the ccb and possibly the Fcb
  401. //
  402. NpDeleteCcb( Ccb, DeferredList );
  403. if (Fcb->OpenCount == 0) {
  404. NpDeleteFcb( Fcb, DeferredList );
  405. }
  406. //
  407. // And now complete the irp
  408. //
  409. Status = STATUS_SUCCESS;
  410. break;
  411. case FILE_PIPE_CONNECTED_STATE:
  412. //
  413. // The pipe is connected so decide who is trying to do the close
  414. // and then fall into common code
  415. //
  416. if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
  417. DebugTrace(0, Dbg, "Pipe was connected, server doing close\n", 0);
  418. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  419. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  420. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  421. //
  422. // For safety sake we'll zero out the file objects context
  423. // pointers to use
  424. //
  425. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  426. NULL,
  427. NULL,
  428. FILE_PIPE_SERVER_END );
  429. Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
  430. } else {
  431. DebugTrace(0, Dbg, "Pipe was connected, client doing close\n", 0);
  432. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  433. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  434. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  435. //
  436. // For safety sake we'll zero out the file objects context
  437. // pointers to use
  438. //
  439. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  440. NULL,
  441. NULL,
  442. FILE_PIPE_CLIENT_END );
  443. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  444. }
  445. //
  446. // To do a close on a connected pipe we set its state to closing
  447. // drain the read queue and drain reads on the write queue.
  448. //
  449. //
  450. // Closing <---ReadQueue---- [ Remove all entries ]
  451. // End
  452. // ---WriteQueue---> [ Remove only read entries ]
  453. //
  454. Ccb->NamedPipeState = FILE_PIPE_CLOSING_STATE;
  455. while (!NpIsDataQueueEmpty( ReadQueue )) {
  456. if ((LocalIrp = NpRemoveDataQueueEntry( ReadQueue, FALSE, DeferredList )) != NULL) {
  457. NpDeferredCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN, DeferredList );
  458. }
  459. }
  460. while (!NpIsDataQueueEmpty( WriteQueue ) &&
  461. (WriteQueue->QueueState == ReadEntries)) {
  462. if ((LocalIrp = NpRemoveDataQueueEntry( WriteQueue, FALSE, DeferredList )) != NULL) {
  463. NpDeferredCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN, DeferredList );
  464. }
  465. }
  466. Status = STATUS_SUCCESS;
  467. //
  468. // Now signal the other sides event to show that something has
  469. // happened
  470. //
  471. NpSignalEventTableEntry( Event );
  472. break;
  473. case FILE_PIPE_CLOSING_STATE:
  474. //
  475. // The pipe is closing so decide who is trying to complete the close
  476. // and then fall into common code
  477. //
  478. if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
  479. DebugTrace(0, Dbg, "Pipe was closing, server doing close\n", 0);
  480. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  481. //
  482. // For safety sake we'll zero out the file objects context
  483. // pointers to use
  484. //
  485. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  486. NULL,
  487. NULL,
  488. FILE_PIPE_SERVER_END );
  489. Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
  490. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  491. NULL,
  492. NULL,
  493. FILE_PIPE_CLIENT_END );
  494. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  495. } else {
  496. DebugTrace(0, Dbg, "Pipe was closing, client doing close\n", 0);
  497. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  498. //
  499. // For safety sake we'll zero out the file objects context
  500. // pointers to use
  501. //
  502. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_SERVER_END ],
  503. NULL,
  504. NULL,
  505. FILE_PIPE_SERVER_END );
  506. Ccb->FileObject[ FILE_PIPE_SERVER_END ] = NULL;
  507. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  508. NULL,
  509. NULL,
  510. FILE_PIPE_CLIENT_END );
  511. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  512. }
  513. //
  514. // To do a close on a closing pipe we drain the read queue of
  515. // all its entries, delete the instance, and possibly delete the
  516. // Fcb if its open count is now zero.
  517. //
  518. //
  519. // Previously <-----Closed----- Closing
  520. // Closed End
  521. // End ----ReadQueue--->
  522. //
  523. while (!NpIsDataQueueEmpty( ReadQueue )) {
  524. if ((LocalIrp = NpRemoveDataQueueEntry( ReadQueue, FALSE, DeferredList )) != NULL) {
  525. NpDeferredCompleteRequest( LocalIrp, STATUS_PIPE_BROKEN, DeferredList );
  526. }
  527. }
  528. NpUninitializeSecurity (Ccb);
  529. if (Ccb->ClientInfo != NULL) {
  530. NpFreePool (Ccb->ClientInfo);
  531. Ccb->ClientInfo = NULL;
  532. }
  533. NpDeleteCcb( Ccb, DeferredList );
  534. if (Fcb->OpenCount == 0) {
  535. NpDeleteFcb( Fcb, DeferredList );
  536. }
  537. Status = STATUS_SUCCESS;
  538. break;
  539. default:
  540. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  541. }
  542. //
  543. // and return to our caller
  544. //
  545. DebugTrace(-1, Dbg, "NpSetClosingPipeState -> %08lx\n", Status);
  546. return Status;
  547. }
  548. NTSTATUS
  549. NpSetDisconnectedPipeState (
  550. IN PCCB Ccb,
  551. IN PLIST_ENTRY DeferredList
  552. )
  553. /*++
  554. Routine Description:
  555. This routine sets a pipe state to disconnected, only the server is
  556. allowed to do this transition
  557. Arguments:
  558. Ccb - Supplies a pointer to the Ccb representing the pipe instance
  559. DeferredList - List of IRPs to complete later after we drop the locks
  560. Return Value:
  561. NTSTATUS
  562. --*/
  563. {
  564. NTSTATUS Status;
  565. PNONPAGED_CCB NonpagedCcb;
  566. PIRP Irp;
  567. PDATA_QUEUE Inbound;
  568. PDATA_QUEUE Outbound;
  569. PEVENT_TABLE_ENTRY ClientEvent;
  570. DebugTrace(+1, Dbg, "NpSetDisconnectedPipeState, Ccb = %08lx\n", Ccb);
  571. //
  572. // Save a pointer to the nonpaged ccb, we really need to do this now so when we
  573. // complete our listening waiters we won't touch paged pool
  574. //
  575. NonpagedCcb = Ccb->NonpagedCcb;
  576. //
  577. // Case on the current state of the named pipe
  578. //
  579. switch (Ccb->NamedPipeState) {
  580. case FILE_PIPE_DISCONNECTED_STATE:
  581. DebugTrace(0, Dbg, "Pipe already disconnected\n", 0);
  582. //
  583. // pipe already disconnected so there is no work for us to do
  584. //
  585. Status = STATUS_PIPE_DISCONNECTED;
  586. break;
  587. case FILE_PIPE_LISTENING_STATE:
  588. DebugTrace(0, Dbg, "Pipe was listening\n", 0);
  589. //
  590. // Pipe in listening state, so complete all IRPs that are in the
  591. // listening queue with a disconnected status
  592. //
  593. while (!IsListEmpty( &Ccb->ListeningQueue )) {
  594. PLIST_ENTRY Links;
  595. Links = RemoveHeadList( &Ccb->ListeningQueue );
  596. Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  597. //
  598. // Remove the cancel routine and detect if cancel is active. If it is leave the IRP to the
  599. // cancel routine.
  600. if (IoSetCancelRoutine( Irp, NULL ) != NULL) {
  601. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  602. } else {
  603. InitializeListHead (&Irp->Tail.Overlay.ListEntry);
  604. }
  605. }
  606. Status = STATUS_SUCCESS;
  607. break;
  608. case FILE_PIPE_CONNECTED_STATE:
  609. DebugTrace(0, Dbg, "Pipe was connected\n", 0);
  610. Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  611. Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  612. ClientEvent = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  613. //
  614. // Pipe is connected so we need to discard all of the data queues
  615. // and complete any of their IRPs with status disconnected.
  616. //
  617. while (!NpIsDataQueueEmpty( Inbound )) {
  618. if ((Irp = NpRemoveDataQueueEntry( Inbound, FALSE, DeferredList )) != NULL) {
  619. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  620. }
  621. }
  622. while (!NpIsDataQueueEmpty( Outbound )) {
  623. if ((Irp = NpRemoveDataQueueEntry( Outbound, FALSE, DeferredList )) != NULL) {
  624. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  625. }
  626. }
  627. //
  628. // Signal the client event and then remove it from the pipe
  629. //
  630. NpSignalEventTableEntry( ClientEvent );
  631. NpDeleteEventTableEntry( &NpVcb->EventTable, ClientEvent );
  632. NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ] = NULL;
  633. //
  634. // Disable the client's file object
  635. //
  636. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  637. NULL,
  638. NULL,
  639. FILE_PIPE_CLIENT_END );
  640. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  641. NpUninitializeSecurity (Ccb);
  642. if (Ccb->ClientInfo != NULL) {
  643. NpFreePool (Ccb->ClientInfo);
  644. Ccb->ClientInfo = NULL;
  645. }
  646. Status = STATUS_SUCCESS;
  647. break;
  648. case FILE_PIPE_CLOSING_STATE:
  649. DebugTrace(0, Dbg, "Pipe was closing\n", 0);
  650. Inbound = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  651. Outbound = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  652. ClientEvent = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  653. //
  654. // Pipe is closing (this had to have been done by the client) we
  655. // need to discard all of the data queues (only the inbound can have
  656. // entries) and complete any of their IRPs with status disconnected.
  657. //
  658. //
  659. // Server <----Inbound---- Client
  660. // End End
  661. // ----Closed----->
  662. //
  663. while (!NpIsDataQueueEmpty( Inbound )) {
  664. if ((Irp = NpRemoveDataQueueEntry( Inbound, FALSE, DeferredList )) != NULL) {
  665. NpDeferredCompleteRequest( Irp, STATUS_PIPE_DISCONNECTED, DeferredList );
  666. }
  667. }
  668. ASSERT( NpIsDataQueueEmpty( Outbound ) );
  669. //
  670. // The client event should already be gone but for safety sake
  671. // we'll make sure its gone.
  672. //
  673. NpDeleteEventTableEntry( &NpVcb->EventTable, ClientEvent );
  674. NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ] = NULL;
  675. //
  676. // Also if it's still connected, disable the client's file object
  677. //
  678. NpSetFileObject( Ccb->FileObject[ FILE_PIPE_CLIENT_END ],
  679. NULL,
  680. NULL,
  681. FILE_PIPE_CLIENT_END );
  682. Ccb->FileObject[ FILE_PIPE_CLIENT_END ] = NULL;
  683. NpUninitializeSecurity (Ccb);
  684. if (Ccb->ClientInfo != NULL) {
  685. NpFreePool (Ccb->ClientInfo);
  686. Ccb->ClientInfo = NULL;
  687. }
  688. Status = STATUS_SUCCESS;
  689. break;
  690. default:
  691. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  692. }
  693. //
  694. // Set the state to disconnected
  695. //
  696. Ccb->NamedPipeState = FILE_PIPE_DISCONNECTED_STATE;
  697. //
  698. // and return to our caller
  699. //
  700. DebugTrace(-1, Dbg, "NpSetDisconnectedPipeState -> %08lx\n", Status);
  701. return Status;
  702. }
  703. //
  704. // Local support routine
  705. //
  706. VOID
  707. NpCancelListeningQueueIrp (
  708. IN PDEVICE_OBJECT DeviceObject,
  709. IN PIRP Irp
  710. )
  711. /*++
  712. Routine Description:
  713. This routine implements the cancel function for an IRP saved in a listening
  714. queue
  715. Arguments:
  716. DeviceObject - ignored
  717. Irp - Supplies the Irp being cancelled. A pointer to the ccb
  718. structure is stored in the information field of the Irp Iosb
  719. field.
  720. Return Value:
  721. None.
  722. --*/
  723. {
  724. UNREFERENCED_PARAMETER( DeviceObject );
  725. IoReleaseCancelSpinLock( Irp->CancelIrql );
  726. //
  727. // Get exclusive access to the named pipe vcb so we can now do our work
  728. //
  729. FsRtlEnterFileSystem();
  730. NpAcquireExclusiveVcb();
  731. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  732. NpReleaseVcb();
  733. FsRtlExitFileSystem();
  734. NpCompleteRequest( Irp, STATUS_CANCELLED );
  735. //
  736. // And return to our caller
  737. //
  738. return;
  739. }