set most of trunk svn property eol-style:native
[reactos.git] / reactos / ntoskrnl / lpc / ntlpc / close.c
1 /*
2 * PROJECT: ReactOS Kernel
3 * LICENSE: GPL - See COPYING in the top level directory
4 * FILE: ntoskrnl/lpc/close.c
5 * PURPOSE: Local Procedure Call: Rundown, Cleanup, Deletion
6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
7 */
8
9 /* INCLUDES ******************************************************************/
10
11 #include <ntoskrnl.h>
12 #include "lpc.h"
13 #define NDEBUG
14 #include <internal/debug.h>
15
16 /* PRIVATE FUNCTIONS *********************************************************/
17
18 VOID
19 NTAPI
20 LpcExitThread(IN PETHREAD Thread)
21 {
22 PLPCP_MESSAGE Message;
23
24 /* Acquire the lock */
25 KeAcquireGuardedMutex(&LpcpLock);
26
27 /* Make sure that the Reply Chain is empty */
28 if (!IsListEmpty(&Thread->LpcReplyChain))
29 {
30 /* It's not, remove the entry */
31 RemoveEntryList(&Thread->LpcReplyChain);
32 }
33
34 /* Set the thread in exit mode */
35 Thread->LpcExitThreadCalled = TRUE;
36 Thread->LpcReplyMessageId = 0;
37
38 /* Check if there's a reply message */
39 Message = Thread->LpcReplyMessage;
40 if (Message)
41 {
42 /* FIXME: TODO */
43 KEBUGCHECK(0);
44 }
45
46 /* Release the lock */
47 KeReleaseGuardedMutex(&LpcpLock);
48 }
49
50 VOID
51 NTAPI
52 LpcpFreeToPortZone(IN PLPCP_MESSAGE Message,
53 IN ULONG Flags)
54 {
55 PLPCP_CONNECTION_MESSAGE ConnectMessage;
56 PLPCP_PORT_OBJECT ClientPort = NULL;
57 PETHREAD Thread = NULL;
58 BOOLEAN LockHeld = Flags & 1;
59 PAGED_CODE();
60 LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. Flags: %lx\n", Message, Flags);
61
62 /* Acquire the lock if not already */
63 if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
64
65 /* Check if the queue list is empty */
66 if (!IsListEmpty(&Message->Entry))
67 {
68 /* Remove and re-initialize */
69 RemoveEntryList(&Message->Entry);
70 InitializeListHead(&Message->Entry);
71 }
72
73 /* Check if we've already replied */
74 if (Message->RepliedToThread)
75 {
76 /* Set thread to dereference and clean up */
77 Thread = Message->RepliedToThread;
78 Message->RepliedToThread = NULL;
79 }
80
81 /* Check if this is a connection request */
82 if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
83 {
84 /* Get the connection message */
85 ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
86
87 /* Clear the client port */
88 ClientPort = ConnectMessage->ClientPort;
89 if (ClientPort) ConnectMessage->ClientPort = NULL;
90 }
91
92 /* Release the lock */
93 KeReleaseGuardedMutex(&LpcpLock);
94
95 /* Check if we had anything to dereference */
96 if (Thread) ObDereferenceObject(Thread);
97 if (ClientPort) ObDereferenceObject(ClientPort);
98
99 /* Free the entry */
100 ExFreeToPagedLookasideList(&LpcpMessagesLookaside, Message);
101
102 /* Reacquire the lock if needed */
103 if ((LockHeld) && !(Flags & 2)) KeAcquireGuardedMutex(&LpcpLock);
104 }
105
106 VOID
107 NTAPI
108 LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port,
109 IN BOOLEAN Destroy)
110 {
111 PLIST_ENTRY ListHead, NextEntry;
112 PETHREAD Thread;
113 PLPCP_MESSAGE Message;
114 PLPCP_CONNECTION_MESSAGE ConnectMessage;
115 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
116
117 /* Hold the lock */
118 KeAcquireGuardedMutex(&LpcpLock);
119
120 /* Disconnect the port to which this port is connected */
121 if (Port->ConnectedPort) Port->ConnectedPort->ConnectedPort = NULL;
122
123 /* Check if this is a connection port */
124 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
125 {
126 /* Delete the name */
127 Port->Flags |= LPCP_NAME_DELETED;
128 }
129
130 /* Walk all the threads waiting and signal them */
131 ListHead = &Port->LpcReplyChainHead;
132 NextEntry = ListHead->Flink;
133 while (NextEntry != ListHead)
134 {
135 /* Get the Thread */
136 Thread = CONTAINING_RECORD(NextEntry, ETHREAD, LpcReplyChain);
137
138 /* Make sure we're not in exit */
139 if (Thread->LpcExitThreadCalled) break;
140
141 /* Move to the next entry */
142 NextEntry = NextEntry->Flink;
143
144 /* Remove and reinitialize the List */
145 RemoveEntryList(&Thread->LpcReplyChain);
146 InitializeListHead(&Thread->LpcReplyChain);
147
148 /* Check if someone is waiting */
149 if (!KeReadStateSemaphore(&Thread->LpcReplySemaphore))
150 {
151 /* Get the message and check if it's a connection request */
152 Message = Thread->LpcReplyMessage;
153 if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
154 {
155 /* Get the connection message */
156 ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
157
158 /* Check if it had a section */
159 if (ConnectMessage->SectionToMap)
160 {
161 /* Dereference it */
162 ObDereferenceObject(ConnectMessage->SectionToMap);
163 }
164 }
165
166 /* Clear the reply message */
167 Thread->LpcReplyMessage = NULL;
168
169 /* And remove the message from the port zone */
170 LpcpFreeToPortZone(Message, TRUE);
171 }
172
173 /* Release the semaphore and reset message id count */
174 Thread->LpcReplyMessageId = 0;
175 LpcpCompleteWait(&Thread->LpcReplySemaphore);
176 }
177
178 /* Reinitialize the list head */
179 InitializeListHead(&Port->LpcReplyChainHead);
180
181 /* Loop queued messages */
182 ListHead = &Port->MsgQueue.ReceiveHead;
183 NextEntry = ListHead->Flink;
184 while (ListHead != NextEntry)
185 {
186 /* Get the message */
187 Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
188 NextEntry = NextEntry->Flink;
189
190 /* Free and reinitialize it's list head */
191 InitializeListHead(&Message->Entry);
192
193 /* Remove it from the port zone */
194 LpcpFreeToPortZone(Message, TRUE);
195 }
196
197 /* Reinitialize the message queue list head */
198 InitializeListHead(&Port->MsgQueue.ReceiveHead);
199
200 /* Release the lock */
201 KeReleaseGuardedMutex(&LpcpLock);
202
203 /* Check if we have to free the port entirely */
204 if (Destroy)
205 {
206 /* Check if the semaphore exists */
207 if (Port->MsgQueue.Semaphore)
208 {
209 /* Use the semaphore to find the port queue and free it */
210 ExFreePool(CONTAINING_RECORD(Port->MsgQueue.Semaphore,
211 LPCP_NONPAGED_PORT_QUEUE,
212 Semaphore));
213 }
214 }
215 }
216
217 VOID
218 NTAPI
219 LpcpClosePort(IN PEPROCESS Process OPTIONAL,
220 IN PVOID Object,
221 IN ACCESS_MASK GrantedAccess,
222 IN ULONG ProcessHandleCount,
223 IN ULONG SystemHandleCount)
224 {
225 PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object;
226 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
227
228 /* Only Server-side Connection Ports need clean up*/
229 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
230 {
231 /* Check the handle count */
232 switch (SystemHandleCount)
233 {
234 /* No handles left */
235 case 0:
236
237 /* Destroy the port queue */
238 LpcpDestroyPortQueue(Port, TRUE);
239 break;
240
241 /* Last handle remaining */
242 case 1:
243
244 /* Reset the queue only */
245 LpcpDestroyPortQueue(Port, FALSE);
246
247 /* More handles remain, do nothing */
248 default:
249 break;
250 }
251 }
252 }
253
254 VOID
255 NTAPI
256 LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port)
257 {
258 /* Check if this is a client port */
259 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
260 {
261 /* Check if security is static */
262 if (!(Port->Flags & LPCP_SECURITY_DYNAMIC))
263 {
264 /* Check if we have a token */
265 if (Port->StaticSecurity.ClientToken)
266 {
267 /* Free security */
268 SeDeleteClientSecurity(&Port->StaticSecurity);
269 }
270 }
271 }
272 }
273
274 VOID
275 NTAPI
276 LpcpDeletePort(IN PVOID ObjectBody)
277 {
278 LARGE_INTEGER Timeout;
279 PETHREAD Thread;
280 PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody;
281 PLPCP_PORT_OBJECT ConnectionPort;
282 PLPCP_MESSAGE Message;
283 PLIST_ENTRY ListHead, NextEntry;
284 HANDLE Pid;
285 CLIENT_DIED_MSG ClientDiedMsg;
286 Timeout.QuadPart = -1000000;
287 PAGED_CODE();
288 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
289
290 /* Check if this is a communication port */
291 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT)
292 {
293 /* Acquire the lock */
294 KeAcquireGuardedMutex(&LpcpLock);
295
296 /* Get the thread */
297 Thread = Port->ClientThread;
298 if (Thread)
299 {
300 /* Clear it */
301 Port->ClientThread = NULL;
302
303 /* Release the lock and dereference */
304 KeReleaseGuardedMutex(&LpcpLock);
305 ObDereferenceObject(Thread);
306 }
307 else
308 {
309 /* Release the lock */
310 KeReleaseGuardedMutex(&LpcpLock);
311 }
312 }
313
314 /* Check if this is a client-side port */
315 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
316 {
317 /* Setup the client died message */
318 ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg);
319 ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime);
320 ClientDiedMsg.h.u2.ZeroInit = LPC_PORT_CLOSED;
321 ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime;
322
323 /* Send it */
324 for (;;)
325 {
326 /* Send the message */
327 if (LpcRequestPort(Port,
328 &ClientDiedMsg.h) != STATUS_NO_MEMORY) break;
329
330 /* Wait until trying again */
331 KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
332 }
333 }
334
335 /* Destroy the port queue */
336 LpcpDestroyPortQueue(Port, TRUE);
337
338 /* Check if we had a client view */
339 if (Port->ClientSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
340 Port->ClientSectionBase);
341
342 /* Check for a server view */
343 if (Port->ServerSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
344 Port->ServerSectionBase);
345
346 /* Get the connection port */
347 ConnectionPort = Port->ConnectionPort;
348 if (ConnectionPort)
349 {
350 /* Get the PID */
351 Pid = PsGetCurrentProcessId();
352
353 /* Acquire the lock */
354 KeAcquireGuardedMutex(&LpcpLock);
355
356 /* Loop the data lists */
357 ListHead = &ConnectionPort->LpcDataInfoChainHead;
358 NextEntry = ListHead->Flink;
359 while (NextEntry != ListHead)
360 {
361 /* Get the message */
362 Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
363 NextEntry = NextEntry->Flink;
364
365 /* Check if the PID matches */
366 if (Message->Request.ClientId.UniqueProcess == Pid)
367 {
368 /* Remove it */
369 RemoveEntryList(&Message->Entry);
370 LpcpFreeToPortZone(Message, TRUE);
371 }
372 }
373
374 /* Release the lock */
375 KeReleaseGuardedMutex(&LpcpLock);
376
377 /* Dereference the object unless it's the same port */
378 if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort);
379 }
380
381 /* Check if this is a connection port with a server process*/
382 if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) &&
383 (ConnectionPort->ServerProcess))
384 {
385 /* Dereference the server process */
386 ObDereferenceObject(ConnectionPort->ServerProcess);
387 ConnectionPort->ServerProcess = NULL;
388 }
389
390 /* Free client security */
391 LpcpFreePortClientSecurity(Port);
392 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port);
393 }
394
395 /* EOF */