mirror of
https://github.com/reactos/reactos.git
synced 2025-06-01 15:38:37 +00:00
- Commit NTLPC and remove old implementation.
- Yeah, this adds another regression on top of the new Ob stuff, but in the end it's for the better, as it removes more race conditions and buggy code. - This whole week I've fixed about 45 bugs and removed a dozen race conditions, sorry for the 2-3 regressions, they will be fixed ASAP. - DELETE MAKEFILE.AUTO BEFORE BUILDING THIS BUILD. svn path=/trunk/; revision=25411
This commit is contained in:
parent
d8160f0676
commit
6af685313a
25 changed files with 2554 additions and 5332 deletions
|
@ -75,6 +75,6 @@
|
|||
working on the \ntlpc directory. Leave this disabled unless you really know
|
||||
what you're doing.
|
||||
-->
|
||||
<property name="NTLPC" value="0" />
|
||||
<property name="NTLPC" value="1" />
|
||||
|
||||
</rbuild>
|
||||
|
|
|
@ -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"
|
||||
|
|
|
@ -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;
|
||||
}
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcExitThread(IN PETHREAD Thread)
|
||||
{
|
||||
PLPCP_MESSAGE Message;
|
||||
|
||||
/* Acquire the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Make sure that the Reply Chain is empty */
|
||||
if (!IsListEmpty(&Thread->LpcReplyChain))
|
||||
{
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* 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 */
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/**********************************************************************
|
||||
* NAME
|
||||
* LpcpVerifyCreateParameters/5
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Verify user parameters in NtCreatePort and in
|
||||
* NtCreateWaitablePort.
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* RETURN VALUE
|
||||
*/
|
||||
static NTSTATUS STDCALL
|
||||
LpcpVerifyCreateParameters (IN PHANDLE PortHandle,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN ULONG MaxConnectInfoLength,
|
||||
IN ULONG MaxDataLength,
|
||||
IN ULONG MaxPoolUsage)
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
|
||||
{
|
||||
if (NULL == PortHandle)
|
||||
{
|
||||
return (STATUS_INVALID_PARAMETER_1);
|
||||
}
|
||||
if (NULL == ObjectAttributes)
|
||||
{
|
||||
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 */
|
||||
|
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
* NAME EXPORTED
|
||||
* NtListenPort@8
|
||||
*
|
||||
* DESCRIPTION
|
||||
* Listen on a named port and wait for a connection attempt.
|
||||
*
|
||||
* ARGUMENTS
|
||||
* PortHandle [IN] LPC port to listen on.
|
||||
*
|
||||
* ConnectMsg [IN] User provided storage for a
|
||||
* possible connection request LPC message.
|
||||
*
|
||||
* RETURN VALUE
|
||||
* STATUS_SUCCESS if a connection request is received
|
||||
* successfully; otherwise an error code.
|
||||
*
|
||||
* The buffer ConnectMessage is filled with the connection
|
||||
* request message queued by NtConnectPort() in PortHandle.
|
||||
*
|
||||
* NOTE
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
/*EXPORTED*/ NTSTATUS STDCALL
|
||||
NtListenPort (IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE ConnectMsg)
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtListenPort(IN HANDLE PortHandle,
|
||||
OUT PPORT_MESSAGE ConnectMessage)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcExitThread(IN PETHREAD Thread)
|
||||
{
|
||||
PLPCP_MESSAGE Message;
|
||||
|
||||
/* Acquire the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Make sure that the Reply Chain is empty */
|
||||
if (!IsListEmpty(&Thread->LpcReplyChain))
|
||||
{
|
||||
/* It's not, remove the entry */
|
||||
RemoveEntryList(&Thread->LpcReplyChain);
|
||||
}
|
||||
|
||||
/* Set the thread in exit mode */
|
||||
Thread->LpcExitThreadCalled = TRUE;
|
||||
Thread->LpcReplyMessageId = 0;
|
||||
|
||||
/* Check if there's a reply message */
|
||||
Message = Thread->LpcReplyMessage;
|
||||
if (Message)
|
||||
{
|
||||
/* FIXME: TODO */
|
||||
KEBUGCHECK(0);
|
||||
}
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpFreeToPortZone(IN PLPCP_MESSAGE Message,
|
||||
IN ULONG Flags)
|
||||
{
|
||||
PLPCP_CONNECTION_MESSAGE ConnectMessage;
|
||||
PLPCP_PORT_OBJECT ClientPort = NULL;
|
||||
PETHREAD Thread = NULL;
|
||||
BOOLEAN LockHeld = Flags & 1;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. Flags: %lx\n", Message, Flags);
|
||||
|
||||
/* Acquire the lock if not already */
|
||||
if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if the queue list is empty */
|
||||
if (!IsListEmpty(&Message->Entry))
|
||||
{
|
||||
/* Remove and re-initialize */
|
||||
RemoveEntryList(&Message->Entry);
|
||||
InitializeListHead(&Message->Entry);
|
||||
}
|
||||
|
||||
/* Check if we've already replied */
|
||||
if (Message->RepliedToThread)
|
||||
{
|
||||
/* Set thread to dereference and clean up */
|
||||
Thread = Message->RepliedToThread;
|
||||
Message->RepliedToThread = NULL;
|
||||
}
|
||||
|
||||
/* Check if this is a connection request */
|
||||
if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
|
||||
{
|
||||
/* Get the connection message */
|
||||
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
|
||||
|
||||
/* Clear the client port */
|
||||
ClientPort = ConnectMessage->ClientPort;
|
||||
if (ClientPort) ConnectMessage->ClientPort = NULL;
|
||||
}
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if we had anything to dereference */
|
||||
if (Thread) ObDereferenceObject(Thread);
|
||||
if (ClientPort) ObDereferenceObject(ClientPort);
|
||||
|
||||
/* Free the entry */
|
||||
ExFreeToPagedLookasideList(&LpcpMessagesLookaside, Message);
|
||||
|
||||
/* Reacquire the lock if needed */
|
||||
if ((LockHeld) && !(Flags & 2)) KeAcquireGuardedMutex(&LpcpLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port,
|
||||
IN BOOLEAN Destroy)
|
||||
{
|
||||
PLIST_ENTRY ListHead, NextEntry;
|
||||
PETHREAD Thread;
|
||||
PLPCP_MESSAGE Message;
|
||||
PLPCP_CONNECTION_MESSAGE ConnectMessage;
|
||||
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
|
||||
|
||||
/* Hold the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Disconnect the port to which this port is connected */
|
||||
if (Port->ConnectedPort) Port->ConnectedPort->ConnectedPort = NULL;
|
||||
|
||||
/* Check if this is a connection port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
|
||||
{
|
||||
/* Delete the name */
|
||||
Port->Flags |= LPCP_NAME_DELETED;
|
||||
}
|
||||
|
||||
/* Walk all the threads waiting and signal them */
|
||||
ListHead = &Port->LpcReplyChainHead;
|
||||
NextEntry = ListHead->Flink;
|
||||
while (NextEntry != ListHead)
|
||||
{
|
||||
/* Get the Thread */
|
||||
Thread = CONTAINING_RECORD(NextEntry, ETHREAD, LpcReplyChain);
|
||||
|
||||
/* Make sure we're not in exit */
|
||||
if (Thread->LpcExitThreadCalled) break;
|
||||
|
||||
/* Move to the next entry */
|
||||
NextEntry = NextEntry->Flink;
|
||||
|
||||
/* Remove and reinitialize the List */
|
||||
RemoveEntryList(&Thread->LpcReplyChain);
|
||||
InitializeListHead(&Thread->LpcReplyChain);
|
||||
|
||||
/* Check if someone is waiting */
|
||||
if (!KeReadStateSemaphore(&Thread->LpcReplySemaphore))
|
||||
{
|
||||
/* Get the message and check if it's a connection request */
|
||||
Message = Thread->LpcReplyMessage;
|
||||
if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
|
||||
{
|
||||
/* Get the connection message */
|
||||
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
|
||||
|
||||
/* Check if it had a section */
|
||||
if (ConnectMessage->SectionToMap)
|
||||
{
|
||||
/* Dereference it */
|
||||
ObDereferenceObject(ConnectMessage->SectionToMap);
|
||||
}
|
||||
}
|
||||
|
||||
/* Clear the reply message */
|
||||
Thread->LpcReplyMessage = NULL;
|
||||
|
||||
/* And remove the message from the port zone */
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
}
|
||||
|
||||
/* Release the semaphore and reset message id count */
|
||||
Thread->LpcReplyMessageId = 0;
|
||||
LpcpCompleteWait(&Thread->LpcReplySemaphore);
|
||||
}
|
||||
|
||||
/* Reinitialize the list head */
|
||||
InitializeListHead(&Port->LpcReplyChainHead);
|
||||
|
||||
/* Loop queued messages */
|
||||
ListHead = &Port->MsgQueue.ReceiveHead;
|
||||
NextEntry = ListHead->Flink;
|
||||
while (ListHead != NextEntry)
|
||||
{
|
||||
/* Get the message */
|
||||
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
|
||||
NextEntry = NextEntry->Flink;
|
||||
|
||||
/* Free and reinitialize it's list head */
|
||||
InitializeListHead(&Message->Entry);
|
||||
|
||||
/* Remove it from the port zone */
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
}
|
||||
|
||||
/* Reinitialize the message queue list head */
|
||||
InitializeListHead(&Port->MsgQueue.ReceiveHead);
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if we have to free the port entirely */
|
||||
if (Destroy)
|
||||
{
|
||||
/* Check if the semaphore exists */
|
||||
if (Port->MsgQueue.Semaphore)
|
||||
{
|
||||
/* Use the semaphore to find the port queue and free it */
|
||||
ExFreePool(CONTAINING_RECORD(Port->MsgQueue.Semaphore,
|
||||
LPCP_NONPAGED_PORT_QUEUE,
|
||||
Semaphore));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpClosePort(IN PEPROCESS Process OPTIONAL,
|
||||
IN PVOID Object,
|
||||
IN ACCESS_MASK GrantedAccess,
|
||||
IN ULONG ProcessHandleCount,
|
||||
IN ULONG SystemHandleCount)
|
||||
{
|
||||
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object;
|
||||
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
|
||||
|
||||
/* Only Server-side Connection Ports need clean up*/
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
|
||||
{
|
||||
/* Check the handle count */
|
||||
switch (SystemHandleCount)
|
||||
{
|
||||
/* No handles left */
|
||||
case 0:
|
||||
|
||||
/* Destroy the port queue */
|
||||
LpcpDestroyPortQueue(Port, TRUE);
|
||||
break;
|
||||
|
||||
/* Last handle remaining */
|
||||
case 1:
|
||||
|
||||
/* Reset the queue only */
|
||||
LpcpDestroyPortQueue(Port, FALSE);
|
||||
|
||||
/* More handles remain, do nothing */
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port)
|
||||
{
|
||||
/* Check if this is a client port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
|
||||
{
|
||||
/* Check if security is static */
|
||||
if (!(Port->Flags & LPCP_SECURITY_DYNAMIC))
|
||||
{
|
||||
/* Check if we have a token */
|
||||
if (Port->StaticSecurity.ClientToken)
|
||||
{
|
||||
/* Free security */
|
||||
SeDeleteClientSecurity(&Port->StaticSecurity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpDeletePort(IN PVOID ObjectBody)
|
||||
{
|
||||
LARGE_INTEGER Timeout;
|
||||
PETHREAD Thread;
|
||||
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody;
|
||||
PLPCP_PORT_OBJECT ConnectionPort;
|
||||
PLPCP_MESSAGE Message;
|
||||
PLIST_ENTRY ListHead, NextEntry;
|
||||
HANDLE Pid;
|
||||
CLIENT_DIED_MSG ClientDiedMsg;
|
||||
Timeout.QuadPart = -1000000;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
|
||||
|
||||
/* Check if this is a communication port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT)
|
||||
{
|
||||
/* Acquire the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Get the thread */
|
||||
Thread = Port->ClientThread;
|
||||
if (Thread)
|
||||
{
|
||||
/* Clear it */
|
||||
Port->ClientThread = NULL;
|
||||
|
||||
/* Release the lock and dereference */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(Thread);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if this is a client-side port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
|
||||
{
|
||||
/* Setup the client died message */
|
||||
ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg);
|
||||
ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime);
|
||||
ClientDiedMsg.h.u2.ZeroInit = LPC_PORT_CLOSED;
|
||||
ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime;
|
||||
|
||||
/* Send it */
|
||||
for (;;)
|
||||
{
|
||||
/* Send the message */
|
||||
if (LpcRequestPort(Port,
|
||||
&ClientDiedMsg.h) != STATUS_NO_MEMORY) break;
|
||||
|
||||
/* Wait until trying again */
|
||||
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
|
||||
}
|
||||
}
|
||||
|
||||
/* Destroy the port queue */
|
||||
LpcpDestroyPortQueue(Port, TRUE);
|
||||
|
||||
/* Check if we had a client view */
|
||||
if (Port->ClientSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
|
||||
Port->ClientSectionBase);
|
||||
|
||||
/* Check for a server view */
|
||||
if (Port->ServerSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
|
||||
Port->ServerSectionBase);
|
||||
|
||||
/* Get the connection port */
|
||||
ConnectionPort = Port->ConnectionPort;
|
||||
if (ConnectionPort)
|
||||
{
|
||||
/* Get the PID */
|
||||
Pid = PsGetCurrentProcessId();
|
||||
|
||||
/* Acquire the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Loop the data lists */
|
||||
ListHead = &ConnectionPort->LpcDataInfoChainHead;
|
||||
NextEntry = ListHead->Flink;
|
||||
while (NextEntry != ListHead)
|
||||
{
|
||||
/* Get the message */
|
||||
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
|
||||
NextEntry = NextEntry->Flink;
|
||||
|
||||
/* Check if the PID matches */
|
||||
if (Message->Request.ClientId.UniqueProcess == Pid)
|
||||
{
|
||||
/* Remove it */
|
||||
RemoveEntryList(&Message->Entry);
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Dereference the object unless it's the same port */
|
||||
if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort);
|
||||
}
|
||||
|
||||
/* Check if this is a connection port with a server process*/
|
||||
if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) &&
|
||||
(ConnectionPort->ServerProcess))
|
||||
{
|
||||
/* Dereference the server process */
|
||||
ObDereferenceObject(ConnectionPort->ServerProcess);
|
||||
ConnectionPort->ServerProcess = NULL;
|
||||
}
|
||||
|
||||
/* Free client security */
|
||||
LpcpFreePortClientSecurity(Port);
|
||||
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port);
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpPrepareToWakeClient(IN PETHREAD Thread)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* Make sure the thread isn't dying and it has a valid chain */
|
||||
if (!(Thread->LpcExitThreadCalled) &&
|
||||
!(IsListEmpty(&Thread->LpcReplyChain)))
|
||||
{
|
||||
/* Remove it from the list and reinitialize it */
|
||||
RemoveEntryList(&Thread->LpcReplyChain);
|
||||
InitializeListHead(&Thread->LpcReplyChain);
|
||||
}
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtAcceptConnectPort(OUT PHANDLE PortHandle,
|
||||
IN PVOID PortContext OPTIONAL,
|
||||
IN PPORT_MESSAGE ReplyMessage,
|
||||
IN BOOLEAN AcceptConnection,
|
||||
IN PPORT_VIEW ServerView,
|
||||
IN PREMOTE_PORT_VIEW ClientView)
|
||||
{
|
||||
PLPCP_PORT_OBJECT ConnectionPort, ServerPort, ClientPort;
|
||||
PVOID ClientSectionToMap = NULL;
|
||||
HANDLE Handle;
|
||||
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||
NTSTATUS Status;
|
||||
ULONG ConnectionInfoLength;
|
||||
PLPCP_MESSAGE Message;
|
||||
PLPCP_CONNECTION_MESSAGE ConnectMessage;
|
||||
PEPROCESS ClientProcess;
|
||||
PETHREAD ClientThread;
|
||||
LARGE_INTEGER SectionOffset;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_COMPLETE_DEBUG,
|
||||
"Context: %p. Message: %p. Accept: %lx. Views: %p/%p\n",
|
||||
PortContext,
|
||||
ReplyMessage,
|
||||
AcceptConnection,
|
||||
ClientView,
|
||||
ServerView);
|
||||
|
||||
/* Validate the size of the server view */
|
||||
if ((ServerView) && (ServerView->Length != sizeof(PORT_VIEW)))
|
||||
{
|
||||
/* Invalid size */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Validate the size of the client view */
|
||||
if ((ClientView) && (ClientView->Length != sizeof(REMOTE_PORT_VIEW)))
|
||||
{
|
||||
/* Invalid size */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Get the client process and thread */
|
||||
Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
|
||||
&ClientProcess,
|
||||
&ClientThread);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Acquire the LPC Lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Make sure that the client wants a reply, and this is the right one */
|
||||
if (!(ClientThread->LpcReplyMessage) ||
|
||||
!(ReplyMessage->MessageId) ||
|
||||
(ClientThread->LpcReplyMessageId != ReplyMessage->MessageId))
|
||||
{
|
||||
/* Not the reply asked for, or no reply wanted, fail */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(ClientProcess);
|
||||
ObDereferenceObject(ClientThread);
|
||||
return STATUS_REPLY_MESSAGE_MISMATCH;
|
||||
}
|
||||
|
||||
/* Now get the message and connection message */
|
||||
Message = ClientThread->LpcReplyMessage;
|
||||
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
|
||||
|
||||
/* Get the client and connection port as well */
|
||||
ClientPort = ConnectMessage->ClientPort;
|
||||
ConnectionPort = ClientPort->ConnectionPort;
|
||||
|
||||
/* Make sure that the reply is being sent to the proper server process */
|
||||
if (ConnectionPort->ServerProcess != PsGetCurrentProcess())
|
||||
{
|
||||
/* It's not, so fail */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(ClientProcess);
|
||||
ObDereferenceObject(ClientThread);
|
||||
return STATUS_REPLY_MESSAGE_MISMATCH;
|
||||
}
|
||||
|
||||
/* At this point, don't let other accept attempts happen */
|
||||
ClientThread->LpcReplyMessage = NULL;
|
||||
ClientThread->LpcReplyMessageId = 0;
|
||||
|
||||
/* Clear the client port for now as well, then release the lock */
|
||||
ConnectMessage->ClientPort = NULL;
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Get the connection information length */
|
||||
ConnectionInfoLength = ReplyMessage->u1.s1.DataLength;
|
||||
if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength)
|
||||
{
|
||||
/* Normalize it since it's too large */
|
||||
ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength;
|
||||
}
|
||||
|
||||
/* Set the sizes of our reply message */
|
||||
Message->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
|
||||
ConnectionInfoLength;
|
||||
Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
|
||||
Message->Request.u1.s1.DataLength;
|
||||
|
||||
/* Setup the reply message */
|
||||
Message->Request.u2.s2.Type = LPC_REPLY;
|
||||
Message->Request.u2.s2.DataInfoOffset = 0;
|
||||
Message->Request.ClientId = ReplyMessage->ClientId;
|
||||
Message->Request.MessageId = ReplyMessage->MessageId;
|
||||
Message->Request.ClientViewSize = 0;
|
||||
RtlMoveMemory(ConnectMessage + 1, ReplyMessage + 1, ConnectionInfoLength);
|
||||
|
||||
/* At this point, if the caller refused the connection, go to cleanup */
|
||||
if (!AcceptConnection) goto Cleanup;
|
||||
|
||||
/* Otherwise, create the actual port */
|
||||
Status = ObCreateObject(PreviousMode,
|
||||
LpcPortObjectType,
|
||||
NULL,
|
||||
PreviousMode,
|
||||
NULL,
|
||||
sizeof(LPCP_PORT_OBJECT),
|
||||
0,
|
||||
0,
|
||||
(PVOID*)&ServerPort);
|
||||
if (!NT_SUCCESS(Status)) goto Cleanup;
|
||||
|
||||
/* Set it up */
|
||||
RtlZeroMemory(ServerPort, sizeof(LPCP_PORT_OBJECT));
|
||||
ServerPort->PortContext = PortContext;
|
||||
ServerPort->Flags = LPCP_COMMUNICATION_PORT;
|
||||
ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength;
|
||||
InitializeListHead(&ServerPort->LpcReplyChainHead);
|
||||
InitializeListHead(&ServerPort->LpcDataInfoChainHead);
|
||||
|
||||
/* Reference the connection port until we're fully setup */
|
||||
ObReferenceObject(ConnectionPort);
|
||||
|
||||
/* Link the ports together */
|
||||
ServerPort->ConnectionPort = ConnectionPort;
|
||||
ServerPort->ConnectedPort = ClientPort;
|
||||
ClientPort->ConnectedPort = ServerPort;
|
||||
|
||||
/* Also set the creator CID */
|
||||
ServerPort->Creator = PsGetCurrentThread()->Cid;
|
||||
ClientPort->Creator = Message->Request.ClientId;
|
||||
|
||||
/* Get the section associated and then clear it, while inside the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
ClientSectionToMap = ConnectMessage->SectionToMap;
|
||||
ConnectMessage->SectionToMap = NULL;
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Now check if there's a client section */
|
||||
if (ClientSectionToMap)
|
||||
{
|
||||
/* Setup the offset */
|
||||
SectionOffset.QuadPart = ConnectMessage->ClientView.SectionOffset;
|
||||
|
||||
/* Map the section */
|
||||
Status = MmMapViewOfSection(ClientSectionToMap,
|
||||
PsGetCurrentProcess(),
|
||||
&ServerPort->ClientSectionBase,
|
||||
0,
|
||||
0,
|
||||
&SectionOffset,
|
||||
&ConnectMessage->ClientView.ViewSize,
|
||||
ViewUnmap,
|
||||
0,
|
||||
PAGE_READWRITE);
|
||||
|
||||
/* Update the offset and check for mapping status */
|
||||
ConnectMessage->ClientView.SectionOffset = SectionOffset.LowPart;
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Set the view base */
|
||||
ConnectMessage->ClientView.ViewRemoteBase = ServerPort->
|
||||
ClientSectionBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, quit */
|
||||
ObDereferenceObject(ServerPort);
|
||||
goto Cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if there's a server section */
|
||||
if (ServerView)
|
||||
{
|
||||
/* FIXME: TODO */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* Reference the server port until it's fully inserted */
|
||||
ObReferenceObject(ServerPort);
|
||||
|
||||
/* Insert the server port in the namespace */
|
||||
Status = ObInsertObject(ServerPort,
|
||||
NULL,
|
||||
PORT_ALL_ACCESS,
|
||||
0,
|
||||
NULL,
|
||||
&Handle);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* We failed, remove the extra reference and cleanup */
|
||||
ObDereferenceObject(ServerPort);
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Check if the caller gave a client view */
|
||||
if (ClientView)
|
||||
{
|
||||
/* Fill it out */
|
||||
ClientView->ViewBase = ConnectMessage->ClientView.ViewRemoteBase;
|
||||
ClientView->ViewSize = ConnectMessage->ClientView.ViewSize;
|
||||
}
|
||||
|
||||
/* Return the handle to user mode */
|
||||
*PortHandle = Handle;
|
||||
LPCTRACE(LPC_COMPLETE_DEBUG,
|
||||
"Handle: %lx. Messages: %p/%p. Ports: %p/%p/%p\n",
|
||||
Handle,
|
||||
Message,
|
||||
ConnectMessage,
|
||||
ServerPort,
|
||||
ClientPort,
|
||||
ConnectionPort);
|
||||
|
||||
/* If there was no port context, use the handle by default */
|
||||
if (!PortContext) ServerPort->PortContext = Handle;
|
||||
ServerPort->ClientThread = ClientThread;
|
||||
|
||||
/* Set this message as the LPC Reply message while holding the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
ClientThread->LpcReplyMessage = Message;
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Clear the thread pointer so it doesn't get cleaned later */
|
||||
ClientThread = NULL;
|
||||
|
||||
/* Remove the extra reference we had added */
|
||||
ObDereferenceObject(ServerPort);
|
||||
|
||||
Cleanup:
|
||||
/* If there was a section, dereference it */
|
||||
if (ClientSectionToMap) ObDereferenceObject(ClientSectionToMap);
|
||||
|
||||
/* Check if we got here while still having a client thread */
|
||||
if (ClientThread)
|
||||
{
|
||||
/* FIXME: Complex cleanup code */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* Dereference the client port if we have one, and the process */
|
||||
LPCTRACE(LPC_COMPLETE_DEBUG,
|
||||
"Status: %lx. Thread: %p. Process: [%.16s]\n",
|
||||
Status,
|
||||
ClientThread,
|
||||
ClientProcess->ImageFileName);
|
||||
if (ClientPort) ObDereferenceObject(ClientPort);
|
||||
ObDereferenceObject(ClientProcess);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtCompleteConnectPort(IN HANDLE PortHandle)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PLPCP_PORT_OBJECT Port;
|
||||
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||
PETHREAD Thread;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_COMPLETE_DEBUG, "Handle: %lx\n", PortHandle);
|
||||
|
||||
/* Get the Port Object */
|
||||
Status = ObReferenceObjectByHandle(PortHandle,
|
||||
PORT_ALL_ACCESS,
|
||||
LpcPortObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&Port,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Make sure this is a connection port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
|
||||
{
|
||||
/* It isn't, fail */
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_INVALID_PORT_HANDLE;
|
||||
}
|
||||
|
||||
/* Acquire the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Make sure we have a client thread */
|
||||
if (!Port->ClientThread)
|
||||
{
|
||||
/* We don't, fail */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Get the thread */
|
||||
Thread = Port->ClientThread;
|
||||
|
||||
/* Make sure it has a reply message */
|
||||
if (!Thread->LpcReplyMessage)
|
||||
{
|
||||
/* It doesn't, fail */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_PORT_DISCONNECTED;
|
||||
}
|
||||
|
||||
/* Clear the client thread and wake it up */
|
||||
Port->ClientThread = NULL;
|
||||
LpcpPrepareToWakeClient(Thread);
|
||||
|
||||
/* Release the lock and wait for an answer */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
LpcpCompleteWait(&Thread->LpcReplySemaphore);
|
||||
|
||||
/* Dereference the Thread and Port and return */
|
||||
ObDereferenceObject(Port);
|
||||
ObDereferenceObject(Thread);
|
||||
LPCTRACE(LPC_COMPLETE_DEBUG, "Port: %p. Thread: %p\n", Port, Thread);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
PVOID
|
||||
NTAPI
|
||||
LpcpFreeConMsg(IN OUT PLPCP_MESSAGE *Message,
|
||||
IN OUT PLPCP_CONNECTION_MESSAGE *ConnectMessage,
|
||||
IN PETHREAD CurrentThread)
|
||||
{
|
||||
PVOID SectionToMap;
|
||||
|
||||
/* Acquire the LPC lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if the reply chain is not empty */
|
||||
if (!IsListEmpty(&CurrentThread->LpcReplyChain))
|
||||
{
|
||||
/* Remove this entry and re-initialize it */
|
||||
RemoveEntryList(&CurrentThread->LpcReplyChain);
|
||||
InitializeListHead(&CurrentThread->LpcReplyChain);
|
||||
}
|
||||
|
||||
/* Check if there's a reply message */
|
||||
if (CurrentThread->LpcReplyMessage)
|
||||
{
|
||||
/* Get the message */
|
||||
*Message = CurrentThread->LpcReplyMessage;
|
||||
|
||||
/* Clear message data */
|
||||
CurrentThread->LpcReceivedMessageId = 0;
|
||||
CurrentThread->LpcReplyMessage = NULL;
|
||||
|
||||
/* Get the connection message and clear the section */
|
||||
*ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(*Message + 1);
|
||||
SectionToMap = (*ConnectMessage)->SectionToMap;
|
||||
(*ConnectMessage)->SectionToMap = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No message to return */
|
||||
*Message = NULL;
|
||||
SectionToMap = NULL;
|
||||
}
|
||||
|
||||
/* Release the lock and return the section */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
return SectionToMap;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtSecureConnectPort(OUT PHANDLE PortHandle,
|
||||
IN PUNICODE_STRING PortName,
|
||||
IN PSECURITY_QUALITY_OF_SERVICE Qos,
|
||||
IN OUT PPORT_VIEW ClientView OPTIONAL,
|
||||
IN PSID ServerSid OPTIONAL,
|
||||
IN OUT PREMOTE_PORT_VIEW ServerView OPTIONAL,
|
||||
OUT PULONG MaxMessageLength OPTIONAL,
|
||||
IN OUT PVOID ConnectionInformation OPTIONAL,
|
||||
IN OUT PULONG ConnectionInformationLength OPTIONAL)
|
||||
{
|
||||
ULONG ConnectionInfoLength = 0;
|
||||
PLPCP_PORT_OBJECT Port, ClientPort;
|
||||
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||
NTSTATUS Status = STATUS_SUCCESS;
|
||||
HANDLE Handle;
|
||||
PVOID SectionToMap;
|
||||
PLPCP_MESSAGE Message;
|
||||
PLPCP_CONNECTION_MESSAGE ConnectMessage;
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
ULONG PortMessageLength;
|
||||
LARGE_INTEGER SectionOffset;
|
||||
PTOKEN Token;
|
||||
PTOKEN_USER TokenUserInfo;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_CONNECT_DEBUG,
|
||||
"Name: %wZ. Qos: %p. Views: %p/%p. Sid: %p\n",
|
||||
PortName,
|
||||
Qos,
|
||||
ClientView,
|
||||
ServerView,
|
||||
ServerSid);
|
||||
|
||||
/* Validate client view */
|
||||
if ((ClientView) && (ClientView->Length != sizeof(PORT_VIEW)))
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Validate server view */
|
||||
if ((ServerView) && (ServerView->Length != sizeof(REMOTE_PORT_VIEW)))
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Check if caller sent connection information length */
|
||||
if (ConnectionInformationLength)
|
||||
{
|
||||
/* Retrieve the input length */
|
||||
ConnectionInfoLength = *ConnectionInformationLength;
|
||||
}
|
||||
|
||||
/* Get the port */
|
||||
Status = ObReferenceObjectByName(PortName,
|
||||
0,
|
||||
NULL,
|
||||
PORT_ALL_ACCESS,
|
||||
LpcPortObjectType,
|
||||
PreviousMode,
|
||||
NULL,
|
||||
(PVOID *)&Port);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* This has to be a connection port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
|
||||
{
|
||||
/* It isn't, so fail */
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_INVALID_PORT_HANDLE;
|
||||
}
|
||||
|
||||
/* Check if we have a SID */
|
||||
if (ServerSid)
|
||||
{
|
||||
/* Make sure that we have a server */
|
||||
if (Port->ServerProcess)
|
||||
{
|
||||
/* Get its token and query user information */
|
||||
Token = PsReferencePrimaryToken(Port->ServerProcess);
|
||||
//Status = SeQueryInformationToken(Token, TokenUser, (PVOID*)&TokenUserInfo);
|
||||
// FIXME: Need SeQueryInformationToken
|
||||
Status = STATUS_SUCCESS;
|
||||
TokenUserInfo = ExAllocatePool(PagedPool, sizeof(TOKEN_USER));
|
||||
TokenUserInfo->User.Sid = ServerSid;
|
||||
PsDereferencePrimaryToken(Token);
|
||||
|
||||
/* Check for success */
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Compare the SIDs */
|
||||
if (!RtlEqualSid(ServerSid, TokenUserInfo->User.Sid))
|
||||
{
|
||||
/* Fail */
|
||||
Status = STATUS_SERVER_SID_MISMATCH;
|
||||
}
|
||||
|
||||
/* Free token information */
|
||||
ExFreePool(TokenUserInfo);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Invalid SID */
|
||||
Status = STATUS_SERVER_SID_MISMATCH;
|
||||
}
|
||||
|
||||
/* Check if SID failed */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Quit */
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the client port */
|
||||
Status = ObCreateObject(PreviousMode,
|
||||
LpcPortObjectType,
|
||||
NULL,
|
||||
PreviousMode,
|
||||
NULL,
|
||||
sizeof(LPCP_PORT_OBJECT),
|
||||
0,
|
||||
0,
|
||||
(PVOID *)&ClientPort);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Failed, dereference the server port and return */
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Setup the client port */
|
||||
RtlZeroMemory(ClientPort, sizeof(LPCP_PORT_OBJECT));
|
||||
ClientPort->Flags = LPCP_CLIENT_PORT;
|
||||
ClientPort->ConnectionPort = Port;
|
||||
ClientPort->MaxMessageLength = Port->MaxMessageLength;
|
||||
ClientPort->SecurityQos = *Qos;
|
||||
InitializeListHead(&ClientPort->LpcReplyChainHead);
|
||||
InitializeListHead(&ClientPort->LpcDataInfoChainHead);
|
||||
|
||||
/* Check if we have dynamic security */
|
||||
if (Qos->ContextTrackingMode == SECURITY_DYNAMIC_TRACKING)
|
||||
{
|
||||
/* Remember that */
|
||||
ClientPort->Flags |= LPCP_SECURITY_DYNAMIC;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Create our own client security */
|
||||
Status = SeCreateClientSecurity(Thread,
|
||||
Qos,
|
||||
FALSE,
|
||||
&ClientPort->StaticSecurity);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Security failed, dereference and return */
|
||||
ObDereferenceObject(ClientPort);
|
||||
return Status;
|
||||
}
|
||||
}
|
||||
|
||||
/* Initialize the port queue */
|
||||
Status = LpcpInitializePortQueue(ClientPort);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Failed */
|
||||
ObDereferenceObject(ClientPort);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Check if we have a client view */
|
||||
if (ClientView)
|
||||
{
|
||||
/* Get the section handle */
|
||||
Status = ObReferenceObjectByHandle(ClientView->SectionHandle,
|
||||
SECTION_MAP_READ |
|
||||
SECTION_MAP_WRITE,
|
||||
MmSectionObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&SectionToMap,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Fail */
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Set the section offset */
|
||||
SectionOffset.QuadPart = ClientView->SectionOffset;
|
||||
|
||||
/* Map it */
|
||||
Status = MmMapViewOfSection(SectionToMap,
|
||||
PsGetCurrentProcess(),
|
||||
&Port->ClientSectionBase,
|
||||
0,
|
||||
0,
|
||||
&SectionOffset,
|
||||
&ClientView->ViewSize,
|
||||
ViewUnmap,
|
||||
0,
|
||||
PAGE_READWRITE);
|
||||
|
||||
/* Update the offset */
|
||||
ClientView->SectionOffset = SectionOffset.LowPart;
|
||||
|
||||
/* Check for failure */
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Fail */
|
||||
ObDereferenceObject(SectionToMap);
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Update the base */
|
||||
ClientView->ViewBase = Port->ClientSectionBase;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No section */
|
||||
SectionToMap = NULL;
|
||||
}
|
||||
|
||||
/* Normalize connection information */
|
||||
if (ConnectionInfoLength > Port->MaxConnectionInfoLength)
|
||||
{
|
||||
/* Use the port's maximum allowed value */
|
||||
ConnectionInfoLength = Port->MaxConnectionInfoLength;
|
||||
}
|
||||
|
||||
/* Allocate a message from the port zone */
|
||||
Message = LpcpAllocateFromPortZone();
|
||||
if (!Message)
|
||||
{
|
||||
/* Fail if we couldn't allocate a message */
|
||||
if (SectionToMap) ObDereferenceObject(SectionToMap);
|
||||
ObDereferenceObject(ClientPort);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Set pointer to the connection message and fill in the CID */
|
||||
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
|
||||
Message->Request.ClientId = Thread->Cid;
|
||||
|
||||
/* Check if we have a client view */
|
||||
if (ClientView)
|
||||
{
|
||||
/* Set the view size */
|
||||
Message->Request.ClientViewSize = ClientView->ViewSize;
|
||||
|
||||
/* Copy the client view and clear the server view */
|
||||
RtlMoveMemory(&ConnectMessage->ClientView,
|
||||
ClientView,
|
||||
sizeof(PORT_VIEW));
|
||||
RtlZeroMemory(&ConnectMessage->ServerView, sizeof(REMOTE_PORT_VIEW));
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set the size to 0 and clear the connect message */
|
||||
Message->Request.ClientViewSize = 0;
|
||||
RtlZeroMemory(ConnectMessage, sizeof(LPCP_CONNECTION_MESSAGE));
|
||||
}
|
||||
|
||||
/* Set the section and client port. Port is NULL for now */
|
||||
ConnectMessage->ClientPort = NULL;
|
||||
ConnectMessage->SectionToMap = SectionToMap;
|
||||
|
||||
/* Set the data for the connection request message */
|
||||
Message->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
|
||||
ConnectionInfoLength;
|
||||
Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
|
||||
Message->Request.u1.s1.DataLength;
|
||||
Message->Request.u2.s2.Type = LPC_CONNECTION_REQUEST;
|
||||
|
||||
/* Check if we have connection information */
|
||||
if (ConnectionInformation)
|
||||
{
|
||||
/* Copy it in */
|
||||
RtlMoveMemory(ConnectMessage + 1,
|
||||
ConnectionInformation,
|
||||
ConnectionInfoLength);
|
||||
}
|
||||
|
||||
/* Acquire the port lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if someone already deleted the port name */
|
||||
if (Port->Flags & LPCP_NAME_DELETED)
|
||||
{
|
||||
/* Fail the request */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
goto Cleanup;
|
||||
}
|
||||
|
||||
/* Associate no thread yet */
|
||||
Message->RepliedToThread = NULL;
|
||||
|
||||
/* Generate the Message ID and set it */
|
||||
Message->Request.MessageId = LpcpNextMessageId++;
|
||||
if (!LpcpNextMessageId) LpcpNextMessageId = 1;
|
||||
Thread->LpcReplyMessageId = Message->Request.MessageId;
|
||||
|
||||
/* Insert the message into the queue and thread chain */
|
||||
InsertTailList(&Port->MsgQueue.ReceiveHead, &Message->Entry);
|
||||
InsertTailList(&Port->LpcReplyChainHead, &Thread->LpcReplyChain);
|
||||
Thread->LpcReplyMessage = Message;
|
||||
|
||||
/* Now we can finally reference the client port and link it*/
|
||||
ObReferenceObject(ClientPort);
|
||||
ConnectMessage->ClientPort = ClientPort;
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
LPCTRACE(LPC_CONNECT_DEBUG,
|
||||
"Messages: %p/%p. Ports: %p/%p. Status: %lx\n",
|
||||
Message,
|
||||
ConnectMessage,
|
||||
Port,
|
||||
ClientPort,
|
||||
Status);
|
||||
|
||||
/* If this is a waitable port, set the event */
|
||||
if (Port->Flags & LPCP_WAITABLE_PORT) KeSetEvent(&Port->WaitEvent,
|
||||
1,
|
||||
FALSE);
|
||||
|
||||
/* Release the queue semaphore */
|
||||
LpcpCompleteWait(Port->MsgQueue.Semaphore);
|
||||
|
||||
/* Now wait for a reply */
|
||||
LpcpConnectWait(&Thread->LpcReplySemaphore, PreviousMode);
|
||||
|
||||
/* Check if our wait ended in success */
|
||||
if (Status != STATUS_SUCCESS) goto Cleanup;
|
||||
|
||||
/* Free the connection message */
|
||||
SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
|
||||
|
||||
/* Check if we got a message back */
|
||||
if (Message)
|
||||
{
|
||||
/* Check for new return length */
|
||||
if ((Message->Request.u1.s1.DataLength -
|
||||
sizeof(LPCP_CONNECTION_MESSAGE)) < ConnectionInfoLength)
|
||||
{
|
||||
/* Set new normalized connection length */
|
||||
ConnectionInfoLength = Message->Request.u1.s1.DataLength -
|
||||
sizeof(LPCP_CONNECTION_MESSAGE);
|
||||
}
|
||||
|
||||
/* Check if we had connection information */
|
||||
if (ConnectionInformation)
|
||||
{
|
||||
/* Check if we had a length pointer */
|
||||
if (ConnectionInformationLength)
|
||||
{
|
||||
/* Return the length */
|
||||
*ConnectionInformationLength = ConnectionInfoLength;
|
||||
}
|
||||
|
||||
/* Return the connection information */
|
||||
RtlMoveMemory(ConnectionInformation,
|
||||
ConnectMessage + 1,
|
||||
ConnectionInfoLength );
|
||||
}
|
||||
|
||||
/* Make sure we had a connected port */
|
||||
if (ClientPort->ConnectedPort)
|
||||
{
|
||||
/* Get the message length before the port might get killed */
|
||||
PortMessageLength = Port->MaxMessageLength;
|
||||
|
||||
/* Insert the client port */
|
||||
Status = ObInsertObject(ClientPort,
|
||||
NULL,
|
||||
PORT_ALL_ACCESS,
|
||||
0,
|
||||
(PVOID *)NULL,
|
||||
&Handle);
|
||||
if (NT_SUCCESS(Status))
|
||||
{
|
||||
/* Return the handle */
|
||||
*PortHandle = Handle;
|
||||
LPCTRACE(LPC_CONNECT_DEBUG,
|
||||
"Handle: %lx. Length: %lx\n",
|
||||
Handle,
|
||||
PortMessageLength);
|
||||
|
||||
/* Check if maximum length was requested */
|
||||
if (MaxMessageLength) *MaxMessageLength = PortMessageLength;
|
||||
|
||||
/* Check if we had a client view */
|
||||
if (ClientView)
|
||||
{
|
||||
/* Copy it back */
|
||||
RtlMoveMemory(ClientView,
|
||||
&ConnectMessage->ClientView,
|
||||
sizeof(PORT_VIEW));
|
||||
}
|
||||
|
||||
/* Check if we had a server view */
|
||||
if (ServerView)
|
||||
{
|
||||
/* Copy it back */
|
||||
RtlMoveMemory(ServerView,
|
||||
&ConnectMessage->ServerView,
|
||||
sizeof(REMOTE_PORT_VIEW));
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No connection port, we failed */
|
||||
if (SectionToMap) ObDereferenceObject(SectionToMap);
|
||||
|
||||
/* Check if it's because the name got deleted */
|
||||
if (Port->Flags & LPCP_NAME_DELETED)
|
||||
{
|
||||
/* Set the correct status */
|
||||
Status = STATUS_OBJECT_NAME_NOT_FOUND;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, the caller refused us */
|
||||
Status = STATUS_PORT_CONNECTION_REFUSED;
|
||||
}
|
||||
|
||||
/* Kill the port */
|
||||
ObDereferenceObject(ClientPort);
|
||||
}
|
||||
|
||||
/* Free the message */
|
||||
LpcpFreeToPortZone(Message, FALSE);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* No reply message, fail */
|
||||
if (SectionToMap) ObDereferenceObject(SectionToMap);
|
||||
ObDereferenceObject(ClientPort);
|
||||
return STATUS_PORT_CONNECTION_REFUSED;
|
||||
|
||||
Cleanup:
|
||||
/* We failed, free the message */
|
||||
SectionToMap = LpcpFreeConMsg(&Message, &ConnectMessage, Thread);
|
||||
|
||||
/* Check if the semaphore got signaled */
|
||||
if (KeReadStateSemaphore(&Thread->LpcReplySemaphore))
|
||||
{
|
||||
/* Wait on it */
|
||||
KeWaitForSingleObject(&Thread->LpcReplySemaphore,
|
||||
KernelMode,
|
||||
Executive,
|
||||
FALSE,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/* Check if we had a message and free it */
|
||||
if (Message) LpcpFreeToPortZone(Message, FALSE);
|
||||
|
||||
/* Dereference other objects */
|
||||
if (SectionToMap) ObDereferenceObject(SectionToMap);
|
||||
ObDereferenceObject(ClientPort);
|
||||
|
||||
/* Return status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtConnectPort(OUT PHANDLE PortHandle,
|
||||
IN PUNICODE_STRING PortName,
|
||||
IN PSECURITY_QUALITY_OF_SERVICE Qos,
|
||||
IN PPORT_VIEW ClientView,
|
||||
IN PREMOTE_PORT_VIEW ServerView,
|
||||
OUT PULONG MaxMessageLength,
|
||||
IN PVOID ConnectionInformation,
|
||||
OUT PULONG ConnectionInformationLength)
|
||||
{
|
||||
/* Call the newer API */
|
||||
return NtSecureConnectPort(PortHandle,
|
||||
PortName,
|
||||
Qos,
|
||||
ClientView,
|
||||
NULL,
|
||||
ServerView,
|
||||
MaxMessageLength,
|
||||
ConnectionInformation,
|
||||
ConnectionInformationLength);
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
|
||||
{
|
||||
PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
|
||||
|
||||
/* Allocate the queue */
|
||||
MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
|
||||
sizeof(LPCP_NONPAGED_PORT_QUEUE),
|
||||
TAG('P', 'o', 'r', 't'));
|
||||
if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
|
||||
|
||||
/* Set it up */
|
||||
KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
|
||||
MessageQueue->BackPointer = Port;
|
||||
|
||||
/* And link it with the Paged Pool part */
|
||||
Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
|
||||
InitializeListHead(&Port->MsgQueue.ReceiveHead);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LpcpCreatePort(OUT PHANDLE PortHandle,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN ULONG MaxConnectionInfoLength,
|
||||
IN ULONG MaxMessageLength,
|
||||
IN ULONG MaxPoolUsage,
|
||||
IN BOOLEAN Waitable)
|
||||
{
|
||||
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||
NTSTATUS Status;
|
||||
PLPCP_PORT_OBJECT Port;
|
||||
LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName);
|
||||
|
||||
/* Create the Object */
|
||||
Status = ObCreateObject(PreviousMode,
|
||||
LpcPortObjectType,
|
||||
ObjectAttributes,
|
||||
PreviousMode,
|
||||
NULL,
|
||||
sizeof(LPCP_PORT_OBJECT),
|
||||
0,
|
||||
0,
|
||||
(PVOID*)&Port);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Set up the Object */
|
||||
RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
|
||||
Port->ConnectionPort = Port;
|
||||
Port->Creator = PsGetCurrentThread()->Cid;
|
||||
InitializeListHead(&Port->LpcDataInfoChainHead);
|
||||
InitializeListHead(&Port->LpcReplyChainHead);
|
||||
|
||||
/* Check if we don't have a name */
|
||||
if (!ObjectAttributes->ObjectName->Buffer)
|
||||
{
|
||||
/* Set up for an unconnected port */
|
||||
Port->Flags = LPCP_UNCONNECTED_PORT;
|
||||
Port->ConnectedPort = Port;
|
||||
Port->ServerProcess = NULL;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Set up for a named connection port */
|
||||
Port->Flags = LPCP_CONNECTION_PORT;
|
||||
Port->ServerProcess = PsGetCurrentProcess();
|
||||
|
||||
/* Don't let the process die on us */
|
||||
ObReferenceObject(Port->ServerProcess);
|
||||
}
|
||||
|
||||
/* Check if this is a waitable port */
|
||||
if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
|
||||
|
||||
/* Setup the port queue */
|
||||
Status = LpcpInitializePortQueue(Port);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* Fail */
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Check if this is a waitable port */
|
||||
if (Port->Flags & LPCP_WAITABLE_PORT)
|
||||
{
|
||||
/* Setup the wait event */
|
||||
KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
|
||||
}
|
||||
|
||||
/* Set the maximum message size allowed */
|
||||
Port->MaxMessageLength = LpcpMaxMessageSize -
|
||||
FIELD_OFFSET(LPCP_MESSAGE, Request);
|
||||
|
||||
/* Now subtract the actual message structures and get the data size */
|
||||
Port->MaxConnectionInfoLength = Port->MaxMessageLength -
|
||||
sizeof(PORT_MESSAGE) -
|
||||
sizeof(LPCP_CONNECTION_MESSAGE);
|
||||
|
||||
/* Validate the sizes */
|
||||
if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
|
||||
{
|
||||
/* Not enough space for your request */
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_INVALID_PARAMETER_3;
|
||||
}
|
||||
else if (Port->MaxMessageLength < MaxMessageLength)
|
||||
{
|
||||
/* Not enough space for your request */
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_INVALID_PARAMETER_4;
|
||||
}
|
||||
|
||||
/* Now set the custom setting */
|
||||
Port->MaxMessageLength = MaxMessageLength;
|
||||
|
||||
/* Insert it now */
|
||||
Status = ObInsertObject((PVOID)Port,
|
||||
NULL,
|
||||
PORT_ALL_ACCESS,
|
||||
0,
|
||||
NULL,
|
||||
PortHandle);
|
||||
|
||||
/* Return success or the error */
|
||||
LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %lx\n", Port, *PortHandle);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtCreatePort(OUT PHANDLE PortHandle,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN ULONG MaxConnectInfoLength,
|
||||
IN ULONG MaxDataLength,
|
||||
IN ULONG MaxPoolUsage)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* Call the internal API */
|
||||
return LpcpCreatePort(PortHandle,
|
||||
ObjectAttributes,
|
||||
MaxConnectInfoLength,
|
||||
MaxDataLength,
|
||||
MaxPoolUsage,
|
||||
FALSE);
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtCreateWaitablePort(OUT PHANDLE PortHandle,
|
||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||
IN ULONG MaxConnectInfoLength,
|
||||
IN ULONG MaxDataLength,
|
||||
IN ULONG MaxPoolUsage)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* Call the internal API */
|
||||
return LpcpCreatePort(PortHandle,
|
||||
ObjectAttributes,
|
||||
MaxConnectInfoLength,
|
||||
MaxDataLength,
|
||||
MaxPoolUsage,
|
||||
TRUE);
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtListenPort(IN HANDLE PortHandle,
|
||||
OUT PPORT_MESSAGE ConnectMessage)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_LISTEN_DEBUG, "Handle: %lx\n", PortHandle);
|
||||
|
||||
/* Wait forever for a connection request. */
|
||||
for (;;)
|
||||
{
|
||||
/* Do the wait */
|
||||
Status = NtReplyWaitReceivePort(PortHandle,
|
||||
NULL,
|
||||
NULL,
|
||||
ConnectMessage);
|
||||
|
||||
/* Accept only LPC_CONNECTION_REQUEST requests. */
|
||||
if ((Status != STATUS_SUCCESS) ||
|
||||
(LpcpGetMessageType(ConnectMessage) == LPC_CONNECTION_REQUEST))
|
||||
{
|
||||
/* Break out */
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Return status */
|
||||
return Status;
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
|
@ -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"
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
POBJECT_TYPE LpcPortObjectType;
|
||||
ULONG LpcpMaxMessageSize;
|
||||
PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
|
||||
KGUARDED_MUTEX LpcpLock;
|
||||
ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG;
|
||||
ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;
|
||||
|
||||
static GENERIC_MAPPING LpcpPortMapping =
|
||||
{
|
||||
STANDARD_RIGHTS_READ,
|
||||
STANDARD_RIGHTS_WRITE,
|
||||
0,
|
||||
PORT_ALL_ACCESS
|
||||
};
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
NTSTATUS
|
||||
INIT_FUNCTION
|
||||
NTAPI
|
||||
LpcpInitSystem(VOID)
|
||||
{
|
||||
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
||||
UNICODE_STRING Name;
|
||||
|
||||
/* Setup the LPC Lock */
|
||||
KeInitializeGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Create the Port Object Type */
|
||||
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
||||
RtlInitUnicodeString(&Name, L"Port");
|
||||
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
||||
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(LPCP_PORT_OBJECT);
|
||||
ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(LPCP_NONPAGED_PORT_QUEUE);
|
||||
ObjectTypeInitializer.GenericMapping = LpcpPortMapping;
|
||||
ObjectTypeInitializer.PoolType = PagedPool;
|
||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
||||
ObjectTypeInitializer.CloseProcedure = LpcpClosePort;
|
||||
ObjectTypeInitializer.DeleteProcedure = LpcpDeletePort;
|
||||
ObjectTypeInitializer.ValidAccessMask = PORT_ALL_ACCESS;
|
||||
ObjectTypeInitializer.MaintainTypeList = TRUE;
|
||||
ObCreateObjectType(&Name,
|
||||
&ObjectTypeInitializer,
|
||||
NULL,
|
||||
&LpcPortObjectType);
|
||||
|
||||
/* Allocate the LPC lookaside list */
|
||||
LpcpMaxMessageSize = LPCP_MAX_MESSAGE_SIZE;
|
||||
ExInitializePagedLookasideList(&LpcpMessagesLookaside,
|
||||
NULL,
|
||||
NULL,
|
||||
0,
|
||||
LpcpMaxMessageSize,
|
||||
TAG('L', 'p', 'c', 'M'),
|
||||
32);
|
||||
|
||||
/* We're done */
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtImpersonateClientOfPort(IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE ClientMessage)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtQueryPortInformationProcess(VOID)
|
||||
{
|
||||
/* This is all this function does */
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtQueryInformationPort(IN HANDLE PortHandle,
|
||||
IN PORT_INFORMATION_CLASS PortInformationClass,
|
||||
OUT PVOID PortInformation,
|
||||
IN ULONG PortInformationLength,
|
||||
OUT PULONG ReturnLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* PRIVATE FUNCTIONS *********************************************************/
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
|
||||
IN ULONG MessageId,
|
||||
IN ULONG CallbackId)
|
||||
{
|
||||
PLPCP_MESSAGE Message;
|
||||
PLIST_ENTRY ListHead, NextEntry;
|
||||
|
||||
/* Check if the port we want is the connection port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
|
||||
{
|
||||
/* Use it */
|
||||
Port = Port->ConnectionPort;
|
||||
}
|
||||
|
||||
/* Loop the list */
|
||||
ListHead = &Port->LpcDataInfoChainHead;
|
||||
NextEntry = ListHead->Flink;
|
||||
while (ListHead != NextEntry)
|
||||
{
|
||||
/* Get the message */
|
||||
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
|
||||
|
||||
/* Make sure it matches */
|
||||
if ((Message->Request.MessageId == MessageId) &&
|
||||
(Message->Request.CallbackId == CallbackId))
|
||||
{
|
||||
/* Unlink and free it */
|
||||
RemoveEntryList(&Message->Entry);
|
||||
InitializeListHead(&Message->Entry);
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
break;
|
||||
}
|
||||
|
||||
/* Go to the next entry */
|
||||
NextEntry = NextEntry->Flink;
|
||||
}
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpSaveDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
|
||||
IN PLPCP_MESSAGE Message)
|
||||
{
|
||||
PAGED_CODE();
|
||||
|
||||
/* Acquire the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if the port we want is the connection port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
|
||||
{
|
||||
/* Use it */
|
||||
Port = Port->ConnectionPort;
|
||||
}
|
||||
|
||||
/* Link the message */
|
||||
InsertTailList(&Port->LpcDataInfoChainHead, &Message->Entry);
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
}
|
||||
|
||||
VOID
|
||||
NTAPI
|
||||
LpcpMoveMessage(IN PPORT_MESSAGE Destination,
|
||||
IN PPORT_MESSAGE Origin,
|
||||
IN PVOID Data,
|
||||
IN ULONG MessageType,
|
||||
IN PCLIENT_ID ClientId)
|
||||
{
|
||||
/* Set the Message size */
|
||||
LPCTRACE((LPC_REPLY_DEBUG | LPC_SEND_DEBUG),
|
||||
"Destination/Origin: %p/%p. Data: %p. Length: %lx\n",
|
||||
Destination,
|
||||
Origin,
|
||||
Data,
|
||||
Origin->u1.Length);
|
||||
Destination->u1.Length = Origin->u1.Length;
|
||||
|
||||
/* Set the Message Type */
|
||||
Destination->u2.s2.Type = !MessageType ?
|
||||
Origin->u2.s2.Type : MessageType & 0xFFFF;
|
||||
|
||||
/* Check if we have a Client ID */
|
||||
if (ClientId)
|
||||
{
|
||||
/* Set the Client ID */
|
||||
Destination->ClientId.UniqueProcess = ClientId->UniqueProcess;
|
||||
Destination->ClientId.UniqueThread = ClientId->UniqueThread;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, copy it */
|
||||
Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess;
|
||||
Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread;
|
||||
}
|
||||
|
||||
/* Copy the MessageId and ClientViewSize */
|
||||
Destination->MessageId = Origin->MessageId;
|
||||
Destination->ClientViewSize = Origin->ClientViewSize;
|
||||
|
||||
/* Copy the Message Data */
|
||||
RtlMoveMemory(Destination + 1,
|
||||
Data,
|
||||
((Destination->u1.Length & 0xFFFF) + 3) &~3);
|
||||
}
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtReplyPort(IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE LpcReply)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
|
||||
OUT PVOID *PortContext OPTIONAL,
|
||||
IN PPORT_MESSAGE ReplyMessage OPTIONAL,
|
||||
OUT PPORT_MESSAGE ReceiveMessage,
|
||||
IN PLARGE_INTEGER Timeout OPTIONAL)
|
||||
{
|
||||
PLPCP_PORT_OBJECT Port, ReceivePort;
|
||||
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode(), WaitMode = PreviousMode;
|
||||
NTSTATUS Status;
|
||||
PLPCP_MESSAGE Message;
|
||||
PETHREAD Thread = PsGetCurrentThread(), WakeupThread;
|
||||
PLPCP_CONNECTION_MESSAGE ConnectMessage;
|
||||
ULONG ConnectionInfoLength;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_REPLY_DEBUG,
|
||||
"Handle: %lx. Messages: %p/%p. Context: %p\n",
|
||||
PortHandle,
|
||||
ReplyMessage,
|
||||
ReceiveMessage,
|
||||
PortContext);
|
||||
|
||||
/* If this is a system thread, then let it page out its stack */
|
||||
if (Thread->SystemThread) WaitMode = UserMode;
|
||||
|
||||
/* Check if caller has a reply message */
|
||||
if (ReplyMessage)
|
||||
{
|
||||
/* Validate its length */
|
||||
if ((ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
|
||||
ReplyMessage->u1.s1.TotalLength)
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Make sure it has a valid ID */
|
||||
if (!ReplyMessage->MessageId) return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Get the Port object */
|
||||
Status = ObReferenceObjectByHandle(PortHandle,
|
||||
0,
|
||||
LpcPortObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&Port,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Check if the caller has a reply message */
|
||||
if (ReplyMessage)
|
||||
{
|
||||
/* Validate its length in respect to the port object */
|
||||
if ((ReplyMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
|
||||
(ReplyMessage->u1.s1.TotalLength <= ReplyMessage->u1.s1.DataLength))
|
||||
{
|
||||
/* Too large, fail */
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_PORT_MESSAGE_TOO_LONG;
|
||||
}
|
||||
}
|
||||
|
||||
/* Check if this is anything but a client port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CLIENT_PORT)
|
||||
{
|
||||
/* Use the connection port */
|
||||
ReceivePort = Port->ConnectionPort;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, use the port itself */
|
||||
ReceivePort = Port;
|
||||
}
|
||||
|
||||
/* Check if the caller gave a reply message */
|
||||
if (ReplyMessage)
|
||||
{
|
||||
/* Get the ETHREAD corresponding to it */
|
||||
Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
|
||||
NULL,
|
||||
&WakeupThread);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
/* No thread found, fail */
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* Allocate a message from the port zone */
|
||||
Message = LpcpAllocateFromPortZone();
|
||||
if (!Message)
|
||||
{
|
||||
/* Fail if we couldn't allocate a message */
|
||||
ObDereferenceObject(WakeupThread);
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Keep the lock acquired */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Make sure this is the reply the thread is waiting for */
|
||||
if (WakeupThread->LpcReplyMessageId != ReplyMessage->MessageId)
|
||||
{
|
||||
/* It isn't, fail */
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(WakeupThread);
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_REPLY_MESSAGE_MISMATCH;
|
||||
}
|
||||
|
||||
/* Copy the message */
|
||||
LpcpMoveMessage(&Message->Request,
|
||||
ReplyMessage,
|
||||
ReplyMessage + 1,
|
||||
LPC_REPLY,
|
||||
NULL);
|
||||
|
||||
/* Free any data information */
|
||||
LpcpFreeDataInfoMessage(Port,
|
||||
ReplyMessage->MessageId,
|
||||
ReplyMessage->CallbackId);
|
||||
|
||||
/* Reference the thread while we use it */
|
||||
ObReferenceObject(WakeupThread);
|
||||
Message->RepliedToThread = WakeupThread;
|
||||
|
||||
/* Set this as the reply message */
|
||||
WakeupThread->LpcReplyMessageId = 0;
|
||||
WakeupThread->LpcReplyMessage = (PVOID)Message;
|
||||
|
||||
/* Check if we have messages on the reply chain */
|
||||
if (!(WakeupThread->LpcExitThreadCalled) &&
|
||||
!(IsListEmpty(&WakeupThread->LpcReplyChain)))
|
||||
{
|
||||
/* Remove us from it and reinitialize it */
|
||||
RemoveEntryList(&WakeupThread->LpcReplyChain);
|
||||
InitializeListHead(&WakeupThread->LpcReplyChain);
|
||||
}
|
||||
|
||||
/* Check if this is the message the thread had received */
|
||||
if ((Thread->LpcReceivedMsgIdValid) &&
|
||||
(Thread->LpcReceivedMessageId == ReplyMessage->MessageId))
|
||||
{
|
||||
/* Clear this data */
|
||||
Thread->LpcReceivedMessageId = 0;
|
||||
Thread->LpcReceivedMsgIdValid = FALSE;
|
||||
}
|
||||
|
||||
/* Release the lock and release the LPC semaphore to wake up waiters */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
LpcpCompleteWait(&WakeupThread->LpcReplySemaphore);
|
||||
|
||||
/* Now we can let go of the thread */
|
||||
ObDereferenceObject(WakeupThread);
|
||||
}
|
||||
|
||||
/* Now wait for someone to reply to us */
|
||||
LpcpReceiveWait(ReceivePort->MsgQueue.Semaphore, WaitMode);
|
||||
if (Status != STATUS_SUCCESS) goto Cleanup;
|
||||
|
||||
/* Wait done, get the LPC lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if we've received nothing */
|
||||
if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
|
||||
{
|
||||
/* Check if this was a waitable port and wake it */
|
||||
if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
|
||||
{
|
||||
/* Reset its event */
|
||||
KeResetEvent(&ReceivePort->WaitEvent);
|
||||
}
|
||||
|
||||
/* Release the lock and fail */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_UNSUCCESSFUL;
|
||||
}
|
||||
|
||||
/* Get the message on the queue */
|
||||
Message = CONTAINING_RECORD(RemoveHeadList(&ReceivePort->
|
||||
MsgQueue.ReceiveHead),
|
||||
LPCP_MESSAGE,
|
||||
Entry);
|
||||
|
||||
/* Check if the queue is empty now */
|
||||
if (IsListEmpty(&ReceivePort->MsgQueue.ReceiveHead))
|
||||
{
|
||||
/* Check if this was a waitable port */
|
||||
if (ReceivePort->Flags & LPCP_WAITABLE_PORT)
|
||||
{
|
||||
/* Reset its event */
|
||||
KeResetEvent(&ReceivePort->WaitEvent);
|
||||
}
|
||||
}
|
||||
|
||||
/* Re-initialize the message's list entry */
|
||||
InitializeListHead(&Message->Entry);
|
||||
|
||||
/* Set this as the received message */
|
||||
Thread->LpcReceivedMessageId = Message->Request.MessageId;
|
||||
Thread->LpcReceivedMsgIdValid = TRUE;
|
||||
|
||||
/* Done touching global data, release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if this was a connection request */
|
||||
if (LpcpGetMessageType(&Message->Request) == LPC_CONNECTION_REQUEST)
|
||||
{
|
||||
/* Get the connection message */
|
||||
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
|
||||
LPCTRACE(LPC_REPLY_DEBUG,
|
||||
"Request Messages: %p/%p\n",
|
||||
Message,
|
||||
ConnectMessage);
|
||||
|
||||
/* Get its length */
|
||||
ConnectionInfoLength = Message->Request.u1.s1.DataLength -
|
||||
sizeof(LPCP_CONNECTION_MESSAGE);
|
||||
|
||||
/* Return it as the receive message */
|
||||
*ReceiveMessage = Message->Request;
|
||||
|
||||
/* Clear our stack variable so the message doesn't get freed */
|
||||
Message = NULL;
|
||||
|
||||
/* Setup the receive message */
|
||||
ReceiveMessage->u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
|
||||
ConnectionInfoLength;
|
||||
ReceiveMessage->u1.s1.DataLength = ConnectionInfoLength;
|
||||
RtlMoveMemory(ReceiveMessage + 1,
|
||||
ConnectMessage + 1,
|
||||
ConnectionInfoLength);
|
||||
|
||||
/* Clear the port context if the caller requested one */
|
||||
if (PortContext) *PortContext = NULL;
|
||||
}
|
||||
else if (Message->Request.u2.s2.Type != LPC_REPLY)
|
||||
{
|
||||
/* Otherwise, this is a new message or event */
|
||||
LPCTRACE(LPC_REPLY_DEBUG,
|
||||
"Non-Reply Messages: %p/%p\n",
|
||||
&Message->Request,
|
||||
(&Message->Request) + 1);
|
||||
|
||||
/* Copy it */
|
||||
LpcpMoveMessage(ReceiveMessage,
|
||||
&Message->Request,
|
||||
(&Message->Request) + 1,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
/* Return its context */
|
||||
if (PortContext) *PortContext = Message->PortContext;
|
||||
|
||||
/* And check if it has data information */
|
||||
if (Message->Request.u2.s2.DataInfoOffset)
|
||||
{
|
||||
/* It does, save it, and don't free the message below */
|
||||
LpcpSaveDataInfoMessage(Port, Message);
|
||||
Message = NULL;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a reply message, should never happen! */
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
|
||||
/* If we have a message pointer here, free it */
|
||||
if (Message) LpcpFreeToPortZone(Message, FALSE);
|
||||
|
||||
Cleanup:
|
||||
/* All done, dereference the port and return the status */
|
||||
LPCTRACE(LPC_REPLY_DEBUG,
|
||||
"Port: %p. Status: %p\n",
|
||||
Port,
|
||||
Status);
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtReplyWaitReceivePort(IN HANDLE PortHandle,
|
||||
OUT PVOID *PortContext OPTIONAL,
|
||||
IN PPORT_MESSAGE ReplyMessage OPTIONAL,
|
||||
OUT PPORT_MESSAGE ReceiveMessage)
|
||||
{
|
||||
/* Call the newer API */
|
||||
return NtReplyWaitReceivePortEx(PortHandle,
|
||||
PortContext,
|
||||
ReplyMessage,
|
||||
ReceiveMessage,
|
||||
NULL);
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtReplyWaitReplyPort(IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE ReplyMessage)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtReadRequestData(IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE Message,
|
||||
IN ULONG Index,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferLength,
|
||||
OUT PULONG Returnlength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtWriteRequestData(IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE Message,
|
||||
IN ULONG Index,
|
||||
IN PVOID Buffer,
|
||||
IN ULONG BufferLength,
|
||||
OUT PULONG ReturnLength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LpcRequestPort(IN PVOID PortObject,
|
||||
IN PPORT_MESSAGE LpcMessage)
|
||||
{
|
||||
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject, QueuePort;
|
||||
ULONG MessageType;
|
||||
PLPCP_MESSAGE Message;
|
||||
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage);
|
||||
|
||||
/* Check if this is a non-datagram message */
|
||||
if (LpcMessage->u2.s2.Type)
|
||||
{
|
||||
/* Get the message type */
|
||||
MessageType = LpcpGetMessageType(LpcMessage);
|
||||
|
||||
/* Validate it */
|
||||
if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Mark this as a kernel-mode message only if we really came from there */
|
||||
if ((PreviousMode == KernelMode) &&
|
||||
(LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))
|
||||
{
|
||||
/* We did, this is a kernel mode message */
|
||||
MessageType |= LPC_KERNELMODE_MESSAGE;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a datagram */
|
||||
MessageType = LPC_DATAGRAM;
|
||||
}
|
||||
|
||||
/* Can't have data information on this type of call */
|
||||
if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;
|
||||
|
||||
/* Validate message sizes */
|
||||
if ((LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
|
||||
(LpcMessage->u1.s1.TotalLength <= LpcMessage->u1.s1.DataLength))
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_PORT_MESSAGE_TOO_LONG;
|
||||
}
|
||||
|
||||
/* Allocate a new message */
|
||||
Message = LpcpAllocateFromPortZone();
|
||||
if (!Message) return STATUS_NO_MEMORY;
|
||||
|
||||
/* Clear the context */
|
||||
Message->PortContext = NULL;
|
||||
|
||||
/* Copy the message */
|
||||
LpcpMoveMessage(&Message->Request,
|
||||
LpcMessage,
|
||||
LpcMessage + 1,
|
||||
MessageType,
|
||||
&PsGetCurrentThread()->Cid);
|
||||
|
||||
/* Acquire the LPC lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if this is anything but a connection port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
|
||||
{
|
||||
/* The queue port is the connected port */
|
||||
QueuePort = Port->ConnectedPort;
|
||||
if (QueuePort)
|
||||
{
|
||||
/* Check if this is a client port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
|
||||
{
|
||||
/* Then copy the context */
|
||||
Message->PortContext = QueuePort->PortContext;
|
||||
QueuePort = Port->ConnectionPort;
|
||||
}
|
||||
else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
|
||||
{
|
||||
/* Any other kind of port, use the connection port */
|
||||
QueuePort = Port->ConnectionPort;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* For connection ports, use the port itself */
|
||||
QueuePort = PortObject;
|
||||
}
|
||||
|
||||
/* Make sure we have a port */
|
||||
if (QueuePort)
|
||||
{
|
||||
/* Generate the Message ID and set it */
|
||||
Message->Request.MessageId = LpcpNextMessageId++;
|
||||
if (!LpcpNextMessageId) LpcpNextMessageId = 1;
|
||||
Message->Request.CallbackId = 0;
|
||||
|
||||
/* No Message ID for the thread */
|
||||
PsGetCurrentThread()->LpcReplyMessageId = 0;
|
||||
|
||||
/* Insert the message in our chain */
|
||||
InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
|
||||
|
||||
/* Release the lock and release the semaphore */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);
|
||||
|
||||
/* If this is a waitable port, wake it up */
|
||||
if (QueuePort->Flags & LPCP_WAITABLE_PORT)
|
||||
{
|
||||
/* Wake it */
|
||||
KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
|
||||
/* We're done */
|
||||
LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
/* If we got here, then free the message and fail */
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
return STATUS_PORT_DISCONNECTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LpcRequestWaitReplyPort(IN PVOID Port,
|
||||
IN PPORT_MESSAGE LpcMessageRequest,
|
||||
OUT PPORT_MESSAGE LpcMessageReply)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @unimplemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtRequestPort(IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE LpcMessage)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return STATUS_NOT_IMPLEMENTED;
|
||||
}
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
NtRequestWaitReplyPort(IN HANDLE PortHandle,
|
||||
IN PPORT_MESSAGE LpcRequest,
|
||||
IN OUT PPORT_MESSAGE LpcReply)
|
||||
{
|
||||
PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort;
|
||||
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||
NTSTATUS Status;
|
||||
PLPCP_MESSAGE Message;
|
||||
PETHREAD Thread = PsGetCurrentThread();
|
||||
BOOLEAN Callback;
|
||||
PKSEMAPHORE Semaphore;
|
||||
ULONG MessageType;
|
||||
PAGED_CODE();
|
||||
LPCTRACE(LPC_SEND_DEBUG,
|
||||
"Handle: %lx. Messages: %p/%p. Type: %lx\n",
|
||||
PortHandle,
|
||||
LpcRequest,
|
||||
LpcReply,
|
||||
LpcpGetMessageType(LpcRequest));
|
||||
|
||||
/* Check if the thread is dying */
|
||||
if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;
|
||||
|
||||
/* Check if this is an LPC Request */
|
||||
if (LpcpGetMessageType(LpcRequest) == LPC_REQUEST)
|
||||
{
|
||||
/* Then it's a callback */
|
||||
Callback = TRUE;
|
||||
}
|
||||
else if (LpcpGetMessageType(LpcRequest))
|
||||
{
|
||||
/* This is a not kernel-mode message */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* This is a kernel-mode message without a callback */
|
||||
LpcRequest->u2.s2.Type |= LPC_REQUEST;
|
||||
Callback = FALSE;
|
||||
}
|
||||
|
||||
/* Get the message type */
|
||||
MessageType = LpcRequest->u2.s2.Type;
|
||||
|
||||
/* Validate the length */
|
||||
if ((LpcRequest->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
|
||||
LpcRequest->u1.s1.TotalLength)
|
||||
{
|
||||
/* Fail */
|
||||
return STATUS_INVALID_PARAMETER;
|
||||
}
|
||||
|
||||
/* Reference the object */
|
||||
Status = ObReferenceObjectByHandle(PortHandle,
|
||||
0,
|
||||
LpcPortObjectType,
|
||||
PreviousMode,
|
||||
(PVOID*)&Port,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status)) return Status;
|
||||
|
||||
/* Validate the message length */
|
||||
if ((LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
|
||||
(LpcRequest->u1.s1.TotalLength <= LpcRequest->u1.s1.DataLength))
|
||||
{
|
||||
/* Fail */
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_PORT_MESSAGE_TOO_LONG;
|
||||
}
|
||||
|
||||
/* Allocate a message from the port zone */
|
||||
Message = LpcpAllocateFromPortZone();
|
||||
if (!Message)
|
||||
{
|
||||
/* Fail if we couldn't allocate a message */
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_NO_MEMORY;
|
||||
}
|
||||
|
||||
/* Check if this is a callback */
|
||||
if (Callback)
|
||||
{
|
||||
/* FIXME: TODO */
|
||||
Semaphore = NULL; // we'd use the Thread Semaphore here
|
||||
ASSERT(FALSE);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* No callback, just copy the message */
|
||||
LpcpMoveMessage(&Message->Request,
|
||||
LpcRequest,
|
||||
LpcRequest + 1,
|
||||
MessageType,
|
||||
&Thread->Cid);
|
||||
|
||||
/* Acquire the LPC lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Right now clear the port context */
|
||||
Message->PortContext = NULL;
|
||||
|
||||
/* Check if this is a not connection port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
|
||||
{
|
||||
/* We want the connected port */
|
||||
QueuePort = Port->ConnectedPort;
|
||||
if (!QueuePort)
|
||||
{
|
||||
/* We have no connected port, fail */
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
ObDereferenceObject(Port);
|
||||
return STATUS_PORT_DISCONNECTED;
|
||||
}
|
||||
|
||||
/* This will be the rundown port */
|
||||
ReplyPort = QueuePort;
|
||||
|
||||
/* Check if this is a communication port */
|
||||
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
|
||||
{
|
||||
/* Copy the port context and use the connection port */
|
||||
Message->PortContext = ReplyPort->PortContext;
|
||||
QueuePort = Port->ConnectionPort;
|
||||
}
|
||||
else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
|
||||
LPCP_COMMUNICATION_PORT)
|
||||
{
|
||||
/* Use the connection port for anything but communication ports */
|
||||
QueuePort = Port->ConnectionPort;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, for a connection port, use the same port object */
|
||||
QueuePort = ReplyPort = Port;
|
||||
}
|
||||
|
||||
/* No reply thread */
|
||||
Message->RepliedToThread = NULL;
|
||||
|
||||
/* Generate the Message ID and set it */
|
||||
Message->Request.MessageId = LpcpNextMessageId++;
|
||||
if (!LpcpNextMessageId) LpcpNextMessageId = 1;
|
||||
Message->Request.CallbackId = 0;
|
||||
|
||||
/* Set the message ID for our thread now */
|
||||
Thread->LpcReplyMessageId = Message->Request.MessageId;
|
||||
Thread->LpcReplyMessage = NULL;
|
||||
|
||||
/* Insert the message in our chain */
|
||||
InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
|
||||
InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
|
||||
|
||||
/* Release the lock and get the semaphore we'll use later */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
Semaphore = QueuePort->MsgQueue.Semaphore;
|
||||
|
||||
/* If this is a waitable port, wake it up */
|
||||
if (QueuePort->Flags & LPCP_WAITABLE_PORT)
|
||||
{
|
||||
/* Wake it */
|
||||
KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
/* Now release the semaphore */
|
||||
LpcpCompleteWait(Semaphore);
|
||||
|
||||
/* And let's wait for the reply */
|
||||
LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);
|
||||
|
||||
/* Acquire the LPC lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Get the LPC Message and clear our thread's reply data */
|
||||
Message = Thread->LpcReplyMessage;
|
||||
Thread->LpcReplyMessage = NULL;
|
||||
Thread->LpcReplyMessageId = 0;
|
||||
|
||||
/* Check if we have anything on the reply chain*/
|
||||
if (!IsListEmpty(&Thread->LpcReplyChain))
|
||||
{
|
||||
/* Remove this thread and reinitialize the list */
|
||||
RemoveEntryList(&Thread->LpcReplyChain);
|
||||
InitializeListHead(&Thread->LpcReplyChain);
|
||||
}
|
||||
|
||||
/* Release the lock */
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
|
||||
/* Check if we got a reply */
|
||||
if (Status == STATUS_SUCCESS)
|
||||
{
|
||||
/* Check if we have a valid message */
|
||||
if (Message)
|
||||
{
|
||||
LPCTRACE(LPC_SEND_DEBUG,
|
||||
"Reply Messages: %p/%p\n",
|
||||
&Message->Request,
|
||||
(&Message->Request) + 1);
|
||||
|
||||
/* Move the message */
|
||||
LpcpMoveMessage(LpcReply,
|
||||
&Message->Request,
|
||||
(&Message->Request) + 1,
|
||||
0,
|
||||
NULL);
|
||||
|
||||
/* Check if this is an LPC request with data information */
|
||||
if ((LpcpGetMessageType(&Message->Request) == LPC_REQUEST) &&
|
||||
(Message->Request.u2.s2.DataInfoOffset))
|
||||
{
|
||||
/* Save the data information */
|
||||
LpcpSaveDataInfoMessage(Port, Message);
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Otherwise, just free it */
|
||||
LpcpFreeToPortZone(Message, FALSE);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* We don't have a reply */
|
||||
Status = STATUS_LPC_REPLY_LOST;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
/* The wait failed, free the message while holding the lock */
|
||||
KeAcquireGuardedMutex(&LpcpLock);
|
||||
LpcpFreeToPortZone(Message, TRUE);
|
||||
KeReleaseGuardedMutex(&LpcpLock);
|
||||
}
|
||||
|
||||
/* All done */
|
||||
LPCTRACE(LPC_SEND_DEBUG,
|
||||
"Port: %p. Status: %p\n",
|
||||
Port,
|
||||
Status);
|
||||
ObDereferenceObject(Port);
|
||||
return Status;
|
||||
}
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
#if defined (ALLOC_PRAGMA)
|
||||
#pragma alloc_text(INIT, LpcpInitSystem)
|
||||
#endif
|
||||
|
||||
|
||||
/* GLOBALS *******************************************************************/
|
||||
|
||||
POBJECT_TYPE LpcPortObjectType = 0;
|
||||
ULONG LpcpNextMessageId = 0; /* 0 is not a valid ID */
|
||||
FAST_MUTEX LpcpLock; /* global internal sync in LPC facility */
|
||||
POBJECT_TYPE LpcPortObjectType;
|
||||
ULONG LpcpMaxMessageSize;
|
||||
PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
|
||||
KGUARDED_MUTEX LpcpLock;
|
||||
ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG;
|
||||
ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;
|
||||
|
||||
static GENERIC_MAPPING LpcpPortMapping =
|
||||
{
|
||||
|
@ -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 */
|
||||
|
|
|
@ -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 <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
* NAME EXPORTED
|
||||
* NtQueryInformationPort@20
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* ARGUMENTS
|
||||
* PortHandle [IN]
|
||||
* PortInformationClass [IN]
|
||||
* PortInformation [OUT]
|
||||
* PortInformationLength [IN]
|
||||
* ReturnLength [OUT]
|
||||
*
|
||||
* RETURN VALUE
|
||||
* STATUS_SUCCESS if the call succedeed. An error code
|
||||
* otherwise.
|
||||
*
|
||||
* NOTES
|
||||
* P. Dabak reports that this system service seems to return
|
||||
* no information.
|
||||
*/
|
||||
/*EXPORTED*/ NTSTATUS STDCALL
|
||||
NtQueryInformationPort (IN HANDLE PortHandle,
|
||||
IN PORT_INFORMATION_CLASS PortInformationClass,
|
||||
OUT PVOID PortInformation,
|
||||
IN ULONG PortInformationLength,
|
||||
OUT PULONG ReturnLength)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PEPORT Port;
|
||||
|
||||
Status = ObReferenceObjectByHandle (PortHandle,
|
||||
PORT_ALL_ACCESS, /* AccessRequired */
|
||||
LpcPortObjectType,
|
||||
UserMode,
|
||||
(PVOID *) & Port,
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT("NtQueryInformationPort() = %x\n", Status);
|
||||
return (Status);
|
||||
}
|
||||
/*
|
||||
* FIXME: NT does nothing here!
|
||||
*/
|
||||
ObDereferenceObject (Port);
|
||||
return STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
VOID STDCALL
|
||||
EiEnqueueMessagePort (IN OUT PEPORT Port,
|
||||
IN PQUEUEDMESSAGE Message)
|
||||
{
|
||||
InsertTailList (&Port->QueueListHead,
|
||||
&Message->QueueListEntry);
|
||||
Port->QueueLength++;
|
||||
}
|
||||
|
||||
VOID STDCALL
|
||||
EiEnqueueMessageAtHeadPort (IN OUT PEPORT Port,
|
||||
IN PQUEUEDMESSAGE Message)
|
||||
{
|
||||
InsertTailList (&Port->QueueListHead,
|
||||
&Message->QueueListEntry);
|
||||
Port->QueueLength++;
|
||||
}
|
||||
|
||||
PQUEUEDMESSAGE STDCALL
|
||||
EiDequeueMessagePort (IN OUT PEPORT Port)
|
||||
{
|
||||
PQUEUEDMESSAGE Message;
|
||||
PLIST_ENTRY entry;
|
||||
|
||||
if (IsListEmpty(&Port->QueueListHead))
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
entry = RemoveHeadList (&Port->QueueListHead);
|
||||
Message = CONTAINING_RECORD (entry, QUEUEDMESSAGE, QueueListEntry);
|
||||
Port->QueueLength--;
|
||||
|
||||
return (Message);
|
||||
}
|
||||
|
||||
|
||||
VOID STDCALL
|
||||
EiEnqueueConnectMessagePort (IN OUT PEPORT Port,
|
||||
IN PQUEUEDMESSAGE Message)
|
||||
{
|
||||
InsertTailList (&Port->ConnectQueueListHead,
|
||||
&Message->QueueListEntry);
|
||||
Port->ConnectQueueLength++;
|
||||
}
|
||||
|
||||
|
||||
PQUEUEDMESSAGE STDCALL
|
||||
EiDequeueConnectMessagePort (IN OUT PEPORT Port)
|
||||
{
|
||||
PQUEUEDMESSAGE Message;
|
||||
PLIST_ENTRY entry;
|
||||
|
||||
if (IsListEmpty(&Port->ConnectQueueListHead))
|
||||
{
|
||||
return(NULL);
|
||||
}
|
||||
entry = RemoveHeadList (&Port->ConnectQueueListHead);
|
||||
Message = CONTAINING_RECORD (entry, QUEUEDMESSAGE, QueueListEntry);
|
||||
Port->ConnectQueueLength--;
|
||||
|
||||
return (Message);
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* FUNCTIONS *****************************************************************/
|
||||
|
||||
/**********************************************************************
|
||||
* NAME SYSTEM
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* RETURN VALUE
|
||||
*/
|
||||
NTSTATUS STDCALL
|
||||
NtReadRequestData (HANDLE PortHandle,
|
||||
PPORT_MESSAGE Message,
|
||||
ULONG Index,
|
||||
PVOID Buffer,
|
||||
ULONG BufferLength,
|
||||
PULONG Returnlength)
|
||||
{
|
||||
UNIMPLEMENTED;
|
||||
return(STATUS_NOT_IMPLEMENTED);
|
||||
}
|
||||
|
||||
|
||||
/* EOF */
|
|
@ -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 <ntoskrnl.h>
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/* 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 */
|
||||
|
|
|
@ -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 <ntoskrnl.h>
|
||||
|
||||
#include "lpc.h"
|
||||
#define NDEBUG
|
||||
#include <internal/debug.h>
|
||||
|
||||
/**********************************************************************
|
||||
* NAME
|
||||
* LpcRequestPort/2
|
||||
*
|
||||
* DESCRIPTION
|
||||
*
|
||||
* ARGUMENTS
|
||||
*
|
||||
* RETURN VALUE
|
||||
*
|
||||
* REVISIONS
|
||||
* 2002-03-01 EA
|
||||
* I investigated this function a bit more in depth.
|
||||
* It looks like the legal values for the MessageType field in the
|
||||
* message to send are in the range LPC_NEW_MESSAGE .. LPC_CLIENT_DIED,
|
||||
* but LPC_DATAGRAM is explicitly forbidden.
|
||||
*
|
||||
/* PUBLIC FUNCTIONS **********************************************************/
|
||||
|
||||
/*
|
||||
* @implemented
|
||||
*/
|
||||
NTSTATUS STDCALL LpcRequestPort (IN PVOID PortObject,
|
||||
IN PPORT_MESSAGE LpcMessage)
|
||||
NTSTATUS
|
||||
NTAPI
|
||||
LpcRequestPort(IN PVOID PortObject,
|
||||
IN PPORT_MESSAGE LpcMessage)
|
||||
{
|
||||
NTSTATUS Status;
|
||||
PEPORT Port = (PEPORT)PortObject;
|
||||
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 */
|
||||
|
|
|
@ -9,9 +9,6 @@
|
|||
<define name="__NO_CTYPE_INLINES" />
|
||||
<define name="__USE_W32API" />
|
||||
<define name="WIN9X_COMPAT_SPINLOCK" />
|
||||
<if property="NTLPC" value="1">
|
||||
<define name="NTLPC" />
|
||||
</if>
|
||||
<include base="cmlib">.</include>
|
||||
<include base="ntoskrnl">include</include>
|
||||
<include base="ReactOS">include/reactos/drivers</include>
|
||||
|
@ -230,35 +227,16 @@
|
|||
<file>loader.c</file>
|
||||
<file>rtl.c</file>
|
||||
</directory>
|
||||
<if property="NTLPC" value="0">
|
||||
<directory name="lpc">
|
||||
<file>close.c</file>
|
||||
<file>complete.c</file>
|
||||
<file>connect.c</file>
|
||||
<file>create.c</file>
|
||||
<file>listen.c</file>
|
||||
<file>port.c</file>
|
||||
<file>query.c</file>
|
||||
<file>queue.c</file>
|
||||
<file>receive.c</file>
|
||||
<file>reply.c</file>
|
||||
<file>send.c</file>
|
||||
</directory>
|
||||
</if>
|
||||
<if property="NTLPC" value="1">
|
||||
<directory name="lpc">
|
||||
<directory name="ntlpc">
|
||||
<file>close.c</file>
|
||||
<file>complete.c</file>
|
||||
<file>connect.c</file>
|
||||
<file>create.c</file>
|
||||
<file>listen.c</file>
|
||||
<file>port.c</file>
|
||||
<file>reply.c</file>
|
||||
<file>send.c</file>
|
||||
</directory>
|
||||
</directory>
|
||||
</if>
|
||||
<directory name="lpc">
|
||||
<file>close.c</file>
|
||||
<file>complete.c</file>
|
||||
<file>connect.c</file>
|
||||
<file>create.c</file>
|
||||
<file>listen.c</file>
|
||||
<file>port.c</file>
|
||||
<file>reply.c</file>
|
||||
<file>send.c</file>
|
||||
</directory>
|
||||
<directory name="mm">
|
||||
<if property="ARCH" value="i386">
|
||||
<directory name="i386">
|
||||
|
|
|
@ -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();
|
||||
|
||||
|
|
Loading…
Reference in a new issue