3 * COPYRIGHT: See COPYING in the top level directory
4 * PROJECT: ReactOS kernel
5 * FILE: ntoskrnl/lpc/reply.c
6 * PURPOSE: Communication mechanism
8 * PROGRAMMERS: David Welch (welch@cwcom.net)
11 /* INCLUDES ******************************************************************/
15 #include <internal/debug.h>
17 /* GLOBALS *******************************************************************/
19 /* FUNCTIONS *****************************************************************/
21 /**********************************************************************
33 EiReplyOrRequestPort (IN PEPORT Port
,
34 IN PPORT_MESSAGE LpcReply
,
39 PQUEUEDMESSAGE MessageReply
;
47 Size
= sizeof(QUEUEDMESSAGE
);
48 if (LpcReply
&& LpcReply
->u1
.s1
.TotalLength
> (CSHORT
)sizeof(PORT_MESSAGE
))
50 Size
+= LpcReply
->u1
.s1
.TotalLength
- sizeof(PORT_MESSAGE
);
52 MessageReply
= ExAllocatePoolWithTag(NonPagedPool
, Size
,
54 MessageReply
->Sender
= Sender
;
58 memcpy(&MessageReply
->Message
, LpcReply
, LpcReply
->u1
.s1
.TotalLength
);
62 MessageReply
->Message
.u1
.s1
.TotalLength
= sizeof(PORT_MESSAGE
);
63 MessageReply
->Message
.u1
.s1
.DataLength
= 0;
66 MessageReply
->Message
.ClientId
.UniqueProcess
= PsGetCurrentProcessId();
67 MessageReply
->Message
.ClientId
.UniqueThread
= PsGetCurrentThreadId();
68 MessageReply
->Message
.u2
.s2
.Type
= MessageType
;
69 MessageReply
->Message
.MessageId
= InterlockedIncrementUL(&LpcpNextMessageId
);
71 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
72 EiEnqueueMessagePort(Port
, MessageReply
);
73 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
75 return(STATUS_SUCCESS
);
79 /**********************************************************************
91 NtReplyPort (IN HANDLE PortHandle
,
92 IN PPORT_MESSAGE LpcReply
)
97 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle
, LpcReply
);
99 Status
= ObReferenceObjectByHandle(PortHandle
,
100 PORT_ALL_ACCESS
, /* AccessRequired */
105 if (!NT_SUCCESS(Status
))
107 DPRINT("NtReplyPort() = %x\n", Status
);
111 if (EPORT_DISCONNECTED
== Port
->State
)
113 ObDereferenceObject(Port
);
114 return STATUS_PORT_DISCONNECTED
;
117 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
121 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
123 ObDereferenceObject(Port
);
129 /**********************************************************************
131 * NtReplyWaitReceivePortEx
134 * Can be used with waitable ports.
135 * Present only in w2k+.
149 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
150 OUT PVOID
*PortContext OPTIONAL
,
151 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
152 OUT PPORT_MESSAGE ReceiveMessage
,
153 IN PLARGE_INTEGER Timeout OPTIONAL
)
157 PQUEUEDMESSAGE Request
;
158 BOOLEAN Disconnected
;
160 KPROCESSOR_MODE PreviousMode
;
161 NTSTATUS Status
= STATUS_SUCCESS
;
163 PreviousMode
= ExGetPreviousMode();
165 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
166 "LpcMessage %x)\n", PortHandle
, ReplyMessage
, ReceiveMessage
);
168 if (PreviousMode
!= KernelMode
)
172 ProbeForWrite(ReceiveMessage
,
173 sizeof(PORT_MESSAGE
),
178 Status
= _SEH_GetExceptionCode();
182 if (!NT_SUCCESS(Status
))
188 Status
= ObReferenceObjectByHandle(PortHandle
,
194 if (!NT_SUCCESS(Status
))
196 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
199 if( Port
->State
== EPORT_DISCONNECTED
)
201 /* If the port is disconnected, force the timeout to be 0
202 * so we don't wait for new messages, because there won't be
203 * any, only try to remove any existing messages
209 else Disconnected
= FALSE
;
212 * Send the reply, only if port is connected
214 if (ReplyMessage
!= NULL
&& !Disconnected
)
216 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
220 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1,
223 if (!NT_SUCCESS(Status
))
225 ObDereferenceObject(Port
);
226 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
232 * Want for a message to be received
234 Status
= KeWaitForSingleObject(&Port
->Semaphore
,
239 if( Status
== STATUS_TIMEOUT
)
242 * if the port is disconnected, and there are no remaining messages,
243 * return STATUS_PORT_DISCONNECTED
245 ObDereferenceObject(Port
);
246 return(Disconnected
? STATUS_PORT_DISCONNECTED
: STATUS_TIMEOUT
);
249 if (!NT_SUCCESS(Status
))
251 if (STATUS_THREAD_IS_TERMINATING
!= Status
)
253 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
255 ObDereferenceObject(Port
);
260 * Dequeue the message
262 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
263 Request
= EiDequeueMessagePort(Port
);
264 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
268 ObDereferenceObject(Port
);
269 return STATUS_UNSUCCESSFUL
;
272 if (Request
->Message
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
275 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
277 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)&Request
->Message
;
278 memcpy(&Header
, &Request
->Message
, sizeof(PORT_MESSAGE
));
279 Header
.u1
.s1
.DataLength
= CRequest
->ConnectDataLength
;
280 Header
.u1
.s1
.TotalLength
= Header
.u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
);
282 if (PreviousMode
!= KernelMode
)
286 ProbeForWrite((PVOID
)(ReceiveMessage
+ 1),
287 CRequest
->ConnectDataLength
,
290 RtlCopyMemory(ReceiveMessage
,
292 sizeof(PORT_MESSAGE
));
293 RtlCopyMemory((PVOID
)(ReceiveMessage
+ 1),
294 CRequest
->ConnectData
,
295 CRequest
->ConnectDataLength
);
299 Status
= _SEH_GetExceptionCode();
305 RtlCopyMemory(ReceiveMessage
,
307 sizeof(PORT_MESSAGE
));
308 RtlCopyMemory((PVOID
)(ReceiveMessage
+ 1),
309 CRequest
->ConnectData
,
310 CRequest
->ConnectDataLength
);
315 if (PreviousMode
!= KernelMode
)
319 ProbeForWrite(ReceiveMessage
,
320 Request
->Message
.u1
.s1
.TotalLength
,
323 RtlCopyMemory(ReceiveMessage
,
325 Request
->Message
.u1
.s1
.TotalLength
);
329 Status
= _SEH_GetExceptionCode();
335 RtlCopyMemory(ReceiveMessage
,
337 Request
->Message
.u1
.s1
.TotalLength
);
340 if (!NT_SUCCESS(Status
))
343 * Copying the message to the caller's buffer failed so
344 * undo what we did and return.
345 * FIXME: Also increment semaphore.
347 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
348 EiEnqueueMessageAtHeadPort(Port
, Request
);
349 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
350 ObDereferenceObject(Port
);
353 if (Request
->Message
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
355 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
356 EiEnqueueConnectMessagePort(Port
, Request
);
357 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
365 * Dereference the port
367 ObDereferenceObject(Port
);
368 return(STATUS_SUCCESS
);
372 /**********************************************************************
374 * NtReplyWaitReceivePort
377 * Can be used with waitable ports.
390 NtReplyWaitReceivePort(IN HANDLE PortHandle
,
391 OUT PVOID
*PortContext OPTIONAL
,
392 IN PPORT_MESSAGE ReplyMessage OPTIONAL
,
393 OUT PPORT_MESSAGE ReceiveMessage
)
395 return NtReplyWaitReceivePortEx(PortHandle
,
402 /**********************************************************************
414 NtReplyWaitReplyPort (HANDLE PortHandle
,
415 PPORT_MESSAGE ReplyMessage
)
418 return(STATUS_NOT_IMPLEMENTED
);
426 LpcRequestWaitReplyPort (
428 IN PPORT_MESSAGE LpcMessageRequest
,
429 OUT PPORT_MESSAGE LpcMessageReply
433 return STATUS_NOT_IMPLEMENTED
;