Fix closing of LPC ports
[reactos.git] / reactos / ntoskrnl / lpc / reply.c
1 /* $Id: reply.c,v 1.22 2004/09/13 19:10:45 gvg Exp $
2 *
3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/reply.c
6 * PURPOSE: Communication mechanism
7 * PROGRAMMER: David Welch (welch@cwcom.net)
8 * UPDATE HISTORY:
9 * Created 22/05/98
10 */
11
12 /* INCLUDES ******************************************************************/
13
14 #include <ntoskrnl.h>
15 #define NDEBUG
16 #include <internal/debug.h>
17
18 /* GLOBALS *******************************************************************/
19
20 #define TAG_LPC_MESSAGE TAG('L', 'P', 'C', 'M')
21
22 /* FUNCTIONS *****************************************************************/
23
24 /**********************************************************************
25 * NAME
26 *
27 * DESCRIPTION
28 *
29 * ARGUMENTS
30 *
31 * RETURN VALUE
32 *
33 * REVISIONS
34 */
35 NTSTATUS STDCALL
36 EiReplyOrRequestPort (IN PEPORT Port,
37 IN PLPC_MESSAGE LpcReply,
38 IN ULONG MessageType,
39 IN PEPORT Sender)
40 {
41 KIRQL oldIrql;
42 PQUEUEDMESSAGE MessageReply;
43
44 if (Port == NULL)
45 {
46 KEBUGCHECK(0);
47 }
48
49 MessageReply = ExAllocatePoolWithTag(NonPagedPool, sizeof(QUEUEDMESSAGE),
50 TAG_LPC_MESSAGE);
51 MessageReply->Sender = Sender;
52
53 if (LpcReply != NULL)
54 {
55 memcpy(&MessageReply->Message, LpcReply, LpcReply->MessageSize);
56 }
57
58 MessageReply->Message.ClientId.UniqueProcess = PsGetCurrentProcessId();
59 MessageReply->Message.ClientId.UniqueThread = PsGetCurrentThreadId();
60 MessageReply->Message.MessageType = MessageType;
61 MessageReply->Message.MessageId = InterlockedIncrement((LONG *)&EiNextLpcMessageId);
62
63 KeAcquireSpinLock(&Port->Lock, &oldIrql);
64 EiEnqueueMessagePort(Port, MessageReply);
65 KeReleaseSpinLock(&Port->Lock, oldIrql);
66
67 return(STATUS_SUCCESS);
68 }
69
70
71 /**********************************************************************
72 * NAME EXPORTED
73 *
74 * DESCRIPTION
75 *
76 * ARGUMENTS
77 *
78 * RETURN VALUE
79 *
80 * REVISIONS
81 */
82 NTSTATUS STDCALL
83 NtReplyPort (IN HANDLE PortHandle,
84 IN PLPC_MESSAGE LpcReply)
85 {
86 NTSTATUS Status;
87 PEPORT Port;
88
89 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle, LpcReply);
90
91 Status = ObReferenceObjectByHandle(PortHandle,
92 PORT_ALL_ACCESS, /* AccessRequired */
93 ExPortType,
94 UserMode,
95 (PVOID*)&Port,
96 NULL);
97 if (!NT_SUCCESS(Status))
98 {
99 DPRINT("NtReplyPort() = %x\n", Status);
100 return(Status);
101 }
102
103 if (EPORT_DISCONNECTED == Port->State)
104 {
105 ObDereferenceObject(Port);
106 return STATUS_PORT_DISCONNECTED;
107 }
108
109 Status = EiReplyOrRequestPort(Port->OtherPort,
110 LpcReply,
111 LPC_REPLY,
112 Port);
113 KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
114
115 ObDereferenceObject(Port);
116
117 return(Status);
118 }
119
120
121 /**********************************************************************
122 * NAME EXPORTED
123 * NtReplyWaitReceivePortEx
124 *
125 * DESCRIPTION
126 * Can be used with waitable ports.
127 * Present only in w2k+.
128 *
129 * ARGUMENTS
130 * PortHandle
131 * PortId
132 * LpcReply
133 * LpcMessage
134 * Timeout
135 *
136 * RETURN VALUE
137 *
138 * REVISIONS
139 */
140 NTSTATUS STDCALL
141 NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
142 OUT PULONG PortId,
143 IN PLPC_MESSAGE LpcReply,
144 OUT PLPC_MESSAGE LpcMessage,
145 IN PLARGE_INTEGER Timeout)
146 {
147 NTSTATUS Status;
148 PEPORT Port;
149 KIRQL oldIrql;
150 PQUEUEDMESSAGE Request;
151 BOOLEAN Disconnected;
152 LARGE_INTEGER to;
153
154 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
155 "LpcMessage %x)\n", PortHandle, LpcReply, LpcMessage);
156
157 Status = ObReferenceObjectByHandle(PortHandle,
158 PORT_ALL_ACCESS,
159 ExPortType,
160 UserMode,
161 (PVOID*)&Port,
162 NULL);
163 if (!NT_SUCCESS(Status))
164 {
165 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
166 return(Status);
167 }
168 if( Port->State == EPORT_DISCONNECTED )
169 {
170 /* If the port is disconnected, force the timeout to be 0
171 * so we don't wait for new messages, because there won't be
172 * any, only try to remove any existing messages
173 */
174 Disconnected = TRUE;
175 to.QuadPart = 0;
176 Timeout = &to;
177 }
178 else Disconnected = FALSE;
179
180 /*
181 * Send the reply, only if port is connected
182 */
183 if (LpcReply != NULL && !Disconnected)
184 {
185 Status = EiReplyOrRequestPort(Port->OtherPort,
186 LpcReply,
187 LPC_REPLY,
188 Port);
189 KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1,
190 FALSE);
191
192 if (!NT_SUCCESS(Status))
193 {
194 ObDereferenceObject(Port);
195 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
196 return(Status);
197 }
198 }
199
200 /*
201 * Want for a message to be received
202 */
203 Status = KeWaitForSingleObject(&Port->Semaphore,
204 UserRequest,
205 UserMode,
206 FALSE,
207 Timeout);
208 if( Status == STATUS_TIMEOUT )
209 {
210 /*
211 * if the port is disconnected, and there are no remaining messages,
212 * return STATUS_PORT_DISCONNECTED
213 */
214 ObDereferenceObject(Port);
215 return(Disconnected ? STATUS_PORT_DISCONNECTED : STATUS_TIMEOUT);
216 }
217
218 if (!NT_SUCCESS(Status))
219 {
220 if (STATUS_THREAD_IS_TERMINATING != Status)
221 {
222 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
223 }
224 ObDereferenceObject(Port);
225 return(Status);
226 }
227
228 /*
229 * Dequeue the message
230 */
231 KeAcquireSpinLock(&Port->Lock, &oldIrql);
232 Request = EiDequeueMessagePort(Port);
233 KeReleaseSpinLock(&Port->Lock, oldIrql);
234
235 if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
236 {
237 LPC_MESSAGE Header;
238 PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
239
240 CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)&Request->Message;
241 memcpy(&Header, &Request->Message, sizeof(LPC_MESSAGE));
242 Header.DataSize = CRequest->ConnectDataLength;
243 Header.MessageSize = Header.DataSize + sizeof(LPC_MESSAGE);
244 Status = MmCopyToCaller(LpcMessage, &Header, sizeof(LPC_MESSAGE));
245 if (NT_SUCCESS(Status))
246 {
247 Status = MmCopyToCaller((PVOID)(LpcMessage + 1),
248 CRequest->ConnectData,
249 CRequest->ConnectDataLength);
250 }
251 }
252 else
253 {
254 Status = MmCopyToCaller(LpcMessage, &Request->Message,
255 Request->Message.MessageSize);
256 }
257 if (!NT_SUCCESS(Status))
258 {
259 /*
260 * Copying the message to the caller's buffer failed so
261 * undo what we did and return.
262 * FIXME: Also increment semaphore.
263 */
264 KeAcquireSpinLock(&Port->Lock, &oldIrql);
265 EiEnqueueMessageAtHeadPort(Port, Request);
266 KeReleaseSpinLock(&Port->Lock, oldIrql);
267 ObDereferenceObject(Port);
268 return(Status);
269 }
270 if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
271 {
272 KeAcquireSpinLock(&Port->Lock, &oldIrql);
273 EiEnqueueConnectMessagePort(Port, Request);
274 KeReleaseSpinLock(&Port->Lock, oldIrql);
275 }
276 else
277 {
278 ExFreePool(Request);
279 }
280
281 /*
282 * Dereference the port
283 */
284 ObDereferenceObject(Port);
285 return(STATUS_SUCCESS);
286 }
287
288
289 /**********************************************************************
290 * NAME EXPORTED
291 * NtReplyWaitReceivePort
292 *
293 * DESCRIPTION
294 * Can be used with waitable ports.
295 *
296 * ARGUMENTS
297 * PortHandle
298 * PortId
299 * LpcReply
300 * LpcMessage
301 *
302 * RETURN VALUE
303 *
304 * REVISIONS
305 */
306 NTSTATUS STDCALL
307 NtReplyWaitReceivePort (IN HANDLE PortHandle,
308 OUT PULONG PortId,
309 IN PLPC_MESSAGE LpcReply,
310 OUT PLPC_MESSAGE LpcMessage)
311 {
312 return(NtReplyWaitReceivePortEx (PortHandle,
313 PortId,
314 LpcReply,
315 LpcMessage,
316 NULL));
317 }
318
319 /**********************************************************************
320 * NAME
321 *
322 * DESCRIPTION
323 *
324 * ARGUMENTS
325 *
326 * RETURN VALUE
327 *
328 * REVISIONS
329 */
330 NTSTATUS STDCALL
331 NtReplyWaitReplyPort (HANDLE PortHandle,
332 PLPC_MESSAGE ReplyMessage)
333 {
334 UNIMPLEMENTED;
335 return(STATUS_NOT_IMPLEMENTED);
336 }
337
338 /*
339 * @unimplemented
340 */
341 NTSTATUS
342 STDCALL
343 LpcRequestWaitReplyPort (
344 IN PEPORT Port,
345 IN PLPC_MESSAGE LpcMessageRequest,
346 OUT PLPC_MESSAGE LpcMessageReply
347 )
348 {
349 UNIMPLEMENTED;
350 return STATUS_NOT_IMPLEMENTED;
351 }
352
353 /* EOF */