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);