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.

410 lines
9.1 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. lpcclose.c
  5. Abstract:
  6. Local Inter-Process Communication close procedures that are called when
  7. a connection port or a communications port is closed.
  8. Author:
  9. Steve Wood (stevewo) 15-May-1989
  10. Revision History:
  11. --*/
  12. #include "lpcp.h"
  13. #ifdef ALLOC_PRAGMA
  14. #pragma alloc_text(PAGE,LpcpClosePort)
  15. #pragma alloc_text(PAGE,LpcpDeletePort)
  16. #pragma alloc_text(PAGE,LpcExitThread)
  17. #endif
  18. VOID
  19. LpcpClosePort (
  20. IN PEPROCESS Process OPTIONAL,
  21. IN PVOID Object,
  22. IN ACCESS_MASK GrantedAccess,
  23. IN ULONG ProcessHandleCount,
  24. IN ULONG SystemHandleCount
  25. )
  26. /*++
  27. Routine Description:
  28. This routine is the callback used for closing a port object.
  29. Arguments:
  30. Process - Supplies an optional pointer to the process whose port is being
  31. closed
  32. Object - Supplies a pointer to the port object being closed
  33. GrantedAccess - Supplies the access granted to the handle closing port
  34. object
  35. ProcessHandleCount - Supplies the number of process handles remaining to
  36. the object
  37. SystemHandleCount - Supplies the number of system handles remaining to
  38. the object
  39. Return Value:
  40. None.
  41. --*/
  42. {
  43. //
  44. // Translate the object to what it really is, an LPCP port object
  45. //
  46. PLPCP_PORT_OBJECT Port = Object;
  47. UNREFERENCED_PARAMETER (Process);
  48. UNREFERENCED_PARAMETER (GrantedAccess);
  49. UNREFERENCED_PARAMETER (ProcessHandleCount);
  50. //
  51. // We only have work to do if the object is a server communication port
  52. //
  53. if ( (Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT ) {
  54. //
  55. // If this is a server communication port without any system handles
  56. // then we can completely destroy the communication queue for the
  57. // port
  58. //
  59. if ( SystemHandleCount == 0 ) {
  60. LpcpDestroyPortQueue( Port, TRUE );
  61. //
  62. // If there is only one system handle left then we'll reset the
  63. // communication queue for the port
  64. //
  65. } else if ( SystemHandleCount == 1 ) {
  66. LpcpDestroyPortQueue( Port, FALSE );
  67. }
  68. //
  69. // Otherwise we do nothing
  70. //
  71. }
  72. return;
  73. }
  74. VOID
  75. LpcpDeletePort (
  76. IN PVOID Object
  77. )
  78. /*++
  79. Routine Description:
  80. This routine is the callback used for deleting a port object.
  81. Arguments:
  82. Object - Supplies a pointer to the port object being deleted
  83. Return Value:
  84. None.
  85. --*/
  86. {
  87. PETHREAD CurrentThread;
  88. PLPCP_PORT_OBJECT Port = Object;
  89. PLPCP_PORT_OBJECT ConnectionPort;
  90. LPC_CLIENT_DIED_MSG ClientPortClosedDatagram;
  91. PLPCP_MESSAGE Msg;
  92. PLIST_ENTRY Head, Next;
  93. HANDLE CurrentProcessId;
  94. PAGED_CODE();
  95. CurrentThread = PsGetCurrentThread ();
  96. //
  97. // If the port is a server communication port then make sure that if
  98. // there is a dangling client thread that we get rid of it. This
  99. // handles the case of someone calling NtAcceptConnectPort and not
  100. // calling NtCompleteConnectPort
  101. //
  102. if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) {
  103. PETHREAD ClientThread;
  104. LpcpAcquireLpcpLockByThread(CurrentThread);
  105. if ((ClientThread = Port->ClientThread) != NULL) {
  106. Port->ClientThread = NULL;
  107. LpcpReleaseLpcpLock();
  108. ObDereferenceObject( ClientThread );
  109. } else {
  110. LpcpReleaseLpcpLock();
  111. }
  112. }
  113. //
  114. // Send an LPC_PORT_CLOSED datagram to whoever is connected
  115. // to this port so they know they are no longer connected.
  116. //
  117. if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {
  118. ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram );
  119. ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime );
  120. ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED;
  121. ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0;
  122. ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime;
  123. LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );
  124. }
  125. //
  126. // If connected, disconnect the port, and then scan the message queue
  127. // for this port and dereference any messages in the queue.
  128. //
  129. LpcpDestroyPortQueue( Port, TRUE );
  130. //
  131. // If we had mapped sections into the server or client communication ports,
  132. // we need to unmap them in the context of that process.
  133. //
  134. if ( (Port->ClientSectionBase != NULL) ||
  135. (Port->ServerSectionBase != NULL) ) {
  136. //
  137. // If the client has a port memory view, then unmap it
  138. //
  139. if (Port->ClientSectionBase != NULL) {
  140. MmUnmapViewOfSection( Port->MappingProcess,
  141. Port->ClientSectionBase );
  142. }
  143. //
  144. // If the server has a port memory view, then unmap it
  145. //
  146. if (Port->ServerSectionBase != NULL) {
  147. MmUnmapViewOfSection( Port->MappingProcess,
  148. Port->ServerSectionBase );
  149. }
  150. //
  151. // Removing the reference added while mapping the section
  152. //
  153. ObDereferenceObject( Port->MappingProcess );
  154. Port->MappingProcess = NULL;
  155. }
  156. //
  157. // Dereference the pointer to the connection port if it is not
  158. // this port.
  159. //
  160. LpcpAcquireLpcpLockByThread(CurrentThread);
  161. ConnectionPort = Port->ConnectionPort;
  162. if (ConnectionPort) {
  163. CurrentProcessId = CurrentThread->Cid.UniqueProcess;
  164. Head = &ConnectionPort->LpcDataInfoChainHead;
  165. Next = Head->Flink;
  166. while (Next != Head) {
  167. Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
  168. Next = Next->Flink;
  169. //
  170. // Test whether the message come from the same port and process
  171. //
  172. if ((Msg->Request.ClientId.UniqueProcess == CurrentProcessId)
  173. &&
  174. ((Msg->SenderPort == Port)
  175. ||
  176. (Msg->SenderPort == Port->ConnectedPort)
  177. ||
  178. (Msg->SenderPort == ConnectionPort))) {
  179. LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n",
  180. PsGetCurrentProcess()->ImageFileName,
  181. Msg,
  182. Msg->Request.MessageId,
  183. Msg->Request.CallbackId,
  184. ConnectionPort ));
  185. RemoveEntryList( &Msg->Entry );
  186. LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED );
  187. //
  188. // In LpcpFreeToPortZone the LPC lock is released and reacquired.
  189. // Another thread might free the LPC message captured above
  190. // in Next. We need to restart the search at the list head.
  191. //
  192. Next = Head->Flink;
  193. }
  194. }
  195. LpcpReleaseLpcpLock();
  196. if (ConnectionPort != Port) {
  197. ObDereferenceObject( ConnectionPort );
  198. }
  199. } else {
  200. LpcpReleaseLpcpLock();
  201. }
  202. if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) &&
  203. (ConnectionPort->ServerProcess != NULL)) {
  204. ObDereferenceObject( ConnectionPort->ServerProcess );
  205. ConnectionPort->ServerProcess = NULL;
  206. }
  207. //
  208. // Free any static client security context
  209. //
  210. LpcpFreePortClientSecurity( Port );
  211. //
  212. // And return to our caller
  213. //
  214. return;
  215. }
  216. VOID
  217. LpcExitThread (
  218. PETHREAD Thread
  219. )
  220. /*++
  221. Routine Description:
  222. This routine is called whenever a thread is exiting and need to cleanup the
  223. lpc port for the thread.
  224. Arguments:
  225. Thread - Supplies the thread being terminated
  226. Return Value:
  227. None.
  228. --*/
  229. {
  230. PLPCP_MESSAGE Msg;
  231. //
  232. // Acquire the mutex that protects the LpcReplyMessage field of
  233. // the thread. Zero the field so nobody else tries to process it
  234. // when we release the lock.
  235. //
  236. ASSERT (Thread == PsGetCurrentThread());
  237. LpcpAcquireLpcpLockByThread(Thread);
  238. if (!IsListEmpty( &Thread->LpcReplyChain )) {
  239. RemoveEntryList( &Thread->LpcReplyChain );
  240. }
  241. //
  242. // Indicate that this thread is exiting
  243. //
  244. Thread->LpcExitThreadCalled = TRUE;
  245. Thread->LpcReplyMessageId = 0;
  246. //
  247. // If we need to reply to a message then if the thread that we need to reply
  248. // to is still around we want to dereference the thread and free the message
  249. //
  250. Msg = LpcpGetThreadMessage(Thread);
  251. if (Msg != NULL) {
  252. Thread->LpcReplyMessage = NULL;
  253. if (Msg->RepliedToThread != NULL) {
  254. ObDereferenceObject( Msg->RepliedToThread );
  255. Msg->RepliedToThread = NULL;
  256. }
  257. LpcpTrace(( "Cleanup Msg %lx (%d) for Thread %lx allocated\n", Msg, IsListEmpty( &Msg->Entry ), Thread ));
  258. LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED | LPCP_MUTEX_RELEASE_ON_RETURN );
  259. }
  260. else {
  261. //
  262. // Free the global lpc mutex.
  263. //
  264. LpcpReleaseLpcpLock();
  265. }
  266. //
  267. // And return to our caller
  268. //
  269. return;
  270. }