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