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 /**********************************************************************
43 EiReplyOrRequestPort (IN PEPORT Port,
44 IN PLPC_MESSAGE LpcReply,
49 PQUEUEDMESSAGE MessageReply;
56 MessageReply = ExAllocatePoolWithTag(NonPagedPool, sizeof(QUEUEDMESSAGE),
58 MessageReply->Sender = Sender;
62 memcpy(&MessageReply->Message, LpcReply, LpcReply->MessageSize);
65 MessageReply->Message.Cid.UniqueProcess = PsGetCurrentProcessId();
66 MessageReply->Message.Cid.UniqueThread = PsGetCurrentThreadId();
67 MessageReply->Message.MessageType = MessageType;
68 MessageReply->Message.MessageId = InterlockedIncrement(&EiNextLpcMessageId);
70 KeAcquireSpinLock(&Port->Lock, &oldIrql);
71 EiEnqueueMessagePort(Port, MessageReply);
72 KeReleaseSpinLock(&Port->Lock, oldIrql);
74 return(STATUS_SUCCESS);
78 /**********************************************************************
91 NtReplyPort (IN HANDLE PortHandle,
92 IN PLPC_MESSAGE LpcReply)
97 DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle, LpcReply);
99 Status = ObReferenceObjectByHandle(PortHandle,
100 PORT_ALL_ACCESS, /* AccessRequired */
105 if (!NT_SUCCESS(Status))
107 DPRINT("NtReplyPort() = %x\n", Status);
111 Status = EiReplyOrRequestPort(Port->OtherPort,
115 KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
117 ObDereferenceObject(Port);
123 /**********************************************************************
125 * NtReplyWaitReceivePortEx
128 * Can be used with waitable ports.
129 * Present only in w2k+.
144 NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
146 IN PLPC_MESSAGE LpcReply,
147 OUT PLPC_MESSAGE LpcMessage,
148 IN PLARGE_INTEGER Timeout)
153 PQUEUEDMESSAGE Request;
154 BOOLEAN Disconnected;
157 DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
158 "LpcMessage %x)\n", PortHandle, LpcReply, LpcMessage);
160 Status = ObReferenceObjectByHandle(PortHandle,
166 if (!NT_SUCCESS(Status))
168 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
171 if( Port->State == EPORT_DISCONNECTED )
173 /* If the port is disconnected, force the timeout to be 0
174 * so we don't wait for new messages, because there won't be
175 * any, only try to remove any existing messages
181 else Disconnected = FALSE;
184 * Send the reply, only if port is connected
186 if (LpcReply != NULL && !Disconnected)
188 Status = EiReplyOrRequestPort(Port->OtherPort,
192 KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1,
195 if (!NT_SUCCESS(Status))
197 ObDereferenceObject(Port);
198 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
204 * Want for a message to be received
206 Status = KeWaitForSingleObject(&Port->Semaphore,
211 if( Status == STATUS_TIMEOUT )
214 * if the port is disconnected, and there are no remaining messages,
215 * return STATUS_PORT_DISCONNECTED
217 ObDereferenceObject(Port);
218 return(Disconnected ? STATUS_PORT_DISCONNECTED : STATUS_TIMEOUT);
221 if (!NT_SUCCESS(Status))
223 DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
224 ObDereferenceObject(Port);
229 * Dequeue the message
231 KeAcquireSpinLock(&Port->Lock, &oldIrql);
232 Request = EiDequeueMessagePort(Port);
234 if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
237 PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
239 CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)&Request->Message;
240 memcpy(&Header, &Request->Message, sizeof(LPC_MESSAGE));
241 Header.DataSize = CRequest->ConnectDataLength;
242 Header.MessageSize = Header.DataSize + sizeof(LPC_MESSAGE);
243 Status = MmCopyToCaller(LpcMessage, &Header, sizeof(LPC_MESSAGE));
244 if (!NT_SUCCESS(Status))
246 Status = MmCopyToCaller((PVOID)(LpcMessage + 1),
247 CRequest->ConnectData,
248 CRequest->ConnectDataLength);
253 Status = MmCopyToCaller(LpcMessage, &Request->Message,
254 Request->Message.MessageSize);
256 if (!NT_SUCCESS(Status))
259 * Copying the message to the caller's buffer failed so
260 * undo what we did and return.
261 * FIXME: Also increment semaphore.
263 EiEnqueueMessageAtHeadPort(Port, Request);
264 KeReleaseSpinLock(&Port->Lock, oldIrql);
265 ObDereferenceObject(Port);
268 if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
270 EiEnqueueConnectMessagePort(Port, Request);
271 KeReleaseSpinLock(&Port->Lock, oldIrql);
275 KeReleaseSpinLock(&Port->Lock, oldIrql);
280 * Dereference the port
282 ObDereferenceObject(Port);
283 return(STATUS_SUCCESS);
287 /**********************************************************************
289 * NtReplyWaitReceivePort
292 * Can be used with waitable ports.
306 NtReplyWaitReceivePort (IN HANDLE PortHandle,
308 IN PLPC_MESSAGE LpcReply,
309 OUT PLPC_MESSAGE LpcMessage)
311 return(NtReplyWaitReceivePortEx (PortHandle,
318 /**********************************************************************
331 NtReplyWaitReplyPort (HANDLE PortHandle,
332 PLPC_MESSAGE ReplyMessage)