- Yeah, this adds another regression on top of the new Ob stuff, but in the end it's for the better, as it removes more race conditions and buggy code.
- This whole week I've fixed about 45 bugs and removed a dozen race conditions, sorry for the 2-3 regressions, they will be fixed ASAP.
- DELETE MAKEFILE.AUTO BEFORE BUILDING THIS BUILD.
svn path=/trunk/; revision=25411
working on the \ntlpc directory. Leave this disabled unless you really know
what you're doing.
-->
-<property name="NTLPC" value="0" />
+<property name="NTLPC" value="1" />
</rbuild>
-#ifndef __INCLUDE_INTERNAL_PORT_H
-#define __INCLUDE_INTERNAL_PORT_H
-
-/* EPORT.Type */
-
-#define EPORT_TYPE_SERVER_RQST_PORT (0)
-#define EPORT_TYPE_SERVER_COMM_PORT (1)
-#define EPORT_TYPE_CLIENT_COMM_PORT (2)
-
-/* EPORT.State */
-
-#define EPORT_INACTIVE (0)
-#define EPORT_WAIT_FOR_CONNECT (1)
-#define EPORT_WAIT_FOR_ACCEPT (2)
-#define EPORT_WAIT_FOR_COMPLETE_SRV (3)
-#define EPORT_WAIT_FOR_COMPLETE_CLT (4)
-#define EPORT_CONNECTED_CLIENT (5)
-#define EPORT_CONNECTED_SERVER (6)
-#define EPORT_DISCONNECTED (7)
-
-extern POBJECT_TYPE LpcPortObjectType;
-extern ULONG LpcpNextMessageId;
-#ifndef NTLPC
-extern FAST_MUTEX LpcpLock;
+/*
+* PROJECT: ReactOS Kernel
+* LICENSE: GPL - See COPYING in the top level directory
+* FILE: ntoskrnl/include/lpc.h
+* PURPOSE: Internal header for the Local Procedure Call
+* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+*/
+
+//
+// Define this if you want debugging support
+//
+#define _LPC_DEBUG_ 0x01
+
+//
+// These define the Debug Masks Supported
+//
+#define LPC_CREATE_DEBUG 0x01
+#define LPC_CLOSE_DEBUG 0x02
+#define LPC_CONNECT_DEBUG 0x04
+#define LPC_LISTEN_DEBUG 0x08
+#define LPC_REPLY_DEBUG 0x10
+#define LPC_COMPLETE_DEBUG 0x20
+#define LPC_SEND_DEBUG 0x40
+
+//
+// Debug/Tracing support
+//
+#if _LPC_DEBUG_
+#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
+#define LPCTRACE(x, ...) \
+ { \
+ DbgPrintEx("%s [%.16s] - ", \
+ __FUNCTION__, \
+ PsGetCurrentProcess()->ImageFileName); \
+ DbgPrintEx(__VA_ARGS__); \
+ }
+#else
+#define LPCTRACE(x, ...) \
+ if (x & LpcpTraceLevel) \
+ { \
+ DbgPrint("%s [%.16s:%lx] - ", \
+ __FUNCTION__, \
+ PsGetCurrentProcess()->ImageFileName, \
+ PsGetCurrentThreadId()); \
+ DbgPrint(__VA_ARGS__); \
+ }
+#endif
#endif
-typedef struct _EPORT_LISTENER
-{
- HANDLE ListenerPid;
- LIST_ENTRY ListenerListEntry;
-} EPORT_LISTENER, *PEPORT_LISTENER;
-
-typedef struct _EPORT
-{
- KSPIN_LOCK Lock;
- KSEMAPHORE Semaphore;
- USHORT Type;
- USHORT State;
- struct _EPORT *RequestPort;
- struct _EPORT *OtherPort;
- ULONG QueueLength;
- LIST_ENTRY QueueListHead;
- ULONG ConnectQueueLength;
- LIST_ENTRY ConnectQueueListHead;
- ULONG MaxDataLength;
- ULONG MaxConnectInfoLength;
- ULONG MaxPoolUsage; /* size of NP zone */
-} EPORT, *PEPORT;
-
-typedef struct _EPORT_CONNECT_REQUEST_MESSAGE
-{
- PORT_MESSAGE MessageHeader;
- PEPROCESS ConnectingProcess;
- struct _SECTION_OBJECT* SendSectionObject;
- LARGE_INTEGER SendSectionOffset;
- ULONG SendViewSize;
- ULONG ConnectDataLength;
- UCHAR ConnectData[0];
-} EPORT_CONNECT_REQUEST_MESSAGE, *PEPORT_CONNECT_REQUEST_MESSAGE;
-
-typedef struct _EPORT_CONNECT_REPLY_MESSAGE
-{
- PORT_MESSAGE MessageHeader;
- PVOID SendServerViewBase;
- ULONG ReceiveClientViewSize;
- PVOID ReceiveClientViewBase;
- ULONG MaximumMessageSize;
- ULONG ConnectDataLength;
- UCHAR ConnectData[0];
-} EPORT_CONNECT_REPLY_MESSAGE, *PEPORT_CONNECT_REPLY_MESSAGE;
-
-typedef struct _QUEUEDMESSAGE
-{
- PEPORT Sender;
- LIST_ENTRY QueueListEntry;
- PORT_MESSAGE Message;
-} QUEUEDMESSAGE, *PQUEUEDMESSAGE;
-
-NTSTATUS
-NTAPI
-LpcSendTerminationPort(
- PEPORT Port,
- LARGE_INTEGER CreationTime
-);
-
-/* Code in ntoskrnl/lpc/close.c */
-
-VOID
+//
+// Internal Port Management
+//
+VOID
NTAPI
LpcpClosePort(
IN PEPROCESS Process OPTIONAL,
VOID
NTAPI
-LpcpDeletePort(IN PVOID ObjectBody);
+LpcpDeletePort(
+ IN PVOID ObjectBody
+);
-VOID
+NTSTATUS
NTAPI
-LpcExitThread(IN PETHREAD Thread);
-
-/* Code in ntoskrnl/lpc/queue.c */
+LpcpInitializePortQueue(
+ IN PLPCP_PORT_OBJECT Port
+);
VOID
NTAPI
-EiEnqueueConnectMessagePort(
- IN OUT PEPORT Port,
- IN PQUEUEDMESSAGE Message
+LpcpFreeToPortZone(
+ IN PLPCP_MESSAGE Message,
+ IN ULONG Flags
);
VOID
NTAPI
-EiEnqueueMessagePort(
- IN OUT PEPORT Port,
- IN PQUEUEDMESSAGE Message
+LpcpMoveMessage(
+ IN PPORT_MESSAGE Destination,
+ IN PPORT_MESSAGE Origin,
+ IN PVOID Data,
+ IN ULONG MessageType,
+ IN PCLIENT_ID ClientId
);
VOID
NTAPI
-EiEnqueueMessageAtHeadPort(
- IN OUT PEPORT Port,
- IN PQUEUEDMESSAGE Message
+LpcpSaveDataInfoMessage(
+ IN PLPCP_PORT_OBJECT Port,
+ IN PLPCP_MESSAGE Message
);
-PQUEUEDMESSAGE
-NTAPI
-EiDequeueConnectMessagePort(IN OUT PEPORT Port);
-
-PQUEUEDMESSAGE
-NTAPI
-EiDequeueMessagePort(IN OUT PEPORT Port);
-
-/* Code in ntoskrnl/lpc/port.c */
-
-NTSTATUS
+//
+// Module-external utlity functions
+//
+VOID
NTAPI
-LpcpInitializePort(
- IN OUT PEPORT Port,
- IN USHORT Type,
- IN PEPORT Parent OPTIONAL
+LpcExitThread(
+ IN PETHREAD Thread
);
+//
+// Initialization functions
+//
NTSTATUS
NTAPI
-LpcpInitSystem (VOID);
-
-/* Code in ntoskrnl/lpc/reply.c */
-
-NTSTATUS
-NTAPI
-EiReplyOrRequestPort(
- IN PEPORT Port,
- IN PPORT_MESSAGE LpcReply,
- IN ULONG MessageType,
- IN PEPORT Sender
+LpcpInitSystem(
+ VOID
);
-#endif /* __INCLUDE_INTERNAL_PORT_H */
+//
+// Global data inside the Process Manager
+//
+extern POBJECT_TYPE LpcPortObjectType;
+extern ULONG LpcpNextMessageId, LpcpNextCallbackId;
+extern KGUARDED_MUTEX LpcpLock;
+extern PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
+extern ULONG LpcpMaxMessageSize;
+extern ULONG LpcpTraceLevel;
+
+//
+// Inlined Functions
+//
+#include "lpc_x.h"
-/*
-* PROJECT: ReactOS Kernel
-* LICENSE: GPL - See COPYING in the top level directory
-* FILE: ntoskrnl/include/lpc_x.h
-* PURPOSE: Intenral Inlined Functions for Local Procedure Call
-* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
-*/
-
-//
-// Gets the message type, removing the kernel-mode flag
-//
-#define LpcpGetMessageType(x) \
- ((x)->u2.s2.Type &~ LPC_KERNELMODE_MESSAGE)
-
-//
-// Waits on an LPC semaphore for a receive operation
-//
-#define LpcpReceiveWait(s, w) \
-{ \
- LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \
- Status = KeWaitForSingleObject(s, \
- WrLpcReceive, \
- w, \
- FALSE, \
- NULL); \
- LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \
-}
-
-//
-// Waits on an LPC semaphore for a reply operation
-//
-#define LpcpReplyWait(s, w) \
-{ \
- LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \
- Status = KeWaitForSingleObject(s, \
- WrLpcReply, \
- w, \
- FALSE, \
- NULL); \
- LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \
- if (Status == STATUS_USER_APC) \
- { \
- /* We were preempted by an APC */ \
- if (KeReadStateSemaphore(s)) \
- { \
- /* It's still signaled, so wait on it */ \
- KeWaitForSingleObject(s, \
- Executive, \
- KernelMode, \
- FALSE, \
- NULL); \
- Status = STATUS_SUCCESS; \
- } \
- } \
-}
-
-//
-// Waits on an LPC semaphore for a connect operation
-//
-#define LpcpConnectWait(s, w) \
-{ \
- LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \
- Status = KeWaitForSingleObject(s, \
- Executive, \
- w, \
- FALSE, \
- NULL); \
- LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\
- if (Status == STATUS_USER_APC) \
- { \
- /* We were preempted by an APC */ \
- if (KeReadStateSemaphore(s)) \
- { \
- /* It's still signaled, so wait on it */ \
- KeWaitForSingleObject(s, \
- Executive, \
- KernelMode, \
- FALSE, \
- NULL); \
- Status = STATUS_SUCCESS; \
- } \
- } \
-}
-
-//
-// Releases an LPC Semaphore to complete a wait
-//
-#define LpcpCompleteWait(s) \
-{ \
- /* Release the semaphore */ \
- LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \
- KeReleaseSemaphore(s, 1, 1, FALSE); \
-}
-
-//
-// Allocates a new message
-//
-PLPCP_MESSAGE
-FORCEINLINE
-LpcpAllocateFromPortZone(VOID)
-{
- PLPCP_MESSAGE Message;
-
- /* Allocate a message from the port zone while holding the lock */
- KeAcquireGuardedMutex(&LpcpLock);
- Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);
- if (!Message)
- {
- /* Fail, and let caller cleanup */
- KeReleaseGuardedMutex(&LpcpLock);
- return NULL;
- }
-
- /* Initialize it */
- InitializeListHead(&Message->Entry);
- Message->RepliedToThread = NULL;
- Message->Request.u2.ZeroInit = 0;
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
- return Message;
-}
+/*\r
+* PROJECT: ReactOS Kernel\r
+* LICENSE: GPL - See COPYING in the top level directory\r
+* FILE: ntoskrnl/include/lpc_x.h\r
+* PURPOSE: Intenral Inlined Functions for Local Procedure Call\r
+* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)\r
+*/\r
+\r
+//\r
+// Gets the message type, removing the kernel-mode flag\r
+//\r
+#define LpcpGetMessageType(x) \\r
+ ((x)->u2.s2.Type &~ LPC_KERNELMODE_MESSAGE)\r
+\r
+//\r
+// Waits on an LPC semaphore for a receive operation\r
+//\r
+#define LpcpReceiveWait(s, w) \\r
+{ \\r
+ LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \\r
+ Status = KeWaitForSingleObject(s, \\r
+ WrLpcReceive, \\r
+ w, \\r
+ FALSE, \\r
+ NULL); \\r
+ LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \\r
+}\r
+\r
+//\r
+// Waits on an LPC semaphore for a reply operation\r
+//\r
+#define LpcpReplyWait(s, w) \\r
+{ \\r
+ LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \\r
+ Status = KeWaitForSingleObject(s, \\r
+ WrLpcReply, \\r
+ w, \\r
+ FALSE, \\r
+ NULL); \\r
+ LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \\r
+ if (Status == STATUS_USER_APC) \\r
+ { \\r
+ /* We were preempted by an APC */ \\r
+ if (KeReadStateSemaphore(s)) \\r
+ { \\r
+ /* It's still signaled, so wait on it */ \\r
+ KeWaitForSingleObject(s, \\r
+ Executive, \\r
+ KernelMode, \\r
+ FALSE, \\r
+ NULL); \\r
+ Status = STATUS_SUCCESS; \\r
+ } \\r
+ } \\r
+}\r
+\r
+//\r
+// Waits on an LPC semaphore for a connect operation\r
+//\r
+#define LpcpConnectWait(s, w) \\r
+{ \\r
+ LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \\r
+ Status = KeWaitForSingleObject(s, \\r
+ Executive, \\r
+ w, \\r
+ FALSE, \\r
+ NULL); \\r
+ LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\\r
+ if (Status == STATUS_USER_APC) \\r
+ { \\r
+ /* We were preempted by an APC */ \\r
+ if (KeReadStateSemaphore(s)) \\r
+ { \\r
+ /* It's still signaled, so wait on it */ \\r
+ KeWaitForSingleObject(s, \\r
+ Executive, \\r
+ KernelMode, \\r
+ FALSE, \\r
+ NULL); \\r
+ Status = STATUS_SUCCESS; \\r
+ } \\r
+ } \\r
+}\r
+\r
+//\r
+// Releases an LPC Semaphore to complete a wait\r
+//\r
+#define LpcpCompleteWait(s) \\r
+{ \\r
+ /* Release the semaphore */ \\r
+ LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \\r
+ KeReleaseSemaphore(s, 1, 1, FALSE); \\r
+}\r
+\r
+//\r
+// Allocates a new message\r
+//\r
+PLPCP_MESSAGE\r
+FORCEINLINE\r
+LpcpAllocateFromPortZone(VOID)\r
+{\r
+ PLPCP_MESSAGE Message;\r
+\r
+ /* Allocate a message from the port zone while holding the lock */\r
+ KeAcquireGuardedMutex(&LpcpLock);\r
+ Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);\r
+ if (!Message)\r
+ {\r
+ /* Fail, and let caller cleanup */\r
+ KeReleaseGuardedMutex(&LpcpLock);\r
+ return NULL;\r
+ }\r
+\r
+ /* Initialize it */\r
+ InitializeListHead(&Message->Entry);\r
+ Message->RepliedToThread = NULL;\r
+ Message->Request.u2.ZeroInit = 0;\r
+\r
+ /* Release the lock */\r
+ KeReleaseGuardedMutex(&LpcpLock);\r
+ return Message;\r
+}\r
-/* $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/close.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * PURPOSE: Local Procedure Call: Rundown, Cleanup, Deletion
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-/* FUNCTIONS *****************************************************************/
+/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
LpcExitThread(IN PETHREAD Thread)
{
+ PLPCP_MESSAGE Message;
+
+ /* Acquire the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
/* Make sure that the Reply Chain is empty */
if (!IsListEmpty(&Thread->LpcReplyChain))
{
Thread->LpcExitThreadCalled = TRUE;
Thread->LpcReplyMessageId = 0;
- /* FIXME: Reply to the LpcReplyMessage */
+ /* Check if there's a reply message */
+ Message = Thread->LpcReplyMessage;
+ if (Message)
+ {
+ /* FIXME: TODO */
+ KEBUGCHECK(0);
+ }
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
}
-/**********************************************************************
- * NAME
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- */
-VOID STDCALL
-LpcpClosePort (IN PEPROCESS Process OPTIONAL,
- IN PVOID ObjectBody,
- IN ACCESS_MASK GrantedAccess,
- IN ULONG HandleCount,
- IN ULONG SystemHandleCount)
+VOID
+NTAPI
+LpcpFreeToPortZone(IN PLPCP_MESSAGE Message,
+ IN ULONG Flags)
{
- PEPORT Port = (PEPORT)ObjectBody;
- PORT_MESSAGE Message;
+ PLPCP_CONNECTION_MESSAGE ConnectMessage;
+ PLPCP_PORT_OBJECT ClientPort = NULL;
+ PETHREAD Thread = NULL;
+ BOOLEAN LockHeld = Flags & 1;
+ PAGED_CODE();
+ LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. Flags: %lx\n", Message, Flags);
+
+ /* Acquire the lock if not already */
+ if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
- /* FIXME Race conditions here! */
+ /* Check if the queue list is empty */
+ if (!IsListEmpty(&Message->Entry))
+ {
+ /* Remove and re-initialize */
+ RemoveEntryList(&Message->Entry);
+ InitializeListHead(&Message->Entry);
+ }
- /*
- * If the client has just closed its handle then tell the server what
- * happened and disconnect this port.
- */
- if (!(HandleCount)&& (Port->State == EPORT_CONNECTED_CLIENT))
+ /* Check if we've already replied */
+ if (Message->RepliedToThread)
{
- DPRINT("Informing server\n");
- Message.u1.s1.TotalLength = sizeof(PORT_MESSAGE);
- Message.u1.s1.DataLength = 0;
- EiReplyOrRequestPort (Port->OtherPort,
- &Message,
- LPC_PORT_CLOSED,
- Port);
- Port->OtherPort->OtherPort = NULL;
- Port->OtherPort->State = EPORT_DISCONNECTED;
- KeReleaseSemaphore( &Port->OtherPort->Semaphore,
- IO_NO_INCREMENT,
- 1,
- FALSE );
- ObDereferenceObject (Port);
+ /* Set thread to dereference and clean up */
+ Thread = Message->RepliedToThread;
+ Message->RepliedToThread = NULL;
}
- /*
- * If the server has closed all of its handles then disconnect the port,
- * don't actually notify the client until it attempts an operation.
- */
- if (!(HandleCount)&& (Port->State == EPORT_CONNECTED_SERVER))
+ /* Check if this is a connection request */
+ if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
{
- DPRINT("Cleaning up server\n");
- Port->OtherPort->OtherPort = NULL;
- Port->OtherPort->State = EPORT_DISCONNECTED;
- ObDereferenceObject(Port->OtherPort);
- }
+ /* Get the connection message */
+ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
+
+ /* Clear the client port */
+ ClientPort = ConnectMessage->ClientPort;
+ if (ClientPort) ConnectMessage->ClientPort = NULL;
+ }
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Check if we had anything to dereference */
+ if (Thread) ObDereferenceObject(Thread);
+ if (ClientPort) ObDereferenceObject(ClientPort);
+
+ /* Free the entry */
+ ExFreeToPagedLookasideList(&LpcpMessagesLookaside, Message);
+
+ /* Reacquire the lock if needed */
+ if ((LockHeld) && !(Flags & 2)) KeAcquireGuardedMutex(&LpcpLock);
}
+VOID
+NTAPI
+LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port,
+ IN BOOLEAN Destroy)
+{
+ PLIST_ENTRY ListHead, NextEntry;
+ PETHREAD Thread;
+ PLPCP_MESSAGE Message;
+ PLPCP_CONNECTION_MESSAGE ConnectMessage;
+ LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
+
+ /* Hold the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
-/**********************************************************************
- * NAME
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- */
-VOID STDCALL
-LpcpDeletePort (PVOID ObjectBody)
+ /* Disconnect the port to which this port is connected */
+ if (Port->ConnectedPort) Port->ConnectedPort->ConnectedPort = NULL;
+
+ /* Check if this is a connection port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
+ {
+ /* Delete the name */
+ Port->Flags |= LPCP_NAME_DELETED;
+ }
+
+ /* Walk all the threads waiting and signal them */
+ ListHead = &Port->LpcReplyChainHead;
+ NextEntry = ListHead->Flink;
+ while (NextEntry != ListHead)
+ {
+ /* Get the Thread */
+ Thread = CONTAINING_RECORD(NextEntry, ETHREAD, LpcReplyChain);
+
+ /* Make sure we're not in exit */
+ if (Thread->LpcExitThreadCalled) break;
+
+ /* Move to the next entry */
+ NextEntry = NextEntry->Flink;
+
+ /* Remove and reinitialize the List */
+ RemoveEntryList(&Thread->LpcReplyChain);
+ InitializeListHead(&Thread->LpcReplyChain);
+
+ /* Check if someone is waiting */
+ if (!KeReadStateSemaphore(&Thread->LpcReplySemaphore))
+ {
+ /* Get the message and check if it's a connection request */
+ Message = Thread->LpcReplyMessage;
+ if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
+ {
+ /* Get the connection message */
+ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
+
+ /* Check if it had a section */
+ if (ConnectMessage->SectionToMap)
+ {
+ /* Dereference it */
+ ObDereferenceObject(ConnectMessage->SectionToMap);
+ }
+ }
+
+ /* Clear the reply message */
+ Thread->LpcReplyMessage = NULL;
+
+ /* And remove the message from the port zone */
+ LpcpFreeToPortZone(Message, TRUE);
+ }
+
+ /* Release the semaphore and reset message id count */
+ Thread->LpcReplyMessageId = 0;
+ LpcpCompleteWait(&Thread->LpcReplySemaphore);
+ }
+
+ /* Reinitialize the list head */
+ InitializeListHead(&Port->LpcReplyChainHead);
+
+ /* Loop queued messages */
+ ListHead = &Port->MsgQueue.ReceiveHead;
+ NextEntry = ListHead->Flink;
+ while (ListHead != NextEntry)
+ {
+ /* Get the message */
+ Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
+ NextEntry = NextEntry->Flink;
+
+ /* Free and reinitialize it's list head */
+ InitializeListHead(&Message->Entry);
+
+ /* Remove it from the port zone */
+ LpcpFreeToPortZone(Message, TRUE);
+ }
+
+ /* Reinitialize the message queue list head */
+ InitializeListHead(&Port->MsgQueue.ReceiveHead);
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Check if we have to free the port entirely */
+ if (Destroy)
+ {
+ /* Check if the semaphore exists */
+ if (Port->MsgQueue.Semaphore)
+ {
+ /* Use the semaphore to find the port queue and free it */
+ ExFreePool(CONTAINING_RECORD(Port->MsgQueue.Semaphore,
+ LPCP_NONPAGED_PORT_QUEUE,
+ Semaphore));
+ }
+ }
+}
+
+VOID
+NTAPI
+LpcpClosePort(IN PEPROCESS Process OPTIONAL,
+ IN PVOID Object,
+ IN ACCESS_MASK GrantedAccess,
+ IN ULONG ProcessHandleCount,
+ IN ULONG SystemHandleCount)
+{
+ PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object;
+ LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
+
+ /* Only Server-side Connection Ports need clean up*/
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
+ {
+ /* Check the handle count */
+ switch (SystemHandleCount)
+ {
+ /* No handles left */
+ case 0:
+
+ /* Destroy the port queue */
+ LpcpDestroyPortQueue(Port, TRUE);
+ break;
+
+ /* Last handle remaining */
+ case 1:
+
+ /* Reset the queue only */
+ LpcpDestroyPortQueue(Port, FALSE);
+
+ /* More handles remain, do nothing */
+ default:
+ break;
+ }
+ }
+}
+
+VOID
+NTAPI
+LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port)
{
- PLIST_ENTRY Entry;
- PQUEUEDMESSAGE Message;
-
- PEPORT Port = (PEPORT)ObjectBody;
-
- DPRINT("Deleting port %x\n", Port);
-
- /* Free all waiting messages */
- while (!IsListEmpty(&Port->QueueListHead))
- {
- Entry = RemoveHeadList(&Port->QueueListHead);
- Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry);
- ExFreePool(Message);
- }
-
- while (!IsListEmpty(&Port->ConnectQueueListHead))
- {
- Entry = RemoveHeadList(&Port->ConnectQueueListHead);
- Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry);
- ExFreePool(Message);
- }
+ /* Check if this is a client port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
+ {
+ /* Check if security is static */
+ if (!(Port->Flags & LPCP_SECURITY_DYNAMIC))
+ {
+ /* Check if we have a token */
+ if (Port->StaticSecurity.ClientToken)
+ {
+ /* Free security */
+ SeDeleteClientSecurity(&Port->StaticSecurity);
+ }
+ }
+ }
}
+VOID
+NTAPI
+LpcpDeletePort(IN PVOID ObjectBody)
+{
+ LARGE_INTEGER Timeout;
+ PETHREAD Thread;
+ PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody;
+ PLPCP_PORT_OBJECT ConnectionPort;
+ PLPCP_MESSAGE Message;
+ PLIST_ENTRY ListHead, NextEntry;
+ HANDLE Pid;
+ CLIENT_DIED_MSG ClientDiedMsg;
+ Timeout.QuadPart = -1000000;
+ PAGED_CODE();
+ LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
+
+ /* Check if this is a communication port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT)
+ {
+ /* Acquire the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Get the thread */
+ Thread = Port->ClientThread;
+ if (Thread)
+ {
+ /* Clear it */
+ Port->ClientThread = NULL;
+
+ /* Release the lock and dereference */
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(Thread);
+ }
+ else
+ {
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+ }
+ }
+
+ /* Check if this is a client-side port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
+ {
+ /* Setup the client died message */
+ ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg);
+ ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime);
+ ClientDiedMsg.h.u2.ZeroInit = LPC_PORT_CLOSED;
+ ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime;
+
+ /* Send it */
+ for (;;)
+ {
+ /* Send the message */
+ if (LpcRequestPort(Port,
+ &ClientDiedMsg.h) != STATUS_NO_MEMORY) break;
+
+ /* Wait until trying again */
+ KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
+ }
+ }
+
+ /* Destroy the port queue */
+ LpcpDestroyPortQueue(Port, TRUE);
+
+ /* Check if we had a client view */
+ if (Port->ClientSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
+ Port->ClientSectionBase);
+
+ /* Check for a server view */
+ if (Port->ServerSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
+ Port->ServerSectionBase);
+
+ /* Get the connection port */
+ ConnectionPort = Port->ConnectionPort;
+ if (ConnectionPort)
+ {
+ /* Get the PID */
+ Pid = PsGetCurrentProcessId();
+
+ /* Acquire the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Loop the data lists */
+ ListHead = &ConnectionPort->LpcDataInfoChainHead;
+ NextEntry = ListHead->Flink;
+ while (NextEntry != ListHead)
+ {
+ /* Get the message */
+ Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
+ NextEntry = NextEntry->Flink;
+
+ /* Check if the PID matches */
+ if (Message->Request.ClientId.UniqueProcess == Pid)
+ {
+ /* Remove it */
+ RemoveEntryList(&Message->Entry);
+ LpcpFreeToPortZone(Message, TRUE);
+ }
+ }
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Dereference the object unless it's the same port */
+ if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort);
+ }
+
+ /* Check if this is a connection port with a server process*/
+ if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) &&
+ (ConnectionPort->ServerProcess))
+ {
+ /* Dereference the server process */
+ ObDereferenceObject(ConnectionPort->ServerProcess);
+ ConnectionPort->ServerProcess = NULL;
+ }
+
+ /* Free client security */
+ LpcpFreePortClientSecurity(Port);
+ LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port);
+}
/* EOF */
-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/lpc/complete.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
- */
+/*
+* PROJECT: ReactOS Kernel
+* LICENSE: GPL - See COPYING in the top level directory
+* FILE: ntoskrnl/lpc/complete.c
+* PURPOSE: Local Procedure Call: Connection Completion
+* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
+*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-/* FUNCTIONS *****************************************************************/
-
-/***********************************************************************
- * NAME EXPORTED
- * NtCompleteConnectPort/1
- *
- * DESCRIPTION
- * Wake up the client thread that issued the NtConnectPort call
- * this server-side port was created for communicating with.
- * To be used in LPC servers processes on reply ports only.
- *
- * ARGUMENTS
- * hServerSideCommPort: a reply port handle returned by
- * NtAcceptConnectPort.
- *
- * RETURN VALUE
- * STATUS_SUCCESS or an error code from Ob.
+/* PRIVATE FUNCTIONS *********************************************************/
+
+VOID
+NTAPI
+LpcpPrepareToWakeClient(IN PETHREAD Thread)
+{
+ PAGED_CODE();
+
+ /* Make sure the thread isn't dying and it has a valid chain */
+ if (!(Thread->LpcExitThreadCalled) &&
+ !(IsListEmpty(&Thread->LpcReplyChain)))
+ {
+ /* Remove it from the list and reinitialize it */
+ RemoveEntryList(&Thread->LpcReplyChain);
+ InitializeListHead(&Thread->LpcReplyChain);
+ }
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
*/
-NTSTATUS STDCALL
-NtCompleteConnectPort (HANDLE hServerSideCommPort)
+NTSTATUS
+NTAPI
+NtAcceptConnectPort(OUT PHANDLE PortHandle,
+ IN PVOID PortContext OPTIONAL,
+ IN PPORT_MESSAGE ReplyMessage,
+ IN BOOLEAN AcceptConnection,
+ IN PPORT_VIEW ServerView,
+ IN PREMOTE_PORT_VIEW ClientView)
{
- NTSTATUS Status;
- PEPORT ReplyPort;
-
- DPRINT("NtCompleteConnectPort(hServerSideCommPort %x)\n", hServerSideCommPort);
-
- /*
- * Ask Ob to translate the port handle to EPORT
- */
- Status = ObReferenceObjectByHandle (hServerSideCommPort,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- UserMode,
- (PVOID*)&ReplyPort,
- NULL);
- if (!NT_SUCCESS(Status))
+ PLPCP_PORT_OBJECT ConnectionPort, ServerPort, ClientPort;
+ PVOID ClientSectionToMap = NULL;
+ HANDLE Handle;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ NTSTATUS Status;
+ ULONG ConnectionInfoLength;
+ PLPCP_MESSAGE Message;
+ PLPCP_CONNECTION_MESSAGE ConnectMessage;
+ PEPROCESS ClientProcess;
+ PETHREAD ClientThread;
+ LARGE_INTEGER SectionOffset;
+ PAGED_CODE();
+ LPCTRACE(LPC_COMPLETE_DEBUG,
+ "Context: %p. Message: %p. Accept: %lx. Views: %p/%p\n",
+ PortContext,
+ ReplyMessage,
+ AcceptConnection,
+ ClientView,
+ ServerView);
+
+ /* Validate the size of the server view */
+ if ((ServerView) && (ServerView->Length != sizeof(PORT_VIEW)))
{
- return (Status);
+ /* Invalid size */
+ return STATUS_INVALID_PARAMETER;
}
- /*
- * Verify EPORT type is a server-side reply port;
- * otherwise tell the caller the port handle is not
- * valid.
- */
- if (ReplyPort->Type != EPORT_TYPE_SERVER_COMM_PORT)
+
+ /* Validate the size of the client view */
+ if ((ClientView) && (ClientView->Length != sizeof(REMOTE_PORT_VIEW)))
+ {
+ /* Invalid size */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Get the client process and thread */
+ Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
+ &ClientProcess,
+ &ClientThread);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Acquire the LPC Lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Make sure that the client wants a reply, and this is the right one */
+ if (!(ClientThread->LpcReplyMessage) ||
+ !(ReplyMessage->MessageId) ||
+ (ClientThread->LpcReplyMessageId != ReplyMessage->MessageId))
{
- ObDereferenceObject (ReplyPort);
- return STATUS_INVALID_PORT_HANDLE;
+ /* Not the reply asked for, or no reply wanted, fail */
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(ClientProcess);
+ ObDereferenceObject(ClientThread);
+ return STATUS_REPLY_MESSAGE_MISMATCH;
}
- ReplyPort->State = EPORT_CONNECTED_SERVER;
- /*
- * Wake up the client thread that issued NtConnectPort.
- */
- KeReleaseSemaphore(&ReplyPort->OtherPort->Semaphore, IO_NO_INCREMENT, 1,
- FALSE);
- /*
- * Tell Ob we are no more interested in ReplyPort
- */
- ObDereferenceObject (ReplyPort);
-
- return (STATUS_SUCCESS);
+ /* Now get the message and connection message */
+ Message = ClientThread->LpcReplyMessage;
+ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
+
+ /* Get the client and connection port as well */
+ ClientPort = ConnectMessage->ClientPort;
+ ConnectionPort = ClientPort->ConnectionPort;
+
+ /* Make sure that the reply is being sent to the proper server process */
+ if (ConnectionPort->ServerProcess != PsGetCurrentProcess())
+ {
+ /* It's not, so fail */
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(ClientProcess);
+ ObDereferenceObject(ClientThread);
+ return STATUS_REPLY_MESSAGE_MISMATCH;
+ }
+
+ /* At this point, don't let other accept attempts happen */
+ ClientThread->LpcReplyMessage = NULL;
+ ClientThread->LpcReplyMessageId = 0;
+
+ /* Clear the client port for now as well, then release the lock */
+ ConnectMessage->ClientPort = NULL;
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Get the connection information length */
+ ConnectionInfoLength = ReplyMessage->u1.s1.DataLength;
+ if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength)
+ {
+ /* Normalize it since it's too large */
+ ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength;
+ }
+
+ /* Set the sizes of our reply message */
+ Message->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
+ ConnectionInfoLength;
+ Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
+ Message->Request.u1.s1.DataLength;
+
+ /* Setup the reply message */
+ Message->Request.u2.s2.Type = LPC_REPLY;
+ Message->Request.u2.s2.DataInfoOffset = 0;
+ Message->Request.ClientId = ReplyMessage->ClientId;
+ Message->Request.MessageId = ReplyMessage->MessageId;
+ Message->Request.ClientViewSize = 0;
+ RtlMoveMemory(ConnectMessage + 1, ReplyMessage + 1, ConnectionInfoLength);
+
+ /* At this point, if the caller refused the connection, go to cleanup */
+ if (!AcceptConnection) goto Cleanup;
+
+ /* Otherwise, create the actual port */
+ Status = ObCreateObject(PreviousMode,
+ LpcPortObjectType,
+ NULL,
+ PreviousMode,
+ NULL,
+ sizeof(LPCP_PORT_OBJECT),
+ 0,
+ 0,
+ (PVOID*)&ServerPort);
+ if (!NT_SUCCESS(Status)) goto Cleanup;
+
+ /* Set it up */
+ RtlZeroMemory(ServerPort, sizeof(LPCP_PORT_OBJECT));
+ ServerPort->PortContext = PortContext;
+ ServerPort->Flags = LPCP_COMMUNICATION_PORT;
+ ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength;
+ InitializeListHead(&ServerPort->LpcReplyChainHead);
+ InitializeListHead(&ServerPort->LpcDataInfoChainHead);
+
+ /* Reference the connection port until we're fully setup */
+ ObReferenceObject(ConnectionPort);
+
+ /* Link the ports together */
+ ServerPort->ConnectionPort = ConnectionPort;
+ ServerPort->ConnectedPort = ClientPort;
+ ClientPort->ConnectedPort = ServerPort;
+
+ /* Also set the creator CID */
+ ServerPort->Creator = PsGetCurrentThread()->Cid;
+ ClientPort->Creator = Message->Request.ClientId;
+
+ /* Get the section associated and then clear it, while inside the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+ ClientSectionToMap = ConnectMessage->SectionToMap;
+ ConnectMessage->SectionToMap = NULL;
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Now check if there's a client section */
+ if (ClientSectionToMap)
+ {
+ /* Setup the offset */
+ SectionOffset.QuadPart = ConnectMessage->ClientView.SectionOffset;
+
+ /* Map the section */
+ Status = MmMapViewOfSection(ClientSectionToMap,
+ PsGetCurrentProcess(),
+ &ServerPort->ClientSectionBase,
+ 0,
+ 0,
+ &SectionOffset,
+ &ConnectMessage->ClientView.ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
+
+ /* Update the offset and check for mapping status */
+ ConnectMessage->ClientView.SectionOffset = SectionOffset.LowPart;
+ if (NT_SUCCESS(Status))
+ {
+ /* Set the view base */
+ ConnectMessage->ClientView.ViewRemoteBase = ServerPort->
+ ClientSectionBase;
+ }
+ else
+ {
+ /* Otherwise, quit */
+ ObDereferenceObject(ServerPort);
+ goto Cleanup;
+ }
+ }
+
+ /* Check if there's a server section */
+ if (ServerView)
+ {
+ /* FIXME: TODO */
+ ASSERT(FALSE);
+ }
+
+ /* Reference the server port until it's fully inserted */
+ ObReferenceObject(ServerPort);
+
+ /* Insert the server port in the namespace */
+ Status = ObInsertObject(ServerPort,
+ NULL,
+ PORT_ALL_ACCESS,
+ 0,
+ NULL,
+ &Handle);
+ if (!NT_SUCCESS(Status))
+ {
+ /* We failed, remove the extra reference and cleanup */
+ ObDereferenceObject(ServerPort);
+ goto Cleanup;
+ }
+
+ /* Check if the caller gave a client view */
+ if (ClientView)
+ {
+ /* Fill it out */
+ ClientView->ViewBase = ConnectMessage->ClientView.ViewRemoteBase;
+ ClientView->ViewSize = ConnectMessage->ClientView.ViewSize;
+ }
+
+ /* Return the handle to user mode */
+ *PortHandle = Handle;
+ LPCTRACE(LPC_COMPLETE_DEBUG,
+ "Handle: %lx. Messages: %p/%p. Ports: %p/%p/%p\n",
+ Handle,
+ Message,
+ ConnectMessage,
+ ServerPort,
+ ClientPort,
+ ConnectionPort);
+
+ /* If there was no port context, use the handle by default */
+ if (!PortContext) ServerPort->PortContext = Handle;
+ ServerPort->ClientThread = ClientThread;
+
+ /* Set this message as the LPC Reply message while holding the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+ ClientThread->LpcReplyMessage = Message;
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Clear the thread pointer so it doesn't get cleaned later */
+ ClientThread = NULL;
+
+ /* Remove the extra reference we had added */
+ ObDereferenceObject(ServerPort);
+
+Cleanup:
+ /* If there was a section, dereference it */
+ if (ClientSectionToMap) ObDereferenceObject(ClientSectionToMap);
+
+ /* Check if we got here while still having a client thread */
+ if (ClientThread)
+ {
+ /* FIXME: Complex cleanup code */
+ ASSERT(FALSE);
+ }
+
+ /* Dereference the client port if we have one, and the process */
+ LPCTRACE(LPC_COMPLETE_DEBUG,
+ "Status: %lx. Thread: %p. Process: [%.16s]\n",
+ Status,
+ ClientThread,
+ ClientProcess->ImageFileName);
+ if (ClientPort) ObDereferenceObject(ClientPort);
+ ObDereferenceObject(ClientProcess);
+ return Status;
}
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtCompleteConnectPort(IN HANDLE PortHandle)
+{
+ NTSTATUS Status;
+ PLPCP_PORT_OBJECT Port;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ PETHREAD Thread;
+ PAGED_CODE();
+ LPCTRACE(LPC_COMPLETE_DEBUG, "Handle: %lx\n", PortHandle);
+
+ /* Get the Port Object */
+ Status = ObReferenceObjectByHandle(PortHandle,
+ PORT_ALL_ACCESS,
+ LpcPortObjectType,
+ PreviousMode,
+ (PVOID*)&Port,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Make sure this is a connection port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
+ {
+ /* It isn't, fail */
+ ObDereferenceObject(Port);
+ return STATUS_INVALID_PORT_HANDLE;
+ }
+
+ /* Acquire the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Make sure we have a client thread */
+ if (!Port->ClientThread)
+ {
+ /* We don't, fail */
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(Port);
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Get the thread */
+ Thread = Port->ClientThread;
+
+ /* Make sure it has a reply message */
+ if (!Thread->LpcReplyMessage)
+ {
+ /* It doesn't, fail */
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(Port);
+ return STATUS_PORT_DISCONNECTED;
+ }
+
+ /* Clear the client thread and wake it up */
+ Port->ClientThread = NULL;
+ LpcpPrepareToWakeClient(Thread);
+
+ /* Release the lock and wait for an answer */
+ KeReleaseGuardedMutex(&LpcpLock);
+ LpcpCompleteWait(&Thread->LpcReplySemaphore);
+
+ /* Dereference the Thread and Port and return */
+ ObDereferenceObject(Port);
+ ObDereferenceObject(Thread);
+ LPCTRACE(LPC_COMPLETE_DEBUG, "Port: %p. Thread: %p\n", Port, Thread);
+ return Status;
+}
/* EOF */
-/* $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/connect.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * PURPOSE: Local Procedure Call: Connection Management
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-/* FUNCTIONS *****************************************************************/
-
-/**********************************************************************
- * NAME EXPORTED
- * EiConnectPort/12
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- */
-NTSTATUS STDCALL
-EiConnectPort(IN PEPORT* ConnectedPort,
- IN PEPORT NamedPort,
- IN PVOID Section,
- IN LARGE_INTEGER SectionOffset,
- IN ULONG ViewSize,
- OUT PVOID* ClientSendViewBase,
- OUT PVOID* ServerSendViewBase,
- OUT PULONG ReceiveViewSize,
- OUT PVOID* ReceiveViewBase,
- OUT PULONG MaximumMessageSize,
- IN OUT PVOID ConnectData,
- IN OUT PULONG ConnectDataLength)
+/* PRIVATE FUNCTIONS *********************************************************/
+
+PVOID
+NTAPI
+LpcpFreeConMsg(IN OUT PLPCP_MESSAGE *Message,
+ IN OUT PLPCP_CONNECTION_MESSAGE *ConnectMessage,
+ IN PETHREAD CurrentThread)
{
- PEPORT_CONNECT_REQUEST_MESSAGE RequestMessage;
- ULONG RequestConnectDataLength;
- PEPORT OurPort;
- PQUEUEDMESSAGE Reply;
- PEPORT_CONNECT_REPLY_MESSAGE CReply;
- NTSTATUS Status;
- KIRQL oldIrql;
-
- if (ConnectDataLength == NULL)
- {
- RequestConnectDataLength = 0;
- }
- else
- {
- RequestConnectDataLength = *ConnectDataLength;
- }
+ PVOID SectionToMap;
- /*
- * Create a port to represent our side of the connection
- */
- Status = ObCreateObject (KernelMode,
- LpcPortObjectType,
- NULL,
- KernelMode,
- NULL,
- sizeof(EPORT),
- 0,
- 0,
- (PVOID*)&OurPort);
- if (!NT_SUCCESS(Status))
- {
- return (Status);
- }
- LpcpInitializePort(OurPort, EPORT_TYPE_CLIENT_COMM_PORT, NamedPort);
-
- /*
- * Allocate a request message.
- */
- RequestMessage = ExAllocatePool(NonPagedPool,
- sizeof(EPORT_CONNECT_REQUEST_MESSAGE) +
- RequestConnectDataLength);
- if (RequestMessage == NULL)
- {
- ObDereferenceObject(OurPort);
- return(STATUS_NO_MEMORY);
- }
+ /* Acquire the LPC lock */
+ KeAcquireGuardedMutex(&LpcpLock);
- /*
- * Initialize the request message.
- */
- RequestMessage->MessageHeader.u1.s1.DataLength =
- sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength -
- sizeof(PORT_MESSAGE);
- RequestMessage->MessageHeader.u1.s1.TotalLength =
- sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + RequestConnectDataLength;
- DPRINT("RequestMessageSize %d\n",
- RequestMessage->MessageHeader.u1.s1.TotalLength);
- RequestMessage->MessageHeader.ClientViewSize = 0;
- RequestMessage->ConnectingProcess = PsGetCurrentProcess();
- ObReferenceObjectByPointer(RequestMessage->ConnectingProcess,
- PROCESS_VM_OPERATION,
- NULL,
- KernelMode);
- RequestMessage->SendSectionObject = (struct _SECTION_OBJECT*)Section;
- RequestMessage->SendSectionOffset = SectionOffset;
- RequestMessage->SendViewSize = ViewSize;
- RequestMessage->ConnectDataLength = RequestConnectDataLength;
- if (RequestConnectDataLength > 0)
+ /* Check if the reply chain is not empty */
+ if (!IsListEmpty(&CurrentThread->LpcReplyChain))
{
- memcpy(RequestMessage->ConnectData, ConnectData,
- RequestConnectDataLength);
+ /* Remove this entry and re-initialize it */
+ RemoveEntryList(&CurrentThread->LpcReplyChain);
+ InitializeListHead(&CurrentThread->LpcReplyChain);
}
- /*
- * Queue the message to the named port
- */
- EiReplyOrRequestPort(NamedPort,
- &RequestMessage->MessageHeader,
- LPC_CONNECTION_REQUEST,
- OurPort);
- KeReleaseSemaphore(&NamedPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
- ExFreePool(RequestMessage);
-
- /*
- * Wait for them to accept our connection
- */
- KeWaitForSingleObject(&OurPort->Semaphore,
- UserRequest,
- UserMode,
- FALSE,
- NULL);
-
- /*
- * Dequeue the response
- */
- KeAcquireSpinLock (&OurPort->Lock, &oldIrql);
- Reply = EiDequeueMessagePort (OurPort);
- KeReleaseSpinLock (&OurPort->Lock, oldIrql);
- CReply = (PEPORT_CONNECT_REPLY_MESSAGE)&Reply->Message;
-
- /*
- * Do some initial cleanup.
- */
- ObDereferenceObject(PsGetCurrentProcess());
-
- /*
- * Check for connection refusal.
- */
- if (CReply->MessageHeader.u2.s2.Type == LPC_CONNECTION_REFUSED)
+ /* Check if there's a reply message */
+ if (CurrentThread->LpcReplyMessage)
{
- ObDereferenceObject(OurPort);
- ExFreePool(Reply);
- /*
- * FIXME: Check what NT does here. Giving the user data back on
- * connect failure sounds reasonable; it probably wouldn't break
- * anything anyway.
- */
- if (ConnectDataLength != NULL)
- {
- *ConnectDataLength = CReply->ConnectDataLength;
- memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
- }
- return(STATUS_PORT_CONNECTION_REFUSED);
- }
+ /* Get the message */
+ *Message = CurrentThread->LpcReplyMessage;
- /*
- * Otherwise we are connected. Copy data back to the client.
- */
- *ServerSendViewBase = CReply->SendServerViewBase;
- *ReceiveViewSize = CReply->ReceiveClientViewSize;
- *ReceiveViewBase = CReply->ReceiveClientViewBase;
- *MaximumMessageSize = CReply->MaximumMessageSize;
- if (ConnectDataLength != NULL)
- {
- *ConnectDataLength = CReply->ConnectDataLength;
- memcpy(ConnectData, CReply->ConnectData, CReply->ConnectDataLength);
- }
+ /* Clear message data */
+ CurrentThread->LpcReceivedMessageId = 0;
+ CurrentThread->LpcReplyMessage = NULL;
- /*
- * Create our view of the send section object.
- */
- if (Section != NULL)
+ /* Get the connection message and clear the section */
+ *ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(*Message + 1);
+ SectionToMap = (*ConnectMessage)->SectionToMap;
+ (*ConnectMessage)->SectionToMap = NULL;
+ }
+ else
{
- *ClientSendViewBase = 0;
- Status = MmMapViewOfSection(Section,
- PsGetCurrentProcess(),
- ClientSendViewBase,
- 0,
- ViewSize,
- &SectionOffset,
- &ViewSize,
- ViewUnmap,
- 0 /* MEM_TOP_DOWN? */,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- /* FIXME: Cleanup here. */
- return(Status);
- }
+ /* No message to return */
+ *Message = NULL;
+ SectionToMap = NULL;
}
- /*
- * Do the final initialization of our port.
- */
- OurPort->State = EPORT_CONNECTED_CLIENT;
-
- /*
- * Cleanup.
- */
- ExFreePool(Reply);
- *ConnectedPort = OurPort;
- return(STATUS_SUCCESS);
+ /* Release the lock and return the section */
+ KeReleaseGuardedMutex(&LpcpLock);
+ return SectionToMap;
}
-/**********************************************************************
- * NAME EXPORTED
- * NtConnectPort/8
- *
- * DESCRIPTION
- * Connect to a named port and wait for the other side to
- * accept or reject the connection request.
- *
- * ARGUMENTS
- * ConnectedPort
- * PortName
- * Qos
- * WriteMap
- * ReadMap
- * MaxMessageSize
- * ConnectInfo
- * UserConnectInfoLength
- *
- * RETURN VALUE
- *
- * @unimplemented
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
*/
-NTSTATUS STDCALL
-NtConnectPort (PHANDLE UnsafeConnectedPortHandle,
- PUNICODE_STRING PortName,
- PSECURITY_QUALITY_OF_SERVICE Qos,
- PPORT_VIEW UnsafeWriteMap,
- PREMOTE_PORT_VIEW UnsafeReadMap,
- PULONG UnsafeMaximumMessageSize,
- PVOID UnsafeConnectData,
- PULONG UnsafeConnectDataLength)
+NTSTATUS
+NTAPI
+NtSecureConnectPort(OUT PHANDLE PortHandle,
+ IN PUNICODE_STRING PortName,
+ IN PSECURITY_QUALITY_OF_SERVICE Qos,
+ IN OUT PPORT_VIEW ClientView OPTIONAL,
+ IN PSID ServerSid OPTIONAL,
+ IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
+ OUT PULONG MaxMessageLength OPTIONAL,
+ IN OUT PVOID ConnectionInformation OPTIONAL,
+ IN OUT PULONG ConnectionInformationLength OPTIONAL)
{
- HANDLE ConnectedPortHandle;
- PORT_VIEW WriteMap;
- REMOTE_PORT_VIEW ReadMap;
- ULONG MaximumMessageSize;
- PVOID ConnectData = NULL;
- ULONG ConnectDataLength = 0;
- PVOID SectionObject;
- LARGE_INTEGER SectionOffset;
- PEPORT ConnectedPort;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
- PEPORT NamedPort;
-
- PreviousMode = ExGetPreviousMode();
-
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
+ ULONG ConnectionInfoLength = 0;
+ PLPCP_PORT_OBJECT Port, ClientPort;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ NTSTATUS Status = STATUS_SUCCESS;
+ HANDLE Handle;
+ PVOID SectionToMap;
+ PLPCP_MESSAGE Message;
+ PLPCP_CONNECTION_MESSAGE ConnectMessage;
+ PETHREAD Thread = PsGetCurrentThread();
+ ULONG PortMessageLength;
+ LARGE_INTEGER SectionOffset;
+ PTOKEN Token;
+ PTOKEN_USER TokenUserInfo;
+ PAGED_CODE();
+ LPCTRACE(LPC_CONNECT_DEBUG,
+ "Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n",
+ PortName,
+ Qos,
+ ClientView,
+ ServerView,
+ ServerSid);
+
+ /* Validate client view */
+ if ((ClientView) && (ClientView->Length != sizeof(PORT_VIEW)))
+ {
+ /* Fail */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Validate server view */
+ if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW)))
+ {
+ /* Fail */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Check if caller sent connection information length */
+ if (ConnectionInformationLength)
+ {
+ /* Retrieve the input length */
+ ConnectionInfoLength = *ConnectionInformationLength;
+ }
+
+ /* Get the port */
+ Status = ObReferenceObjectByName(PortName,
+ 0,
+ NULL,
+ PORT_ALL_ACCESS,
+ LpcPortObjectType,
+ PreviousMode,
+ NULL,
+ (PVOID *)&Port);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* This has to be a connection port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
+ {
+ /* It isn't, so fail */
+ ObDereferenceObject(Port);
+ return STATUS_INVALID_PORT_HANDLE;
+ }
+
+ /* Check if we have a SID */
+ if (ServerSid)
+ {
+ /* Make sure that we have a server */
+ if (Port->ServerProcess)
{
- ProbeForWriteHandle(UnsafeConnectedPortHandle);
- if (UnsafeMaximumMessageSize != NULL)
+ /* Get its token and query user information */
+ Token = PsReferencePrimaryToken(Port->ServerProcess);
+ //Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo);
+ // FIXME: Need SeQueryInformationToken
+ Status = STATUS_SUCCESS;
+ TokenUserInfo = ExAllocatePool(PagedPool, sizeof(TOKEN_USER));
+ TokenUserInfo->User.Sid = ServerSid;
+ PsDereferencePrimaryToken(Token);
+
+ /* Check for success */
+ if (NT_SUCCESS(Status))
{
- ProbeForWriteUlong(UnsafeMaximumMessageSize);
+ /* Compare the SIDs */
+ if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid))
+ {
+ /* Fail */
+ Status = STATUS_SERVER_SID_MISMATCH;
+ }
+
+ /* Free token information */
+ ExFreePool(TokenUserInfo);
}
}
- _SEH_HANDLE
+ else
{
- Status = _SEH_GetExceptionCode();
+ /* Invalid SID */
+ Status = STATUS_SERVER_SID_MISMATCH;
}
- _SEH_END;
-
- if (!NT_SUCCESS(Status))
+
+ /* Check if SID failed */
+ if (!NT_SUCCESS(Status))
{
- return Status;
+ /* Quit */
+ ObDereferenceObject(Port);
+ return Status;
}
}
- /*
- * Copy in write map and partially validate.
- */
- if (UnsafeWriteMap != NULL)
- {
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite(UnsafeWriteMap,
- sizeof(PORT_VIEW),
- 1);
- RtlCopyMemory(&WriteMap,
- UnsafeWriteMap,
- sizeof(PORT_VIEW));
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
- else
+ /* Create the client port */
+ Status = ObCreateObject(PreviousMode,
+ LpcPortObjectType,
+ NULL,
+ PreviousMode,
+ NULL,
+ sizeof(LPCP_PORT_OBJECT),
+ 0,
+ 0,
+ (PVOID *)&ClientPort);
+ if (!NT_SUCCESS(Status))
+ {
+ /* Failed, dereference the server port and return */
+ ObDereferenceObject(Port);
+ return Status;
+ }
+
+ /* Setup the client port */
+ RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT));
+ ClientPort->Flags = LPCP_CLIENT_PORT;
+ ClientPort->ConnectionPort = Port;
+ ClientPort->MaxMessageLength = Port->MaxMessageLength;
+ ClientPort->SecurityQos = *Qos;
+ InitializeListHead(&ClientPort->LpcReplyChainHead);
+ InitializeListHead(&ClientPort->LpcDataInfoChainHead);
+
+ /* Check if we have dynamic security */
+ if (Qos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)
+ {
+ /* Remember that */
+ ClientPort->Flags |= LPCP_SECURITY_DYNAMIC;
+ }
+ else
+ {
+ /* Create our own client security */
+ Status = SeCreateClientSecurity(Thread,
+ Qos,
+ FALSE,
+ &ClientPort->StaticSecurity);
+ if (!NT_SUCCESS(Status))
{
- RtlCopyMemory(&WriteMap,
- UnsafeWriteMap,
- sizeof(PORT_VIEW));
+ /* Security failed, dereference and return */
+ ObDereferenceObject(ClientPort);
+ return Status;
}
-
- if (WriteMap.Length != sizeof(PORT_VIEW))
- {
- return(STATUS_INVALID_PARAMETER_4);
- }
- SectionOffset.QuadPart = WriteMap.SectionOffset;
}
- else
+
+ /* Initialize the port queue */
+ Status = LpcpInitializePortQueue(ClientPort);
+ if (!NT_SUCCESS(Status))
{
- WriteMap.SectionHandle = INVALID_HANDLE_VALUE;
+ /* Failed */
+ ObDereferenceObject(ClientPort);
+ return Status;
}
- /*
- * Handle connection data.
- */
- if (UnsafeConnectData)
+ /* Check if we have a client view */
+ if (ClientView)
{
- if (PreviousMode != KernelMode)
+ /* Get the section handle */
+ Status = ObReferenceObjectByHandle(ClientView->SectionHandle,
+ SECTION_MAP_READ |
+ SECTION_MAP_WRITE,
+ MmSectionObjectType,
+ PreviousMode,
+ (PVOID*)&SectionToMap,
+ NULL);
+ if (!NT_SUCCESS(Status))
{
- _SEH_TRY
- {
- ConnectDataLength = ProbeForReadUlong(UnsafeConnectDataLength);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
- else
- {
- ConnectDataLength = *UnsafeConnectDataLength;
+ /* Fail */
+ ObDereferenceObject(Port);
+ return Status;
}
- if (ConnectDataLength != 0)
- {
- ConnectData = ExAllocatePool(NonPagedPool, ConnectDataLength);
- if (ConnectData == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
+ /* Set the section offset */
+ SectionOffset.QuadPart = ClientView->SectionOffset;
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWriteUlong(UnsafeConnectData);
- RtlCopyMemory(ConnectData,
- UnsafeConnectData,
- ConnectDataLength);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
+ /* Map it */
+ Status = MmMapViewOfSection(SectionToMap,
+ PsGetCurrentProcess(),
+ &Port->ClientSectionBase,
+ 0,
+ 0,
+ &SectionOffset,
+ &ClientView->ViewSize,
+ ViewUnmap,
+ 0,
+ PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- ExFreePool(ConnectData);
- return Status;
- }
- }
- else
- {
- RtlCopyMemory(ConnectData,
- UnsafeConnectData,
- ConnectDataLength);
- }
+ /* Update the offset */
+ ClientView->SectionOffset = SectionOffset.LowPart;
+
+ /* Check for failure */
+ if (!NT_SUCCESS(Status))
+ {
+ /* Fail */
+ ObDereferenceObject(SectionToMap);
+ ObDereferenceObject(Port);
+ return Status;
}
- }
- /*
- * Reference the named port.
- */
- Status = ObReferenceObjectByName (PortName,
- 0,
- NULL,
- PORT_ALL_ACCESS, /* DesiredAccess */
- LpcPortObjectType,
- PreviousMode,
- NULL,
- (PVOID*)&NamedPort);
- if (!NT_SUCCESS(Status))
+ /* Update the base */
+ ClientView->ViewBase = Port->ClientSectionBase;
+ }
+ else
{
- if (KeGetPreviousMode() != KernelMode)
- {
- ExFreePool(ConnectData);
- }
- return(Status);
+ /* No section */
+ SectionToMap = NULL;
}
- /*
- * Reference the send section object.
- */
- if (WriteMap.SectionHandle != INVALID_HANDLE_VALUE)
+ /* Normalize connection information */
+ if (ConnectionInfoLength > Port->MaxConnectionInfoLength)
{
- Status = ObReferenceObjectByHandle(WriteMap.SectionHandle,
- SECTION_MAP_READ | SECTION_MAP_WRITE,
- MmSectionObjectType,
- PreviousMode,
- (PVOID*)&SectionObject,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(NamedPort);
- if (KeGetPreviousMode() != KernelMode)
- {
- ExFreePool(ConnectData);
- }
- return(Status);
- }
+ /* Use the port's maximum allowed value */
+ ConnectionInfoLength = Port->MaxConnectionInfoLength;
}
- else
+
+ /* Allocate a message from the port zone */
+ Message = LpcpAllocateFromPortZone();
+ if (!Message)
{
- SectionObject = NULL;
+ /* Fail if we couldn't allocate a message */
+ if (SectionToMap) ObDereferenceObject(SectionToMap);
+ ObDereferenceObject(ClientPort);
+ return STATUS_NO_MEMORY;
}
- /*
- * Do the connection establishment.
- */
- Status = EiConnectPort(&ConnectedPort,
- NamedPort,
- SectionObject,
- SectionOffset,
- WriteMap.ViewSize,
- &WriteMap.ViewBase,
- &WriteMap.ViewRemoteBase,
- &ReadMap.ViewSize,
- &ReadMap.ViewBase,
- &MaximumMessageSize,
- ConnectData,
- &ConnectDataLength);
- if (!NT_SUCCESS(Status))
+ /* Set pointer to the connection message and fill in the CID */
+ ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
+ Message->Request.ClientId = Thread->Cid;
+
+ /* Check if we have a client view */
+ if (ClientView)
{
- /* FIXME: Again, check what NT does here. */
- if (UnsafeConnectDataLength != NULL)
- {
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- RtlCopyMemory(UnsafeConnectData,
- ConnectData,
- ConnectDataLength);
- *UnsafeConnectDataLength = ConnectDataLength;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- else
- {
- RtlCopyMemory(UnsafeConnectData,
- ConnectData,
- ConnectDataLength);
- *UnsafeConnectDataLength = ConnectDataLength;
- }
-
- ExFreePool(ConnectData);
- }
- return(Status);
- }
+ /* Set the view size */
+ Message->Request.ClientViewSize = ClientView->ViewSize;
- /*
- * Do some initial cleanup.
- */
- if (SectionObject != NULL)
+ /* Copy the client view and clear the server view */
+ RtlMoveMemory(&ConnectMessage->ClientView,
+ ClientView,
+ sizeof(PORT_VIEW));
+ RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW));
+ }
+ else
{
- ObDereferenceObject(SectionObject);
- SectionObject = NULL;
+ /* Set the size to 0 and clear the connect message */
+ Message->Request.ClientViewSize = 0;
+ RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE));
}
- ObDereferenceObject(NamedPort);
- NamedPort = NULL;
- /*
- * Copy the data back to the caller.
- */
+ /* Set the section and client port. Port is NULL for now */
+ ConnectMessage->ClientPort = NULL;
+ ConnectMessage->SectionToMap = SectionToMap;
+
+ /* Set the data for the connection request message */
+ Message->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
+ ConnectionInfoLength;
+ Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
+ Message->Request.u1.s1.DataLength;
+ Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST;
- if (UnsafeConnectDataLength != NULL)
+ /* Check if we have connection information */
+ if (ConnectionInformation)
{
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- *UnsafeConnectDataLength = ConnectDataLength;
-
- if (ConnectData != NULL)
- {
- RtlCopyMemory(UnsafeConnectData,
- ConnectData,
- ConnectDataLength);
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
+ /* Copy it in */
+ RtlMoveMemory(ConnectMessage + 1,
+ ConnectionInformation,
+ ConnectionInfoLength);
+ }
- if (!NT_SUCCESS(Status))
- {
- if (ConnectData != NULL)
- {
- ExFreePool(ConnectData);
- }
- return(Status);
- }
- }
- else
- {
- *UnsafeConnectDataLength = ConnectDataLength;
-
- if (ConnectData != NULL)
- {
- RtlCopyMemory(UnsafeConnectData,
- ConnectData,
- ConnectDataLength);
- }
- }
+ /* Acquire the port lock */
+ KeAcquireGuardedMutex(&LpcpLock);
- if (ConnectData != NULL)
- {
- ExFreePool(ConnectData);
- }
- }
- Status = ObInsertObject(ConnectedPort,
- NULL,
- PORT_ALL_ACCESS,
- 1,
- (PVOID*)&ConnectedPort,
- &ConnectedPortHandle);
- if (!NT_SUCCESS(Status))
+ /* Check if someone already deleted the port name */
+ if (Port->Flags & LPCP_NAME_DELETED)
{
- return(Status);
+ /* Fail the request */
+ KeReleaseGuardedMutex(&LpcpLock);
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ goto Cleanup;
}
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- *UnsafeConnectedPortHandle = ConnectedPortHandle;
-
- if (UnsafeWriteMap != NULL)
- {
- RtlCopyMemory(UnsafeWriteMap,
- &WriteMap,
- sizeof(PORT_VIEW));
- }
+ /* Associate no thread yet */
+ Message->RepliedToThread = NULL;
- if (UnsafeReadMap != NULL)
- {
- RtlCopyMemory(UnsafeReadMap,
- &ReadMap,
- sizeof(REMOTE_PORT_VIEW));
- }
+ /* Generate the Message ID and set it */
+ Message->Request.MessageId = LpcpNextMessageId++;
+ if (!LpcpNextMessageId) LpcpNextMessageId = 1;
+ Thread->LpcReplyMessageId = Message->Request.MessageId;
- if (UnsafeMaximumMessageSize != NULL)
- {
- *UnsafeMaximumMessageSize = MaximumMessageSize;
- }
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
- else
+ /* Insert the message into the queue and thread chain */
+ InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry);
+ InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain);
+ Thread->LpcReplyMessage = Message;
+
+ /* Now we can finally reference the client port and link it*/
+ ObReferenceObject(ClientPort);
+ ConnectMessage->ClientPort = ClientPort;
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+ LPCTRACE(LPC_CONNECT_DEBUG,
+ "Messages: %p/%p. Ports: %p/%p. Status: %lx\n",
+ Message,
+ ConnectMessage,
+ Port,
+ ClientPort,
+ Status);
+
+ /* If this is a waitable port, set the event */
+ if (Port->Flags & LPCP_WAITABLE_PORT) KeSetEvent(&Port->WaitEvent,
+ 1,
+ FALSE);
+
+ /* Release the queue semaphore */
+ LpcpCompleteWait(Port->MsgQueue.Semaphore);
+
+ /* Now wait for a reply */
+ LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode);
+
+ /* Check if our wait ended in success */
+ if (Status != STATUS_SUCCESS) goto Cleanup;
+
+ /* Free the connection message */
+ SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
+
+ /* Check if we got a message back */
+ if (Message)
{
- *UnsafeConnectedPortHandle = ConnectedPortHandle;
-
- if (UnsafeWriteMap != NULL)
+ /* Check for new return length */
+ if ((Message->Request.u1.s1.DataLength -
+ sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength)
{
- RtlCopyMemory(UnsafeWriteMap,
- &WriteMap,
- sizeof(PORT_VIEW));
+ /* Set new normalized connection length */
+ ConnectionInfoLength = Message->Request.u1.s1.DataLength -
+ sizeof(LPCP_CONNECTION_MESSAGE);
}
- if (UnsafeReadMap != NULL)
+ /* Check if we had connection information */
+ if (ConnectionInformation)
{
- RtlCopyMemory(UnsafeReadMap,
- &ReadMap,
- sizeof(REMOTE_PORT_VIEW));
- }
+ /* Check if we had a length pointer */
+ if (ConnectionInformationLength)
+ {
+ /* Return the length */
+ *ConnectionInformationLength = ConnectionInfoLength;
+ }
- if (UnsafeMaximumMessageSize != NULL)
- {
- *UnsafeMaximumMessageSize = MaximumMessageSize;
+ /* Return the connection information */
+ RtlMoveMemory(ConnectionInformation,
+ ConnectMessage + 1,
+ ConnectionInfoLength );
}
- }
- /*
- * All done.
- */
+ /* Make sure we had a connected port */
+ if (ClientPort->ConnectedPort)
+ {
+ /* Get the message length before the port might get killed */
+ PortMessageLength = Port->MaxMessageLength;
- return(STATUS_SUCCESS);
-}
+ /* Insert the client port */
+ Status = ObInsertObject(ClientPort,
+ NULL,
+ PORT_ALL_ACCESS,
+ 0,
+ (PVOID *)NULL,
+ &Handle);
+ if (NT_SUCCESS(Status))
+ {
+ /* Return the handle */
+ *PortHandle = Handle;
+ LPCTRACE(LPC_CONNECT_DEBUG,
+ "Handle: %lx. Length: %lx\n",
+ Handle,
+ PortMessageLength);
+
+ /* Check if maximum length was requested */
+ if (MaxMessageLength) *MaxMessageLength = PortMessageLength;
+
+ /* Check if we had a client view */
+ if (ClientView)
+ {
+ /* Copy it back */
+ RtlMoveMemory(ClientView,
+ &ConnectMessage->ClientView,
+ sizeof(PORT_VIEW));
+ }
+ /* Check if we had a server view */
+ if (ServerView)
+ {
+ /* Copy it back */
+ RtlMoveMemory(ServerView,
+ &ConnectMessage->ServerView,
+ sizeof(REMOTE_PORT_VIEW));
+ }
+ }
+ }
+ else
+ {
+ /* No connection port, we failed */
+ if (SectionToMap) ObDereferenceObject(SectionToMap);
-/**********************************************************************
- * NAME EXPORTED
- * NtAcceptConnectPort/6
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- * ServerPortHandle
- * NamedPortHandle
- * LpcMessage
- * AcceptIt
- * WriteMap
- * ReadMap
- *
- * RETURN VALUE
- */
-/*EXPORTED*/ NTSTATUS STDCALL
-NtAcceptConnectPort (PHANDLE ServerPortHandle,
- HANDLE NamedPortHandle,
- PPORT_MESSAGE LpcMessage,
- BOOLEAN AcceptIt,
- PPORT_VIEW WriteMap,
- PREMOTE_PORT_VIEW ReadMap)
-{
- NTSTATUS Status;
- PEPORT NamedPort;
- PEPORT OurPort = NULL;
- PQUEUEDMESSAGE ConnectionRequest;
- KIRQL oldIrql;
- PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
- PEPORT_CONNECT_REPLY_MESSAGE CReply;
- ULONG Size;
- KPROCESSOR_MODE PreviousMode = ExGetPreviousMode();
-
- Size = sizeof(EPORT_CONNECT_REPLY_MESSAGE);
- if (LpcMessage)
- {
- Size += LpcMessage->u1.s1.DataLength;
- }
-
- CReply = ExAllocatePool(NonPagedPool, Size);
- if (CReply == NULL)
- {
- return(STATUS_NO_MEMORY);
- }
+ /* Check if it's because the name got deleted */
+ if (Port->Flags & LPCP_NAME_DELETED)
+ {
+ /* Set the correct status */
+ Status = STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+ else
+ {
+ /* Otherwise, the caller refused us */
+ Status = STATUS_PORT_CONNECTION_REFUSED;
+ }
- Status = ObReferenceObjectByHandle(NamedPortHandle,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- PreviousMode,
- (PVOID*)&NamedPort,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- ExFreePool(CReply);
- return (Status);
- }
+ /* Kill the port */
+ ObDereferenceObject(ClientPort);
+ }
- /*
- * Create a port object for our side of the connection
- */
- if (AcceptIt)
- {
- Status = ObCreateObject(PreviousMode,
- LpcPortObjectType,
- NULL,
- PreviousMode,
- NULL,
- sizeof(EPORT),
- 0,
- 0,
- (PVOID*)&OurPort);
- if (!NT_SUCCESS(Status))
- {
- ExFreePool(CReply);
- ObDereferenceObject(NamedPort);
- return(Status);
- }
-
- Status = ObInsertObject ((PVOID)OurPort,
- NULL,
- PORT_ALL_ACCESS,
- 0,
- NULL,
- ServerPortHandle);
- if (!NT_SUCCESS(Status))
- {
- ObDereferenceObject(OurPort);
- ExFreePool(CReply);
- ObDereferenceObject(NamedPort);
- return(Status);
- }
-
- LpcpInitializePort(OurPort, EPORT_TYPE_SERVER_COMM_PORT, NamedPort);
+ /* Free the message */
+ LpcpFreeToPortZone(Message, FALSE);
+ return Status;
}
- /*
- * Dequeue the connection request
- */
- KeAcquireSpinLock(&NamedPort->Lock, &oldIrql);
- ConnectionRequest = EiDequeueConnectMessagePort (NamedPort);
- KeReleaseSpinLock(&NamedPort->Lock, oldIrql);
- CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)(&ConnectionRequest->Message);
-
- /*
- * Prepare the reply.
- */
- if (LpcMessage != NULL)
- {
- memcpy(&CReply->MessageHeader, LpcMessage, sizeof(PORT_MESSAGE));
- memcpy(&CReply->ConnectData, (PVOID)(LpcMessage + 1),
- LpcMessage->u1.s1.DataLength);
- CReply->MessageHeader.u1.s1.TotalLength =
- sizeof(EPORT_CONNECT_REPLY_MESSAGE) + LpcMessage->u1.s1.DataLength;
- CReply->MessageHeader.u1.s1.DataLength = CReply->MessageHeader.u1.s1.TotalLength -
- sizeof(PORT_MESSAGE);
- CReply->ConnectDataLength = LpcMessage->u1.s1.DataLength;
- }
- else
- {
- CReply->MessageHeader.u1.s1.TotalLength = sizeof(EPORT_CONNECT_REPLY_MESSAGE);
- CReply->MessageHeader.u1.s1.DataLength = sizeof(EPORT_CONNECT_REPLY_MESSAGE) -
- sizeof(PORT_MESSAGE);
- CReply->ConnectDataLength = 0;
- }
- if (!AcceptIt)
- {
- EiReplyOrRequestPort(ConnectionRequest->Sender,
- &CReply->MessageHeader,
- LPC_CONNECTION_REFUSED,
- NamedPort);
- KeReleaseSemaphore(&ConnectionRequest->Sender->Semaphore,
- IO_NO_INCREMENT,
- 1,
- FALSE);
- ObDereferenceObject(ConnectionRequest->Sender);
- ExFreePool(ConnectionRequest);
- ExFreePool(CReply);
- ObDereferenceObject(NamedPort);
- return (STATUS_SUCCESS);
- }
+ /* No reply message, fail */
+ if (SectionToMap) ObDereferenceObject(SectionToMap);
+ ObDereferenceObject(ClientPort);
+ return STATUS_PORT_CONNECTION_REFUSED;
- /*
- * Prepare the connection.
- */
- if (WriteMap != NULL)
- {
- PVOID SectionObject;
- LARGE_INTEGER SectionOffset;
-
- Status = ObReferenceObjectByHandle(WriteMap->SectionHandle,
- SECTION_MAP_READ | SECTION_MAP_WRITE,
- MmSectionObjectType,
- PreviousMode,
- (PVOID*)&SectionObject,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- SectionOffset.QuadPart = WriteMap->SectionOffset;
- WriteMap->ViewRemoteBase = 0;
- CReply->ReceiveClientViewSize = WriteMap->ViewSize;
- Status = MmMapViewOfSection(SectionObject,
- CRequest->ConnectingProcess,
- &WriteMap->ViewRemoteBase,
- 0,
- CReply->ReceiveClientViewSize,
- &SectionOffset,
- &CReply->ReceiveClientViewSize,
- ViewUnmap,
- 0 /* MEM_TOP_DOWN? */,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- WriteMap->ViewBase = 0;
- Status = MmMapViewOfSection(SectionObject,
- PsGetCurrentProcess(),
- &WriteMap->ViewBase,
- 0,
- WriteMap->ViewSize,
- &SectionOffset,
- &WriteMap->ViewSize,
- ViewUnmap,
- 0 /* MEM_TOP_DOWN? */,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- ObDereferenceObject(SectionObject);
- }
- if (ReadMap != NULL && CRequest->SendSectionObject != NULL)
- {
- LARGE_INTEGER SectionOffset;
-
- SectionOffset = CRequest->SendSectionOffset;
- ReadMap->ViewSize = CRequest->SendViewSize;
- ReadMap->ViewBase = 0;
- Status = MmMapViewOfSection(CRequest->SendSectionObject,
- PsGetCurrentProcess(),
- &ReadMap->ViewBase,
- 0,
- CRequest->SendViewSize,
- &SectionOffset,
- &CRequest->SendViewSize,
- ViewUnmap,
- 0 /* MEM_TOP_DOWN? */,
- PAGE_READWRITE);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
- }
+Cleanup:
+ /* We failed, free the message */
+ SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
- /*
- * Finish the reply.
- */
- if (ReadMap != NULL)
+ /* Check if the semaphore got signaled */
+ if (KeReadStateSemaphore(&Thread->LpcReplySemaphore))
{
- CReply->SendServerViewBase = ReadMap->ViewBase;
+ /* Wait on it */
+ KeWaitForSingleObject(&Thread->LpcReplySemaphore,
+ KernelMode,
+ Executive,
+ FALSE,
+ NULL);
}
- else
- {
- CReply->SendServerViewBase = 0;
- }
- if (WriteMap != NULL)
- {
- CReply->ReceiveClientViewBase = WriteMap->ViewRemoteBase;
- }
- CReply->MaximumMessageSize = LPC_MAX_MESSAGE_LENGTH;
-
- /*
- * Connect the two ports
- */
- OurPort->OtherPort = ConnectionRequest->Sender;
- OurPort->OtherPort->OtherPort = OurPort;
- EiReplyOrRequestPort(ConnectionRequest->Sender,
- (PPORT_MESSAGE)CReply,
- LPC_REPLY,
- OurPort);
- ExFreePool(ConnectionRequest);
- ExFreePool(CReply);
+ /* Check if we had a message and free it */
+ if (Message) LpcpFreeToPortZone(Message, FALSE);
- //ObDereferenceObject(OurPort);
- ObDereferenceObject(NamedPort);
+ /* Dereference other objects */
+ if (SectionToMap) ObDereferenceObject(SectionToMap);
+ ObDereferenceObject(ClientPort);
- return (STATUS_SUCCESS);
+ /* Return status */
+ return Status;
}
-/**********************************************************************
- * NAME EXPORTED
- * NtSecureConnectPort/9
- *
- * DESCRIPTION
- * Connect to a named port and wait for the other side to
- * accept the connection. Possibly verify that the server
- * matches the ServerSid (trusted server).
- * Present in w2k+.
- *
- * ARGUMENTS
- * ConnectedPort
- * PortName: fully qualified name in the Ob name space;
- * Qos
- * WriteMap
- * ServerSid
- * ReadMap
- * MaxMessageSize
- * ConnectInfo
- * UserConnectInfoLength
- *
- * RETURN VALUE
+/*
+ * @implemented
*/
-NTSTATUS STDCALL
-NtSecureConnectPort (OUT PHANDLE ConnectedPort,
- IN PUNICODE_STRING PortName,
- IN PSECURITY_QUALITY_OF_SERVICE Qos,
- IN OUT PPORT_VIEW WriteMap OPTIONAL,
- IN PSID ServerSid OPTIONAL,
- IN OUT PREMOTE_PORT_VIEW ReadMap OPTIONAL,
- OUT PULONG MaxMessageSize OPTIONAL,
- IN OUT PVOID ConnectInfo OPTIONAL,
- IN OUT PULONG UserConnectInfoLength OPTIONAL)
+NTSTATUS
+NTAPI
+NtConnectPort(OUT PHANDLE PortHandle,
+ IN PUNICODE_STRING PortName,
+ IN PSECURITY_QUALITY_OF_SERVICE Qos,
+ IN PPORT_VIEW ClientView,
+ IN PREMOTE_PORT_VIEW ServerView,
+ OUT PULONG MaxMessageLength,
+ IN PVOID ConnectionInformation,
+ OUT PULONG ConnectionInformationLength)
{
- /* TODO: implement a new object type: WaitablePort */
- /* TODO: verify the process' SID that hosts the rendez-vous port equals ServerSid */
- return NtConnectPort (ConnectedPort,
- PortName,
- Qos,
- WriteMap,
- ReadMap,
- MaxMessageSize,
- ConnectInfo,
- UserConnectInfoLength);
+ /* Call the newer API */
+ return NtSecureConnectPort(PortHandle,
+ PortName,
+ Qos,
+ ClientView,
+ NULL,
+ ServerView,
+ MaxMessageLength,
+ ConnectionInformation,
+ ConnectionInformationLength);
}
/* EOF */
-/* $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/create.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * PURPOSE: Local Procedure Call: Port/Queue/Message Creation
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-/**********************************************************************
- * NAME
- * LpcpVerifyCreateParameters/5
- *
- * DESCRIPTION
- * Verify user parameters in NtCreatePort and in
- * NtCreateWaitablePort.
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- */
-static NTSTATUS STDCALL
-LpcpVerifyCreateParameters (IN PHANDLE PortHandle,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- IN ULONG MaxConnectInfoLength,
- IN ULONG MaxDataLength,
- IN ULONG MaxPoolUsage)
+/* PRIVATE FUNCTIONS *********************************************************/
+
+NTSTATUS
+NTAPI
+LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
{
- if (NULL == PortHandle)
- {
- return (STATUS_INVALID_PARAMETER_1);
- }
- if (NULL == ObjectAttributes)
+ PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
+
+ /* Allocate the queue */
+ MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
+ sizeof(LPCP_NONPAGED_PORT_QUEUE),
+ TAG('P', 'o', 'r', 't'));
+ if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
+
+ /* Set it up */
+ KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
+ MessageQueue->BackPointer = Port;
+
+ /* And link it with the Paged Pool part */
+ Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
+ InitializeListHead(&Port->MsgQueue.ReceiveHead);
+ return STATUS_SUCCESS;
+}
+
+NTSTATUS
+NTAPI
+LpcpCreatePort(OUT PHANDLE PortHandle,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN ULONG MaxConnectionInfoLength,
+ IN ULONG MaxMessageLength,
+ IN ULONG MaxPoolUsage,
+ IN BOOLEAN Waitable)
+{
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ NTSTATUS Status;
+ PLPCP_PORT_OBJECT Port;
+ LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName);
+
+ /* Create the Object */
+ Status = ObCreateObject(PreviousMode,
+ LpcPortObjectType,
+ ObjectAttributes,
+ PreviousMode,
+ NULL,
+ sizeof(LPCP_PORT_OBJECT),
+ 0,
+ 0,
+ (PVOID*)&Port);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Set up the Object */
+ RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
+ Port->ConnectionPort = Port;
+ Port->Creator = PsGetCurrentThread()->Cid;
+ InitializeListHead(&Port->LpcDataInfoChainHead);
+ InitializeListHead(&Port->LpcReplyChainHead);
+
+ /* Check if we don't have a name */
+ if (!ObjectAttributes->ObjectName->Buffer)
{
- return (STATUS_INVALID_PARAMETER_2);
+ /* Set up for an unconnected port */
+ Port->Flags = LPCP_UNCONNECTED_PORT;
+ Port->ConnectedPort = Port;
+ Port->ServerProcess = NULL;
}
- if ((ObjectAttributes->Attributes & OBJ_OPENLINK)
- || (ObjectAttributes->Attributes & OBJ_OPENIF)
- || (ObjectAttributes->Attributes & OBJ_EXCLUSIVE)
- || (ObjectAttributes->Attributes & OBJ_PERMANENT)
- || (ObjectAttributes->Attributes & OBJ_INHERIT))
- {
- return (STATUS_INVALID_PORT_ATTRIBUTES);
- }
- if (MaxConnectInfoLength > LPC_MAX_DATA_LENGTH)
+ else
{
- return (STATUS_INVALID_PARAMETER_3);
+ /* Set up for a named connection port */
+ Port->Flags = LPCP_CONNECTION_PORT;
+ Port->ServerProcess = PsGetCurrentProcess();
+
+ /* Don't let the process die on us */
+ ObReferenceObject(Port->ServerProcess);
}
- if (MaxDataLength > LPC_MAX_MESSAGE_LENGTH)
+
+ /* Check if this is a waitable port */
+ if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
+
+ /* Setup the port queue */
+ Status = LpcpInitializePortQueue(Port);
+ if (!NT_SUCCESS(Status))
{
- return (STATUS_INVALID_PARAMETER_4);
+ /* Fail */
+ ObDereferenceObject(Port);
+ return Status;
}
- /* TODO: some checking is done also on MaxPoolUsage
- * to avoid choking the executive */
- return (STATUS_SUCCESS);
-}
-/**********************************************************************
- * NAME EXPORTED
- * NtCreatePort/5
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- * PortHandle,
- * ObjectAttributes,
- * MaxConnectInfoLength,
- * MaxDataLength,
- * MaxPoolUsage: size of NP zone the NP part of msgs is kept in
- *
- * RETURN VALUE
- */
-/*EXPORTED*/ NTSTATUS STDCALL
-NtCreatePort (PHANDLE PortHandle,
- POBJECT_ATTRIBUTES ObjectAttributes,
- ULONG MaxConnectInfoLength,
- ULONG MaxDataLength,
- ULONG MaxPoolUsage)
-{
- PEPORT Port;
- NTSTATUS Status;
-
- DPRINT("NtCreatePort() Name %x\n", ObjectAttributes->ObjectName->Buffer);
-
- /* Verify parameters */
- Status = LpcpVerifyCreateParameters (PortHandle,
- ObjectAttributes,
- MaxConnectInfoLength,
- MaxDataLength,
- MaxPoolUsage);
- if (STATUS_SUCCESS != Status)
+ /* Check if this is a waitable port */
+ if (Port->Flags & LPCP_WAITABLE_PORT)
{
- return (Status);
+ /* Setup the wait event */
+ KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
}
- /* Ask Ob to create the object */
- Status = ObCreateObject (ExGetPreviousMode(),
- LpcPortObjectType,
- ObjectAttributes,
- ExGetPreviousMode(),
- NULL,
- sizeof(EPORT),
- 0,
- 0,
- (PVOID*)&Port);
- if (!NT_SUCCESS(Status))
+ /* Set the maximum message size allowed */
+ Port->MaxMessageLength = LpcpMaxMessageSize -
+ FIELD_OFFSET(LPCP_MESSAGE, Request);
+
+ /* Now subtract the actual message structures and get the data size */
+ Port->MaxConnectionInfoLength = Port->MaxMessageLength -
+ sizeof(PORT_MESSAGE) -
+ sizeof(LPCP_CONNECTION_MESSAGE);
+
+ /* Validate the sizes */
+ if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
{
- return (Status);
+ /* Not enough space for your request */
+ ObDereferenceObject(Port);
+ return STATUS_INVALID_PARAMETER_3;
}
-
- Status = ObInsertObject ((PVOID)Port,
- NULL,
- PORT_ALL_ACCESS,
- 0,
- NULL,
- PortHandle);
- if (!NT_SUCCESS(Status))
+ else if (Port->MaxMessageLength < MaxMessageLength)
{
- ObDereferenceObject (Port);
- return (Status);
+ /* Not enough space for your request */
+ ObDereferenceObject(Port);
+ return STATUS_INVALID_PARAMETER_4;
}
- Status = LpcpInitializePort (Port, EPORT_TYPE_SERVER_RQST_PORT, NULL);
- Port->MaxConnectInfoLength = LPC_MAX_DATA_LENGTH;
- Port->MaxDataLength = LPC_MAX_MESSAGE_LENGTH;
- Port->MaxPoolUsage = MaxPoolUsage;
+ /* Now set the custom setting */
+ Port->MaxMessageLength = MaxMessageLength;
+
+ /* Insert it now */
+ Status = ObInsertObject((PVOID)Port,
+ NULL,
+ PORT_ALL_ACCESS,
+ 0,
+ NULL,
+ PortHandle);
+
+ /* Return success or the error */
+ LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %lx\n", Port, *PortHandle);
+ return Status;
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
+ * @implemented
+ */
+NTSTATUS
+NTAPI
+NtCreatePort(OUT PHANDLE PortHandle,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN ULONG MaxConnectInfoLength,
+ IN ULONG MaxDataLength,
+ IN ULONG MaxPoolUsage)
+{
+ PAGED_CODE();
- return (Status);
+ /* Call the internal API */
+ return LpcpCreatePort(PortHandle,
+ ObjectAttributes,
+ MaxConnectInfoLength,
+ MaxDataLength,
+ MaxPoolUsage,
+ FALSE);
}
-/**********************************************************************
- * NAME EXPORTED
- * NtCreateWaitablePort/5
- *
- * DESCRIPTION
- * Waitable ports can be connected to with NtSecureConnectPort.
- * No port interface can be used with waitable ports but
- * NtReplyWaitReceivePort and NtReplyWaitReceivePortEx.
- * Present only in w2k+.
- *
- * ARGUMENTS
- * PortHandle,
- * ObjectAttributes,
- * MaxConnectInfoLength,
- * MaxDataLength,
- * MaxPoolUsage
- *
- * RETURN VALUE
+/*
+ * @implemented
*/
-/*EXPORTED*/ NTSTATUS STDCALL
-NtCreateWaitablePort (OUT PHANDLE PortHandle,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- IN ULONG MaxConnectInfoLength,
- IN ULONG MaxDataLength,
- IN ULONG MaxPoolUsage)
+NTSTATUS
+NTAPI
+NtCreateWaitablePort(OUT PHANDLE PortHandle,
+ IN POBJECT_ATTRIBUTES ObjectAttributes,
+ IN ULONG MaxConnectInfoLength,
+ IN ULONG MaxDataLength,
+ IN ULONG MaxPoolUsage)
{
- NTSTATUS Status;
-
- /* Verify parameters */
- Status = LpcpVerifyCreateParameters (PortHandle,
- ObjectAttributes,
- MaxConnectInfoLength,
- MaxDataLength,
- MaxPoolUsage);
- if (STATUS_SUCCESS != Status)
- {
- return (Status);
- }
- /* TODO */
- return (STATUS_NOT_IMPLEMENTED);
+ PAGED_CODE();
+
+ /* Call the internal API */
+ return LpcpCreatePort(PortHandle,
+ ObjectAttributes,
+ MaxConnectInfoLength,
+ MaxDataLength,
+ MaxPoolUsage,
+ TRUE);
}
/* EOF */
-/* $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/listen.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * PURPOSE: Local Procedure Call: Listening
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-/* FUNCTIONS *****************************************************************/
+/* PUBLIC FUNCTIONS **********************************************************/
-/**********************************************************************
- * NAME EXPORTED
- * NtListenPort@8
- *
- * DESCRIPTION
- * Listen on a named port and wait for a connection attempt.
- *
- * ARGUMENTS
- * PortHandle [IN] LPC port to listen on.
- *
- * ConnectMsg [IN] User provided storage for a
- * possible connection request LPC message.
- *
- * RETURN VALUE
- * STATUS_SUCCESS if a connection request is received
- * successfully; otherwise an error code.
- *
- * The buffer ConnectMessage is filled with the connection
- * request message queued by NtConnectPort() in PortHandle.
- *
- * NOTE
+/*
+ * @implemented
*/
-/*EXPORTED*/ NTSTATUS STDCALL
-NtListenPort (IN HANDLE PortHandle,
- IN PPORT_MESSAGE ConnectMsg)
+NTSTATUS
+NTAPI
+NtListenPort(IN HANDLE PortHandle,
+ OUT PPORT_MESSAGE ConnectMessage)
{
- NTSTATUS Status;
-
- /*
- * Wait forever for a connection request.
- */
- for (;;)
- {
- Status = NtReplyWaitReceivePort(PortHandle,
- NULL,
- NULL,
- ConnectMsg);
- /*
- * Accept only LPC_CONNECTION_REQUEST requests.
- * Drop any other message.
- */
- if (!NT_SUCCESS(Status) ||
- LPC_CONNECTION_REQUEST == ConnectMsg->u2.s2.Type)
- {
- DPRINT("Got message (type %x)\n", LPC_CONNECTION_REQUEST);
- break;
- }
- DPRINT("Got message (type %x)\n", ConnectMsg->u2.s2.Type);
- }
-
- return (Status);
+ NTSTATUS Status;
+ PAGED_CODE();
+ LPCTRACE(LPC_LISTEN_DEBUG, "Handle: %lx\n", PortHandle);
+
+ /* Wait forever for a connection request. */
+ for (;;)
+ {
+ /* Do the wait */
+ Status = NtReplyWaitReceivePort(PortHandle,
+ NULL,
+ NULL,
+ ConnectMessage);
+
+ /* Accept only LPC_CONNECTION_REQUEST requests. */
+ if ((Status != STATUS_SUCCESS) ||
+ (LpcpGetMessageType(ConnectMessage) == LPC_CONNECTION_REQUEST))
+ {
+ /* Break out */
+ break;
+ }
+ }
+
+ /* Return status */
+ return Status;
}
+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/close.c
- * PURPOSE: Local Procedure Call: Rundown, Cleanup, Deletion
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-VOID
-NTAPI
-LpcExitThread(IN PETHREAD Thread)
-{
- PLPCP_MESSAGE Message;
-
- /* Acquire the lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Make sure that the Reply Chain is empty */
- if (!IsListEmpty(&Thread->LpcReplyChain))
- {
- /* It's not, remove the entry */
- RemoveEntryList(&Thread->LpcReplyChain);
- }
-
- /* Set the thread in exit mode */
- Thread->LpcExitThreadCalled = TRUE;
- Thread->LpcReplyMessageId = 0;
-
- /* Check if there's a reply message */
- Message = Thread->LpcReplyMessage;
- if (Message)
- {
- /* FIXME: TODO */
- KEBUGCHECK(0);
- }
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-}
-
-VOID
-NTAPI
-LpcpFreeToPortZone(IN PLPCP_MESSAGE Message,
- IN ULONG Flags)
-{
- PLPCP_CONNECTION_MESSAGE ConnectMessage;
- PLPCP_PORT_OBJECT ClientPort = NULL;
- PETHREAD Thread = NULL;
- BOOLEAN LockHeld = Flags & 1;
- PAGED_CODE();
- LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. Flags: %lx\n", Message, Flags);
-
- /* Acquire the lock if not already */
- if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
-
- /* Check if the queue list is empty */
- if (!IsListEmpty(&Message->Entry))
- {
- /* Remove and re-initialize */
- RemoveEntryList(&Message->Entry);
- InitializeListHead(&Message->Entry);
- }
-
- /* Check if we've already replied */
- if (Message->RepliedToThread)
- {
- /* Set thread to dereference and clean up */
- Thread = Message->RepliedToThread;
- Message->RepliedToThread = NULL;
- }
-
- /* Check if this is a connection request */
- if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
- {
- /* Get the connection message */
- ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
-
- /* Clear the client port */
- ClientPort = ConnectMessage->ClientPort;
- if (ClientPort) ConnectMessage->ClientPort = NULL;
- }
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* Check if we had anything to dereference */
- if (Thread) ObDereferenceObject(Thread);
- if (ClientPort) ObDereferenceObject(ClientPort);
-
- /* Free the entry */
- ExFreeToPagedLookasideList(&LpcpMessagesLookaside, Message);
-
- /* Reacquire the lock if needed */
- if ((LockHeld) && !(Flags & 2)) KeAcquireGuardedMutex(&LpcpLock);
-}
-
-VOID
-NTAPI
-LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port,
- IN BOOLEAN Destroy)
-{
- PLIST_ENTRY ListHead, NextEntry;
- PETHREAD Thread;
- PLPCP_MESSAGE Message;
- PLPCP_CONNECTION_MESSAGE ConnectMessage;
- LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
-
- /* Hold the lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Disconnect the port to which this port is connected */
- if (Port->ConnectedPort) Port->ConnectedPort->ConnectedPort = NULL;
-
- /* Check if this is a connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
- {
- /* Delete the name */
- Port->Flags |= LPCP_NAME_DELETED;
- }
-
- /* Walk all the threads waiting and signal them */
- ListHead = &Port->LpcReplyChainHead;
- NextEntry = ListHead->Flink;
- while (NextEntry != ListHead)
- {
- /* Get the Thread */
- Thread = CONTAINING_RECORD(NextEntry, ETHREAD, LpcReplyChain);
-
- /* Make sure we're not in exit */
- if (Thread->LpcExitThreadCalled) break;
-
- /* Move to the next entry */
- NextEntry = NextEntry->Flink;
-
- /* Remove and reinitialize the List */
- RemoveEntryList(&Thread->LpcReplyChain);
- InitializeListHead(&Thread->LpcReplyChain);
-
- /* Check if someone is waiting */
- if (!KeReadStateSemaphore(&Thread->LpcReplySemaphore))
- {
- /* Get the message and check if it's a connection request */
- Message = Thread->LpcReplyMessage;
- if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
- {
- /* Get the connection message */
- ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
-
- /* Check if it had a section */
- if (ConnectMessage->SectionToMap)
- {
- /* Dereference it */
- ObDereferenceObject(ConnectMessage->SectionToMap);
- }
- }
-
- /* Clear the reply message */
- Thread->LpcReplyMessage = NULL;
-
- /* And remove the message from the port zone */
- LpcpFreeToPortZone(Message, TRUE);
- }
-
- /* Release the semaphore and reset message id count */
- Thread->LpcReplyMessageId = 0;
- LpcpCompleteWait(&Thread->LpcReplySemaphore);
- }
-
- /* Reinitialize the list head */
- InitializeListHead(&Port->LpcReplyChainHead);
-
- /* Loop queued messages */
- ListHead = &Port->MsgQueue.ReceiveHead;
- NextEntry = ListHead->Flink;
- while (ListHead != NextEntry)
- {
- /* Get the message */
- Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
- NextEntry = NextEntry->Flink;
-
- /* Free and reinitialize it's list head */
- InitializeListHead(&Message->Entry);
-
- /* Remove it from the port zone */
- LpcpFreeToPortZone(Message, TRUE);
- }
-
- /* Reinitialize the message queue list head */
- InitializeListHead(&Port->MsgQueue.ReceiveHead);
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* Check if we have to free the port entirely */
- if (Destroy)
- {
- /* Check if the semaphore exists */
- if (Port->MsgQueue.Semaphore)
- {
- /* Use the semaphore to find the port queue and free it */
- ExFreePool(CONTAINING_RECORD(Port->MsgQueue.Semaphore,
- LPCP_NONPAGED_PORT_QUEUE,
- Semaphore));
- }
- }
-}
-
-VOID
-NTAPI
-LpcpClosePort(IN PEPROCESS Process OPTIONAL,
- IN PVOID Object,
- IN ACCESS_MASK GrantedAccess,
- IN ULONG ProcessHandleCount,
- IN ULONG SystemHandleCount)
-{
- PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object;
- LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
-
- /* Only Server-side Connection Ports need clean up*/
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
- {
- /* Check the handle count */
- switch (SystemHandleCount)
- {
- /* No handles left */
- case 0:
-
- /* Destroy the port queue */
- LpcpDestroyPortQueue(Port, TRUE);
- break;
-
- /* Last handle remaining */
- case 1:
-
- /* Reset the queue only */
- LpcpDestroyPortQueue(Port, FALSE);
-
- /* More handles remain, do nothing */
- default:
- break;
- }
- }
-}
-
-VOID
-NTAPI
-LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port)
-{
- /* Check if this is a client port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
- {
- /* Check if security is static */
- if (!(Port->Flags & LPCP_SECURITY_DYNAMIC))
- {
- /* Check if we have a token */
- if (Port->StaticSecurity.ClientToken)
- {
- /* Free security */
- SeDeleteClientSecurity(&Port->StaticSecurity);
- }
- }
- }
-}
-
-VOID
-NTAPI
-LpcpDeletePort(IN PVOID ObjectBody)
-{
- LARGE_INTEGER Timeout;
- PETHREAD Thread;
- PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody;
- PLPCP_PORT_OBJECT ConnectionPort;
- PLPCP_MESSAGE Message;
- PLIST_ENTRY ListHead, NextEntry;
- HANDLE Pid;
- CLIENT_DIED_MSG ClientDiedMsg;
- Timeout.QuadPart = -1000000;
- PAGED_CODE();
- LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
-
- /* Check if this is a communication port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT)
- {
- /* Acquire the lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Get the thread */
- Thread = Port->ClientThread;
- if (Thread)
- {
- /* Clear it */
- Port->ClientThread = NULL;
-
- /* Release the lock and dereference */
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(Thread);
- }
- else
- {
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
- }
- }
-
- /* Check if this is a client-side port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
- {
- /* Setup the client died message */
- ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg);
- ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime);
- ClientDiedMsg.h.u2.ZeroInit = LPC_PORT_CLOSED;
- ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime;
-
- /* Send it */
- for (;;)
- {
- /* Send the message */
- if (LpcRequestPort(Port,
- &ClientDiedMsg.h) != STATUS_NO_MEMORY) break;
-
- /* Wait until trying again */
- KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
- }
- }
-
- /* Destroy the port queue */
- LpcpDestroyPortQueue(Port, TRUE);
-
- /* Check if we had a client view */
- if (Port->ClientSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
- Port->ClientSectionBase);
-
- /* Check for a server view */
- if (Port->ServerSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
- Port->ServerSectionBase);
-
- /* Get the connection port */
- ConnectionPort = Port->ConnectionPort;
- if (ConnectionPort)
- {
- /* Get the PID */
- Pid = PsGetCurrentProcessId();
-
- /* Acquire the lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Loop the data lists */
- ListHead = &ConnectionPort->LpcDataInfoChainHead;
- NextEntry = ListHead->Flink;
- while (NextEntry != ListHead)
- {
- /* Get the message */
- Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
- NextEntry = NextEntry->Flink;
-
- /* Check if the PID matches */
- if (Message->Request.ClientId.UniqueProcess == Pid)
- {
- /* Remove it */
- RemoveEntryList(&Message->Entry);
- LpcpFreeToPortZone(Message, TRUE);
- }
- }
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* Dereference the object unless it's the same port */
- if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort);
- }
-
- /* Check if this is a connection port with a server process*/
- if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) &&
- (ConnectionPort->ServerProcess))
- {
- /* Dereference the server process */
- ObDereferenceObject(ConnectionPort->ServerProcess);
- ConnectionPort->ServerProcess = NULL;
- }
-
- /* Free client security */
- LpcpFreePortClientSecurity(Port);
- LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port);
-}
-
-/* EOF */
+++ /dev/null
-/*
-* PROJECT: ReactOS Kernel
-* LICENSE: GPL - See COPYING in the top level directory
-* FILE: ntoskrnl/lpc/complete.c
-* PURPOSE: Local Procedure Call: Connection Completion
-* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
-*/
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-VOID
-NTAPI
-LpcpPrepareToWakeClient(IN PETHREAD Thread)
-{
- PAGED_CODE();
-
- /* Make sure the thread isn't dying and it has a valid chain */
- if (!(Thread->LpcExitThreadCalled) &&
- !(IsListEmpty(&Thread->LpcReplyChain)))
- {
- /* Remove it from the list and reinitialize it */
- RemoveEntryList(&Thread->LpcReplyChain);
- InitializeListHead(&Thread->LpcReplyChain);
- }
-}
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtAcceptConnectPort(OUT PHANDLE PortHandle,
- IN PVOID PortContext OPTIONAL,
- IN PPORT_MESSAGE ReplyMessage,
- IN BOOLEAN AcceptConnection,
- IN PPORT_VIEW ServerView,
- IN PREMOTE_PORT_VIEW ClientView)
-{
- PLPCP_PORT_OBJECT ConnectionPort, ServerPort, ClientPort;
- PVOID ClientSectionToMap = NULL;
- HANDLE Handle;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- NTSTATUS Status;
- ULONG ConnectionInfoLength;
- PLPCP_MESSAGE Message;
- PLPCP_CONNECTION_MESSAGE ConnectMessage;
- PEPROCESS ClientProcess;
- PETHREAD ClientThread;
- LARGE_INTEGER SectionOffset;
- PAGED_CODE();
- LPCTRACE(LPC_COMPLETE_DEBUG,
- "Context: %p. Message: %p. Accept: %lx. Views: %p/%p\n",
- PortContext,
- ReplyMessage,
- AcceptConnection,
- ClientView,
- ServerView);
-
- /* Validate the size of the server view */
- if ((ServerView) && (ServerView->Length != sizeof(PORT_VIEW)))
- {
- /* Invalid size */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Validate the size of the client view */
- if ((ClientView) && (ClientView->Length != sizeof(REMOTE_PORT_VIEW)))
- {
- /* Invalid size */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Get the client process and thread */
- Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
- &ClientProcess,
- &ClientThread);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Acquire the LPC Lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Make sure that the client wants a reply, and this is the right one */
- if (!(ClientThread->LpcReplyMessage) ||
- !(ReplyMessage->MessageId) ||
- (ClientThread->LpcReplyMessageId != ReplyMessage->MessageId))
- {
- /* Not the reply asked for, or no reply wanted, fail */
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(ClientProcess);
- ObDereferenceObject(ClientThread);
- return STATUS_REPLY_MESSAGE_MISMATCH;
- }
-
- /* Now get the message and connection message */
- Message = ClientThread->LpcReplyMessage;
- ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
-
- /* Get the client and connection port as well */
- ClientPort = ConnectMessage->ClientPort;
- ConnectionPort = ClientPort->ConnectionPort;
-
- /* Make sure that the reply is being sent to the proper server process */
- if (ConnectionPort->ServerProcess != PsGetCurrentProcess())
- {
- /* It's not, so fail */
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(ClientProcess);
- ObDereferenceObject(ClientThread);
- return STATUS_REPLY_MESSAGE_MISMATCH;
- }
-
- /* At this point, don't let other accept attempts happen */
- ClientThread->LpcReplyMessage = NULL;
- ClientThread->LpcReplyMessageId = 0;
-
- /* Clear the client port for now as well, then release the lock */
- ConnectMessage->ClientPort = NULL;
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* Get the connection information length */
- ConnectionInfoLength = ReplyMessage->u1.s1.DataLength;
- if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength)
- {
- /* Normalize it since it's too large */
- ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength;
- }
-
- /* Set the sizes of our reply message */
- Message->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
- ConnectionInfoLength;
- Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
- Message->Request.u1.s1.DataLength;
-
- /* Setup the reply message */
- Message->Request.u2.s2.Type = LPC_REPLY;
- Message->Request.u2.s2.DataInfoOffset = 0;
- Message->Request.ClientId = ReplyMessage->ClientId;
- Message->Request.MessageId = ReplyMessage->MessageId;
- Message->Request.ClientViewSize = 0;
- RtlMoveMemory(ConnectMessage + 1, ReplyMessage + 1, ConnectionInfoLength);
-
- /* At this point, if the caller refused the connection, go to cleanup */
- if (!AcceptConnection) goto Cleanup;
-
- /* Otherwise, create the actual port */
- Status = ObCreateObject(PreviousMode,
- LpcPortObjectType,
- NULL,
- PreviousMode,
- NULL,
- sizeof(LPCP_PORT_OBJECT),
- 0,
- 0,
- (PVOID*)&ServerPort);
- if (!NT_SUCCESS(Status)) goto Cleanup;
-
- /* Set it up */
- RtlZeroMemory(ServerPort, sizeof(LPCP_PORT_OBJECT));
- ServerPort->PortContext = PortContext;
- ServerPort->Flags = LPCP_COMMUNICATION_PORT;
- ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength;
- InitializeListHead(&ServerPort->LpcReplyChainHead);
- InitializeListHead(&ServerPort->LpcDataInfoChainHead);
-
- /* Reference the connection port until we're fully setup */
- ObReferenceObject(ConnectionPort);
-
- /* Link the ports together */
- ServerPort->ConnectionPort = ConnectionPort;
- ServerPort->ConnectedPort = ClientPort;
- ClientPort->ConnectedPort = ServerPort;
-
- /* Also set the creator CID */
- ServerPort->Creator = PsGetCurrentThread()->Cid;
- ClientPort->Creator = Message->Request.ClientId;
-
- /* Get the section associated and then clear it, while inside the lock */
- KeAcquireGuardedMutex(&LpcpLock);
- ClientSectionToMap = ConnectMessage->SectionToMap;
- ConnectMessage->SectionToMap = NULL;
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* Now check if there's a client section */
- if (ClientSectionToMap)
- {
- /* Setup the offset */
- SectionOffset.QuadPart = ConnectMessage->ClientView.SectionOffset;
-
- /* Map the section */
- Status = MmMapViewOfSection(ClientSectionToMap,
- PsGetCurrentProcess(),
- &ServerPort->ClientSectionBase,
- 0,
- 0,
- &SectionOffset,
- &ConnectMessage->ClientView.ViewSize,
- ViewUnmap,
- 0,
- PAGE_READWRITE);
-
- /* Update the offset and check for mapping status */
- ConnectMessage->ClientView.SectionOffset = SectionOffset.LowPart;
- if (NT_SUCCESS(Status))
- {
- /* Set the view base */
- ConnectMessage->ClientView.ViewRemoteBase = ServerPort->
- ClientSectionBase;
- }
- else
- {
- /* Otherwise, quit */
- ObDereferenceObject(ServerPort);
- goto Cleanup;
- }
- }
-
- /* Check if there's a server section */
- if (ServerView)
- {
- /* FIXME: TODO */
- ASSERT(FALSE);
- }
-
- /* Reference the server port until it's fully inserted */
- ObReferenceObject(ServerPort);
-
- /* Insert the server port in the namespace */
- Status = ObInsertObject(ServerPort,
- NULL,
- PORT_ALL_ACCESS,
- 0,
- NULL,
- &Handle);
- if (!NT_SUCCESS(Status))
- {
- /* We failed, remove the extra reference and cleanup */
- ObDereferenceObject(ServerPort);
- goto Cleanup;
- }
-
- /* Check if the caller gave a client view */
- if (ClientView)
- {
- /* Fill it out */
- ClientView->ViewBase = ConnectMessage->ClientView.ViewRemoteBase;
- ClientView->ViewSize = ConnectMessage->ClientView.ViewSize;
- }
-
- /* Return the handle to user mode */
- *PortHandle = Handle;
- LPCTRACE(LPC_COMPLETE_DEBUG,
- "Handle: %lx. Messages: %p/%p. Ports: %p/%p/%p\n",
- Handle,
- Message,
- ConnectMessage,
- ServerPort,
- ClientPort,
- ConnectionPort);
-
- /* If there was no port context, use the handle by default */
- if (!PortContext) ServerPort->PortContext = Handle;
- ServerPort->ClientThread = ClientThread;
-
- /* Set this message as the LPC Reply message while holding the lock */
- KeAcquireGuardedMutex(&LpcpLock);
- ClientThread->LpcReplyMessage = Message;
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* Clear the thread pointer so it doesn't get cleaned later */
- ClientThread = NULL;
-
- /* Remove the extra reference we had added */
- ObDereferenceObject(ServerPort);
-
-Cleanup:
- /* If there was a section, dereference it */
- if (ClientSectionToMap) ObDereferenceObject(ClientSectionToMap);
-
- /* Check if we got here while still having a client thread */
- if (ClientThread)
- {
- /* FIXME: Complex cleanup code */
- ASSERT(FALSE);
- }
-
- /* Dereference the client port if we have one, and the process */
- LPCTRACE(LPC_COMPLETE_DEBUG,
- "Status: %lx. Thread: %p. Process: [%.16s]\n",
- Status,
- ClientThread,
- ClientProcess->ImageFileName);
- if (ClientPort) ObDereferenceObject(ClientPort);
- ObDereferenceObject(ClientProcess);
- return Status;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtCompleteConnectPort(IN HANDLE PortHandle)
-{
- NTSTATUS Status;
- PLPCP_PORT_OBJECT Port;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- PETHREAD Thread;
- PAGED_CODE();
- LPCTRACE(LPC_COMPLETE_DEBUG, "Handle: %lx\n", PortHandle);
-
- /* Get the Port Object */
- Status = ObReferenceObjectByHandle(PortHandle,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- PreviousMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Make sure this is a connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
- {
- /* It isn't, fail */
- ObDereferenceObject(Port);
- return STATUS_INVALID_PORT_HANDLE;
- }
-
- /* Acquire the lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Make sure we have a client thread */
- if (!Port->ClientThread)
- {
- /* We don't, fail */
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(Port);
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Get the thread */
- Thread = Port->ClientThread;
-
- /* Make sure it has a reply message */
- if (!Thread->LpcReplyMessage)
- {
- /* It doesn't, fail */
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(Port);
- return STATUS_PORT_DISCONNECTED;
- }
-
- /* Clear the client thread and wake it up */
- Port->ClientThread = NULL;
- LpcpPrepareToWakeClient(Thread);
-
- /* Release the lock and wait for an answer */
- KeReleaseGuardedMutex(&LpcpLock);
- LpcpCompleteWait(&Thread->LpcReplySemaphore);
-
- /* Dereference the Thread and Port and return */
- ObDereferenceObject(Port);
- ObDereferenceObject(Thread);
- LPCTRACE(LPC_COMPLETE_DEBUG, "Port: %p. Thread: %p\n", Port, Thread);
- return Status;
-}
-
-/* EOF */
+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/connect.c
- * PURPOSE: Local Procedure Call: Connection Management
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-PVOID
-NTAPI
-LpcpFreeConMsg(IN OUT PLPCP_MESSAGE *Message,
- IN OUT PLPCP_CONNECTION_MESSAGE *ConnectMessage,
- IN PETHREAD CurrentThread)
-{
- PVOID SectionToMap;
-
- /* Acquire the LPC lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Check if the reply chain is not empty */
- if (!IsListEmpty(&CurrentThread->LpcReplyChain))
- {
- /* Remove this entry and re-initialize it */
- RemoveEntryList(&CurrentThread->LpcReplyChain);
- InitializeListHead(&CurrentThread->LpcReplyChain);
- }
-
- /* Check if there's a reply message */
- if (CurrentThread->LpcReplyMessage)
- {
- /* Get the message */
- *Message = CurrentThread->LpcReplyMessage;
-
- /* Clear message data */
- CurrentThread->LpcReceivedMessageId = 0;
- CurrentThread->LpcReplyMessage = NULL;
-
- /* Get the connection message and clear the section */
- *ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(*Message + 1);
- SectionToMap = (*ConnectMessage)->SectionToMap;
- (*ConnectMessage)->SectionToMap = NULL;
- }
- else
- {
- /* No message to return */
- *Message = NULL;
- SectionToMap = NULL;
- }
-
- /* Release the lock and return the section */
- KeReleaseGuardedMutex(&LpcpLock);
- return SectionToMap;
-}
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtSecureConnectPort(OUT PHANDLE PortHandle,
- IN PUNICODE_STRING PortName,
- IN PSECURITY_QUALITY_OF_SERVICE Qos,
- IN OUT PPORT_VIEW ClientView OPTIONAL,
- IN PSID ServerSid OPTIONAL,
- IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
- OUT PULONG MaxMessageLength OPTIONAL,
- IN OUT PVOID ConnectionInformation OPTIONAL,
- IN OUT PULONG ConnectionInformationLength OPTIONAL)
-{
- ULONG ConnectionInfoLength = 0;
- PLPCP_PORT_OBJECT Port, ClientPort;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- NTSTATUS Status = STATUS_SUCCESS;
- HANDLE Handle;
- PVOID SectionToMap;
- PLPCP_MESSAGE Message;
- PLPCP_CONNECTION_MESSAGE ConnectMessage;
- PETHREAD Thread = PsGetCurrentThread();
- ULONG PortMessageLength;
- LARGE_INTEGER SectionOffset;
- PTOKEN Token;
- PTOKEN_USER TokenUserInfo;
- PAGED_CODE();
- LPCTRACE(LPC_CONNECT_DEBUG,
- "Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n",
- PortName,
- Qos,
- ClientView,
- ServerView,
- ServerSid);
-
- /* Validate client view */
- if ((ClientView) && (ClientView->Length != sizeof(PORT_VIEW)))
- {
- /* Fail */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Validate server view */
- if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW)))
- {
- /* Fail */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Check if caller sent connection information length */
- if (ConnectionInformationLength)
- {
- /* Retrieve the input length */
- ConnectionInfoLength = *ConnectionInformationLength;
- }
-
- /* Get the port */
- Status = ObReferenceObjectByName(PortName,
- 0,
- NULL,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- PreviousMode,
- NULL,
- (PVOID *)&Port);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* This has to be a connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
- {
- /* It isn't, so fail */
- ObDereferenceObject(Port);
- return STATUS_INVALID_PORT_HANDLE;
- }
-
- /* Check if we have a SID */
- if (ServerSid)
- {
- /* Make sure that we have a server */
- if (Port->ServerProcess)
- {
- /* Get its token and query user information */
- Token = PsReferencePrimaryToken(Port->ServerProcess);
- //Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo);
- // FIXME: Need SeQueryInformationToken
- Status = STATUS_SUCCESS;
- TokenUserInfo = ExAllocatePool(PagedPool, sizeof(TOKEN_USER));
- TokenUserInfo->User.Sid = ServerSid;
- PsDereferencePrimaryToken(Token);
-
- /* Check for success */
- if (NT_SUCCESS(Status))
- {
- /* Compare the SIDs */
- if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid))
- {
- /* Fail */
- Status = STATUS_SERVER_SID_MISMATCH;
- }
-
- /* Free token information */
- ExFreePool(TokenUserInfo);
- }
- }
- else
- {
- /* Invalid SID */
- Status = STATUS_SERVER_SID_MISMATCH;
- }
-
- /* Check if SID failed */
- if (!NT_SUCCESS(Status))
- {
- /* Quit */
- ObDereferenceObject(Port);
- return Status;
- }
- }
-
- /* Create the client port */
- Status = ObCreateObject(PreviousMode,
- LpcPortObjectType,
- NULL,
- PreviousMode,
- NULL,
- sizeof(LPCP_PORT_OBJECT),
- 0,
- 0,
- (PVOID *)&ClientPort);
- if (!NT_SUCCESS(Status))
- {
- /* Failed, dereference the server port and return */
- ObDereferenceObject(Port);
- return Status;
- }
-
- /* Setup the client port */
- RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT));
- ClientPort->Flags = LPCP_CLIENT_PORT;
- ClientPort->ConnectionPort = Port;
- ClientPort->MaxMessageLength = Port->MaxMessageLength;
- ClientPort->SecurityQos = *Qos;
- InitializeListHead(&ClientPort->LpcReplyChainHead);
- InitializeListHead(&ClientPort->LpcDataInfoChainHead);
-
- /* Check if we have dynamic security */
- if (Qos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)
- {
- /* Remember that */
- ClientPort->Flags |= LPCP_SECURITY_DYNAMIC;
- }
- else
- {
- /* Create our own client security */
- Status = SeCreateClientSecurity(Thread,
- Qos,
- FALSE,
- &ClientPort->StaticSecurity);
- if (!NT_SUCCESS(Status))
- {
- /* Security failed, dereference and return */
- ObDereferenceObject(ClientPort);
- return Status;
- }
- }
-
- /* Initialize the port queue */
- Status = LpcpInitializePortQueue(ClientPort);
- if (!NT_SUCCESS(Status))
- {
- /* Failed */
- ObDereferenceObject(ClientPort);
- return Status;
- }
-
- /* Check if we have a client view */
- if (ClientView)
- {
- /* Get the section handle */
- Status = ObReferenceObjectByHandle(ClientView->SectionHandle,
- SECTION_MAP_READ |
- SECTION_MAP_WRITE,
- MmSectionObjectType,
- PreviousMode,
- (PVOID*)&SectionToMap,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- ObDereferenceObject(Port);
- return Status;
- }
-
- /* Set the section offset */
- SectionOffset.QuadPart = ClientView->SectionOffset;
-
- /* Map it */
- Status = MmMapViewOfSection(SectionToMap,
- PsGetCurrentProcess(),
- &Port->ClientSectionBase,
- 0,
- 0,
- &SectionOffset,
- &ClientView->ViewSize,
- ViewUnmap,
- 0,
- PAGE_READWRITE);
-
- /* Update the offset */
- ClientView->SectionOffset = SectionOffset.LowPart;
-
- /* Check for failure */
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- ObDereferenceObject(SectionToMap);
- ObDereferenceObject(Port);
- return Status;
- }
-
- /* Update the base */
- ClientView->ViewBase = Port->ClientSectionBase;
- }
- else
- {
- /* No section */
- SectionToMap = NULL;
- }
-
- /* Normalize connection information */
- if (ConnectionInfoLength > Port->MaxConnectionInfoLength)
- {
- /* Use the port's maximum allowed value */
- ConnectionInfoLength = Port->MaxConnectionInfoLength;
- }
-
- /* Allocate a message from the port zone */
- Message = LpcpAllocateFromPortZone();
- if (!Message)
- {
- /* Fail if we couldn't allocate a message */
- if (SectionToMap) ObDereferenceObject(SectionToMap);
- ObDereferenceObject(ClientPort);
- return STATUS_NO_MEMORY;
- }
-
- /* Set pointer to the connection message and fill in the CID */
- ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
- Message->Request.ClientId = Thread->Cid;
-
- /* Check if we have a client view */
- if (ClientView)
- {
- /* Set the view size */
- Message->Request.ClientViewSize = ClientView->ViewSize;
-
- /* Copy the client view and clear the server view */
- RtlMoveMemory(&ConnectMessage->ClientView,
- ClientView,
- sizeof(PORT_VIEW));
- RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW));
- }
- else
- {
- /* Set the size to 0 and clear the connect message */
- Message->Request.ClientViewSize = 0;
- RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE));
- }
-
- /* Set the section and client port. Port is NULL for now */
- ConnectMessage->ClientPort = NULL;
- ConnectMessage->SectionToMap = SectionToMap;
-
- /* Set the data for the connection request message */
- Message->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
- ConnectionInfoLength;
- Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
- Message->Request.u1.s1.DataLength;
- Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST;
-
- /* Check if we have connection information */
- if (ConnectionInformation)
- {
- /* Copy it in */
- RtlMoveMemory(ConnectMessage + 1,
- ConnectionInformation,
- ConnectionInfoLength);
- }
-
- /* Acquire the port lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Check if someone already deleted the port name */
- if (Port->Flags & LPCP_NAME_DELETED)
- {
- /* Fail the request */
- KeReleaseGuardedMutex(&LpcpLock);
- Status = STATUS_OBJECT_NAME_NOT_FOUND;
- goto Cleanup;
- }
-
- /* Associate no thread yet */
- Message->RepliedToThread = NULL;
-
- /* Generate the Message ID and set it */
- Message->Request.MessageId = LpcpNextMessageId++;
- if (!LpcpNextMessageId) LpcpNextMessageId = 1;
- Thread->LpcReplyMessageId = Message->Request.MessageId;
-
- /* Insert the message into the queue and thread chain */
- InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry);
- InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain);
- Thread->LpcReplyMessage = Message;
-
- /* Now we can finally reference the client port and link it*/
- ObReferenceObject(ClientPort);
- ConnectMessage->ClientPort = ClientPort;
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
- LPCTRACE(LPC_CONNECT_DEBUG,
- "Messages: %p/%p. Ports: %p/%p. Status: %lx\n",
- Message,
- ConnectMessage,
- Port,
- ClientPort,
- Status);
-
- /* If this is a waitable port, set the event */
- if (Port->Flags & LPCP_WAITABLE_PORT) KeSetEvent(&Port->WaitEvent,
- 1,
- FALSE);
-
- /* Release the queue semaphore */
- LpcpCompleteWait(Port->MsgQueue.Semaphore);
-
- /* Now wait for a reply */
- LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode);
-
- /* Check if our wait ended in success */
- if (Status != STATUS_SUCCESS) goto Cleanup;
-
- /* Free the connection message */
- SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
-
- /* Check if we got a message back */
- if (Message)
- {
- /* Check for new return length */
- if ((Message->Request.u1.s1.DataLength -
- sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength)
- {
- /* Set new normalized connection length */
- ConnectionInfoLength = Message->Request.u1.s1.DataLength -
- sizeof(LPCP_CONNECTION_MESSAGE);
- }
-
- /* Check if we had connection information */
- if (ConnectionInformation)
- {
- /* Check if we had a length pointer */
- if (ConnectionInformationLength)
- {
- /* Return the length */
- *ConnectionInformationLength = ConnectionInfoLength;
- }
-
- /* Return the connection information */
- RtlMoveMemory(ConnectionInformation,
- ConnectMessage + 1,
- ConnectionInfoLength );
- }
-
- /* Make sure we had a connected port */
- if (ClientPort->ConnectedPort)
- {
- /* Get the message length before the port might get killed */
- PortMessageLength = Port->MaxMessageLength;
-
- /* Insert the client port */
- Status = ObInsertObject(ClientPort,
- NULL,
- PORT_ALL_ACCESS,
- 0,
- (PVOID *)NULL,
- &Handle);
- if (NT_SUCCESS(Status))
- {
- /* Return the handle */
- *PortHandle = Handle;
- LPCTRACE(LPC_CONNECT_DEBUG,
- "Handle: %lx. Length: %lx\n",
- Handle,
- PortMessageLength);
-
- /* Check if maximum length was requested */
- if (MaxMessageLength) *MaxMessageLength = PortMessageLength;
-
- /* Check if we had a client view */
- if (ClientView)
- {
- /* Copy it back */
- RtlMoveMemory(ClientView,
- &ConnectMessage->ClientView,
- sizeof(PORT_VIEW));
- }
-
- /* Check if we had a server view */
- if (ServerView)
- {
- /* Copy it back */
- RtlMoveMemory(ServerView,
- &ConnectMessage->ServerView,
- sizeof(REMOTE_PORT_VIEW));
- }
- }
- }
- else
- {
- /* No connection port, we failed */
- if (SectionToMap) ObDereferenceObject(SectionToMap);
-
- /* Check if it's because the name got deleted */
- if (Port->Flags & LPCP_NAME_DELETED)
- {
- /* Set the correct status */
- Status = STATUS_OBJECT_NAME_NOT_FOUND;
- }
- else
- {
- /* Otherwise, the caller refused us */
- Status = STATUS_PORT_CONNECTION_REFUSED;
- }
-
- /* Kill the port */
- ObDereferenceObject(ClientPort);
- }
-
- /* Free the message */
- LpcpFreeToPortZone(Message, FALSE);
- return Status;
- }
-
- /* No reply message, fail */
- if (SectionToMap) ObDereferenceObject(SectionToMap);
- ObDereferenceObject(ClientPort);
- return STATUS_PORT_CONNECTION_REFUSED;
-
-Cleanup:
- /* We failed, free the message */
- SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
-
- /* Check if the semaphore got signaled */
- if (KeReadStateSemaphore(&Thread->LpcReplySemaphore))
- {
- /* Wait on it */
- KeWaitForSingleObject(&Thread->LpcReplySemaphore,
- KernelMode,
- Executive,
- FALSE,
- NULL);
- }
-
- /* Check if we had a message and free it */
- if (Message) LpcpFreeToPortZone(Message, FALSE);
-
- /* Dereference other objects */
- if (SectionToMap) ObDereferenceObject(SectionToMap);
- ObDereferenceObject(ClientPort);
-
- /* Return status */
- return Status;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtConnectPort(OUT PHANDLE PortHandle,
- IN PUNICODE_STRING PortName,
- IN PSECURITY_QUALITY_OF_SERVICE Qos,
- IN PPORT_VIEW ClientView,
- IN PREMOTE_PORT_VIEW ServerView,
- OUT PULONG MaxMessageLength,
- IN PVOID ConnectionInformation,
- OUT PULONG ConnectionInformationLength)
-{
- /* Call the newer API */
- return NtSecureConnectPort(PortHandle,
- PortName,
- Qos,
- ClientView,
- NULL,
- ServerView,
- MaxMessageLength,
- ConnectionInformation,
- ConnectionInformationLength);
-}
-
-/* EOF */
+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/create.c
- * PURPOSE: Local Procedure Call: Port/Queue/Message Creation
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-NTSTATUS
-NTAPI
-LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
-{
- PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
-
- /* Allocate the queue */
- MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
- sizeof(LPCP_NONPAGED_PORT_QUEUE),
- TAG('P', 'o', 'r', 't'));
- if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
-
- /* Set it up */
- KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
- MessageQueue->BackPointer = Port;
-
- /* And link it with the Paged Pool part */
- Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
- InitializeListHead(&Port->MsgQueue.ReceiveHead);
- return STATUS_SUCCESS;
-}
-
-NTSTATUS
-NTAPI
-LpcpCreatePort(OUT PHANDLE PortHandle,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- IN ULONG MaxConnectionInfoLength,
- IN ULONG MaxMessageLength,
- IN ULONG MaxPoolUsage,
- IN BOOLEAN Waitable)
-{
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- NTSTATUS Status;
- PLPCP_PORT_OBJECT Port;
- LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName);
-
- /* Create the Object */
- Status = ObCreateObject(PreviousMode,
- LpcPortObjectType,
- ObjectAttributes,
- PreviousMode,
- NULL,
- sizeof(LPCP_PORT_OBJECT),
- 0,
- 0,
- (PVOID*)&Port);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Set up the Object */
- RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
- Port->ConnectionPort = Port;
- Port->Creator = PsGetCurrentThread()->Cid;
- InitializeListHead(&Port->LpcDataInfoChainHead);
- InitializeListHead(&Port->LpcReplyChainHead);
-
- /* Check if we don't have a name */
- if (!ObjectAttributes->ObjectName->Buffer)
- {
- /* Set up for an unconnected port */
- Port->Flags = LPCP_UNCONNECTED_PORT;
- Port->ConnectedPort = Port;
- Port->ServerProcess = NULL;
- }
- else
- {
- /* Set up for a named connection port */
- Port->Flags = LPCP_CONNECTION_PORT;
- Port->ServerProcess = PsGetCurrentProcess();
-
- /* Don't let the process die on us */
- ObReferenceObject(Port->ServerProcess);
- }
-
- /* Check if this is a waitable port */
- if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
-
- /* Setup the port queue */
- Status = LpcpInitializePortQueue(Port);
- if (!NT_SUCCESS(Status))
- {
- /* Fail */
- ObDereferenceObject(Port);
- return Status;
- }
-
- /* Check if this is a waitable port */
- if (Port->Flags & LPCP_WAITABLE_PORT)
- {
- /* Setup the wait event */
- KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
- }
-
- /* Set the maximum message size allowed */
- Port->MaxMessageLength = LpcpMaxMessageSize -
- FIELD_OFFSET(LPCP_MESSAGE, Request);
-
- /* Now subtract the actual message structures and get the data size */
- Port->MaxConnectionInfoLength = Port->MaxMessageLength -
- sizeof(PORT_MESSAGE) -
- sizeof(LPCP_CONNECTION_MESSAGE);
-
- /* Validate the sizes */
- if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
- {
- /* Not enough space for your request */
- ObDereferenceObject(Port);
- return STATUS_INVALID_PARAMETER_3;
- }
- else if (Port->MaxMessageLength < MaxMessageLength)
- {
- /* Not enough space for your request */
- ObDereferenceObject(Port);
- return STATUS_INVALID_PARAMETER_4;
- }
-
- /* Now set the custom setting */
- Port->MaxMessageLength = MaxMessageLength;
-
- /* Insert it now */
- Status = ObInsertObject((PVOID)Port,
- NULL,
- PORT_ALL_ACCESS,
- 0,
- NULL,
- PortHandle);
-
- /* Return success or the error */
- LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %lx\n", Port, *PortHandle);
- return Status;
-}
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtCreatePort(OUT PHANDLE PortHandle,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- IN ULONG MaxConnectInfoLength,
- IN ULONG MaxDataLength,
- IN ULONG MaxPoolUsage)
-{
- PAGED_CODE();
-
- /* Call the internal API */
- return LpcpCreatePort(PortHandle,
- ObjectAttributes,
- MaxConnectInfoLength,
- MaxDataLength,
- MaxPoolUsage,
- FALSE);
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtCreateWaitablePort(OUT PHANDLE PortHandle,
- IN POBJECT_ATTRIBUTES ObjectAttributes,
- IN ULONG MaxConnectInfoLength,
- IN ULONG MaxDataLength,
- IN ULONG MaxPoolUsage)
-{
- PAGED_CODE();
-
- /* Call the internal API */
- return LpcpCreatePort(PortHandle,
- ObjectAttributes,
- MaxConnectInfoLength,
- MaxDataLength,
- MaxPoolUsage,
- TRUE);
-}
-
-/* EOF */
+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/listen.c
- * PURPOSE: Local Procedure Call: Listening
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtListenPort(IN HANDLE PortHandle,
- OUT PPORT_MESSAGE ConnectMessage)
-{
- NTSTATUS Status;
- PAGED_CODE();
- LPCTRACE(LPC_LISTEN_DEBUG, "Handle: %lx\n", PortHandle);
-
- /* Wait forever for a connection request. */
- for (;;)
- {
- /* Do the wait */
- Status = NtReplyWaitReceivePort(PortHandle,
- NULL,
- NULL,
- ConnectMessage);
-
- /* Accept only LPC_CONNECTION_REQUEST requests. */
- if ((Status != STATUS_SUCCESS) ||
- (LpcpGetMessageType(ConnectMessage) == LPC_CONNECTION_REQUEST))
- {
- /* Break out */
- break;
- }
- }
-
- /* Return status */
- return Status;
-}
-
-
-/* EOF */
+++ /dev/null
-/*
-* PROJECT: ReactOS Kernel
-* LICENSE: GPL - See COPYING in the top level directory
-* FILE: ntoskrnl/include/lpc.h
-* PURPOSE: Internal header for the Local Procedure Call
-* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
-*/
-
-//
-// Define this if you want debugging support
-//
-#define _LPC_DEBUG_ 0x01
-
-//
-// These define the Debug Masks Supported
-//
-#define LPC_CREATE_DEBUG 0x01
-#define LPC_CLOSE_DEBUG 0x02
-#define LPC_CONNECT_DEBUG 0x04
-#define LPC_LISTEN_DEBUG 0x08
-#define LPC_REPLY_DEBUG 0x10
-#define LPC_COMPLETE_DEBUG 0x20
-#define LPC_SEND_DEBUG 0x40
-
-//
-// Debug/Tracing support
-//
-#if _LPC_DEBUG_
-#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
-#define LPCTRACE(x, ...) \
- { \
- DbgPrintEx("%s [%.16s] - ", \
- __FUNCTION__, \
- PsGetCurrentProcess()->ImageFileName); \
- DbgPrintEx(__VA_ARGS__); \
- }
-#else
-#define LPCTRACE(x, ...) \
- if (x & LpcpTraceLevel) \
- { \
- DbgPrint("%s [%.16s:%lx] - ", \
- __FUNCTION__, \
- PsGetCurrentProcess()->ImageFileName, \
- PsGetCurrentThreadId()); \
- DbgPrint(__VA_ARGS__); \
- }
-#endif
-#endif
-
-//
-// Internal Port Management
-//
-VOID
-NTAPI
-LpcpClosePort(
- IN PEPROCESS Process OPTIONAL,
- IN PVOID Object,
- IN ACCESS_MASK GrantedAccess,
- IN ULONG ProcessHandleCount,
- IN ULONG SystemHandleCount
-);
-
-VOID
-NTAPI
-LpcpDeletePort(
- IN PVOID ObjectBody
-);
-
-NTSTATUS
-NTAPI
-LpcpInitializePortQueue(
- IN PLPCP_PORT_OBJECT Port
-);
-
-VOID
-NTAPI
-LpcpFreeToPortZone(
- IN PLPCP_MESSAGE Message,
- IN ULONG Flags
-);
-
-VOID
-NTAPI
-LpcpMoveMessage(
- IN PPORT_MESSAGE Destination,
- IN PPORT_MESSAGE Origin,
- IN PVOID Data,
- IN ULONG MessageType,
- IN PCLIENT_ID ClientId
-);
-
-VOID
-NTAPI
-LpcpSaveDataInfoMessage(
- IN PLPCP_PORT_OBJECT Port,
- IN PLPCP_MESSAGE Message
-);
-
-//
-// Module-external utlity functions
-//
-VOID
-NTAPI
-LpcExitThread(
- IN PETHREAD Thread
-);
-
-//
-// Initialization functions
-//
-NTSTATUS
-NTAPI
-LpcpInitSystem(
- VOID
-);
-
-//
-// Global data inside the Process Manager
-//
-extern POBJECT_TYPE LpcPortObjectType;
-extern ULONG LpcpNextMessageId, LpcpNextCallbackId;
-extern KGUARDED_MUTEX LpcpLock;
-extern PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
-extern ULONG LpcpMaxMessageSize;
-extern ULONG LpcpTraceLevel;
-
-//
-// Inlined Functions
-//
-#include "lpc_x.h"
+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/port.c
- * PURPOSE: Local Procedure Call: Port Management
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* GLOBALS *******************************************************************/
-
-POBJECT_TYPE LpcPortObjectType;
-ULONG LpcpMaxMessageSize;
-PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
-KGUARDED_MUTEX LpcpLock;
-ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG;
-ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;
-
-static GENERIC_MAPPING LpcpPortMapping =
-{
- STANDARD_RIGHTS_READ,
- STANDARD_RIGHTS_WRITE,
- 0,
- PORT_ALL_ACCESS
-};
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-NTSTATUS
-INIT_FUNCTION
-NTAPI
-LpcpInitSystem(VOID)
-{
- OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
- UNICODE_STRING Name;
-
- /* Setup the LPC Lock */
- KeInitializeGuardedMutex(&LpcpLock);
-
- /* Create the Port Object Type */
- RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
- RtlInitUnicodeString(&Name, L"Port");
- ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
- ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(LPCP_PORT_OBJECT);
- ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(LPCP_NONPAGED_PORT_QUEUE);
- ObjectTypeInitializer.GenericMapping = LpcpPortMapping;
- ObjectTypeInitializer.PoolType = PagedPool;
- ObjectTypeInitializer.UseDefaultObject = TRUE;
- ObjectTypeInitializer.CloseProcedure = LpcpClosePort;
- ObjectTypeInitializer.DeleteProcedure = LpcpDeletePort;
- ObjectTypeInitializer.ValidAccessMask = PORT_ALL_ACCESS;
- ObjectTypeInitializer.MaintainTypeList = TRUE;
- ObCreateObjectType(&Name,
- &ObjectTypeInitializer,
- NULL,
- &LpcPortObjectType);
-
- /* Allocate the LPC lookaside list */
- LpcpMaxMessageSize = LPCP_MAX_MESSAGE_SIZE;
- ExInitializePagedLookasideList(&LpcpMessagesLookaside,
- NULL,
- NULL,
- 0,
- LpcpMaxMessageSize,
- TAG('L', 'p', 'c', 'M'),
- 32);
-
- /* We're done */
- return STATUS_SUCCESS;
-}
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-NTSTATUS
-NTAPI
-NtImpersonateClientOfPort(IN HANDLE PortHandle,
- IN PPORT_MESSAGE ClientMessage)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-NTSTATUS
-NTAPI
-NtQueryPortInformationProcess(VOID)
-{
- /* This is all this function does */
- return STATUS_UNSUCCESSFUL;
-}
-
-NTSTATUS
-NTAPI
-NtQueryInformationPort(IN HANDLE PortHandle,
- IN PORT_INFORMATION_CLASS PortInformationClass,
- OUT PVOID PortInformation,
- IN ULONG PortInformationLength,
- OUT PULONG ReturnLength)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/* EOF */
+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/reply.c
- * PURPOSE: Local Procedure Call: Receive (Replies)
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* PRIVATE FUNCTIONS *********************************************************/
-
-VOID
-NTAPI
-LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
- IN ULONG MessageId,
- IN ULONG CallbackId)
-{
- 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;
- }
-
- /* 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.CallbackId == CallbackId))
- {
- /* Unlink and free it */
- RemoveEntryList(&Message->Entry);
- InitializeListHead(&Message->Entry);
- LpcpFreeToPortZone(Message, TRUE);
- break;
- }
-
- /* Go to the next entry */
- NextEntry = NextEntry->Flink;
- }
-}
-
-VOID
-NTAPI
-LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
- IN PLPCP_MESSAGE Message)
-{
- PAGED_CODE();
-
- /* Acquire the lock */
- 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;
- }
-
- /* Link the message */
- InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-}
-
-VOID
-NTAPI
-LpcpMoveMessage(IN PPORT_MESSAGE Destination,
- IN PPORT_MESSAGE Origin,
- IN PVOID Data,
- IN ULONG MessageType,
- IN PCLIENT_ID ClientId)
-{
- /* 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 */
- RtlMoveMemory(Destination + 1,
- Data,
- ((Destination->u1.Length & 0xFFFF) + 3) &~3);
-}
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-NtReplyPort(IN HANDLE PortHandle,
- IN PPORT_MESSAGE LpcReply)
-{
- 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;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
- NTSTATUS Status;
- PLPCP_MESSAGE Message;
- PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
- PLPCP_CONNECTION_MESSAGE ConnectMessage;
- ULONG ConnectionInfoLength;
- PAGED_CODE();
- LPCTRACE(LPC_REPLY_DEBUG,
- "Handle: %lx. Messages: %p/%p. Context: %p\n",
- PortHandle,
- ReplyMessage,
- ReceiveMessage,
- PortContext);
-
- /* 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 ((ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
- 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 ((ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
- (ReplyMessage->u1.s1.TotalLength <= 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)
- {
- /* Use the connection port */
- ReceivePort = Port->ConnectionPort;
- }
- 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);
- return Status;
- }
-
- /* Allocate a message from the port zone */
- Message = LpcpAllocateFromPortZone();
- if (!Message)
- {
- /* Fail if we couldn't allocate a message */
- 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)
- {
- /* It isn't, fail */
- LpcpFreeToPortZone(Message, TRUE);
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(WakeupThread);
- ObDereferenceObject(Port);
- return STATUS_REPLY_MESSAGE_MISMATCH;
- }
-
- /* Copy the message */
- LpcpMoveMessage(&Message->Request,
- ReplyMessage,
- ReplyMessage + 1,
- LPC_REPLY,
- NULL);
-
- /* Free any data information */
- LpcpFreeDataInfoMessage(Port,
- ReplyMessage->MessageId,
- ReplyMessage->CallbackId);
-
- /* 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;
- }
-
- /* 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);
- 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;
-
- /* Done touching global data, release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* 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 = sizeof(LPCP_MESSAGE) +
- ConnectionInfoLength;
- ReceiveMessage->u1.s1.DataLength = ConnectionInfoLength;
- RtlMoveMemory(ReceiveMessage + 1,
- ConnectMessage + 1,
- ConnectionInfoLength);
-
- /* Clear the port context if the caller requested one */
- if (PortContext) *PortContext = NULL;
- }
- else if (Message->Request.u2.s2.Type != 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);
- Message = NULL;
- }
- }
- else
- {
- /* This is a reply message, should never happen! */
- ASSERT(FALSE);
- }
-
- /* If we have a message pointer here, free it */
- if (Message) LpcpFreeToPortZone(Message, FALSE);
-
-Cleanup:
- /* All done, dereference the port and return the status */
- LPCTRACE(LPC_REPLY_DEBUG,
- "Port: %p. Status: %p\n",
- Port,
- Status);
- 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
-NTAPI
-NtReplyWaitReplyPort(IN HANDLE PortHandle,
- IN PPORT_MESSAGE ReplyMessage)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-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
- */
-NTSTATUS
-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;
-}
-
-/* EOF */
+++ /dev/null
-/*
- * PROJECT: ReactOS Kernel
- * LICENSE: GPL - See COPYING in the top level directory
- * FILE: ntoskrnl/lpc/send.c
- * PURPOSE: Local Procedure Call: Sending (Requests)
- * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
- */
-
-/* INCLUDES ******************************************************************/
-
-#include <ntoskrnl.h>
-#include "lpc.h"
-#define NDEBUG
-#include <internal/debug.h>
-
-/* PUBLIC FUNCTIONS **********************************************************/
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-LpcRequestPort(IN PVOID PortObject,
- IN PPORT_MESSAGE LpcMessage)
-{
- PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject, QueuePort;
- ULONG MessageType;
- PLPCP_MESSAGE Message;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- PAGED_CODE();
- LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage);
-
- /* Check if this is a non-datagram message */
- if (LpcMessage->u2.s2.Type)
- {
- /* Get the message type */
- MessageType = LpcpGetMessageType(LpcMessage);
-
- /* Validate it */
- if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))
- {
- /* Fail */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Mark this as a kernel-mode message only if we really came from there */
- if ((PreviousMode == KernelMode) &&
- (LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))
- {
- /* We did, this is a kernel mode message */
- MessageType |= LPC_KERNELMODE_MESSAGE;
- }
- }
- else
- {
- /* This is a datagram */
- MessageType = LPC_DATAGRAM;
- }
-
- /* Can't have data information on this type of call */
- if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;
-
- /* Validate message sizes */
- if ((LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
- (LpcMessage->u1.s1.TotalLength <= LpcMessage->u1.s1.DataLength))
- {
- /* Fail */
- return STATUS_PORT_MESSAGE_TOO_LONG;
- }
-
- /* Allocate a new message */
- Message = LpcpAllocateFromPortZone();
- if (!Message) return STATUS_NO_MEMORY;
-
- /* Clear the context */
- Message->PortContext = NULL;
-
- /* Copy the message */
- LpcpMoveMessage(&Message->Request,
- LpcMessage,
- LpcMessage + 1,
- MessageType,
- &PsGetCurrentThread()->Cid);
-
- /* Acquire the LPC lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Check if this is anything but a connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
- {
- /* The queue port is the connected port */
- QueuePort = Port->ConnectedPort;
- if (QueuePort)
- {
- /* Check if this is a client port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
- {
- /* Then copy the context */
- Message->PortContext = QueuePort->PortContext;
- QueuePort = Port->ConnectionPort;
- }
- else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
- {
- /* Any other kind of port, use the connection port */
- QueuePort = Port->ConnectionPort;
- }
- }
- }
- else
- {
- /* For connection ports, use the port itself */
- QueuePort = PortObject;
- }
-
- /* Make sure we have a port */
- if (QueuePort)
- {
- /* Generate the Message ID and set it */
- Message->Request.MessageId = LpcpNextMessageId++;
- if (!LpcpNextMessageId) LpcpNextMessageId = 1;
- Message->Request.CallbackId = 0;
-
- /* No Message ID for the thread */
- PsGetCurrentThread()->LpcReplyMessageId = 0;
-
- /* Insert the message in our chain */
- InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
-
- /* Release the lock and release the semaphore */
- KeReleaseGuardedMutex(&LpcpLock);
- LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);
-
- /* If this is a waitable port, wake it up */
- if (QueuePort->Flags & LPCP_WAITABLE_PORT)
- {
- /* Wake it */
- KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
- }
-
- /* We're done */
- LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
- return STATUS_SUCCESS;
- }
-
- /* If we got here, then free the message and fail */
- LpcpFreeToPortZone(Message, TRUE);
- KeReleaseGuardedMutex(&LpcpLock);
- return STATUS_PORT_DISCONNECTED;
-}
-
-/*
-* @unimplemented
-*/
-NTSTATUS
-NTAPI
-LpcRequestWaitReplyPort(IN PVOID Port,
- IN PPORT_MESSAGE LpcMessageRequest,
- OUT PPORT_MESSAGE LpcMessageReply)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @unimplemented
- */
-NTSTATUS
-NTAPI
-NtRequestPort(IN HANDLE PortHandle,
- IN PPORT_MESSAGE LpcMessage)
-{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
-}
-
-/*
- * @implemented
- */
-NTSTATUS
-NTAPI
-NtRequestWaitReplyPort(IN HANDLE PortHandle,
- IN PPORT_MESSAGE LpcRequest,
- IN OUT PPORT_MESSAGE LpcReply)
-{
- PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort;
- KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
- NTSTATUS Status;
- PLPCP_MESSAGE Message;
- PETHREAD Thread = PsGetCurrentThread();
- BOOLEAN Callback;
- PKSEMAPHORE Semaphore;
- ULONG MessageType;
- PAGED_CODE();
- LPCTRACE(LPC_SEND_DEBUG,
- "Handle: %lx. Messages: %p/%p. Type: %lx\n",
- PortHandle,
- LpcRequest,
- LpcReply,
- LpcpGetMessageType(LpcRequest));
-
- /* Check if the thread is dying */
- if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;
-
- /* Check if this is an LPC Request */
- if (LpcpGetMessageType(LpcRequest) == LPC_REQUEST)
- {
- /* Then it's a callback */
- Callback = TRUE;
- }
- else if (LpcpGetMessageType(LpcRequest))
- {
- /* This is a not kernel-mode message */
- return STATUS_INVALID_PARAMETER;
- }
- else
- {
- /* This is a kernel-mode message without a callback */
- LpcRequest->u2.s2.Type |= LPC_REQUEST;
- Callback = FALSE;
- }
-
- /* Get the message type */
- MessageType = LpcRequest->u2.s2.Type;
-
- /* Validate the length */
- if ((LpcRequest->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
- LpcRequest->u1.s1.TotalLength)
- {
- /* Fail */
- return STATUS_INVALID_PARAMETER;
- }
-
- /* Reference the object */
- Status = ObReferenceObjectByHandle(PortHandle,
- 0,
- LpcPortObjectType,
- PreviousMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status)) return Status;
-
- /* Validate the message length */
- if ((LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
- (LpcRequest->u1.s1.TotalLength <= LpcRequest->u1.s1.DataLength))
- {
- /* Fail */
- ObDereferenceObject(Port);
- return STATUS_PORT_MESSAGE_TOO_LONG;
- }
-
- /* Allocate a message from the port zone */
- Message = LpcpAllocateFromPortZone();
- if (!Message)
- {
- /* Fail if we couldn't allocate a message */
- ObDereferenceObject(Port);
- return STATUS_NO_MEMORY;
- }
-
- /* Check if this is a callback */
- if (Callback)
- {
- /* FIXME: TODO */
- Semaphore = NULL; // we'd use the Thread Semaphore here
- ASSERT(FALSE);
- }
- else
- {
- /* No callback, just copy the message */
- LpcpMoveMessage(&Message->Request,
- LpcRequest,
- LpcRequest + 1,
- MessageType,
- &Thread->Cid);
-
- /* Acquire the LPC lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Right now clear the port context */
- Message->PortContext = NULL;
-
- /* Check if this is a not connection port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
- {
- /* We want the connected port */
- QueuePort = Port->ConnectedPort;
- if (!QueuePort)
- {
- /* We have no connected port, fail */
- LpcpFreeToPortZone(Message, TRUE);
- KeReleaseGuardedMutex(&LpcpLock);
- ObDereferenceObject(Port);
- return STATUS_PORT_DISCONNECTED;
- }
-
- /* This will be the rundown port */
- ReplyPort = QueuePort;
-
- /* Check if this is a communication port */
- if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
- {
- /* Copy the port context and use the connection port */
- Message->PortContext = ReplyPort->PortContext;
- QueuePort = Port->ConnectionPort;
- }
- else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
- LPCP_COMMUNICATION_PORT)
- {
- /* Use the connection port for anything but communication ports */
- QueuePort = Port->ConnectionPort;
- }
- }
- else
- {
- /* Otherwise, for a connection port, use the same port object */
- QueuePort = ReplyPort = Port;
- }
-
- /* No reply thread */
- Message->RepliedToThread = NULL;
-
- /* Generate the Message ID and set it */
- Message->Request.MessageId = LpcpNextMessageId++;
- if (!LpcpNextMessageId) LpcpNextMessageId = 1;
- Message->Request.CallbackId = 0;
-
- /* Set the message ID for our thread now */
- Thread->LpcReplyMessageId = Message->Request.MessageId;
- Thread->LpcReplyMessage = NULL;
-
- /* Insert the message in our chain */
- InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
- InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
-
- /* Release the lock and get the semaphore we'll use later */
- KeReleaseGuardedMutex(&LpcpLock);
- Semaphore = QueuePort->MsgQueue.Semaphore;
-
- /* If this is a waitable port, wake it up */
- if (QueuePort->Flags & LPCP_WAITABLE_PORT)
- {
- /* Wake it */
- KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
- }
- }
-
- /* Now release the semaphore */
- LpcpCompleteWait(Semaphore);
-
- /* And let's wait for the reply */
- LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);
-
- /* Acquire the LPC lock */
- KeAcquireGuardedMutex(&LpcpLock);
-
- /* Get the LPC Message and clear our thread's reply data */
- Message = Thread->LpcReplyMessage;
- Thread->LpcReplyMessage = NULL;
- Thread->LpcReplyMessageId = 0;
-
- /* Check if we have anything on the reply chain*/
- if (!IsListEmpty(&Thread->LpcReplyChain))
- {
- /* Remove this thread and reinitialize the list */
- RemoveEntryList(&Thread->LpcReplyChain);
- InitializeListHead(&Thread->LpcReplyChain);
- }
-
- /* Release the lock */
- KeReleaseGuardedMutex(&LpcpLock);
-
- /* Check if we got a reply */
- if (Status == STATUS_SUCCESS)
- {
- /* Check if we have a valid message */
- if (Message)
- {
- LPCTRACE(LPC_SEND_DEBUG,
- "Reply Messages: %p/%p\n",
- &Message->Request,
- (&Message->Request) + 1);
-
- /* Move the message */
- LpcpMoveMessage(LpcReply,
- &Message->Request,
- (&Message->Request) + 1,
- 0,
- NULL);
-
- /* Check if this is an LPC request with data information */
- if ((LpcpGetMessageType(&Message->Request) == LPC_REQUEST) &&
- (Message->Request.u2.s2.DataInfoOffset))
- {
- /* Save the data information */
- LpcpSaveDataInfoMessage(Port, Message);
- }
- else
- {
- /* Otherwise, just free it */
- LpcpFreeToPortZone(Message, FALSE);
- }
- }
- else
- {
- /* We don't have a reply */
- Status = STATUS_LPC_REPLY_LOST;
- }
- }
- else
- {
- /* The wait failed, free the message while holding the lock */
- KeAcquireGuardedMutex(&LpcpLock);
- LpcpFreeToPortZone(Message, TRUE);
- KeReleaseGuardedMutex(&LpcpLock);
- }
-
- /* All done */
- LPCTRACE(LPC_SEND_DEBUG,
- "Port: %p. Status: %p\n",
- Port,
- Status);
- ObDereferenceObject(Port);
- return Status;
-}
-
-/* EOF */
-/* $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/port.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * PURPOSE: Local Procedure Call: Port Management
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-#if defined (ALLOC_PRAGMA)
-#pragma alloc_text(INIT, LpcpInitSystem)
-#endif
-
-
/* GLOBALS *******************************************************************/
-POBJECT_TYPE LpcPortObjectType = 0;
-ULONG LpcpNextMessageId = 0; /* 0 is not a valid ID */
-FAST_MUTEX LpcpLock; /* global internal sync in LPC facility */
+POBJECT_TYPE LpcPortObjectType;
+ULONG LpcpMaxMessageSize;
+PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
+KGUARDED_MUTEX LpcpLock;
+ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG;
+ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;
static GENERIC_MAPPING LpcpPortMapping =
{
PORT_ALL_ACCESS
};
-/* FUNCTIONS *****************************************************************/
-
+/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUS
INIT_FUNCTION
NTAPI
-LpcpInitSystem (VOID)
+LpcpInitSystem(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
- DPRINT("Creating Port Object Type\n");
-
+ /* Setup the LPC Lock */
+ KeInitializeGuardedMutex(&LpcpLock);
+
/* Create the Port Object Type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Port");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
- ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EPORT);
+ ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(LPCP_PORT_OBJECT);
+ ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(LPCP_NONPAGED_PORT_QUEUE);
ObjectTypeInitializer.GenericMapping = LpcpPortMapping;
- ObjectTypeInitializer.PoolType = NonPagedPool;
+ ObjectTypeInitializer.PoolType = PagedPool;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.CloseProcedure = LpcpClosePort;
ObjectTypeInitializer.DeleteProcedure = LpcpDeletePort;
ObjectTypeInitializer.ValidAccessMask = PORT_ALL_ACCESS;
- ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &LpcPortObjectType);
-
- LpcpNextMessageId = 0;
- ExInitializeFastMutex (& LpcpLock);
-
- return(STATUS_SUCCESS);
-}
-
-
-/**********************************************************************
- * NAME INTERNAL
- * NiInitializePort/3
- *
- * DESCRIPTION
- * Initialize the EPORT object attributes. The Port
- * object enters the inactive state.
- *
- * ARGUMENTS
- * Port Pointer to an EPORT object to initialize.
- * Type connect (RQST), or communication port (COMM)
- * Parent OPTIONAL connect port a communication port
- * is created from
- *
- * RETURN VALUE
- * STATUS_SUCCESS if initialization succedeed. An error code
- * otherwise.
- */
-NTSTATUS STDCALL
-LpcpInitializePort (IN OUT PEPORT Port,
- IN USHORT Type,
- IN PEPORT Parent OPTIONAL)
-{
- if ((Type != EPORT_TYPE_SERVER_RQST_PORT) &&
- (Type != EPORT_TYPE_SERVER_COMM_PORT) &&
- (Type != EPORT_TYPE_CLIENT_COMM_PORT))
- {
- return STATUS_INVALID_PARAMETER_2;
- }
- memset (Port, 0, sizeof(EPORT));
- KeInitializeSpinLock (& Port->Lock);
- KeInitializeSemaphore( &Port->Semaphore, 0, MAXLONG );
- Port->RequestPort = Parent;
- Port->OtherPort = NULL;
- Port->QueueLength = 0;
- Port->ConnectQueueLength = 0;
- Port->Type = Type;
- Port->State = EPORT_INACTIVE;
- InitializeListHead (& Port->QueueListHead);
- InitializeListHead (& Port->ConnectQueueListHead);
-
- return (STATUS_SUCCESS);
+ ObjectTypeInitializer.MaintainTypeList = TRUE;
+ ObCreateObjectType(&Name,
+ &ObjectTypeInitializer,
+ NULL,
+ &LpcPortObjectType);
+
+ /* Allocate the LPC lookaside list */
+ LpcpMaxMessageSize = LPCP_MAX_MESSAGE_SIZE;
+ ExInitializePagedLookasideList(&LpcpMessagesLookaside,
+ NULL,
+ NULL,
+ 0,
+ LpcpMaxMessageSize,
+ TAG('L', 'p', 'c', 'M'),
+ 32);
+
+ /* We're done */
+ return STATUS_SUCCESS;
}
+/* PUBLIC FUNCTIONS **********************************************************/
-/* MISCELLANEA SYSTEM SERVICES */
-
-
-/**********************************************************************
- * NAME SYSTEM
- * NtImpersonateClientOfPort/2
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- * PortHandle,
- * ClientMessage
- *
- * RETURN VALUE
- */
-NTSTATUS STDCALL
-NtImpersonateClientOfPort (HANDLE PortHandle,
- PPORT_MESSAGE ClientMessage)
+NTSTATUS
+NTAPI
+NtImpersonateClientOfPort(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE ClientMessage)
{
- UNIMPLEMENTED;
- return(STATUS_NOT_IMPLEMENTED);
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
return STATUS_UNSUCCESSFUL;
}
+NTSTATUS
+NTAPI
+NtQueryInformationPort(IN HANDLE PortHandle,
+ IN PORT_INFORMATION_CLASS PortInformationClass,
+ OUT PVOID PortInformation,
+ IN ULONG PortInformationLength,
+ OUT PULONG ReturnLength)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
/* EOF */
+++ /dev/null
-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/lpc/query.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
- */
-
-/* INCLUDES *****************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <internal/debug.h>
-
-/* FUNCTIONS *****************************************************************/
-
-/**********************************************************************
- * NAME EXPORTED
- * NtQueryInformationPort@20
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- * PortHandle [IN]
- * PortInformationClass [IN]
- * PortInformation [OUT]
- * PortInformationLength [IN]
- * ReturnLength [OUT]
- *
- * RETURN VALUE
- * STATUS_SUCCESS if the call succedeed. An error code
- * otherwise.
- *
- * NOTES
- * P. Dabak reports that this system service seems to return
- * no information.
- */
-/*EXPORTED*/ NTSTATUS STDCALL
-NtQueryInformationPort (IN HANDLE PortHandle,
- IN PORT_INFORMATION_CLASS PortInformationClass,
- OUT PVOID PortInformation,
- IN ULONG PortInformationLength,
- OUT PULONG ReturnLength)
-{
- NTSTATUS Status;
- PEPORT Port;
-
- Status = ObReferenceObjectByHandle (PortHandle,
- PORT_ALL_ACCESS, /* AccessRequired */
- LpcPortObjectType,
- UserMode,
- (PVOID *) & Port,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NtQueryInformationPort() = %x\n", Status);
- return (Status);
- }
- /*
- * FIXME: NT does nothing here!
- */
- ObDereferenceObject (Port);
- return STATUS_SUCCESS;
-}
-
-
-/* EOF */
+++ /dev/null
-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/lpc/queue.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
- */
-
-/* INCLUDES *****************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <internal/debug.h>
-
-/* FUNCTIONS *****************************************************************/
-
-VOID STDCALL
-EiEnqueueMessagePort (IN OUT PEPORT Port,
- IN PQUEUEDMESSAGE Message)
-{
- InsertTailList (&Port->QueueListHead,
- &Message->QueueListEntry);
- Port->QueueLength++;
-}
-
-VOID STDCALL
-EiEnqueueMessageAtHeadPort (IN OUT PEPORT Port,
- IN PQUEUEDMESSAGE Message)
-{
- InsertTailList (&Port->QueueListHead,
- &Message->QueueListEntry);
- Port->QueueLength++;
-}
-
-PQUEUEDMESSAGE STDCALL
-EiDequeueMessagePort (IN OUT PEPORT Port)
-{
- PQUEUEDMESSAGE Message;
- PLIST_ENTRY entry;
-
- if (IsListEmpty(&Port->QueueListHead))
- {
- return(NULL);
- }
- entry = RemoveHeadList (&Port->QueueListHead);
- Message = CONTAINING_RECORD (entry, QUEUEDMESSAGE, QueueListEntry);
- Port->QueueLength--;
-
- return (Message);
-}
-
-
-VOID STDCALL
-EiEnqueueConnectMessagePort (IN OUT PEPORT Port,
- IN PQUEUEDMESSAGE Message)
-{
- InsertTailList (&Port->ConnectQueueListHead,
- &Message->QueueListEntry);
- Port->ConnectQueueLength++;
-}
-
-
-PQUEUEDMESSAGE STDCALL
-EiDequeueConnectMessagePort (IN OUT PEPORT Port)
-{
- PQUEUEDMESSAGE Message;
- PLIST_ENTRY entry;
-
- if (IsListEmpty(&Port->ConnectQueueListHead))
- {
- return(NULL);
- }
- entry = RemoveHeadList (&Port->ConnectQueueListHead);
- Message = CONTAINING_RECORD (entry, QUEUEDMESSAGE, QueueListEntry);
- Port->ConnectQueueLength--;
-
- return (Message);
-}
-
-
-/* EOF */
+++ /dev/null
-/* $Id$
- *
- * COPYRIGHT: See COPYING in the top level directory
- * PROJECT: ReactOS kernel
- * FILE: ntoskrnl/lpc/receive.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
- */
-
-/* INCLUDES *****************************************************************/
-
-#include <ntoskrnl.h>
-#define NDEBUG
-#include <internal/debug.h>
-
-/* FUNCTIONS *****************************************************************/
-
-/**********************************************************************
- * NAME SYSTEM
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- */
-NTSTATUS STDCALL
-NtReadRequestData (HANDLE PortHandle,
- PPORT_MESSAGE Message,
- ULONG Index,
- PVOID Buffer,
- ULONG BufferLength,
- PULONG Returnlength)
-{
- UNIMPLEMENTED;
- return(STATUS_NOT_IMPLEMENTED);
-}
-
-
-/* EOF */
-/* $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>
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-/* GLOBALS *******************************************************************/
+/* PRIVATE FUNCTIONS *********************************************************/
-/* FUNCTIONS *****************************************************************/
+VOID
+NTAPI
+LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
+ IN ULONG MessageId,
+ IN ULONG CallbackId)
+{
+ 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;
+ }
+
+ /* 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.CallbackId == CallbackId))
+ {
+ /* Unlink and free it */
+ RemoveEntryList(&Message->Entry);
+ InitializeListHead(&Message->Entry);
+ LpcpFreeToPortZone(Message, TRUE);
+ break;
+ }
+
+ /* Go to the next entry */
+ NextEntry = NextEntry->Flink;
+ }
+}
-/**********************************************************************
- * NAME
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- */
-NTSTATUS STDCALL
-EiReplyOrRequestPort (IN PEPORT Port,
- IN PPORT_MESSAGE LpcReply,
- IN ULONG MessageType,
- IN PEPORT Sender)
+VOID
+NTAPI
+LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
+ IN PLPCP_MESSAGE Message)
{
- KIRQL oldIrql;
- PQUEUEDMESSAGE MessageReply;
- ULONG Size;
-
- if (Port == NULL)
- {
- KEBUGCHECK(0);
- }
-
- Size = sizeof(QUEUEDMESSAGE);
- if (LpcReply && LpcReply->u1.s1.TotalLength > (CSHORT)sizeof(PORT_MESSAGE))
- {
- Size += LpcReply->u1.s1.TotalLength - sizeof(PORT_MESSAGE);
- }
- MessageReply = ExAllocatePoolWithTag(NonPagedPool, Size,
- TAG_LPC_MESSAGE);
- MessageReply->Sender = Sender;
-
- if (LpcReply != NULL)
- {
- memcpy(&MessageReply->Message, LpcReply, LpcReply->u1.s1.TotalLength);
- }
- else
- {
- MessageReply->Message.u1.s1.TotalLength = sizeof(PORT_MESSAGE);
- MessageReply->Message.u1.s1.DataLength = 0;
- }
-
- MessageReply->Message.ClientId.UniqueProcess = PsGetCurrentProcessId();
- MessageReply->Message.ClientId.UniqueThread = PsGetCurrentThreadId();
- MessageReply->Message.u2.s2.Type = (CSHORT)MessageType;
- MessageReply->Message.MessageId = InterlockedIncrementUL(&LpcpNextMessageId);
-
- KeAcquireSpinLock(&Port->Lock, &oldIrql);
- EiEnqueueMessagePort(Port, MessageReply);
- KeReleaseSpinLock(&Port->Lock, oldIrql);
-
- return(STATUS_SUCCESS);
+ PAGED_CODE();
+
+ /* Acquire the lock */
+ 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;
+ }
+
+ /* Link the message */
+ InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
}
+VOID
+NTAPI
+LpcpMoveMessage(IN PPORT_MESSAGE Destination,
+ IN PPORT_MESSAGE Origin,
+ IN PVOID Data,
+ IN ULONG MessageType,
+ IN PCLIENT_ID ClientId)
+{
+ /* 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 */
+ RtlMoveMemory(Destination + 1,
+ Data,
+ ((Destination->u1.Length & 0xFFFF) + 3) &~3);
+}
+
+/* PUBLIC FUNCTIONS **********************************************************/
-/**********************************************************************
- * NAME EXPORTED
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
+/*
+ * @unimplemented
*/
-NTSTATUS STDCALL
-NtReplyPort (IN HANDLE PortHandle,
- IN PPORT_MESSAGE LpcReply)
+NTSTATUS
+NTAPI
+NtReplyPort(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE LpcReply)
{
- 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);
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
-
-/**********************************************************************
- * NAME EXPORTED
- * NtReplyWaitReceivePortEx
- *
- * DESCRIPTION
- * Can be used with waitable ports.
- * Present only in w2k+.
- *
- * ARGUMENTS
- * PortHandle
- * PortId
- * LpcReply
- * LpcMessage
- * Timeout
- *
- * RETURN VALUE
- *
- * REVISIONS
+/*
+ * @implemented
*/
-NTSTATUS STDCALL
+NTSTATUS
+NTAPI
NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
OUT PVOID *PortContext OPTIONAL,
IN PPORT_MESSAGE ReplyMessage OPTIONAL,
OUT PPORT_MESSAGE ReceiveMessage,
- IN PLARGE_INTEGER Timeout OPTIONAL)
+ IN PLARGE_INTEGER Timeout OPTIONAL)
{
- PEPORT Port;
- KIRQL oldIrql;
- PQUEUEDMESSAGE Request;
- BOOLEAN Disconnected;
- LARGE_INTEGER to;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
-
- PreviousMode = ExGetPreviousMode();
-
- DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
- "LpcMessage %x)\n", PortHandle, ReplyMessage, ReceiveMessage);
-
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite(ReceiveMessage,
- sizeof(PORT_MESSAGE),
- 1);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
-
- 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 (ReplyMessage != NULL && !Disconnected)
- {
- Status = EiReplyOrRequestPort(Port->OtherPort,
- ReplyMessage,
- 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 == NULL)
- {
- ObDereferenceObject(Port);
- return STATUS_UNSUCCESSFUL;
- }
-
- if (Request->Message.u2.s2.Type == LPC_CONNECTION_REQUEST)
- {
- PORT_MESSAGE Header;
- PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
-
- CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)&Request->Message;
- memcpy(&Header, &Request->Message, sizeof(PORT_MESSAGE));
- Header.u1.s1.DataLength = (CSHORT)CRequest->ConnectDataLength;
- Header.u1.s1.TotalLength = Header.u1.s1.DataLength + sizeof(PORT_MESSAGE);
-
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite((PVOID)(ReceiveMessage + 1),
- CRequest->ConnectDataLength,
- 1);
-
- RtlCopyMemory(ReceiveMessage,
- &Header,
- sizeof(PORT_MESSAGE));
- RtlCopyMemory((PVOID)(ReceiveMessage + 1),
- CRequest->ConnectData,
- CRequest->ConnectDataLength);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- else
- {
- RtlCopyMemory(ReceiveMessage,
- &Header,
- sizeof(PORT_MESSAGE));
- RtlCopyMemory((PVOID)(ReceiveMessage + 1),
- CRequest->ConnectData,
- CRequest->ConnectDataLength);
- }
- }
- else
- {
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForWrite(ReceiveMessage,
- Request->Message.u1.s1.TotalLength,
- 1);
-
- RtlCopyMemory(ReceiveMessage,
- &Request->Message,
- Request->Message.u1.s1.TotalLength);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- else
- {
- RtlCopyMemory(ReceiveMessage,
- &Request->Message,
- Request->Message.u1.s1.TotalLength);
- }
- }
- 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.u2.s2.Type == 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);
+ PLPCP_PORT_OBJECT Port, ReceivePort;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
+ NTSTATUS Status;
+ PLPCP_MESSAGE Message;
+ PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
+ PLPCP_CONNECTION_MESSAGE ConnectMessage;
+ ULONG ConnectionInfoLength;
+ PAGED_CODE();
+ LPCTRACE(LPC_REPLY_DEBUG,
+ "Handle: %lx. Messages: %p/%p. Context: %p\n",
+ PortHandle,
+ ReplyMessage,
+ ReceiveMessage,
+ PortContext);
+
+ /* 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 ((ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
+ 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 ((ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
+ (ReplyMessage->u1.s1.TotalLength <= 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)
+ {
+ /* Use the connection port */
+ ReceivePort = Port->ConnectionPort;
+ }
+ 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);
+ return Status;
+ }
+
+ /* Allocate a message from the port zone */
+ Message = LpcpAllocateFromPortZone();
+ if (!Message)
+ {
+ /* Fail if we couldn't allocate a message */
+ 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)
+ {
+ /* It isn't, fail */
+ LpcpFreeToPortZone(Message, TRUE);
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(WakeupThread);
+ ObDereferenceObject(Port);
+ return STATUS_REPLY_MESSAGE_MISMATCH;
+ }
+
+ /* Copy the message */
+ LpcpMoveMessage(&Message->Request,
+ ReplyMessage,
+ ReplyMessage + 1,
+ LPC_REPLY,
+ NULL);
+
+ /* Free any data information */
+ LpcpFreeDataInfoMessage(Port,
+ ReplyMessage->MessageId,
+ ReplyMessage->CallbackId);
+
+ /* 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;
+ }
+
+ /* 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);
+ 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;
+
+ /* Done touching global data, release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* 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 = sizeof(LPCP_MESSAGE) +
+ ConnectionInfoLength;
+ ReceiveMessage->u1.s1.DataLength = ConnectionInfoLength;
+ RtlMoveMemory(ReceiveMessage + 1,
+ ConnectMessage + 1,
+ ConnectionInfoLength);
+
+ /* Clear the port context if the caller requested one */
+ if (PortContext) *PortContext = NULL;
+ }
+ else if (Message->Request.u2.s2.Type != 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);
+ Message = NULL;
+ }
+ }
+ else
+ {
+ /* This is a reply message, should never happen! */
+ ASSERT(FALSE);
+ }
+
+ /* If we have a message pointer here, free it */
+ if (Message) LpcpFreeToPortZone(Message, FALSE);
+
+Cleanup:
+ /* All done, dereference the port and return the status */
+ LPCTRACE(LPC_REPLY_DEBUG,
+ "Port: %p. Status: %p\n",
+ Port,
+ Status);
+ ObDereferenceObject(Port);
+ return Status;
}
-
-/**********************************************************************
- * NAME EXPORTED
- * NtReplyWaitReceivePort
- *
- * DESCRIPTION
- * Can be used with waitable ports.
- *
- * ARGUMENTS
- * PortHandle
- * PortId
- * LpcReply
- * LpcMessage
- *
- * RETURN VALUE
- *
- * REVISIONS
+/*
+ * @implemented
*/
-NTSTATUS STDCALL
+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);
+ PortContext,
+ ReplyMessage,
+ ReceiveMessage,
+ NULL);
}
-/**********************************************************************
- * NAME
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
+/*
+ * @unimplemented
*/
-NTSTATUS STDCALL
-NtReplyWaitReplyPort (HANDLE PortHandle,
- PPORT_MESSAGE ReplyMessage)
+NTSTATUS
+NTAPI
+NtReplyWaitReplyPort(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE ReplyMessage)
{
- UNIMPLEMENTED;
- return(STATUS_NOT_IMPLEMENTED);
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
/*
- * @implemented
+ * @unimplemented
*/
NTSTATUS
NTAPI
-LpcRequestWaitReplyPort(IN PVOID Port,
- IN PPORT_MESSAGE LpcMessageRequest,
- OUT PPORT_MESSAGE LpcMessageReply)
+NtReadRequestData(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE Message,
+ IN ULONG Index,
+ IN PVOID Buffer,
+ IN ULONG BufferLength,
+ OUT PULONG Returnlength)
{
- HANDLE PortHandle;
- NTSTATUS Status;
- UNICODE_STRING PortName;
- ULONG ConnectInfoLength;
-
- //
- // OMG HAXX!
- //
- RtlInitUnicodeString(&PortName, L"\\Windows\\ApiPort");
- ConnectInfoLength = 0;
- Status = ZwConnectPort(&PortHandle,
- &PortName,
- NULL,
- NULL,
- NULL,
- NULL,
- NULL,
- &ConnectInfoLength);
-
- Status = ZwRequestWaitReplyPort(PortHandle,
- LpcMessageRequest,
- LpcMessageReply);
-
- /* Close the handle */
- ObCloseHandle(PortHandle, KernelMode);
- return Status;
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
+
+/*
+ * @unimplemented
+ */
+NTSTATUS
+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;
}
/* EOF */
-/* $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/send.c
- * PURPOSE: Communication mechanism
- *
- * PROGRAMMERS: David Welch (welch@cwcom.net)
+ * PURPOSE: Local Procedure Call: Sending (Requests)
+ * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
-/* INCLUDES *****************************************************************/
+/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
-
+#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
-/**********************************************************************
- * NAME
- * LpcRequestPort/2
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- * 2002-03-01 EA
- * I investigated this function a bit more in depth.
- * It looks like the legal values for the MessageType field in the
- * message to send are in the range LPC_NEW_MESSAGE .. LPC_CLIENT_DIED,
- * but LPC_DATAGRAM is explicitly forbidden.
- *
+/* PUBLIC FUNCTIONS **********************************************************/
+
+/*
* @implemented
*/
-NTSTATUS STDCALL LpcRequestPort (IN PVOID PortObject,
- IN PPORT_MESSAGE LpcMessage)
+NTSTATUS
+NTAPI
+LpcRequestPort(IN PVOID PortObject,
+ IN PPORT_MESSAGE LpcMessage)
{
- NTSTATUS Status;
- PEPORT Port = (PEPORT)PortObject;
-
- DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage);
-
-#ifdef __USE_NT_LPC__
- /* Check the message's type */
- if (LPC_NEW_MESSAGE == LpcMessage->u2.s2.Type)
- {
- LpcMessage->u2.s2.Type = LPC_DATAGRAM;
- }
- else if (LPC_DATAGRAM == LpcMessage->u2.s2.Type)
- {
- return STATUS_INVALID_PARAMETER;
- }
- else if (LpcMessage->u2.s2.Type > LPC_CLIENT_DIED)
- {
- return STATUS_INVALID_PARAMETER;
- }
- /* Check the range offset */
- if (0 != LpcMessage->VirtualRangesOffset)
- {
- return STATUS_INVALID_PARAMETER;
- }
-#endif
-
- Status = EiReplyOrRequestPort(Port,
- LpcMessage,
- LPC_DATAGRAM,
- Port);
- KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );
-
- return(Status);
+ PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject, QueuePort;
+ ULONG MessageType;
+ PLPCP_MESSAGE Message;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ PAGED_CODE();
+ LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage);
+
+ /* Check if this is a non-datagram message */
+ if (LpcMessage->u2.s2.Type)
+ {
+ /* Get the message type */
+ MessageType = LpcpGetMessageType(LpcMessage);
+
+ /* Validate it */
+ if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))
+ {
+ /* Fail */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Mark this as a kernel-mode message only if we really came from there */
+ if ((PreviousMode == KernelMode) &&
+ (LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))
+ {
+ /* We did, this is a kernel mode message */
+ MessageType |= LPC_KERNELMODE_MESSAGE;
+ }
+ }
+ else
+ {
+ /* This is a datagram */
+ MessageType = LPC_DATAGRAM;
+ }
+
+ /* Can't have data information on this type of call */
+ if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;
+
+ /* Validate message sizes */
+ if ((LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
+ (LpcMessage->u1.s1.TotalLength <= LpcMessage->u1.s1.DataLength))
+ {
+ /* Fail */
+ return STATUS_PORT_MESSAGE_TOO_LONG;
+ }
+
+ /* Allocate a new message */
+ Message = LpcpAllocateFromPortZone();
+ if (!Message) return STATUS_NO_MEMORY;
+
+ /* Clear the context */
+ Message->PortContext = NULL;
+
+ /* Copy the message */
+ LpcpMoveMessage(&Message->Request,
+ LpcMessage,
+ LpcMessage + 1,
+ MessageType,
+ &PsGetCurrentThread()->Cid);
+
+ /* Acquire the LPC lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Check if this is anything but a connection port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
+ {
+ /* The queue port is the connected port */
+ QueuePort = Port->ConnectedPort;
+ if (QueuePort)
+ {
+ /* Check if this is a client port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
+ {
+ /* Then copy the context */
+ Message->PortContext = QueuePort->PortContext;
+ QueuePort = Port->ConnectionPort;
+ }
+ else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
+ {
+ /* Any other kind of port, use the connection port */
+ QueuePort = Port->ConnectionPort;
+ }
+ }
+ }
+ else
+ {
+ /* For connection ports, use the port itself */
+ QueuePort = PortObject;
+ }
+
+ /* Make sure we have a port */
+ if (QueuePort)
+ {
+ /* Generate the Message ID and set it */
+ Message->Request.MessageId = LpcpNextMessageId++;
+ if (!LpcpNextMessageId) LpcpNextMessageId = 1;
+ Message->Request.CallbackId = 0;
+
+ /* No Message ID for the thread */
+ PsGetCurrentThread()->LpcReplyMessageId = 0;
+
+ /* Insert the message in our chain */
+ InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
+
+ /* Release the lock and release the semaphore */
+ KeReleaseGuardedMutex(&LpcpLock);
+ LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);
+
+ /* If this is a waitable port, wake it up */
+ if (QueuePort->Flags & LPCP_WAITABLE_PORT)
+ {
+ /* Wake it */
+ KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
+ }
+
+ /* We're done */
+ LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
+ return STATUS_SUCCESS;
+ }
+
+ /* If we got here, then free the message and fail */
+ LpcpFreeToPortZone(Message, TRUE);
+ KeReleaseGuardedMutex(&LpcpLock);
+ return STATUS_PORT_DISCONNECTED;
}
+/*
+* @unimplemented
+*/
+NTSTATUS
+NTAPI
+LpcRequestWaitReplyPort(IN PVOID Port,
+ IN PPORT_MESSAGE LpcMessageRequest,
+ OUT PPORT_MESSAGE LpcMessageReply)
+{
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
+}
-/**********************************************************************
- * NAME
- * NtRequestPort/2
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- *
- * @implemented
+/*
+ * @unimplemented
*/
-NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle,
- IN PPORT_MESSAGE LpcMessage)
+NTSTATUS
+NTAPI
+NtRequestPort(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE LpcMessage)
{
- NTSTATUS Status;
- PEPORT Port;
-
- DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle,
- LpcMessage);
-
- Status = ObReferenceObjectByHandle(PortHandle,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- UserMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- DPRINT("NtRequestPort() = %x\n", Status);
- return(Status);
- }
-
- Status = LpcRequestPort(Port->OtherPort,
- LpcMessage);
-
- ObDereferenceObject(Port);
- return(Status);
+ UNIMPLEMENTED;
+ return STATUS_NOT_IMPLEMENTED;
}
-
-/**********************************************************************
- * NAME
- * NtRequestWaitReplyPort/3
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- *
+/*
* @implemented
*/
-NTSTATUS STDCALL
-NtRequestWaitReplyPort (IN HANDLE PortHandle,
- PPORT_MESSAGE UnsafeLpcRequest,
- PPORT_MESSAGE UnsafeLpcReply)
+NTSTATUS
+NTAPI
+NtRequestWaitReplyPort(IN HANDLE PortHandle,
+ IN PPORT_MESSAGE LpcRequest,
+ IN OUT PPORT_MESSAGE LpcReply)
{
- PETHREAD CurrentThread;
- struct _KPROCESS *AttachedProcess;
- PEPORT Port;
- PQUEUEDMESSAGE Message;
- KIRQL oldIrql;
- PPORT_MESSAGE LpcRequest;
- USHORT LpcRequestMessageSize = 0, LpcRequestDataSize = 0;
- KPROCESSOR_MODE PreviousMode;
- NTSTATUS Status = STATUS_SUCCESS;
-
- PreviousMode = ExGetPreviousMode();
-
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- ProbeForRead(UnsafeLpcRequest,
- sizeof(PORT_MESSAGE),
- 1);
- ProbeForWrite(UnsafeLpcReply,
- sizeof(PORT_MESSAGE),
- 1);
- LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if (!NT_SUCCESS(Status))
- {
- return Status;
- }
- }
- else
- {
- LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
- }
-
- DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
- "LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
-
- Status = ObReferenceObjectByHandle(PortHandle,
- PORT_ALL_ACCESS,
- LpcPortObjectType,
- UserMode,
- (PVOID*)&Port,
- NULL);
- if (!NT_SUCCESS(Status))
- {
- return(Status);
- }
-
- if (EPORT_DISCONNECTED == Port->State)
- {
- ObDereferenceObject(Port);
- return STATUS_PORT_DISCONNECTED;
- }
-
- /* win32k sometimes needs to KeAttach() the CSRSS process in order to make
- the PortHandle valid. Now that we've got the EPORT structure from the
- handle we can undo this, so everything is normal again. Need to
- re-KeAttach() before returning though */
- CurrentThread = PsGetCurrentThread();
- if (&CurrentThread->ThreadsProcess->Pcb == CurrentThread->Tcb.ApcState.Process)
- {
- AttachedProcess = NULL;
- }
- else
- {
- AttachedProcess = CurrentThread->Tcb.ApcState.Process;
- KeDetachProcess();
- }
-
- if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
- {
- if (NULL != AttachedProcess)
- {
- KeAttachProcess(AttachedProcess);
- }
- ObDereferenceObject(Port);
- return(STATUS_PORT_MESSAGE_TOO_LONG);
- }
- LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
- if (LpcRequest == NULL)
- {
- if (NULL != AttachedProcess)
- {
- KeAttachProcess(AttachedProcess);
- }
- ObDereferenceObject(Port);
- return(STATUS_NO_MEMORY);
- }
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- RtlCopyMemory(LpcRequest,
- UnsafeLpcRequest,
- LpcRequestMessageSize);
- LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
- LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
-
- if (!NT_SUCCESS(Status))
- {
- ExFreePool(LpcRequest);
- if (NULL != AttachedProcess)
- {
- KeAttachProcess(AttachedProcess);
- }
- ObDereferenceObject(Port);
- return(Status);
- }
- }
- else
- {
- RtlCopyMemory(LpcRequest,
- UnsafeLpcRequest,
- LpcRequestMessageSize);
- LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
- LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
- }
-
- if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
- {
- ExFreePool(LpcRequest);
- if (NULL != AttachedProcess)
- {
- KeAttachProcess(AttachedProcess);
- }
- ObDereferenceObject(Port);
- return(STATUS_PORT_MESSAGE_TOO_LONG);
- }
- if (LpcRequestDataSize > LPC_MAX_DATA_LENGTH)
- {
- ExFreePool(LpcRequest);
- if (NULL != AttachedProcess)
- {
- KeAttachProcess(AttachedProcess);
- }
- ObDereferenceObject(Port);
- return(STATUS_PORT_MESSAGE_TOO_LONG);
- }
-
- Status = EiReplyOrRequestPort(Port->OtherPort,
- LpcRequest,
- LpcRequest->u2.s2.Type == LPC_ERROR_EVENT ? LPC_ERROR_EVENT : LPC_REQUEST,
- Port);
- if (!NT_SUCCESS(Status))
- {
- DPRINT1("Enqueue failed\n");
- ExFreePool(LpcRequest);
- if (NULL != AttachedProcess)
- {
- KeAttachProcess(AttachedProcess);
- }
- ObDereferenceObject(Port);
- return(Status);
- }
- ExFreePool(LpcRequest);
- KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
- 1, FALSE);
-
- /*
- * Wait for a reply
- */
- Status = KeWaitForSingleObject(&Port->Semaphore,
- UserRequest,
- UserMode,
- FALSE,
- NULL);
- if (Status == STATUS_SUCCESS)
- {
-
- /*
- * Dequeue the reply
- */
- KeAcquireSpinLock(&Port->Lock, &oldIrql);
- Message = EiDequeueMessagePort(Port);
- KeReleaseSpinLock(&Port->Lock, oldIrql);
- if (Message)
- {
- DPRINT("Message->Message.u1.s1.TotalLength %d\n",
- Message->Message.u1.s1.TotalLength);
- if (PreviousMode != KernelMode)
- {
- _SEH_TRY
- {
- RtlCopyMemory(UnsafeLpcReply,
- &Message->Message,
- Message->Message.u1.s1.TotalLength);
- }
- _SEH_HANDLE
- {
- Status = _SEH_GetExceptionCode();
- }
- _SEH_END;
- }
- else
- {
- RtlCopyMemory(UnsafeLpcReply,
- &Message->Message,
- Message->Message.u1.s1.TotalLength);
- }
- ExFreePool(Message);
- }
- else
- Status = STATUS_UNSUCCESSFUL;
- }
- else
- {
- if (NT_SUCCESS(Status))
- {
- Status = STATUS_UNSUCCESSFUL;
- }
- }
- if (NULL != AttachedProcess)
- {
- KeAttachProcess(AttachedProcess);
- }
- ObDereferenceObject(Port);
-
- return(Status);
-}
+ PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ NTSTATUS Status;
+ PLPCP_MESSAGE Message;
+ PETHREAD Thread = PsGetCurrentThread();
+ BOOLEAN Callback;
+ PKSEMAPHORE Semaphore;
+ ULONG MessageType;
+ PAGED_CODE();
+ LPCTRACE(LPC_SEND_DEBUG,
+ "Handle: %lx. Messages: %p/%p. Type: %lx\n",
+ PortHandle,
+ LpcRequest,
+ LpcReply,
+ LpcpGetMessageType(LpcRequest));
+ /* Check if the thread is dying */
+ if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;
-/**********************************************************************
- * NAME
- * NtWriteRequestData/6
- *
- * DESCRIPTION
- *
- * ARGUMENTS
- *
- * RETURN VALUE
- *
- * REVISIONS
- */
-NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
- PPORT_MESSAGE Message,
- ULONG Index,
- PVOID Buffer,
- ULONG BufferLength,
- PULONG ReturnLength)
-{
- UNIMPLEMENTED;
- return(STATUS_NOT_IMPLEMENTED);
-}
+ /* Check if this is an LPC Request */
+ if (LpcpGetMessageType(LpcRequest) == LPC_REQUEST)
+ {
+ /* Then it's a callback */
+ Callback = TRUE;
+ }
+ else if (LpcpGetMessageType(LpcRequest))
+ {
+ /* This is a not kernel-mode message */
+ return STATUS_INVALID_PARAMETER;
+ }
+ else
+ {
+ /* This is a kernel-mode message without a callback */
+ LpcRequest->u2.s2.Type |= LPC_REQUEST;
+ Callback = FALSE;
+ }
+ /* Get the message type */
+ MessageType = LpcRequest->u2.s2.Type;
+
+ /* Validate the length */
+ if ((LpcRequest->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
+ LpcRequest->u1.s1.TotalLength)
+ {
+ /* Fail */
+ return STATUS_INVALID_PARAMETER;
+ }
+
+ /* Reference the object */
+ Status = ObReferenceObjectByHandle(PortHandle,
+ 0,
+ LpcPortObjectType,
+ PreviousMode,
+ (PVOID*)&Port,
+ NULL);
+ if (!NT_SUCCESS(Status)) return Status;
+
+ /* Validate the message length */
+ if ((LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
+ (LpcRequest->u1.s1.TotalLength <= LpcRequest->u1.s1.DataLength))
+ {
+ /* Fail */
+ ObDereferenceObject(Port);
+ return STATUS_PORT_MESSAGE_TOO_LONG;
+ }
+
+ /* Allocate a message from the port zone */
+ Message = LpcpAllocateFromPortZone();
+ if (!Message)
+ {
+ /* Fail if we couldn't allocate a message */
+ ObDereferenceObject(Port);
+ return STATUS_NO_MEMORY;
+ }
+
+ /* Check if this is a callback */
+ if (Callback)
+ {
+ /* FIXME: TODO */
+ Semaphore = NULL; // we'd use the Thread Semaphore here
+ ASSERT(FALSE);
+ }
+ else
+ {
+ /* No callback, just copy the message */
+ LpcpMoveMessage(&Message->Request,
+ LpcRequest,
+ LpcRequest + 1,
+ MessageType,
+ &Thread->Cid);
+
+ /* Acquire the LPC lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Right now clear the port context */
+ Message->PortContext = NULL;
+
+ /* Check if this is a not connection port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
+ {
+ /* We want the connected port */
+ QueuePort = Port->ConnectedPort;
+ if (!QueuePort)
+ {
+ /* We have no connected port, fail */
+ LpcpFreeToPortZone(Message, TRUE);
+ KeReleaseGuardedMutex(&LpcpLock);
+ ObDereferenceObject(Port);
+ return STATUS_PORT_DISCONNECTED;
+ }
+
+ /* This will be the rundown port */
+ ReplyPort = QueuePort;
+
+ /* Check if this is a communication port */
+ if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
+ {
+ /* Copy the port context and use the connection port */
+ Message->PortContext = ReplyPort->PortContext;
+ QueuePort = Port->ConnectionPort;
+ }
+ else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
+ LPCP_COMMUNICATION_PORT)
+ {
+ /* Use the connection port for anything but communication ports */
+ QueuePort = Port->ConnectionPort;
+ }
+ }
+ else
+ {
+ /* Otherwise, for a connection port, use the same port object */
+ QueuePort = ReplyPort = Port;
+ }
+
+ /* No reply thread */
+ Message->RepliedToThread = NULL;
+
+ /* Generate the Message ID and set it */
+ Message->Request.MessageId = LpcpNextMessageId++;
+ if (!LpcpNextMessageId) LpcpNextMessageId = 1;
+ Message->Request.CallbackId = 0;
+
+ /* Set the message ID for our thread now */
+ Thread->LpcReplyMessageId = Message->Request.MessageId;
+ Thread->LpcReplyMessage = NULL;
+
+ /* Insert the message in our chain */
+ InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
+ InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
+
+ /* Release the lock and get the semaphore we'll use later */
+ KeReleaseGuardedMutex(&LpcpLock);
+ Semaphore = QueuePort->MsgQueue.Semaphore;
+
+ /* If this is a waitable port, wake it up */
+ if (QueuePort->Flags & LPCP_WAITABLE_PORT)
+ {
+ /* Wake it */
+ KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
+ }
+ }
+
+ /* Now release the semaphore */
+ LpcpCompleteWait(Semaphore);
+
+ /* And let's wait for the reply */
+ LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);
+
+ /* Acquire the LPC lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Get the LPC Message and clear our thread's reply data */
+ Message = Thread->LpcReplyMessage;
+ Thread->LpcReplyMessage = NULL;
+ Thread->LpcReplyMessageId = 0;
+
+ /* Check if we have anything on the reply chain*/
+ if (!IsListEmpty(&Thread->LpcReplyChain))
+ {
+ /* Remove this thread and reinitialize the list */
+ RemoveEntryList(&Thread->LpcReplyChain);
+ InitializeListHead(&Thread->LpcReplyChain);
+ }
+
+ /* Release the lock */
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Check if we got a reply */
+ if (Status == STATUS_SUCCESS)
+ {
+ /* Check if we have a valid message */
+ if (Message)
+ {
+ LPCTRACE(LPC_SEND_DEBUG,
+ "Reply Messages: %p/%p\n",
+ &Message->Request,
+ (&Message->Request) + 1);
+
+ /* Move the message */
+ LpcpMoveMessage(LpcReply,
+ &Message->Request,
+ (&Message->Request) + 1,
+ 0,
+ NULL);
+
+ /* Check if this is an LPC request with data information */
+ if ((LpcpGetMessageType(&Message->Request) == LPC_REQUEST) &&
+ (Message->Request.u2.s2.DataInfoOffset))
+ {
+ /* Save the data information */
+ LpcpSaveDataInfoMessage(Port, Message);
+ }
+ else
+ {
+ /* Otherwise, just free it */
+ LpcpFreeToPortZone(Message, FALSE);
+ }
+ }
+ else
+ {
+ /* We don't have a reply */
+ Status = STATUS_LPC_REPLY_LOST;
+ }
+ }
+ else
+ {
+ /* The wait failed, free the message while holding the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+ LpcpFreeToPortZone(Message, TRUE);
+ KeReleaseGuardedMutex(&LpcpLock);
+ }
+
+ /* All done */
+ LPCTRACE(LPC_SEND_DEBUG,
+ "Port: %p. Status: %p\n",
+ Port,
+ Status);
+ ObDereferenceObject(Port);
+ return Status;
+}
/* EOF */
<define name="__NO_CTYPE_INLINES" />
<define name="__USE_W32API" />
<define name="WIN9X_COMPAT_SPINLOCK" />
- <if property="NTLPC" value="1">
- <define name="NTLPC" />
- </if>
<include base="cmlib">.</include>
<include base="ntoskrnl">include</include>
<include base="ReactOS">include/reactos/drivers</include>
<file>loader.c</file>
<file>rtl.c</file>
</directory>
- <if property="NTLPC" value="0">
- <directory name="lpc">
- <file>close.c</file>
- <file>complete.c</file>
- <file>connect.c</file>
- <file>create.c</file>
- <file>listen.c</file>
- <file>port.c</file>
- <file>query.c</file>
- <file>queue.c</file>
- <file>receive.c</file>
- <file>reply.c</file>
- <file>send.c</file>
- </directory>
- </if>
- <if property="NTLPC" value="1">
- <directory name="lpc">
- <directory name="ntlpc">
- <file>close.c</file>
- <file>complete.c</file>
- <file>connect.c</file>
- <file>create.c</file>
- <file>listen.c</file>
- <file>port.c</file>
- <file>reply.c</file>
- <file>send.c</file>
- </directory>
- </directory>
- </if>
+ <directory name="lpc">
+ <file>close.c</file>
+ <file>complete.c</file>
+ <file>connect.c</file>
+ <file>create.c</file>
+ <file>listen.c</file>
+ <file>port.c</file>
+ <file>reply.c</file>
+ <file>send.c</file>
+ </directory>
<directory name="mm">
<if property="ARCH" value="i386">
<directory name="i386">
IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
IN PVOID Context)
{
- POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo =
- (POBP_SET_HANDLE_ATTRIBUTES_CONTEXT)Context;
+ POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = Context;
POBJECT_HEADER ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry);
PAGED_CODE();