1 /* $Id: reply.c,v 1.16 2003/07/10 20:42:53 royce 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 /**********************************************************************
44 EiReplyOrRequestPort (IN PEPORT Port
,
45 IN PLPC_MESSAGE LpcReply
,
50 PQUEUEDMESSAGE MessageReply
;
57 MessageReply
= ExAllocatePoolWithTag(NonPagedPool
, sizeof(QUEUEDMESSAGE
),
59 MessageReply
->Sender
= Sender
;
63 memcpy(&MessageReply
->Message
, LpcReply
, LpcReply
->MessageSize
);
66 MessageReply
->Message
.Cid
.UniqueProcess
= PsGetCurrentProcessId();
67 MessageReply
->Message
.Cid
.UniqueThread
= PsGetCurrentThreadId();
68 MessageReply
->Message
.MessageType
= MessageType
;
69 MessageReply
->Message
.MessageId
= InterlockedIncrement((LONG
*)&EiNextLpcMessageId
);
71 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
72 EiEnqueueMessagePort(Port
, MessageReply
);
73 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
75 return(STATUS_SUCCESS
);
79 /**********************************************************************
93 NtReplyPort (IN HANDLE PortHandle
,
94 IN PLPC_MESSAGE LpcReply
)
99 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle
, LpcReply
);
101 Status
= ObReferenceObjectByHandle(PortHandle
,
102 PORT_ALL_ACCESS
, /* AccessRequired */
107 if (!NT_SUCCESS(Status
))
109 DPRINT("NtReplyPort() = %x\n", Status
);
113 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
117 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1, FALSE
);
119 ObDereferenceObject(Port
);
125 /**********************************************************************
127 * NtReplyWaitReceivePortEx
130 * Can be used with waitable ports.
131 * Present only in w2k+.
147 NtReplyWaitReceivePortEx(IN HANDLE PortHandle
,
149 IN PLPC_MESSAGE LpcReply
,
150 OUT PLPC_MESSAGE LpcMessage
,
151 IN PLARGE_INTEGER Timeout
)
156 PQUEUEDMESSAGE Request
;
157 BOOLEAN Disconnected
;
160 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
161 "LpcMessage %x)\n", PortHandle
, LpcReply
, LpcMessage
);
163 Status
= ObReferenceObjectByHandle(PortHandle
,
169 if (!NT_SUCCESS(Status
))
171 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
174 if( Port
->State
== EPORT_DISCONNECTED
)
176 /* If the port is disconnected, force the timeout to be 0
177 * so we don't wait for new messages, because there won't be
178 * any, only try to remove any existing messages
184 else Disconnected
= FALSE
;
187 * Send the reply, only if port is connected
189 if (LpcReply
!= NULL
&& !Disconnected
)
191 Status
= EiReplyOrRequestPort(Port
->OtherPort
,
195 KeReleaseSemaphore(&Port
->OtherPort
->Semaphore
, IO_NO_INCREMENT
, 1,
198 if (!NT_SUCCESS(Status
))
200 ObDereferenceObject(Port
);
201 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
207 * Want for a message to be received
209 Status
= KeWaitForSingleObject(&Port
->Semaphore
,
214 if( Status
== STATUS_TIMEOUT
)
217 * if the port is disconnected, and there are no remaining messages,
218 * return STATUS_PORT_DISCONNECTED
220 ObDereferenceObject(Port
);
221 return(Disconnected
? STATUS_PORT_DISCONNECTED
: STATUS_TIMEOUT
);
224 if (!NT_SUCCESS(Status
))
226 if (STATUS_THREAD_IS_TERMINATING
!= Status
)
228 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status
);
230 ObDereferenceObject(Port
);
235 * Dequeue the message
237 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
238 Request
= EiDequeueMessagePort(Port
);
239 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
241 if (Request
->Message
.MessageType
== LPC_CONNECTION_REQUEST
)
244 PEPORT_CONNECT_REQUEST_MESSAGE CRequest
;
246 CRequest
= (PEPORT_CONNECT_REQUEST_MESSAGE
)&Request
->Message
;
247 memcpy(&Header
, &Request
->Message
, sizeof(LPC_MESSAGE
));
248 Header
.DataSize
= CRequest
->ConnectDataLength
;
249 Header
.MessageSize
= Header
.DataSize
+ sizeof(LPC_MESSAGE
);
250 Status
= MmCopyToCaller(LpcMessage
, &Header
, sizeof(LPC_MESSAGE
));
251 if (NT_SUCCESS(Status
))
253 Status
= MmCopyToCaller((PVOID
)(LpcMessage
+ 1),
254 CRequest
->ConnectData
,
255 CRequest
->ConnectDataLength
);
260 Status
= MmCopyToCaller(LpcMessage
, &Request
->Message
,
261 Request
->Message
.MessageSize
);
263 if (!NT_SUCCESS(Status
))
266 * Copying the message to the caller's buffer failed so
267 * undo what we did and return.
268 * FIXME: Also increment semaphore.
270 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
271 EiEnqueueMessageAtHeadPort(Port
, Request
);
272 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
273 ObDereferenceObject(Port
);
276 if (Request
->Message
.MessageType
== LPC_CONNECTION_REQUEST
)
278 KeAcquireSpinLock(&Port
->Lock
, &oldIrql
);
279 EiEnqueueConnectMessagePort(Port
, Request
);
280 KeReleaseSpinLock(&Port
->Lock
, oldIrql
);
288 * Dereference the port
290 ObDereferenceObject(Port
);
291 return(STATUS_SUCCESS
);
295 /**********************************************************************
297 * NtReplyWaitReceivePort
300 * Can be used with waitable ports.
315 NtReplyWaitReceivePort (IN HANDLE PortHandle
,
317 IN PLPC_MESSAGE LpcReply
,
318 OUT PLPC_MESSAGE LpcMessage
)
320 return(NtReplyWaitReceivePortEx (PortHandle
,
327 /**********************************************************************
341 NtReplyWaitReplyPort (HANDLE PortHandle
,
342 PLPC_MESSAGE ReplyMessage
)
345 return(STATUS_NOT_IMPLEMENTED
);