1 /* $Id: reply.c,v 1.22 2004/09/13 19:10:45 gvg Exp $
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)
12 /* INCLUDES ******************************************************************/
16 #include <internal/debug.h>
18 /* GLOBALS *******************************************************************/
20 #define TAG_LPC_MESSAGE TAG('L', 'P', 'C', 'M')
22 /* FUNCTIONS *****************************************************************/
24 /**********************************************************************
36 EiReplyOrRequestPort (IN PEPORT Port
,
37 IN PLPC_MESSAGE LpcReply
,
42 PQUEUEDMESSAGE MessageReply
;
49 MessageReply
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(QUEUEDMESSAGE
),
51 MessageReply
->Sender
= Sender
;
55 memcpy(&MessageReply
->Message
, LpcReply
, LpcReply
->MessageSize
);
58 MessageReply
->Message
.ClientId
.UniqueProcess
= PsGetCurrentProcessId();
59 MessageReply
->Message
.ClientId
.UniqueThread
= PsGetCurrentThreadId();
60 MessageReply
->Message
.MessageType
= MessageType
;
61 MessageReply
->Message
.MessageId
= InterlockedIncrement((LONG
*)&EiNextLpcMessageId
);
63 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
64 EiEnqueueMessagePort(Port
, MessageReply
);
65 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
67 return(STATUS_SUCCESS
);
71 /**********************************************************************
83 NtReplyPort (IN HANDLE PortHandle
,
84 IN PLPC_MESSAGE LpcReply
)
89 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle
, LpcReply
);
91 Status
= ObReferenceObjectByHandle(PortHandle
,
92 PORT_ALL_ACCESS
, /* AccessRequired */
97 if (!NT_SUCCESS(Status
))
99 DPRINT("NtReplyPort() = %x\n", Status
);
103 if (EPORT_DISCONNECTED
== Port
->State
)
105 ObDereferenceObject(Port
);
106 return STATUS_PORT_DISCONNECTED
;
109 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
113 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
115 ObDereferenceObject(Port
);
121 /**********************************************************************
123 * NtReplyWaitReceivePortEx
126 * Can be used with waitable ports.
127 * Present only in w2k+.
141 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
143 IN PLPC_MESSAGE LpcReply
,
144 OUT PLPC_MESSAGE LpcMessage
,
145 IN PLARGE_INTEGER Timeout
)
150 PQUEUEDMESSAGE Request
;
151 BOOLEAN Disconnected
;
154 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
155 "LpcMessage %x)\n", PortHandle
, LpcReply
, LpcMessage
);
157 Status
= ObReferenceObjectByHandle(PortHandle
,
163 if (!NT_SUCCESS(Status
))
165 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
168 if( Port
->State
== EPORT_DISCONNECTED
)
170 /* If the port is disconnected, force the timeout to be 0
171 * so we don't wait for new messages, because there won't be
172 * any, only try to remove any existing messages
178 else Disconnected
= FALSE
;
181 * Send the reply, only if port is connected
183 if (LpcReply
!= NULL
&& !Disconnected
)
185 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
189 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1,
192 if (!NT_SUCCESS(Status
))
194 ObDereferenceObject(Port
);
195 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
201 * Want for a message to be received
203 Status
= KeWaitForSingleObject(&Port
->Semaphore
,
208 if( Status
== STATUS_TIMEOUT
)
211 * if the port is disconnected, and there are no remaining messages,
212 * return STATUS_PORT_DISCONNECTED
214 ObDereferenceObject(Port
);
215 return(Disconnected
? STATUS_PORT_DISCONNECTED
: STATUS_TIMEOUT
);
218 if (!NT_SUCCESS(Status
))
220 if (STATUS_THREAD_IS_TERMINATING
!= Status
)
222 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
224 ObDereferenceObject(Port
);
229 * Dequeue the message
231 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
232 Request
= EiDequeueMessagePort(Port
);
233 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
235 if (Request
->Message
.MessageType
== LPC_CONNECTION_REQUEST
)
238 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
240 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)&Request
->Message
;
241 memcpy(&Header
, &Request
->Message
, sizeof(LPC_MESSAGE
));
242 Header
.DataSize
= CRequest
->ConnectDataLength
;
243 Header
.MessageSize
= Header
.DataSize
+ sizeof(LPC_MESSAGE
);
244 Status
= MmCopyToCaller(LpcMessage
, &Header
, sizeof(LPC_MESSAGE
));
245 if (NT_SUCCESS(Status
))
247 Status
= MmCopyToCaller((PVOID
)(LpcMessage
+ 1),
248 CRequest
->ConnectData
,
249 CRequest
->ConnectDataLength
);
254 Status
= MmCopyToCaller(LpcMessage
, &Request
->Message
,
255 Request
->Message
.MessageSize
);
257 if (!NT_SUCCESS(Status
))
260 * Copying the message to the caller's buffer failed so
261 * undo what we did and return.
262 * FIXME: Also increment semaphore.
264 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
265 EiEnqueueMessageAtHeadPort(Port
, Request
);
266 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
267 ObDereferenceObject(Port
);
270 if (Request
->Message
.MessageType
== LPC_CONNECTION_REQUEST
)
272 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
273 EiEnqueueConnectMessagePort(Port
, Request
);
274 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
282 * Dereference the port
284 ObDereferenceObject(Port
);
285 return(STATUS_SUCCESS
);
289 /**********************************************************************
291 * NtReplyWaitReceivePort
294 * Can be used with waitable ports.
307 NtReplyWaitReceivePort (IN HANDLE PortHandle
,
309 IN PLPC_MESSAGE LpcReply
,
310 OUT PLPC_MESSAGE LpcMessage
)
312 return(NtReplyWaitReceivePortEx (PortHandle
,
319 /**********************************************************************
331 NtReplyWaitReplyPort (HANDLE PortHandle
,
332 PLPC_MESSAGE ReplyMessage
)
335 return(STATUS_NOT_IMPLEMENTED
);
343 LpcRequestWaitReplyPort (
345 IN PLPC_MESSAGE LpcMessageRequest
,
346 OUT PLPC_MESSAGE LpcMessageReply
350 return STATUS_NOT_IMPLEMENTED
;