1 /* $Id: reply.c,v 1.20 2004/06/23 19:49:21 ion 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 ******************************************************************/
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>
22 #include <internal/debug.h>
24 /* GLOBALS *******************************************************************/
26 #define TAG_LPC_MESSAGE TAG('L', 'P', 'C', 'M')
28 /* FUNCTIONS *****************************************************************/
30 /**********************************************************************
42 EiReplyOrRequestPort (IN PEPORT Port
,
43 IN PLPC_MESSAGE LpcReply
,
48 PQUEUEDMESSAGE MessageReply
;
55 MessageReply
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(QUEUEDMESSAGE
),
57 MessageReply
->Sender
= Sender
;
61 memcpy(&MessageReply
->Message
, LpcReply
, LpcReply
->MessageSize
);
64 MessageReply
->Message
.ClientId
.UniqueProcess
= PsGetCurrentProcessId();
65 MessageReply
->Message
.ClientId
.UniqueThread
= PsGetCurrentThreadId();
66 MessageReply
->Message
.MessageType
= MessageType
;
67 MessageReply
->Message
.MessageId
= InterlockedIncrement((LONG
*)&EiNextLpcMessageId
);
69 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
70 EiEnqueueMessagePort(Port
, MessageReply
);
71 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
73 return(STATUS_SUCCESS
);
77 /**********************************************************************
89 NtReplyPort (IN HANDLE PortHandle
,
90 IN PLPC_MESSAGE LpcReply
)
95 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle
, LpcReply
);
97 Status
= ObReferenceObjectByHandle(PortHandle
,
98 PORT_ALL_ACCESS
, /* AccessRequired */
103 if (!NT_SUCCESS(Status
))
105 DPRINT("NtReplyPort() = %x\n", Status
);
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
;