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
;
46 MessageReply
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(QUEUEDMESSAGE
),
48 MessageReply
->Sender
= Sender
;
52 memcpy(&MessageReply
->Message
, LpcReply
, LpcReply
->u1
.s1
.TotalLength
);
55 MessageReply
->Message
.ClientId
.UniqueProcess
= PsGetCurrentProcessId();
56 MessageReply
->Message
.ClientId
.UniqueThread
= PsGetCurrentThreadId();
57 MessageReply
->Message
.u2
.s2
.Type
= MessageType
;
58 MessageReply
->Message
.MessageId
= InterlockedIncrementUL(&LpcpNextMessageId
);
60 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
61 EiEnqueueMessagePort(Port
, MessageReply
);
62 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
64 return(STATUS_SUCCESS
);
68 /**********************************************************************
80 NtReplyPort (IN HANDLE PortHandle
,
81 IN PPORT_MESSAGE LpcReply
)
86 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle
, LpcReply
);
88 Status
= ObReferenceObjectByHandle(PortHandle
,
89 PORT_ALL_ACCESS
, /* AccessRequired */
94 if (!NT_SUCCESS(Status
))
96 DPRINT("NtReplyPort() = %x\n", Status
);
100 if (EPORT_DISCONNECTED
== Port
->State
)
102 ObDereferenceObject(Port
);
103 return STATUS_PORT_DISCONNECTED
;
106 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
110 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
112 ObDereferenceObject(Port
);
118 /**********************************************************************
120 * NtReplyWaitReceivePortEx
123 * Can be used with waitable ports.
124 * Present only in w2k+.
138 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
140 IN PPORT_MESSAGE LpcReply
,
141 OUT PPORT_MESSAGE LpcMessage
,
142 IN PLARGE_INTEGER Timeout
)
146 PQUEUEDMESSAGE Request
;
147 BOOLEAN Disconnected
;
149 KPROCESSOR_MODE PreviousMode
;
150 NTSTATUS Status
= STATUS_SUCCESS
;
152 PreviousMode
= ExGetPreviousMode();
154 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
155 "LpcMessage %x)\n", PortHandle
, LpcReply
, LpcMessage
);
157 if (PreviousMode
!= KernelMode
)
161 ProbeForWrite(LpcMessage
,
162 sizeof(PORT_MESSAGE
),
167 Status
= _SEH_GetExceptionCode();
171 if (!NT_SUCCESS(Status
))
177 Status
= ObReferenceObjectByHandle(PortHandle
,
183 if (!NT_SUCCESS(Status
))
185 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
188 if( Port
->State
== EPORT_DISCONNECTED
)
190 /* If the port is disconnected, force the timeout to be 0
191 * so we don't wait for new messages, because there won't be
192 * any, only try to remove any existing messages
198 else Disconnected
= FALSE
;
201 * Send the reply, only if port is connected
203 if (LpcReply
!= NULL
&& !Disconnected
)
205 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
209 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1,
212 if (!NT_SUCCESS(Status
))
214 ObDereferenceObject(Port
);
215 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
221 * Want for a message to be received
223 Status
= KeWaitForSingleObject(&Port
->Semaphore
,
228 if( Status
== STATUS_TIMEOUT
)
231 * if the port is disconnected, and there are no remaining messages,
232 * return STATUS_PORT_DISCONNECTED
234 ObDereferenceObject(Port
);
235 return(Disconnected
? STATUS_PORT_DISCONNECTED
: STATUS_TIMEOUT
);
238 if (!NT_SUCCESS(Status
))
240 if (STATUS_THREAD_IS_TERMINATING
!= Status
)
242 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
244 ObDereferenceObject(Port
);
249 * Dequeue the message
251 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
252 Request
= EiDequeueMessagePort(Port
);
253 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
255 if (Request
->Message
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
258 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
260 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)&Request
->Message
;
261 memcpy(&Header
, &Request
->Message
, sizeof(PORT_MESSAGE
));
262 Header
.u1
.s1
.DataLength
= CRequest
->ConnectDataLength
;
263 Header
.u1
.s1
.TotalLength
= Header
.u1
.s1
.DataLength
+ sizeof(PORT_MESSAGE
);
265 if (PreviousMode
!= KernelMode
)
269 ProbeForWrite((PVOID
)(LpcMessage
+ 1),
270 CRequest
->ConnectDataLength
,
273 RtlCopyMemory(LpcMessage
,
275 sizeof(PORT_MESSAGE
));
276 RtlCopyMemory((PVOID
)(LpcMessage
+ 1),
277 CRequest
->ConnectData
,
278 CRequest
->ConnectDataLength
);
282 Status
= _SEH_GetExceptionCode();
288 RtlCopyMemory(LpcMessage
,
290 sizeof(PORT_MESSAGE
));
291 RtlCopyMemory((PVOID
)(LpcMessage
+ 1),
292 CRequest
->ConnectData
,
293 CRequest
->ConnectDataLength
);
298 if (PreviousMode
!= KernelMode
)
302 ProbeForWrite(LpcMessage
,
303 Request
->Message
.u1
.s1
.TotalLength
,
306 RtlCopyMemory(LpcMessage
,
308 Request
->Message
.u1
.s1
.TotalLength
);
312 Status
= _SEH_GetExceptionCode();
318 RtlCopyMemory(LpcMessage
,
320 Request
->Message
.u1
.s1
.TotalLength
);
323 if (!NT_SUCCESS(Status
))
326 * Copying the message to the caller's buffer failed so
327 * undo what we did and return.
328 * FIXME: Also increment semaphore.
330 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
331 EiEnqueueMessageAtHeadPort(Port
, Request
);
332 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
333 ObDereferenceObject(Port
);
336 if (Request
->Message
.u2
.s2
.Type
== LPC_CONNECTION_REQUEST
)
338 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
339 EiEnqueueConnectMessagePort(Port
, Request
);
340 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
348 * Dereference the port
350 ObDereferenceObject(Port
);
351 return(STATUS_SUCCESS
);
355 /**********************************************************************
357 * NtReplyWaitReceivePort
360 * Can be used with waitable ports.
373 NtReplyWaitReceivePort (IN HANDLE PortHandle
,
375 IN PPORT_MESSAGE LpcReply
,
376 OUT PPORT_MESSAGE LpcMessage
)
378 return(NtReplyWaitReceivePortEx (PortHandle
,
385 /**********************************************************************
397 NtReplyWaitReplyPort (HANDLE PortHandle
,
398 PPORT_MESSAGE ReplyMessage
)
401 return(STATUS_NOT_IMPLEMENTED
);
409 LpcRequestWaitReplyPort (
411 IN PPORT_MESSAGE LpcMessageRequest
,
412 OUT PPORT_MESSAGE LpcMessageReply
416 return STATUS_NOT_IMPLEMENTED
;