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.

439 lines
11 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_PTR ProcessHandleCount,
  24. IN ULONG_PTR 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. NTSTATUS Status;
  95. LARGE_INTEGER RetryInterval = {(ULONG)(-10 * 1000 * 100), -1}; // 100 milliseconds
  96. PAGED_CODE();
  97. CurrentThread = PsGetCurrentThread ();
  98. //
  99. // If the port is a server communication port then make sure that if
  100. // there is a dangling client thread that we get rid of it. This
  101. // handles the case of someone calling NtAcceptConnectPort and not
  102. // calling NtCompleteConnectPort
  103. //
  104. if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) {
  105. PETHREAD ClientThread;
  106. LpcpAcquireLpcpLockByThread(CurrentThread);
  107. if ((ClientThread = Port->ClientThread) != NULL) {
  108. Port->ClientThread = NULL;
  109. LpcpReleaseLpcpLock();
  110. ObDereferenceObject( ClientThread );
  111. } else {
  112. LpcpReleaseLpcpLock();
  113. }
  114. }
  115. //
  116. // Send an LPC_PORT_CLOSED datagram to whoever is connected
  117. // to this port so they know they are no longer connected.
  118. //
  119. if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {
  120. ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram );
  121. ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime );
  122. ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED;
  123. ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0;
  124. ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime;
  125. Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );
  126. while (Status == STATUS_NO_MEMORY) {
  127. KeDelayExecutionThread(KernelMode, FALSE, &RetryInterval);
  128. Status = LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );
  129. }
  130. }
  131. //
  132. // If connected, disconnect the port, and then scan the message queue
  133. // for this port and dereference any messages in the queue.
  134. //
  135. LpcpDestroyPortQueue( Port, TRUE );
  136. //
  137. // If we had mapped sections into the server or client communication ports,
  138. // we need to unmap them in the context of that process.
  139. //
  140. if ( (Port->ClientSectionBase != NULL) ||
  141. (Port->ServerSectionBase != NULL) ) {
  142. //
  143. // If the client has a port memory view, then unmap it
  144. //
  145. if (Port->ClientSectionBase != NULL) {
  146. MmUnmapViewOfSection( Port->MappingProcess,
  147. Port->ClientSectionBase );
  148. }
  149. //
  150. // If the server has a port memory view, then unmap it
  151. //
  152. if (Port->ServerSectionBase != NULL) {
  153. MmUnmapViewOfSection( Port->MappingProcess,
  154. Port->ServerSectionBase );
  155. }
  156. //
  157. // Removing the reference added while mapping the section
  158. //
  159. ObDereferenceObject( Port->MappingProcess );
  160. Port->MappingProcess = NULL;
  161. }
  162. //
  163. // Dereference the pointer to the connection port if it is not
  164. // this port.
  165. //
  166. LpcpAcquireLpcpLockByThread(CurrentThread);
  167. ConnectionPort = Port->ConnectionPort;
  168. if (ConnectionPort) {
  169. CurrentProcessId = CurrentThread->Cid.UniqueProcess;
  170. Head = &ConnectionPort->LpcDataInfoChainHead;
  171. Next = Head->Flink;
  172. while (Next != Head) {
  173. Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
  174. Next = Next->Flink;
  175. if (Port == ConnectionPort) {
  176. //
  177. // If the Connection port is going away free all queued messages
  178. //
  179. RemoveEntryList( &Msg->Entry );
  180. InitializeListHead( &Msg->Entry );
  181. LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED );
  182. //
  183. // In LpcpFreeToPortZone the LPC lock is released and reacquired.
  184. // Another thread might free the LPC message captured above
  185. // in Next. We need to restart the search at the list head.
  186. //
  187. Next = Head->Flink;
  188. } else if ((Msg->Request.ClientId.UniqueProcess == CurrentProcessId)
  189. &&
  190. ((Msg->SenderPort == Port)
  191. ||
  192. (Msg->SenderPort == Port->ConnectedPort)
  193. ||
  194. (Msg->SenderPort == ConnectionPort))) {
  195. //
  196. // Test whether the message come from the same port and process
  197. //
  198. LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n",
  199. PsGetCurrentProcess()->ImageFileName,
  200. Msg,
  201. Msg->Request.MessageId,
  202. Msg->Request.CallbackId,
  203. ConnectionPort ));
  204. RemoveEntryList( &Msg->Entry );
  205. InitializeListHead( &Msg->Entry );
  206. LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED );
  207. //
  208. // In LpcpFreeToPortZone the LPC lock is released and reacquired.
  209. // Another thread might free the LPC message captured above
  210. // in Next. We need to restart the search at the list head.
  211. //
  212. Next = Head->Flink;
  213. }
  214. }
  215. LpcpReleaseLpcpLock();
  216. if (ConnectionPort != Port) {
  217. ObDereferenceObject( ConnectionPort );
  218. }
  219. } else {
  220. LpcpReleaseLpcpLock();
  221. }
  222. if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) &&
  223. (ConnectionPort->ServerProcess != NULL)) {
  224. ObDereferenceObject( ConnectionPort->ServerProcess );
  225. ConnectionPort->ServerProcess = NULL;
  226. }
  227. //
  228. // Free any static client security context
  229. //
  230. LpcpFreePortClientSecurity( Port );
  231. //
  232. // And return to our caller
  233. //
  234. return;
  235. }
  236. VOID
  237. LpcExitThread (
  238. PETHREAD Thread
  239. )
  240. /*++
  241. Routine Description:
  242. This routine is called whenever a thread is exiting and need to cleanup the
  243. lpc port for the thread.
  244. Arguments:
  245. Thread - Supplies the thread being terminated
  246. Return Value:
  247. None.
  248. --*/
  249. {
  250. PLPCP_MESSAGE Msg;
  251. //
  252. // Acquire the mutex that protects the LpcReplyMessage field of
  253. // the thread. Zero the field so nobody else tries to process it
  254. // when we release the lock.
  255. //
  256. ASSERT (Thread == PsGetCurrentThread());
  257. LpcpAcquireLpcpLockByThread(Thread);
  258. if (!IsListEmpty( &Thread->LpcReplyChain )) {
  259. RemoveEntryList( &Thread->LpcReplyChain );
  260. }
  261. //
  262. // Indicate that this thread is exiting
  263. //
  264. Thread->LpcExitThreadCalled = TRUE;
  265. Thread->LpcReplyMessageId = 0;
  266. //
  267. // If we need to reply to a message then if the thread that we need to reply
  268. // to is still around we want to dereference the thread and free the message
  269. //
  270. Msg = LpcpGetThreadMessage(Thread);
  271. if (Msg != NULL) {
  272. Thread->LpcReplyMessage = NULL;
  273. if (Msg->RepliedToThread != NULL) {
  274. ObDereferenceObject( Msg->RepliedToThread );
  275. Msg->RepliedToThread = NULL;
  276. }
  277. LpcpTrace(( "Cleanup Msg %lx (%d) for Thread %lx allocated\n", Msg, IsListEmpty( &Msg->Entry ), Thread ));
  278. LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED | LPCP_MUTEX_RELEASE_ON_RETURN );
  279. }
  280. else {
  281. //
  282. // Free the global lpc mutex.
  283. //
  284. LpcpReleaseLpcpLock();
  285. }
  286. //
  287. // And return to our caller
  288. //
  289. return;
  290. }