diff --git a/reactos/config.template.rbuild b/reactos/config.template.rbuild index 92c8107b284..252e5234a78 100644 --- a/reactos/config.template.rbuild +++ b/reactos/config.template.rbuild @@ -75,6 +75,6 @@ working on the \ntlpc directory. Leave this disabled unless you really know what you're doing. --> - + diff --git a/reactos/ntoskrnl/include/internal/lpc.h b/reactos/ntoskrnl/include/internal/lpc.h index 8803f81ad6d..5570e81c6dc 100644 --- a/reactos/ntoskrnl/include/internal/lpc.h +++ b/reactos/ntoskrnl/include/internal/lpc.h @@ -1,91 +1,56 @@ -#ifndef __INCLUDE_INTERNAL_PORT_H -#define __INCLUDE_INTERNAL_PORT_H +/* +* 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) +*/ -/* EPORT.Type */ +// +// Define this if you want debugging support +// +#define _LPC_DEBUG_ 0x01 -#define EPORT_TYPE_SERVER_RQST_PORT (0) -#define EPORT_TYPE_SERVER_COMM_PORT (1) -#define EPORT_TYPE_CLIENT_COMM_PORT (2) +// +// 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 -/* 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; +// +// 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, @@ -97,66 +62,69 @@ LpcpClosePort( VOID NTAPI -LpcpDeletePort(IN PVOID ObjectBody); - -VOID -NTAPI -LpcExitThread(IN PETHREAD Thread); - -/* Code in ntoskrnl/lpc/queue.c */ - -VOID -NTAPI -EiEnqueueConnectMessagePort( - IN OUT PEPORT Port, - IN PQUEUEDMESSAGE Message -); - -VOID -NTAPI -EiEnqueueMessagePort( - IN OUT PEPORT Port, - IN PQUEUEDMESSAGE Message -); - -VOID -NTAPI -EiEnqueueMessageAtHeadPort( - IN OUT PEPORT Port, - IN PQUEUEDMESSAGE Message -); - -PQUEUEDMESSAGE -NTAPI -EiDequeueConnectMessagePort(IN OUT PEPORT Port); - -PQUEUEDMESSAGE -NTAPI -EiDequeueMessagePort(IN OUT PEPORT Port); - -/* Code in ntoskrnl/lpc/port.c */ - -NTSTATUS -NTAPI -LpcpInitializePort( - IN OUT PEPORT Port, - IN USHORT Type, - IN PEPORT Parent OPTIONAL +LpcpDeletePort( + IN PVOID ObjectBody ); NTSTATUS NTAPI -LpcpInitSystem (VOID); +LpcpInitializePortQueue( + IN PLPCP_PORT_OBJECT Port +); -/* Code in ntoskrnl/lpc/reply.c */ - -NTSTATUS +VOID NTAPI -EiReplyOrRequestPort( - IN PEPORT Port, - IN PPORT_MESSAGE LpcReply, +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 PEPORT Sender + IN PCLIENT_ID ClientId ); -#endif /* __INCLUDE_INTERNAL_PORT_H */ +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" diff --git a/reactos/ntoskrnl/lpc/ntlpc/lpc_x.h b/reactos/ntoskrnl/include/internal/lpc_x.h similarity index 97% rename from reactos/ntoskrnl/lpc/ntlpc/lpc_x.h rename to reactos/ntoskrnl/include/internal/lpc_x.h index 3c0bc8fd86b..0ba3b0aac74 100644 --- a/reactos/ntoskrnl/lpc/ntlpc/lpc_x.h +++ b/reactos/ntoskrnl/include/internal/lpc_x.h @@ -1,122 +1,122 @@ -/* -* 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; -} +/* +* 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; +} diff --git a/reactos/ntoskrnl/lpc/close.c b/reactos/ntoskrnl/lpc/close.c index cf569dc02b6..af9803dbfc7 100644 --- a/reactos/ntoskrnl/lpc/close.c +++ b/reactos/ntoskrnl/lpc/close.c @@ -1,25 +1,29 @@ -/* $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 +#include "lpc.h" #define NDEBUG #include -/* 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)) { @@ -31,104 +35,361 @@ LpcExitThread(IN PETHREAD Thread) Thread->LpcExitThreadCalled = TRUE; Thread->LpcReplyMessageId = 0; - /* FIXME: Reply to the LpcReplyMessage */ -} - -/********************************************************************** - * 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) -{ - PEPORT Port = (PEPORT)ObjectBody; - PORT_MESSAGE Message; - - /* FIXME Race conditions here! */ - - /* - * 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 there's a reply message */ + Message = Thread->LpcReplyMessage; + if (Message) { - 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); + /* FIXME: TODO */ + KEBUGCHECK(0); } - /* - * 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)) - { - DPRINT("Cleaning up server\n"); - Port->OtherPort->OtherPort = NULL; - Port->OtherPort->State = EPORT_DISCONNECTED; - ObDereferenceObject(Port->OtherPort); - } + /* Release the lock */ + KeReleaseGuardedMutex(&LpcpLock); } - -/********************************************************************** - * NAME - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - */ -VOID STDCALL -LpcpDeletePort (PVOID ObjectBody) +VOID +NTAPI +LpcpFreeToPortZone(IN PLPCP_MESSAGE Message, + IN ULONG Flags) { - PLIST_ENTRY Entry; - PQUEUEDMESSAGE 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); - PEPORT Port = (PEPORT)ObjectBody; + /* Acquire the lock if not already */ + if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock); - DPRINT("Deleting port %x\n", Port); + /* Check if the queue list is empty */ + if (!IsListEmpty(&Message->Entry)) + { + /* Remove and re-initialize */ + RemoveEntryList(&Message->Entry); + InitializeListHead(&Message->Entry); + } - /* Free all waiting messages */ - while (!IsListEmpty(&Port->QueueListHead)) - { - Entry = RemoveHeadList(&Port->QueueListHead); - Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry); - ExFreePool(Message); - } + /* Check if we've already replied */ + if (Message->RepliedToThread) + { + /* Set thread to dereference and clean up */ + Thread = Message->RepliedToThread; + Message->RepliedToThread = NULL; + } - while (!IsListEmpty(&Port->ConnectQueueListHead)) - { - Entry = RemoveHeadList(&Port->ConnectQueueListHead); - Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry); - ExFreePool(Message); - } + /* 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 */ diff --git a/reactos/ntoskrnl/lpc/complete.c b/reactos/ntoskrnl/lpc/complete.c index e14350d5623..b5e4e190ee1 100644 --- a/reactos/ntoskrnl/lpc/complete.c +++ b/reactos/ntoskrnl/lpc/complete.c @@ -1,82 +1,376 @@ -/* $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 +#include "lpc.h" #define NDEBUG #include -/* FUNCTIONS *****************************************************************/ +/* PRIVATE 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. - */ -NTSTATUS STDCALL -NtCompleteConnectPort (HANDLE hServerSideCommPort) +VOID +NTAPI +LpcpPrepareToWakeClient(IN PETHREAD Thread) { - NTSTATUS Status; - PEPORT ReplyPort; + PAGED_CODE(); - 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)) + /* Make sure the thread isn't dying and it has a valid chain */ + if (!(Thread->LpcExitThreadCalled) && + !(IsListEmpty(&Thread->LpcReplyChain))) { - return (Status); + /* Remove it from the list and reinitialize it */ + RemoveEntryList(&Thread->LpcReplyChain); + InitializeListHead(&Thread->LpcReplyChain); } - /* - * 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) - { - ObDereferenceObject (ReplyPort); - return STATUS_INVALID_PORT_HANDLE; - } - - 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); } +/* 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 */ diff --git a/reactos/ntoskrnl/lpc/connect.c b/reactos/ntoskrnl/lpc/connect.c index 6aa36904cfe..2b9259ef588 100644 --- a/reactos/ntoskrnl/lpc/connect.c +++ b/reactos/ntoskrnl/lpc/connect.c @@ -1,933 +1,568 @@ -/* $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 +#include "lpc.h" #define NDEBUG #include -/* FUNCTIONS *****************************************************************/ +/* PRIVATE 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) +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; + PVOID SectionToMap; - if (ConnectDataLength == NULL) + /* Acquire the LPC lock */ + KeAcquireGuardedMutex(&LpcpLock); + + /* Check if the reply chain is not empty */ + if (!IsListEmpty(&CurrentThread->LpcReplyChain)) { - RequestConnectDataLength = 0; - } - else - { - RequestConnectDataLength = *ConnectDataLength; + /* Remove this entry and re-initialize it */ + RemoveEntryList(&CurrentThread->LpcReplyChain); + InitializeListHead(&CurrentThread->LpcReplyChain); } - /* - * 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)) + /* Check if there's a reply message */ + if (CurrentThread->LpcReplyMessage) { - return (Status); - } - LpcpInitializePort(OurPort, EPORT_TYPE_CLIENT_COMM_PORT, NamedPort); + /* Get the message */ + *Message = CurrentThread->LpcReplyMessage; - /* - * Allocate a request message. - */ - RequestMessage = ExAllocatePool(NonPagedPool, - sizeof(EPORT_CONNECT_REQUEST_MESSAGE) + - RequestConnectDataLength); - if (RequestMessage == NULL) + /* 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 { - ObDereferenceObject(OurPort); - return(STATUS_NO_MEMORY); + /* No message to return */ + *Message = NULL; + SectionToMap = NULL; } - /* - * 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) - { - memcpy(RequestMessage->ConnectData, ConnectData, - RequestConnectDataLength); - } - - /* - * 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) - { - 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); - } - - /* - * 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); - } - - /* - * Create our view of the send section object. - */ - if (Section != NULL) - { - *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); - } - } - - /* - * 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) + 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))) { - _SEH_TRY - { - ProbeForWriteHandle(UnsafeConnectedPortHandle); - if (UnsafeMaximumMessageSize != NULL) - { - ProbeForWriteUlong(UnsafeMaximumMessageSize); - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) - { - return Status; - } + /* Fail */ + return STATUS_INVALID_PARAMETER; } - /* - * Copy in write map and partially validate. - */ - if (UnsafeWriteMap != NULL) + /* Validate server view */ + if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW))) { - 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 - { - RtlCopyMemory(&WriteMap, - UnsafeWriteMap, - sizeof(PORT_VIEW)); - } - - if (WriteMap.Length != sizeof(PORT_VIEW)) - { - return(STATUS_INVALID_PARAMETER_4); - } - SectionOffset.QuadPart = WriteMap.SectionOffset; - } - else - { - WriteMap.SectionHandle = INVALID_HANDLE_VALUE; + /* Fail */ + return STATUS_INVALID_PARAMETER; } - /* - * Handle connection data. - */ - if (UnsafeConnectData) + /* Check if caller sent connection information length */ + if (ConnectionInformationLength) { - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - ConnectDataLength = ProbeForReadUlong(UnsafeConnectDataLength); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; + /* Retrieve the input length */ + ConnectionInfoLength = *ConnectionInformationLength; + } - if (!NT_SUCCESS(Status)) - { - return Status; - } - } - else - { - ConnectDataLength = *UnsafeConnectDataLength; - } + /* Get the port */ + Status = ObReferenceObjectByName(PortName, + 0, + NULL, + PORT_ALL_ACCESS, + LpcPortObjectType, + PreviousMode, + NULL, + (PVOID *)&Port); + if (!NT_SUCCESS(Status)) return Status; - if (ConnectDataLength != 0) - { - ConnectData = ExAllocatePool(NonPagedPool, ConnectDataLength); - if (ConnectData == NULL) - { - return(STATUS_NO_MEMORY); - } + /* 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; + } - if (PreviousMode != KernelMode) + /* 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)) { - _SEH_TRY + /* Compare the SIDs */ + if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid)) { - ProbeForWriteUlong(UnsafeConnectData); - RtlCopyMemory(ConnectData, - UnsafeConnectData, - ConnectDataLength); + /* Fail */ + Status = STATUS_SERVER_SID_MISMATCH; } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - if (!NT_SUCCESS(Status)) - { - ExFreePool(ConnectData); - return Status; - } - } - else - { - RtlCopyMemory(ConnectData, - UnsafeConnectData, - ConnectDataLength); + /* 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; + } } - /* - * Reference the named port. - */ - Status = ObReferenceObjectByName (PortName, + /* 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, /* DesiredAccess */ - LpcPortObjectType, - PreviousMode, - NULL, - (PVOID*)&NamedPort); - if (!NT_SUCCESS(Status)) - { - if (KeGetPreviousMode() != KernelMode) - { - ExFreePool(ConnectData); - } - return(Status); - } - - /* - * Reference the send section object. - */ - if (WriteMap.SectionHandle != INVALID_HANDLE_VALUE) - { - 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); - } - } - else - { - SectionObject = NULL; - } - - /* - * 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)) - { - /* 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); - } - - /* - * Do some initial cleanup. - */ - if (SectionObject != NULL) - { - ObDereferenceObject(SectionObject); - SectionObject = NULL; - } - ObDereferenceObject(NamedPort); - NamedPort = NULL; - - /* - * Copy the data back to the caller. - */ - - if (UnsafeConnectDataLength != NULL) - { - if (PreviousMode != KernelMode) - { - _SEH_TRY + PORT_ALL_ACCESS, + 0, + (PVOID *)NULL, + &Handle); + if (NT_SUCCESS(Status)) { - *UnsafeConnectDataLength = ConnectDataLength; - - if (ConnectData != NULL) + /* 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) { - RtlCopyMemory(UnsafeConnectData, - ConnectData, - ConnectDataLength); + /* 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)); } } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) - { - if (ConnectData != NULL) - { - ExFreePool(ConnectData); - } - return(Status); - } - } - else + } + else { - *UnsafeConnectDataLength = ConnectDataLength; - - if (ConnectData != NULL) + /* No connection port, we failed */ + if (SectionToMap) ObDereferenceObject(SectionToMap); + + /* Check if it's because the name got deleted */ + if (Port->Flags & LPCP_NAME_DELETED) { - RtlCopyMemory(UnsafeConnectData, - ConnectData, - ConnectDataLength); + /* 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); } - if (ConnectData != NULL) - { - ExFreePool(ConnectData); - } + /* Free the message */ + LpcpFreeToPortZone(Message, FALSE); + return Status; } - Status = ObInsertObject(ConnectedPort, - NULL, - PORT_ALL_ACCESS, - 1, - (PVOID*)&ConnectedPort, - &ConnectedPortHandle); - if (!NT_SUCCESS(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)) { - return(Status); + /* Wait on it */ + KeWaitForSingleObject(&Thread->LpcReplySemaphore, + KernelMode, + Executive, + FALSE, + NULL); } - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - *UnsafeConnectedPortHandle = ConnectedPortHandle; - - if (UnsafeWriteMap != NULL) - { - RtlCopyMemory(UnsafeWriteMap, - &WriteMap, - sizeof(PORT_VIEW)); - } + /* Check if we had a message and free it */ + if (Message) LpcpFreeToPortZone(Message, FALSE); - if (UnsafeReadMap != NULL) - { - RtlCopyMemory(UnsafeReadMap, - &ReadMap, - sizeof(REMOTE_PORT_VIEW)); - } + /* Dereference other objects */ + if (SectionToMap) ObDereferenceObject(SectionToMap); + ObDereferenceObject(ClientPort); - if (UnsafeMaximumMessageSize != NULL) - { - *UnsafeMaximumMessageSize = MaximumMessageSize; - } - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) - { - return Status; - } - } - else - { - *UnsafeConnectedPortHandle = ConnectedPortHandle; - - if (UnsafeWriteMap != NULL) - { - RtlCopyMemory(UnsafeWriteMap, - &WriteMap, - sizeof(PORT_VIEW)); - } - - if (UnsafeReadMap != NULL) - { - RtlCopyMemory(UnsafeReadMap, - &ReadMap, - sizeof(REMOTE_PORT_VIEW)); - } - - if (UnsafeMaximumMessageSize != NULL) - { - *UnsafeMaximumMessageSize = MaximumMessageSize; - } - } - - /* - * All done. - */ - - return(STATUS_SUCCESS); + /* Return status */ + return Status; } - -/********************************************************************** - * NAME EXPORTED - * NtAcceptConnectPort/6 - * - * DESCRIPTION - * - * ARGUMENTS - * ServerPortHandle - * NamedPortHandle - * LpcMessage - * AcceptIt - * WriteMap - * ReadMap - * - * RETURN VALUE +/* + * @implemented */ -/*EXPORTED*/ NTSTATUS STDCALL -NtAcceptConnectPort (PHANDLE ServerPortHandle, - HANDLE NamedPortHandle, - PPORT_MESSAGE LpcMessage, - BOOLEAN AcceptIt, - PPORT_VIEW WriteMap, - PREMOTE_PORT_VIEW ReadMap) +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) { - 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); - } - - Status = ObReferenceObjectByHandle(NamedPortHandle, - PORT_ALL_ACCESS, - LpcPortObjectType, - PreviousMode, - (PVOID*)&NamedPort, - NULL); - if (!NT_SUCCESS(Status)) - { - ExFreePool(CReply); - return (Status); - } - - /* - * 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); - } - - /* - * 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); - } - - /* - * 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); - } - } - - /* - * Finish the reply. - */ - if (ReadMap != NULL) - { - CReply->SendServerViewBase = ReadMap->ViewBase; - } - 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); - - //ObDereferenceObject(OurPort); - ObDereferenceObject(NamedPort); - - return (STATUS_SUCCESS); -} - -/********************************************************************** - * 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 - */ -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) -{ - /* 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 */ diff --git a/reactos/ntoskrnl/lpc/create.c b/reactos/ntoskrnl/lpc/create.c index 1fcefa0d6b0..2bf08c13e11 100644 --- a/reactos/ntoskrnl/lpc/create.c +++ b/reactos/ntoskrnl/lpc/create.c @@ -1,180 +1,195 @@ -/* $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 +#include "lpc.h" #define NDEBUG #include -/********************************************************************** - * 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) - { - return (STATUS_INVALID_PARAMETER_2); - } - 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) - { - return (STATUS_INVALID_PARAMETER_3); - } - if (MaxDataLength > LPC_MAX_MESSAGE_LENGTH) - { - return (STATUS_INVALID_PARAMETER_4); - } - /* TODO: some checking is done also on MaxPoolUsage - * to avoid choking the executive */ - return (STATUS_SUCCESS); + 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; } -/********************************************************************** - * 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) +NTSTATUS +NTAPI +LpcpCreatePort(OUT PHANDLE PortHandle, + IN POBJECT_ATTRIBUTES ObjectAttributes, + IN ULONG MaxConnectionInfoLength, + IN ULONG MaxMessageLength, + IN ULONG MaxPoolUsage, + IN BOOLEAN Waitable) { - PEPORT Port; - NTSTATUS Status; + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(); + NTSTATUS Status; + PLPCP_PORT_OBJECT Port; + LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName); - DPRINT("NtCreatePort() Name %x\n", ObjectAttributes->ObjectName->Buffer); + /* Create the Object */ + Status = ObCreateObject(PreviousMode, + LpcPortObjectType, + ObjectAttributes, + PreviousMode, + NULL, + sizeof(LPCP_PORT_OBJECT), + 0, + 0, + (PVOID*)&Port); + if (!NT_SUCCESS(Status)) return Status; - /* Verify parameters */ - Status = LpcpVerifyCreateParameters (PortHandle, - ObjectAttributes, - MaxConnectInfoLength, - MaxDataLength, - MaxPoolUsage); - if (STATUS_SUCCESS != 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); + /* 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); } - /* Ask Ob to create the object */ - Status = ObCreateObject (ExGetPreviousMode(), - LpcPortObjectType, - ObjectAttributes, - ExGetPreviousMode(), - NULL, - sizeof(EPORT), - 0, - 0, - (PVOID*)&Port); - if (!NT_SUCCESS(Status)) + /* 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); + /* Fail */ + ObDereferenceObject(Port); + return Status; } - Status = ObInsertObject ((PVOID)Port, - NULL, - PORT_ALL_ACCESS, - 0, - NULL, - PortHandle); - if (!NT_SUCCESS(Status)) + /* Check if this is a waitable port */ + if (Port->Flags & LPCP_WAITABLE_PORT) { - ObDereferenceObject (Port); - return (Status); + /* Setup the wait event */ + KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE); } - Status = LpcpInitializePort (Port, EPORT_TYPE_SERVER_RQST_PORT, NULL); - Port->MaxConnectInfoLength = LPC_MAX_DATA_LENGTH; - Port->MaxDataLength = LPC_MAX_MESSAGE_LENGTH; - Port->MaxPoolUsage = MaxPoolUsage; + /* Set the maximum message size allowed */ + Port->MaxMessageLength = LpcpMaxMessageSize - + FIELD_OFFSET(LPCP_MESSAGE, Request); - return (Status); + /* 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; } -/********************************************************************** - * 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 - */ -/*EXPORTED*/ NTSTATUS STDCALL -NtCreateWaitablePort (OUT PHANDLE PortHandle, - IN POBJECT_ATTRIBUTES ObjectAttributes, - IN ULONG MaxConnectInfoLength, - IN ULONG MaxDataLength, - IN ULONG MaxPoolUsage) -{ - NTSTATUS Status; +/* PUBLIC FUNCTIONS **********************************************************/ - /* Verify parameters */ - Status = LpcpVerifyCreateParameters (PortHandle, - ObjectAttributes, - MaxConnectInfoLength, - MaxDataLength, - MaxPoolUsage); - if (STATUS_SUCCESS != Status) - { - return (Status); - } - /* TODO */ - return (STATUS_NOT_IMPLEMENTED); +/* + * @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 */ diff --git a/reactos/ntoskrnl/lpc/listen.c b/reactos/ntoskrnl/lpc/listen.c index 901c816f1ec..ee2ade0c03d 100644 --- a/reactos/ntoskrnl/lpc/listen.c +++ b/reactos/ntoskrnl/lpc/listen.c @@ -1,72 +1,52 @@ -/* $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 +#include "lpc.h" #define NDEBUG #include -/* 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; + NTSTATUS Status; + PAGED_CODE(); + LPCTRACE(LPC_LISTEN_DEBUG, "Handle: %lx\n", PortHandle); - /* - * 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); - } + /* Wait forever for a connection request. */ + for (;;) + { + /* Do the wait */ + Status = NtReplyWaitReceivePort(PortHandle, + NULL, + NULL, + ConnectMessage); - return (Status); + /* Accept only LPC_CONNECTION_REQUEST requests. */ + if ((Status != STATUS_SUCCESS) || + (LpcpGetMessageType(ConnectMessage) == LPC_CONNECTION_REQUEST)) + { + /* Break out */ + break; + } + } + + /* Return status */ + return Status; } diff --git a/reactos/ntoskrnl/lpc/ntlpc/close.c b/reactos/ntoskrnl/lpc/ntlpc/close.c deleted file mode 100644 index af9803dbfc7..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/close.c +++ /dev/null @@ -1,395 +0,0 @@ -/* - * 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/ntlpc/complete.c b/reactos/ntoskrnl/lpc/ntlpc/complete.c deleted file mode 100644 index b5e4e190ee1..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/complete.c +++ /dev/null @@ -1,376 +0,0 @@ -/* -* 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/ntlpc/connect.c b/reactos/ntoskrnl/lpc/ntlpc/connect.c deleted file mode 100644 index 2b9259ef588..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/connect.c +++ /dev/null @@ -1,568 +0,0 @@ -/* - * 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/ntlpc/create.c b/reactos/ntoskrnl/lpc/ntlpc/create.c deleted file mode 100644 index 2bf08c13e11..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/create.c +++ /dev/null @@ -1,195 +0,0 @@ -/* - * 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/ntlpc/listen.c b/reactos/ntoskrnl/lpc/ntlpc/listen.c deleted file mode 100644 index ee2ade0c03d..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/listen.c +++ /dev/null @@ -1,53 +0,0 @@ -/* - * 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/ntlpc/lpc.h b/reactos/ntoskrnl/lpc/ntlpc/lpc.h deleted file mode 100644 index 5570e81c6dc..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/lpc.h +++ /dev/null @@ -1,130 +0,0 @@ -/* -* 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" diff --git a/reactos/ntoskrnl/lpc/ntlpc/port.c b/reactos/ntoskrnl/lpc/ntlpc/port.c deleted file mode 100644 index dcc5a979d44..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/port.c +++ /dev/null @@ -1,109 +0,0 @@ -/* - * 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/ntlpc/reply.c b/reactos/ntoskrnl/lpc/ntlpc/reply.c deleted file mode 100644 index 311002eb2eb..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/reply.c +++ /dev/null @@ -1,491 +0,0 @@ -/* - * 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/ntlpc/send.c b/reactos/ntoskrnl/lpc/ntlpc/send.c deleted file mode 100644 index f49e0a6550f..00000000000 --- a/reactos/ntoskrnl/lpc/ntlpc/send.c +++ /dev/null @@ -1,426 +0,0 @@ -/* - * 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 -#include "lpc.h" -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/port.c b/reactos/ntoskrnl/lpc/port.c index 18fec96de83..dcc5a979d44 100644 --- a/reactos/ntoskrnl/lpc/port.c +++ b/reactos/ntoskrnl/lpc/port.c @@ -1,29 +1,26 @@ -/* $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 +#include "lpc.h" #define NDEBUG #include -#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 = { @@ -33,105 +30,60 @@ 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); + ObjectTypeInitializer.MaintainTypeList = TRUE; + ObCreateObjectType(&Name, + &ObjectTypeInitializer, + NULL, + &LpcPortObjectType); - LpcpNextMessageId = 0; - ExInitializeFastMutex (& LpcpLock); + /* Allocate the LPC lookaside list */ + LpcpMaxMessageSize = LPCP_MAX_MESSAGE_SIZE; + ExInitializePagedLookasideList(&LpcpMessagesLookaside, + NULL, + NULL, + 0, + LpcpMaxMessageSize, + TAG('L', 'p', 'c', 'M'), + 32); - return(STATUS_SUCCESS); + /* We're done */ + return STATUS_SUCCESS; } +/* PUBLIC FUNCTIONS **********************************************************/ -/********************************************************************** - * 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) +NTSTATUS +NTAPI +NtImpersonateClientOfPort(IN HANDLE PortHandle, + IN PPORT_MESSAGE ClientMessage) { - 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); -} - - -/* MISCELLANEA SYSTEM SERVICES */ - - -/********************************************************************** - * NAME SYSTEM - * NtImpersonateClientOfPort/2 - * - * DESCRIPTION - * - * ARGUMENTS - * PortHandle, - * ClientMessage - * - * RETURN VALUE - */ -NTSTATUS STDCALL -NtImpersonateClientOfPort (HANDLE PortHandle, - PPORT_MESSAGE ClientMessage) -{ - UNIMPLEMENTED; - return(STATUS_NOT_IMPLEMENTED); + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } NTSTATUS @@ -142,4 +94,16 @@ NtQueryPortInformationProcess(VOID) 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 */ diff --git a/reactos/ntoskrnl/lpc/query.c b/reactos/ntoskrnl/lpc/query.c deleted file mode 100644 index 3463047c82a..00000000000 --- a/reactos/ntoskrnl/lpc/query.c +++ /dev/null @@ -1,69 +0,0 @@ -/* $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 -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/queue.c b/reactos/ntoskrnl/lpc/queue.c deleted file mode 100644 index 971e1085d51..00000000000 --- a/reactos/ntoskrnl/lpc/queue.c +++ /dev/null @@ -1,83 +0,0 @@ -/* $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 -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/receive.c b/reactos/ntoskrnl/lpc/receive.c deleted file mode 100644 index 83631aa388d..00000000000 --- a/reactos/ntoskrnl/lpc/receive.c +++ /dev/null @@ -1,41 +0,0 @@ -/* $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 -#define NDEBUG -#include - -/* 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 */ diff --git a/reactos/ntoskrnl/lpc/reply.c b/reactos/ntoskrnl/lpc/reply.c index 5fb58c22fb6..311002eb2eb 100644 --- a/reactos/ntoskrnl/lpc/reply.c +++ b/reactos/ntoskrnl/lpc/reply.c @@ -1,421 +1,141 @@ -/* $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 +#include "lpc.h" #define NDEBUG #include -/* GLOBALS *******************************************************************/ +/* PRIVATE FUNCTIONS *********************************************************/ -/* FUNCTIONS *****************************************************************/ - -/********************************************************************** - * NAME - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - */ -NTSTATUS STDCALL -EiReplyOrRequestPort (IN PEPORT Port, - IN PPORT_MESSAGE LpcReply, - IN ULONG MessageType, - IN PEPORT Sender) +VOID +NTAPI +LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port, + IN ULONG MessageId, + IN ULONG CallbackId) { - KIRQL oldIrql; - PQUEUEDMESSAGE MessageReply; - ULONG Size; + PLPCP_MESSAGE Message; + PLIST_ENTRY ListHead, NextEntry; - if (Port == NULL) - { - KEBUGCHECK(0); - } + /* 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; + } - 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; + /* Loop the list */ + ListHead = &Port->LpcDataInfoChainHead; + NextEntry = ListHead->Flink; + while (ListHead != NextEntry) + { + /* Get the message */ + Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry); - 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; - } + /* 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; + } - 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); + /* Go to the next entry */ + NextEntry = NextEntry->Flink; + } } - -/********************************************************************** - * NAME EXPORTED - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - */ -NTSTATUS STDCALL -NtReplyPort (IN HANDLE PortHandle, - IN PPORT_MESSAGE LpcReply) +VOID +NTAPI +LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port, + IN PLPCP_MESSAGE Message) { - NTSTATUS Status; - PEPORT Port; + PAGED_CODE(); - DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle, LpcReply); + /* Acquire the lock */ + KeAcquireGuardedMutex(&LpcpLock); - Status = ObReferenceObjectByHandle(PortHandle, - PORT_ALL_ACCESS, /* AccessRequired */ - LpcPortObjectType, - UserMode, - (PVOID*)&Port, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtReplyPort() = %x\n", Status); - return(Status); - } + /* Check if the port we want is the connection port */ + if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT) + { + /* Use it */ + Port = Port->ConnectionPort; + } - if (EPORT_DISCONNECTED == Port->State) - { - ObDereferenceObject(Port); - return STATUS_PORT_DISCONNECTED; - } + /* Link the message */ + InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry); - Status = EiReplyOrRequestPort(Port->OtherPort, - LpcReply, - LPC_REPLY, - Port); - KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE); - - ObDereferenceObject(Port); - - return(Status); + /* Release the lock */ + KeReleaseGuardedMutex(&LpcpLock); } - -/********************************************************************** - * NAME EXPORTED - * NtReplyWaitReceivePortEx - * - * DESCRIPTION - * Can be used with waitable ports. - * Present only in w2k+. - * - * ARGUMENTS - * PortHandle - * PortId - * LpcReply - * LpcMessage - * Timeout - * - * RETURN VALUE - * - * REVISIONS - */ -NTSTATUS STDCALL -NtReplyWaitReceivePortEx(IN HANDLE PortHandle, - OUT PVOID *PortContext OPTIONAL, - IN PPORT_MESSAGE ReplyMessage OPTIONAL, - OUT PPORT_MESSAGE ReceiveMessage, - IN PLARGE_INTEGER Timeout OPTIONAL) +VOID +NTAPI +LpcpMoveMessage(IN PPORT_MESSAGE Destination, + IN PPORT_MESSAGE Origin, + IN PVOID Data, + IN ULONG MessageType, + IN PCLIENT_ID ClientId) { - PEPORT Port; - KIRQL oldIrql; - PQUEUEDMESSAGE Request; - BOOLEAN Disconnected; - LARGE_INTEGER to; - KPROCESSOR_MODE PreviousMode; - NTSTATUS Status = STATUS_SUCCESS; - - PreviousMode = ExGetPreviousMode(); + /* 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; - DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, " - "LpcMessage %x)\n", PortHandle, ReplyMessage, ReceiveMessage); + /* Set the Message Type */ + Destination->u2.s2.Type = !MessageType ? + Origin->u2.s2.Type : MessageType & 0xFFFF; - if (PreviousMode != KernelMode) - { - _SEH_TRY - { - ProbeForWrite(ReceiveMessage, - sizeof(PORT_MESSAGE), - 1); - } - _SEH_HANDLE - { - Status = _SEH_GetExceptionCode(); - } - _SEH_END; - - if (!NT_SUCCESS(Status)) - { - return Status; - } - } + /* 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; + } - 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; + /* Copy the MessageId and ClientViewSize */ + Destination->MessageId = Origin->MessageId; + Destination->ClientViewSize = Origin->ClientViewSize; - /* - * 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); + /* Copy the Message Data */ + RtlMoveMemory(Destination + 1, + Data, + ((Destination->u1.Length & 0xFFFF) + 3) &~3); } +/* PUBLIC FUNCTIONS **********************************************************/ -/********************************************************************** - * NAME EXPORTED - * NtReplyWaitReceivePort - * - * DESCRIPTION - * Can be used with waitable ports. - * - * ARGUMENTS - * PortHandle - * PortId - * LpcReply - * LpcMessage - * - * RETURN VALUE - * - * REVISIONS +/* + * @unimplemented */ -NTSTATUS STDCALL -NtReplyWaitReceivePort(IN HANDLE PortHandle, - OUT PVOID *PortContext OPTIONAL, - IN PPORT_MESSAGE ReplyMessage OPTIONAL, - OUT PPORT_MESSAGE ReceiveMessage) +NTSTATUS +NTAPI +NtReplyPort(IN HANDLE PortHandle, + IN PPORT_MESSAGE LpcReply) { - return NtReplyWaitReceivePortEx(PortHandle, - PortContext, - ReplyMessage, - ReceiveMessage, - NULL); -} - -/********************************************************************** - * NAME - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - */ -NTSTATUS STDCALL -NtReplyWaitReplyPort (HANDLE PortHandle, - PPORT_MESSAGE ReplyMessage) -{ - UNIMPLEMENTED; - return(STATUS_NOT_IMPLEMENTED); + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; } /* @@ -423,36 +143,349 @@ NtReplyWaitReplyPort (HANDLE PortHandle, */ NTSTATUS NTAPI -LpcRequestWaitReplyPort(IN PVOID Port, - IN PPORT_MESSAGE LpcMessageRequest, - OUT PPORT_MESSAGE LpcMessageReply) +NtReplyWaitReceivePortEx(IN HANDLE PortHandle, + OUT PVOID *PortContext OPTIONAL, + IN PPORT_MESSAGE ReplyMessage OPTIONAL, + OUT PPORT_MESSAGE ReceiveMessage, + IN PLARGE_INTEGER Timeout OPTIONAL) { - HANDLE PortHandle; + PLPCP_PORT_OBJECT Port, ReceivePort; + KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode; NTSTATUS Status; - UNICODE_STRING PortName; - ULONG ConnectInfoLength; + 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); - // - // OMG HAXX! - // - RtlInitUnicodeString(&PortName, L"\\Windows\\ApiPort"); - ConnectInfoLength = 0; - Status = ZwConnectPort(&PortHandle, - &PortName, - NULL, - NULL, - NULL, - NULL, - NULL, - &ConnectInfoLength); + /* If this is a system thread, then let it page out its stack */ + if (Thread->SystemThread) WaitMode = UserMode; - Status = ZwRequestWaitReplyPort(PortHandle, - LpcMessageRequest, - LpcMessageReply); + /* 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; + } - /* Close the handle */ - ObCloseHandle(PortHandle, KernelMode); + /* 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 */ diff --git a/reactos/ntoskrnl/lpc/send.c b/reactos/ntoskrnl/lpc/send.c index 1dc522f7e66..f49e0a6550f 100644 --- a/reactos/ntoskrnl/lpc/send.c +++ b/reactos/ntoskrnl/lpc/send.c @@ -1,395 +1,426 @@ -/* $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 - +#include "lpc.h" #define NDEBUG #include -/********************************************************************** - * 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; + 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); - DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage); + /* Check if this is a non-datagram message */ + if (LpcMessage->u2.s2.Type) + { + /* Get the message type */ + MessageType = LpcpGetMessageType(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 + /* Validate it */ + if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED)) + { + /* Fail */ + return STATUS_INVALID_PARAMETER; + } - Status = EiReplyOrRequestPort(Port, - LpcMessage, - LPC_DATAGRAM, - Port); - KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE ); + /* 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; + } - return(Status); + /* 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 - * +/* + * @unimplemented + */ +NTSTATUS +NTAPI +NtRequestPort(IN HANDLE PortHandle, + IN PPORT_MESSAGE LpcMessage) +{ + UNIMPLEMENTED; + return STATUS_NOT_IMPLEMENTED; +} + +/* * @implemented */ -NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle, - IN PPORT_MESSAGE LpcMessage) +NTSTATUS +NTAPI +NtRequestWaitReplyPort(IN HANDLE PortHandle, + IN PPORT_MESSAGE LpcRequest, + IN OUT PPORT_MESSAGE LpcReply) { - NTSTATUS Status; - PEPORT Port; + 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)); - DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle, - LpcMessage); + /* Check if the thread is dying */ + if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING; - Status = ObReferenceObjectByHandle(PortHandle, - PORT_ALL_ACCESS, - LpcPortObjectType, - UserMode, - (PVOID*)&Port, - NULL); - if (!NT_SUCCESS(Status)) - { - DPRINT("NtRequestPort() = %x\n", Status); - return(Status); - } + /* 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; + } - Status = LpcRequestPort(Port->OtherPort, - LpcMessage); + /* Get the message type */ + MessageType = LpcRequest->u2.s2.Type; - ObDereferenceObject(Port); - return(Status); + /* 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; } - -/********************************************************************** - * NAME - * NtRequestWaitReplyPort/3 - * - * DESCRIPTION - * - * ARGUMENTS - * - * RETURN VALUE - * - * REVISIONS - * - * @implemented - */ -NTSTATUS STDCALL -NtRequestWaitReplyPort (IN HANDLE PortHandle, - PPORT_MESSAGE UnsafeLpcRequest, - PPORT_MESSAGE UnsafeLpcReply) -{ - 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); -} - - -/********************************************************************** - * 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); -} - - /* EOF */ diff --git a/reactos/ntoskrnl/ntoskrnl.rbuild b/reactos/ntoskrnl/ntoskrnl.rbuild index 10c6ed34404..dd73ec5d4fc 100644 --- a/reactos/ntoskrnl/ntoskrnl.rbuild +++ b/reactos/ntoskrnl/ntoskrnl.rbuild @@ -9,9 +9,6 @@ - - - . include include/reactos/drivers @@ -230,35 +227,16 @@ loader.c rtl.c - - - close.c - complete.c - connect.c - create.c - listen.c - port.c - query.c - queue.c - receive.c - reply.c - send.c - - - - - - close.c - complete.c - connect.c - create.c - listen.c - port.c - reply.c - send.c - - - + + close.c + complete.c + connect.c + create.c + listen.c + port.c + reply.c + send.c + diff --git a/reactos/ntoskrnl/ob/obhandle.c b/reactos/ntoskrnl/ob/obhandle.c index 34cd8bae2bf..3622370a9c7 100644 --- a/reactos/ntoskrnl/ob/obhandle.c +++ b/reactos/ntoskrnl/ob/obhandle.c @@ -1716,8 +1716,7 @@ ObpSetHandleAttributes(IN PHANDLE_TABLE HandleTable, 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();