-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
+/*
+ * PROJECT: ReactOS Kernel
+ * LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/reply.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * PURPOSE: Local Procedure Call: Receive (Replies)
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#define NDEBUG
-#include <internal/debug.h>
-
-/* GLOBALS *******************************************************************/
-
-/* FUNCTIONS *****************************************************************/
-
-/**********************************************************************
- * NAME
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- */
-NTSTATUS STDCALL
-EiReplyOrRequestPort (IN PEPORT Port,
- IN PLPC_MESSAGE LpcReply,
- IN ULONG MessageType,
- IN PEPORT Sender)
+#include <debug.h>
+
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
+ IN ULONG MessageId,
+ IN ULONG CallbackId,
+ IN CLIENT_ID ClientId)
{
- KIRQL oldIrql;
- PQUEUEDMESSAGE MessageReply;
-
- if (Port == NULL)
- {
- KEBUGCHECK(0);
- }
-
- MessageReply = ExAllocatePoolWithTag(NonPagedPool, sizeof(QUEUEDMESSAGE),
- TAG_LPC_MESSAGE);
- MessageReply->Sender = Sender;
-
- if (LpcReply != NULL)
- {
- memcpy(&MessageReply->Message, LpcReply, LpcReply->MessageSize);
- }
-
- MessageReply->Message.ClientId.UniqueProcess = PsGetCurrentProcessId();
- MessageReply->Message.ClientId.UniqueThread = PsGetCurrentThreadId();
- MessageReply->Message.MessageType = MessageType;
- MessageReply->Message.MessageId = InterlockedIncrementUL(&LpcpNextMessageId);
-
- KeAcquireSpinLock(&Port->Lock, &oldIrql);
- EiEnqueueMessagePort(Port, MessageReply);
- KeReleaseSpinLock(&Port->Lock, oldIrql);
-
- return(STATUS_SUCCESS);
+ PLPCP_MESSAGE Message;
+ PLIST_ENTRY ListHead, NextEntry;
+
+ /* Check if the port we want is the connection port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
+ {
+ /* Use it */
+ Port = Port->ConnectionPort;
+ if (!Port) return;
+ }
+
+ /* Loop the list */
+ ListHead = &Port->LpcDataInfoChainHead;
+ NextEntry = ListHead->Flink;
+ while (ListHead != NextEntry)
+ {
+ /* Get the message */
+ Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
+
+ /* Make sure it matches */
+ if ((Message->Request.MessageId == MessageId) &&
+ (Message->Request.ClientId.UniqueThread == ClientId.UniqueThread) &&
+ (Message->Request.ClientId.UniqueProcess == ClientId.UniqueProcess))
+ {
+ /* Unlink and free it */
+ RemoveEntryList(&Message->Entry);
+ InitializeListHead(&Message->Entry);
+ LpcpFreeToPortZone(Message, 1);
+ break;
+ }
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+ }
}
+VOID
+NTAPI
+LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
+ IN PLPCP_MESSAGE Message,
+ IN ULONG LockHeld)
+{
+ PAGED_CODE();
-/**********************************************************************
- * NAME EXPORTED
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- */
-NTSTATUS STDCALL
-NtReplyPort (IN HANDLE PortHandle,
- IN PLPC_MESSAGE LpcReply)
+ /* Acquire the lock */
+ if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Check if the port we want is the connection port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
+ {
+ /* Use it */
+ Port = Port->ConnectionPort;
+ if (!Port)
+ {
+ /* Release the lock and return */
+ if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
+ return;
+ }
+ }
+
+ /* Link the message */
+ InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
+
+ /* Release the lock */
+ if (!LockHeld) KeReleaseGuardedMutex(&LpcpLock);
+}
+
+VOID
+NTAPI
+LpcpMoveMessage(IN PPORT_MESSAGE Destination,
+ IN PPORT_MESSAGE Origin,
+ IN PVOID Data,
+ IN ULONG MessageType,
+ IN PCLIENT_ID ClientId)
{
- NTSTATUS Status;
- PEPORT Port;
-
- DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle, LpcReply);
-
- Status = ObReferenceObjectByHandle(PortHandle,
- PORT_ALL_ACCESS, /* AccessRequired */
- LpcPortObjectType,
- UserMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NtReplyPort() = %x\n", Status);
- return(Status);
- }
-
- if (EPORT_DISCONNECTED == Port->State)
- {
- ObDereferenceObject(Port);
- return STATUS_PORT_DISCONNECTED;
- }
-
- Status = EiReplyOrRequestPort(Port->OtherPort,
- LpcReply,
- LPC_REPLY,
- Port);
- KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
-
- ObDereferenceObject(Port);
-
- return(Status);
+ /* Set the Message size */
+ LPCTRACE((LPC_REPLY_DEBUG | LPC_SEND_DEBUG),
+ "Destination/Origin: %p/%p. Data: %p. Length: %lx\n",
+ Destination,
+ Origin,
+ Data,
+ Origin->u1.Length);
+ Destination->u1.Length = Origin->u1.Length;
+
+ /* Set the Message Type */
+ Destination->u2.s2.Type = !MessageType ?
+ Origin->u2.s2.Type : MessageType & 0xFFFF;
+
+ /* Check if we have a Client ID */
+ if (ClientId)
+ {
+ /* Set the Client ID */
+ Destination->ClientId.UniqueProcess = ClientId->UniqueProcess;
+ Destination->ClientId.UniqueThread = ClientId->UniqueThread;
+ }
+ else
+ {
+ /* Otherwise, copy it */
+ Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess;
+ Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread;
+ }
+
+ /* Copy the MessageId and ClientViewSize */
+ Destination->MessageId = Origin->MessageId;
+ Destination->ClientViewSize = Origin->ClientViewSize;
+
+ /* Copy the Message Data */
+ RtlCopyMemory(Destination + 1,
+ Data,
+ ((Destination->u1.Length & 0xFFFF) + 3) &~3);
}
+/* PUBLIC FUNCTIONS **********************************************************/
-/**********************************************************************
- * NAME EXPORTED
- * NtReplyWaitReceivePortEx
- *
- * DESCRIPTION
- * Can be used with waitable ports.
- * Present only in w2k+.
- *
- * ARGUMENTS
- * PortHandle
- * PortId
- * LpcReply
- * LpcMessage
- * Timeout
- *
- * RETURN VALUE
- *
- * REVISIONS
+/*
+ * @unimplemented
*/
-NTSTATUS STDCALL
-NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
- OUT PULONG PortId,
- IN PLPC_MESSAGE LpcReply,
- OUT PLPC_MESSAGE LpcMessage,
- IN PLARGE_INTEGER Timeout)
+NTSTATUS
+NTAPI
+NtReplyPort(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE LpcReply)
{
- NTSTATUS Status;
- PEPORT Port;
- KIRQL oldIrql;
- PQUEUEDMESSAGE Request;
- BOOLEAN Disconnected;
- LARGE_INTEGER to;
-
- DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
- "LpcMessage %x)\n", PortHandle, LpcReply, LpcMessage);
-
- Status = ObReferenceObjectByHandle(PortHandle,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- UserMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
- return(Status);
- }
- if( Port->State == EPORT_DISCONNECTED )
- {
- /* If the port is disconnected, force the timeout to be 0
- * so we don't wait for new messages, because there won't be
- * any, only try to remove any existing messages
- */
- Disconnected = TRUE;
- to.QuadPart = 0;
- Timeout = &to;
- }
- else Disconnected = FALSE;
-
- /*
- * Send the reply, only if port is connected
- */
- if (LpcReply != NULL && !Disconnected)
- {
- Status = EiReplyOrRequestPort(Port->OtherPort,
- LpcReply,
- LPC_REPLY,
- Port);
- KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1,
- FALSE);
-
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(Port);
- DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
- return(Status);
- }
- }
-
- /*
- * Want for a message to be received
- */
- Status = KeWaitForSingleObject(&Port->Semaphore,
- UserRequest,
- UserMode,
- FALSE,
- Timeout);
- if( Status == STATUS_TIMEOUT )
- {
- /*
- * if the port is disconnected, and there are no remaining messages,
- * return STATUS_PORT_DISCONNECTED
- */
- ObDereferenceObject(Port);
- return(Disconnected ? STATUS_PORT_DISCONNECTED : STATUS_TIMEOUT);
- }
-
- if (!NT_SUCCESS(Status))
- {
- if (STATUS_THREAD_IS_TERMINATING != Status)
- {
- DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
- }
- ObDereferenceObject(Port);
- return(Status);
- }
-
- /*
- * Dequeue the message
- */
- KeAcquireSpinLock(&Port->Lock, &oldIrql);
- Request = EiDequeueMessagePort(Port);
- KeReleaseSpinLock(&Port->Lock, oldIrql);
-
- if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
- {
- LPC_MESSAGE Header;
- PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
-
- CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)&Request->Message;
- memcpy(&Header, &Request->Message, sizeof(LPC_MESSAGE));
- Header.DataSize = CRequest->ConnectDataLength;
- Header.MessageSize = Header.DataSize + sizeof(LPC_MESSAGE);
- Status = MmCopyToCaller(LpcMessage, &Header, sizeof(LPC_MESSAGE));
- if (NT_SUCCESS(Status))
- {
- Status = MmCopyToCaller((PVOID)(LpcMessage + 1),
- CRequest->ConnectData,
- CRequest->ConnectDataLength);
- }
- }
- else
- {
- Status = MmCopyToCaller(LpcMessage, &Request->Message,
- Request->Message.MessageSize);
- }
- if (!NT_SUCCESS(Status))
- {
- /*
- * Copying the message to the caller's buffer failed so
- * undo what we did and return.
- * FIXME: Also increment semaphore.
- */
- KeAcquireSpinLock(&Port->Lock, &oldIrql);
- EiEnqueueMessageAtHeadPort(Port, Request);
- KeReleaseSpinLock(&Port->Lock, oldIrql);
- ObDereferenceObject(Port);
- return(Status);
- }
- if (Request->Message.MessageType == LPC_CONNECTION_REQUEST)
- {
- KeAcquireSpinLock(&Port->Lock, &oldIrql);
- EiEnqueueConnectMessagePort(Port, Request);
- KeReleaseSpinLock(&Port->Lock, oldIrql);
- }
- else
- {
- ExFreePool(Request);
- }
-
- /*
- * Dereference the port
- */
- ObDereferenceObject(Port);
- return(STATUS_SUCCESS);
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
+ OUT PVOID *PortContext OPTIONAL,
+ IN PPORT_MESSAGE ReplyMessage OPTIONAL,
+ OUT PPORT_MESSAGE ReceiveMessage,
+ IN PLARGE_INTEGER Timeout OPTIONAL)
+{
+ PLPCP_PORT_OBJECT Port, ReceivePort, ConnectionPort = NULL;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
+ NTSTATUS Status;
+ PLPCP_MESSAGE Message;
+ PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
+ PLPCP_CONNECTION_MESSAGE ConnectMessage;
+ ULONG ConnectionInfoLength;
+ //PORT_MESSAGE CapturedReplyMessage;
+ LARGE_INTEGER CapturedTimeout;
+
+ PAGED_CODE();
+ LPCTRACE(LPC_REPLY_DEBUG,
+ "Handle: %lx. Messages: %p/%p. Context: %p\n",
+ PortHandle,
+ ReplyMessage,
+ ReceiveMessage,
+ PortContext);
+
+ if (KeGetPreviousMode() == UserMode)
+ {
+ _SEH2_TRY
+ {
+ if (ReplyMessage != NULL)
+ {
+ ProbeForRead(ReplyMessage, sizeof(PORT_MESSAGE), sizeof(ULONG));
+ /*RtlCopyMemory(&CapturedReplyMessage, ReplyMessage, sizeof(PORT_MESSAGE));
+ ReplyMessage = &CapturedReplyMessage;*/
+ }
+
+ if (Timeout != NULL)
+ {
+ ProbeForReadLargeInteger(Timeout);
+ RtlCopyMemory(&CapturedTimeout, Timeout, sizeof(LARGE_INTEGER));
+ Timeout = &CapturedTimeout;
+ }
+
+ if (PortContext != NULL)
+ ProbeForWritePointer(PortContext);
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ DPRINT1("SEH crash [1]\n");
+ DbgBreakPoint();
+ _SEH2_YIELD(return _SEH2_GetExceptionCode());
+ }
+ _SEH2_END;
+ }
+ else
+ {
+ /* If this is a system thread, then let it page out its stack */
+ if (Thread->SystemThread) WaitMode = UserMode;
+ }
+
+ /* Check if caller has a reply message */
+ if (ReplyMessage)
+ {
+ /* Validate its length */
+ if (((ULONG)ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
+ (ULONG)ReplyMessage->u1.s1.TotalLength)
+ {
+ /* Fail */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Make sure it has a valid ID */
+ if (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Get the Port object */
+ Status = ObReferenceObjectByHandle(PortHandle,
+ 0,
+ LpcPortObjectType,
+ PreviousMode,
+ (PVOID*)&Port,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Check if the caller has a reply message */
+ if (ReplyMessage)
+ {
+ /* Validate its length in respect to the port object */
+ if (((ULONG)ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
+ ((ULONG)ReplyMessage->u1.s1.TotalLength <=
+ (ULONG)ReplyMessage->u1.s1.DataLength))
+ {
+ /* Too large, fail */
+ ObDereferenceObject(Port);
+ return STATUS_PORT_MESSAGE_TOO_LONG;
+ }
+ }
+
+ /* Check if this is anything but a client port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CLIENT_PORT)
+ {
+ /* Check if this is the connection port */
+ if (Port->ConnectionPort == Port)
+ {
+ /* Use this port */
+ ConnectionPort = ReceivePort = Port;
+ ObReferenceObject(ConnectionPort);
+ }
+ else
+ {
+ /* Acquire the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Get the port */
+ ConnectionPort = ReceivePort = Port->ConnectionPort;
+ if (!ConnectionPort)
+ {
+ /* Fail */
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(Port);
+ return STATUS_PORT_DISCONNECTED;
+ }
+
+ /* Release lock and reference */
+ ObReferenceObject(ConnectionPort);
+ KeReleaseGuardedMutex(&LpcpLock);
+ }
+ }
+ else
+ {
+ /* Otherwise, use the port itself */
+ ReceivePort = Port;
+ }
+
+ /* Check if the caller gave a reply message */
+ if (ReplyMessage)
+ {
+ /* Get the ETHREAD corresponding to it */
+ Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
+ NULL,
+ &WakeupThread);
+ if (!NT_SUCCESS(Status))
+ {
+ /* No thread found, fail */
+ ObDereferenceObject(Port);
+ if (ConnectionPort) ObDereferenceObject(ConnectionPort);
+ return Status;
+ }
+
+ /* Allocate a message from the port zone */
+ Message = LpcpAllocateFromPortZone();
+ if (!Message)
+ {
+ /* Fail if we couldn't allocate a message */
+ if (ConnectionPort) ObDereferenceObject(ConnectionPort);
+ ObDereferenceObject(WakeupThread);
+ ObDereferenceObject(Port);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Keep the lock acquired */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Make sure this is the reply the thread is waiting for */
+ if ((WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId) ||
+ ((LpcpGetMessageFromThread(WakeupThread)) &&
+ (LpcpGetMessageType(&LpcpGetMessageFromThread(WakeupThread)->
+ Request) != LPC_REQUEST)))
+ {
+ /* It isn't, fail */
+ LpcpFreeToPortZone(Message, 3);
+ if (ConnectionPort) ObDereferenceObject(ConnectionPort);
+ ObDereferenceObject(WakeupThread);
+ ObDereferenceObject(Port);
+ return STATUS_REPLY_MESSAGE_MISMATCH;
+ }
-/**********************************************************************
- * NAME EXPORTED
- * NtReplyWaitReceivePort
- *
- * DESCRIPTION
- * Can be used with waitable ports.
- *
- * ARGUMENTS
- * PortHandle
- * PortId
- * LpcReply
- * LpcMessage
- *
- * RETURN VALUE
- *
- * REVISIONS
+ /* Copy the message */
+ LpcpMoveMessage(&Message->Request,
+ ReplyMessage,
+ ReplyMessage + 1,
+ LPC_REPLY,
+ NULL);
+
+ /* Reference the thread while we use it */
+ ObReferenceObject(WakeupThread);
+ Message->RepliedToThread = WakeupThread;
+
+ /* Set this as the reply message */
+ WakeupThread->LpcReplyMessageId = 0;
+ WakeupThread->LpcReplyMessage = (PVOID)Message;
+
+ /* Check if we have messages on the reply chain */
+ if (!(WakeupThread->LpcExitThreadCalled) &&
+ !(IsListEmpty(&WakeupThread->LpcReplyChain)))
+ {
+ /* Remove us from it and reinitialize it */
+ RemoveEntryList(&WakeupThread->LpcReplyChain);
+ InitializeListHead(&WakeupThread->LpcReplyChain);
+ }
+
+ /* Check if this is the message the thread had received */
+ if ((Thread->LpcReceivedMsgIdValid) &&
+ (Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
+ {
+ /* Clear this data */
+ Thread->LpcReceivedMessageId = 0;
+ Thread->LpcReceivedMsgIdValid = FALSE;
+ }
+
+ /* Free any data information */
+ LpcpFreeDataInfoMessage(Port,
+ ReplyMessage->MessageId,
+ ReplyMessage->CallbackId,
+ ReplyMessage->ClientId);
+
+ /* Release the lock and release the LPC semaphore to wake up waiters */
+ KeReleaseGuardedMutex(&LpcpLock);
+ LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
+
+ /* Now we can let go of the thread */
+ ObDereferenceObject(WakeupThread);
+ }
+
+ /* Now wait for someone to reply to us */
+ LpcpReceiveWait(ReceivePort->MsgQueue.Semaphore, WaitMode);
+ if (Status != STATUS_SUCCESS) goto Cleanup;
+
+ /* Wait done, get the LPC lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Check if we've received nothing */
+ if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
+ {
+ /* Check if this was a waitable port and wake it */
+ if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
+ {
+ /* Reset its event */
+ KeResetEvent(&ReceivePort->WaitEvent);
+ }
+
+ /* Release the lock and fail */
+ KeReleaseGuardedMutex(&LpcpLock);
+ if (ConnectionPort) ObDereferenceObject(ConnectionPort);
+ ObDereferenceObject(Port);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* Get the message on the queue */
+ Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->
+ MsgQueue.ReceiveHead),
+ LPCP_MESSAGE,
+ Entry);
+
+ /* Check if the queue is empty now */
+ if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
+ {
+ /* Check if this was a waitable port */
+ if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
+ {
+ /* Reset its event */
+ KeResetEvent(&ReceivePort->WaitEvent);
+ }
+ }
+
+ /* Re-initialize the message's list entry */
+ InitializeListHead(&Message->Entry);
+
+ /* Set this as the received message */
+ Thread->LpcReceivedMessageId = Message->Request.MessageId;
+ Thread->LpcReceivedMsgIdValid = TRUE;
+
+ _SEH2_TRY
+ {
+ /* Check if this was a connection request */
+ if (LpcpGetMessageType(&Message->Request) == LPC_CONNECTION_REQUEST)
+ {
+ /* Get the connection message */
+ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
+ LPCTRACE(LPC_REPLY_DEBUG,
+ "Request Messages: %p/%p\n",
+ Message,
+ ConnectMessage);
+
+ /* Get its length */
+ ConnectionInfoLength = Message->Request.u1.s1.DataLength -
+ sizeof(LPCP_CONNECTION_MESSAGE);
+
+ /* Return it as the receive message */
+ *ReceiveMessage = Message->Request;
+
+ /* Clear our stack variable so the message doesn't get freed */
+ Message = NULL;
+
+ /* Setup the receive message */
+ ReceiveMessage->u1.s1.TotalLength = (CSHORT)(sizeof(LPCP_MESSAGE) +
+ ConnectionInfoLength);
+ ReceiveMessage->u1.s1.DataLength = (CSHORT)ConnectionInfoLength;
+ RtlCopyMemory(ReceiveMessage + 1,
+ ConnectMessage + 1,
+ ConnectionInfoLength);
+
+ /* Clear the port context if the caller requested one */
+ if (PortContext) *PortContext = NULL;
+ }
+ else if (LpcpGetMessageType(&Message->Request) != LPC_REPLY)
+ {
+ /* Otherwise, this is a new message or event */
+ LPCTRACE(LPC_REPLY_DEBUG,
+ "Non-Reply Messages: %p/%p\n",
+ &Message->Request,
+ (&Message->Request) + 1);
+
+ /* Copy it */
+ LpcpMoveMessage(ReceiveMessage,
+ &Message->Request,
+ (&Message->Request) + 1,
+ 0,
+ NULL);
+
+ /* Return its context */
+ if (PortContext) *PortContext = Message->PortContext;
+
+ /* And check if it has data information */
+ if (Message->Request.u2.s2.DataInfoOffset)
+ {
+ /* It does, save it, and don't free the message below */
+ LpcpSaveDataInfoMessage(Port, Message, 1);
+ Message = NULL;
+ }
+ }
+ else
+ {
+ /* This is a reply message, should never happen! */
+ ASSERT(FALSE);
+ }
+ }
+ _SEH2_EXCEPT(ExSystemExceptionFilter())
+ {
+ DPRINT1("SEH crash [2]\n");
+ DbgBreakPoint();
+ Status = _SEH2_GetExceptionCode();
+ }
+ _SEH2_END;
+
+ /* Check if we have a message pointer here */
+ if (Message)
+ {
+ /* Free it and release the lock */
+ LpcpFreeToPortZone(Message, 3);
+ }
+ else
+ {
+ /* Just release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+ }
+
+Cleanup:
+ /* All done, dereference the port and return the status */
+ LPCTRACE(LPC_REPLY_DEBUG,
+ "Port: %p. Status: %p\n",
+ Port,
+ Status);
+ if (ConnectionPort) ObDereferenceObject(ConnectionPort);
+ ObDereferenceObject(Port);
+ return Status;
+}
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtReplyWaitReceivePort(IN HANDLE PortHandle,
+ OUT PVOID *PortContext OPTIONAL,
+ IN PPORT_MESSAGE ReplyMessage OPTIONAL,
+ OUT PPORT_MESSAGE ReceiveMessage)
+{
+ /* Call the newer API */
+ return NtReplyWaitReceivePortEx(PortHandle,
+ PortContext,
+ ReplyMessage,
+ ReceiveMessage,
+ NULL);
+}
+
+/*
+ * @unimplemented
*/
-NTSTATUS STDCALL
-NtReplyWaitReceivePort (IN HANDLE PortHandle,
- OUT PULONG PortId,
- IN PLPC_MESSAGE LpcReply,
- OUT PLPC_MESSAGE LpcMessage)
+NTSTATUS
+NTAPI
+NtReplyWaitReplyPort(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE ReplyMessage)
{
- return(NtReplyWaitReceivePortEx (PortHandle,
- PortId,
- LpcReply,
- LpcMessage,
- NULL));
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
-/**********************************************************************
- * NAME
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
+/*
+ * @unimplemented
*/
-NTSTATUS STDCALL
-NtReplyWaitReplyPort (HANDLE PortHandle,
- PLPC_MESSAGE ReplyMessage)
+NTSTATUS
+NTAPI
+NtReadRequestData(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE Message,
+ IN ULONG Index,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG Returnlength)
{
- UNIMPLEMENTED;
- return(STATUS_NOT_IMPLEMENTED);
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
/*
* @unimplemented
*/
NTSTATUS
-STDCALL
-LpcRequestWaitReplyPort (
- IN PEPORT Port,
- IN PLPC_MESSAGE LpcMessageRequest,
- OUT PLPC_MESSAGE LpcMessageReply
- )
+NTAPI
+NtWriteRequestData(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE Message,
+ IN ULONG Index,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG ReturnLength)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
/* EOF */