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 PLPC_MESSAGE LpcReply
,
39 PQUEUEDMESSAGE MessageReply
;
46 MessageReply
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(QUEUEDMESSAGE
),
48 MessageReply
->Sender
= Sender
;
52 memcpy(&MessageReply
->Message
, LpcReply
, LpcReply
->MessageSize
);
55 MessageReply
->Message
.ClientId
.UniqueProcess
= PsGetCurrentProcessId();
56 MessageReply
->Message
.ClientId
.UniqueThread
= PsGetCurrentThreadId();
57 MessageReply
->Message
.MessageType
= 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 PLPC_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 PLPC_MESSAGE LpcReply
,
141 OUT PLPC_MESSAGE LpcMessage
,
142 IN PLARGE_INTEGER Timeout
)
147 PQUEUEDMESSAGE Request
;
148 BOOLEAN Disconnected
;
151 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
152 "LpcMessage %x)\n", PortHandle
, LpcReply
, LpcMessage
);
154 Status
= ObReferenceObjectByHandle(PortHandle
,
160 if (!NT_SUCCESS(Status
))
162 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
165 if( Port
->State
== EPORT_DISCONNECTED
)
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
175 else Disconnected
= FALSE
;
178 * Send the reply, only if port is connected
180 if (LpcReply
!= NULL
&& !Disconnected
)
182 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
186 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1,
189 if (!NT_SUCCESS(Status
))
191 ObDereferenceObject(Port
);
192 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
198 * Want for a message to be received
200 Status
= KeWaitForSingleObject(&Port
->Semaphore
,
205 if( Status
== STATUS_TIMEOUT
)
208 * if the port is disconnected, and there are no remaining messages,
209 * return STATUS_PORT_DISCONNECTED
211 ObDereferenceObject(Port
);
212 return(Disconnected
? STATUS_PORT_DISCONNECTED
: STATUS_TIMEOUT
);
215 if (!NT_SUCCESS(Status
))
217 if (STATUS_THREAD_IS_TERMINATING
!= Status
)
219 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
221 ObDereferenceObject(Port
);
226 * Dequeue the message
228 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
229 Request
= EiDequeueMessagePort(Port
);
230 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
232 if (Request
->Message
.MessageType
== LPC_CONNECTION_REQUEST
)
235 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
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
))
244 Status
= MmCopyToCaller((PVOID
)(LpcMessage
+ 1),
245 CRequest
->ConnectData
,
246 CRequest
->ConnectDataLength
);
251 Status
= MmCopyToCaller(LpcMessage
, &Request
->Message
,
252 Request
->Message
.MessageSize
);
254 if (!NT_SUCCESS(Status
))
257 * Copying the message to the caller's buffer failed so
258 * undo what we did and return.
259 * FIXME: Also increment semaphore.
261 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
262 EiEnqueueMessageAtHeadPort(Port
, Request
);
263 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
264 ObDereferenceObject(Port
);
267 if (Request
->Message
.MessageType
== LPC_CONNECTION_REQUEST
)
269 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
270 EiEnqueueConnectMessagePort(Port
, Request
);
271 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
279 * Dereference the port
281 ObDereferenceObject(Port
);
282 return(STATUS_SUCCESS
);
286 /**********************************************************************
288 * NtReplyWaitReceivePort
291 * Can be used with waitable ports.
304 NtReplyWaitReceivePort (IN HANDLE PortHandle
,
306 IN PLPC_MESSAGE LpcReply
,
307 OUT PLPC_MESSAGE LpcMessage
)
309 return(NtReplyWaitReceivePortEx (PortHandle
,
316 /**********************************************************************
328 NtReplyWaitReplyPort (HANDLE PortHandle
,
329 PLPC_MESSAGE ReplyMessage
)
332 return(STATUS_NOT_IMPLEMENTED
);
340 LpcRequestWaitReplyPort (
342 IN PLPC_MESSAGE LpcMessageRequest
,
343 OUT PLPC_MESSAGE LpcMessageReply
347 return STATUS_NOT_IMPLEMENTED
;