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