mirror of
https://github.com/reactos/reactos.git
synced 2025-08-05 06:33:01 +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
|
working on the \ntlpc directory. Leave this disabled unless you really know
|
||||||
what you're doing.
|
what you're doing.
|
||||||
-->
|
-->
|
||||||
<property name="NTLPC" value="0" />
|
<property name="NTLPC" value="1" />
|
||||||
|
|
||||||
</rbuild>
|
</rbuild>
|
||||||
|
|
|
@ -1,90 +1,55 @@
|
||||||
#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)
|
// These define the Debug Masks Supported
|
||||||
#define EPORT_TYPE_CLIENT_COMM_PORT (2)
|
//
|
||||||
|
#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 */
|
//
|
||||||
|
// Debug/Tracing support
|
||||||
#define EPORT_INACTIVE (0)
|
//
|
||||||
#define EPORT_WAIT_FOR_CONNECT (1)
|
#if _LPC_DEBUG_
|
||||||
#define EPORT_WAIT_FOR_ACCEPT (2)
|
#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
|
||||||
#define EPORT_WAIT_FOR_COMPLETE_SRV (3)
|
#define LPCTRACE(x, ...) \
|
||||||
#define EPORT_WAIT_FOR_COMPLETE_CLT (4)
|
{ \
|
||||||
#define EPORT_CONNECTED_CLIENT (5)
|
DbgPrintEx("%s [%.16s] - ", \
|
||||||
#define EPORT_CONNECTED_SERVER (6)
|
__FUNCTION__, \
|
||||||
#define EPORT_DISCONNECTED (7)
|
PsGetCurrentProcess()->ImageFileName); \
|
||||||
|
DbgPrintEx(__VA_ARGS__); \
|
||||||
extern POBJECT_TYPE LpcPortObjectType;
|
}
|
||||||
extern ULONG LpcpNextMessageId;
|
#else
|
||||||
#ifndef NTLPC
|
#define LPCTRACE(x, ...) \
|
||||||
extern FAST_MUTEX LpcpLock;
|
if (x & LpcpTraceLevel) \
|
||||||
|
{ \
|
||||||
|
DbgPrint("%s [%.16s:%lx] - ", \
|
||||||
|
__FUNCTION__, \
|
||||||
|
PsGetCurrentProcess()->ImageFileName, \
|
||||||
|
PsGetCurrentThreadId()); \
|
||||||
|
DbgPrint(__VA_ARGS__); \
|
||||||
|
}
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
typedef struct _EPORT_LISTENER
|
//
|
||||||
{
|
// Internal Port Management
|
||||||
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
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
LpcpClosePort(
|
LpcpClosePort(
|
||||||
|
@ -97,66 +62,69 @@ LpcpClosePort(
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
LpcpDeletePort(IN PVOID ObjectBody);
|
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
|
|
||||||
);
|
);
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
LpcpInitSystem (VOID);
|
LpcpInitializePortQueue(
|
||||||
|
IN PLPCP_PORT_OBJECT Port
|
||||||
|
);
|
||||||
|
|
||||||
/* Code in ntoskrnl/lpc/reply.c */
|
VOID
|
||||||
|
|
||||||
NTSTATUS
|
|
||||||
NTAPI
|
NTAPI
|
||||||
EiReplyOrRequestPort(
|
LpcpFreeToPortZone(
|
||||||
IN PEPORT Port,
|
IN PLPCP_MESSAGE Message,
|
||||||
IN PPORT_MESSAGE LpcReply,
|
IN ULONG Flags
|
||||||
|
);
|
||||||
|
|
||||||
|
VOID
|
||||||
|
NTAPI
|
||||||
|
LpcpMoveMessage(
|
||||||
|
IN PPORT_MESSAGE Destination,
|
||||||
|
IN PPORT_MESSAGE Origin,
|
||||||
|
IN PVOID Data,
|
||||||
IN ULONG MessageType,
|
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,25 +1,29 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* PROJECT: ReactOS Kernel
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/lpc/close.c
|
* FILE: ntoskrnl/lpc/close.c
|
||||||
* PURPOSE: Communication mechanism
|
* PURPOSE: Local Procedure Call: Rundown, Cleanup, Deletion
|
||||||
*
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include "lpc.h"
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
VOID
|
VOID
|
||||||
NTAPI
|
NTAPI
|
||||||
LpcExitThread(IN PETHREAD Thread)
|
LpcExitThread(IN PETHREAD Thread)
|
||||||
{
|
{
|
||||||
|
PLPCP_MESSAGE Message;
|
||||||
|
|
||||||
|
/* Acquire the lock */
|
||||||
|
KeAcquireGuardedMutex(&LpcpLock);
|
||||||
|
|
||||||
/* Make sure that the Reply Chain is empty */
|
/* Make sure that the Reply Chain is empty */
|
||||||
if (!IsListEmpty(&Thread->LpcReplyChain))
|
if (!IsListEmpty(&Thread->LpcReplyChain))
|
||||||
{
|
{
|
||||||
|
@ -31,104 +35,361 @@ LpcExitThread(IN PETHREAD Thread)
|
||||||
Thread->LpcExitThreadCalled = TRUE;
|
Thread->LpcExitThreadCalled = TRUE;
|
||||||
Thread->LpcReplyMessageId = 0;
|
Thread->LpcReplyMessageId = 0;
|
||||||
|
|
||||||
/* FIXME: Reply to the LpcReplyMessage */
|
/* Check if there's a reply message */
|
||||||
|
Message = Thread->LpcReplyMessage;
|
||||||
|
if (Message)
|
||||||
|
{
|
||||||
|
/* FIXME: TODO */
|
||||||
|
KEBUGCHECK(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Release the lock */
|
||||||
|
KeReleaseGuardedMutex(&LpcpLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
VOID
|
||||||
* NAME
|
NTAPI
|
||||||
*
|
LpcpFreeToPortZone(IN PLPCP_MESSAGE Message,
|
||||||
* DESCRIPTION
|
IN ULONG Flags)
|
||||||
*
|
{
|
||||||
* ARGUMENTS
|
PLPCP_CONNECTION_MESSAGE ConnectMessage;
|
||||||
*
|
PLPCP_PORT_OBJECT ClientPort = NULL;
|
||||||
* RETURN VALUE
|
PETHREAD Thread = NULL;
|
||||||
*
|
BOOLEAN LockHeld = Flags & 1;
|
||||||
* REVISIONS
|
PAGED_CODE();
|
||||||
*/
|
LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. Flags: %lx\n", Message, Flags);
|
||||||
VOID STDCALL
|
|
||||||
LpcpClosePort (IN PEPROCESS Process OPTIONAL,
|
/* Acquire the lock if not already */
|
||||||
IN PVOID ObjectBody,
|
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 ACCESS_MASK GrantedAccess,
|
||||||
IN ULONG HandleCount,
|
IN ULONG ProcessHandleCount,
|
||||||
IN ULONG SystemHandleCount)
|
IN ULONG SystemHandleCount)
|
||||||
{
|
{
|
||||||
PEPORT Port = (PEPORT)ObjectBody;
|
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object;
|
||||||
PORT_MESSAGE Message;
|
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
|
||||||
|
|
||||||
/* FIXME Race conditions here! */
|
/* Only Server-side Connection Ports need clean up*/
|
||||||
|
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
|
||||||
/*
|
|
||||||
* 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))
|
|
||||||
{
|
{
|
||||||
DPRINT("Informing server\n");
|
/* Check the handle count */
|
||||||
Message.u1.s1.TotalLength = sizeof(PORT_MESSAGE);
|
switch (SystemHandleCount)
|
||||||
Message.u1.s1.DataLength = 0;
|
{
|
||||||
EiReplyOrRequestPort (Port->OtherPort,
|
/* No handles left */
|
||||||
&Message,
|
case 0:
|
||||||
LPC_PORT_CLOSED,
|
|
||||||
Port);
|
/* Destroy the port queue */
|
||||||
Port->OtherPort->OtherPort = NULL;
|
LpcpDestroyPortQueue(Port, TRUE);
|
||||||
Port->OtherPort->State = EPORT_DISCONNECTED;
|
break;
|
||||||
KeReleaseSemaphore( &Port->OtherPort->Semaphore,
|
|
||||||
IO_NO_INCREMENT,
|
/* Last handle remaining */
|
||||||
1,
|
case 1:
|
||||||
FALSE );
|
|
||||||
ObDereferenceObject (Port);
|
/* Reset the queue only */
|
||||||
|
LpcpDestroyPortQueue(Port, FALSE);
|
||||||
|
|
||||||
|
/* More handles remain, do nothing */
|
||||||
|
default:
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
|
||||||
* 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);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
VOID
|
||||||
/**********************************************************************
|
NTAPI
|
||||||
* NAME
|
LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port)
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*
|
|
||||||
* REVISIONS
|
|
||||||
*/
|
|
||||||
VOID STDCALL
|
|
||||||
LpcpDeletePort (PVOID ObjectBody)
|
|
||||||
{
|
{
|
||||||
PLIST_ENTRY Entry;
|
/* Check if this is a client port */
|
||||||
PQUEUEDMESSAGE Message;
|
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
|
||||||
|
|
||||||
PEPORT Port = (PEPORT)ObjectBody;
|
|
||||||
|
|
||||||
DPRINT("Deleting port %x\n", Port);
|
|
||||||
|
|
||||||
/* Free all waiting messages */
|
|
||||||
while (!IsListEmpty(&Port->QueueListHead))
|
|
||||||
{
|
{
|
||||||
Entry = RemoveHeadList(&Port->QueueListHead);
|
/* Check if security is static */
|
||||||
Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry);
|
if (!(Port->Flags & LPCP_SECURITY_DYNAMIC))
|
||||||
ExFreePool(Message);
|
{
|
||||||
|
/* Check if we have a token */
|
||||||
|
if (Port->StaticSecurity.ClientToken)
|
||||||
|
{
|
||||||
|
/* Free security */
|
||||||
|
SeDeleteClientSecurity(&Port->StaticSecurity);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
while (!IsListEmpty(&Port->ConnectQueueListHead))
|
|
||||||
{
|
|
||||||
Entry = RemoveHeadList(&Port->ConnectQueueListHead);
|
|
||||||
Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry);
|
|
||||||
ExFreePool(Message);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 */
|
/* EOF */
|
||||||
|
|
|
@ -1,82 +1,376 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* PROJECT: ReactOS Kernel
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
* FILE: ntoskrnl/lpc/complete.c
|
||||||
* FILE: ntoskrnl/lpc/complete.c
|
* PURPOSE: Local Procedure Call: Connection Completion
|
||||||
* PURPOSE: Communication mechanism
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
*
|
*/
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
|
||||||
|
|
||||||
/* INCLUDES ******************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include "lpc.h"
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
/***********************************************************************
|
VOID
|
||||||
* NAME EXPORTED
|
NTAPI
|
||||||
* NtCompleteConnectPort/1
|
LpcpPrepareToWakeClient(IN PETHREAD Thread)
|
||||||
*
|
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
PAGED_CODE();
|
||||||
PEPORT ReplyPort;
|
|
||||||
|
|
||||||
DPRINT("NtCompleteConnectPort(hServerSideCommPort %x)\n", hServerSideCommPort);
|
/* 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 **********************************************************/
|
||||||
* Ask Ob to translate the port handle to EPORT
|
|
||||||
|
/*
|
||||||
|
* @implemented
|
||||||
*/
|
*/
|
||||||
Status = ObReferenceObjectByHandle (hServerSideCommPort,
|
NTSTATUS
|
||||||
PORT_ALL_ACCESS,
|
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,
|
LpcPortObjectType,
|
||||||
UserMode,
|
NULL,
|
||||||
(PVOID*)&ReplyPort,
|
PreviousMode,
|
||||||
NULL);
|
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))
|
if (!NT_SUCCESS(Status))
|
||||||
{
|
{
|
||||||
return (Status);
|
/* We failed, remove the extra reference and cleanup */
|
||||||
|
ObDereferenceObject(ServerPort);
|
||||||
|
goto Cleanup;
|
||||||
}
|
}
|
||||||
/*
|
|
||||||
* Verify EPORT type is a server-side reply port;
|
/* Check if the caller gave a client view */
|
||||||
* otherwise tell the caller the port handle is not
|
if (ClientView)
|
||||||
* valid.
|
|
||||||
*/
|
|
||||||
if (ReplyPort->Type != EPORT_TYPE_SERVER_COMM_PORT)
|
|
||||||
{
|
{
|
||||||
ObDereferenceObject (ReplyPort);
|
/* 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;
|
return STATUS_INVALID_PORT_HANDLE;
|
||||||
}
|
}
|
||||||
|
|
||||||
ReplyPort->State = EPORT_CONNECTED_SERVER;
|
/* Acquire the lock */
|
||||||
/*
|
KeAcquireGuardedMutex(&LpcpLock);
|
||||||
* 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);
|
/* 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 */
|
/* EOF */
|
||||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -1,180 +1,195 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* PROJECT: ReactOS Kernel
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/lpc/create.c
|
* FILE: ntoskrnl/lpc/create.c
|
||||||
* PURPOSE: Communication mechanism
|
* PURPOSE: Local Procedure Call: Port/Queue/Message Creation
|
||||||
*
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include "lpc.h"
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
/**********************************************************************
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
* NAME
|
|
||||||
* LpcpVerifyCreateParameters/5
|
NTSTATUS
|
||||||
*
|
NTAPI
|
||||||
* DESCRIPTION
|
LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
|
||||||
* 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)
|
|
||||||
{
|
{
|
||||||
if (NULL == PortHandle)
|
PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
|
||||||
{
|
|
||||||
return (STATUS_INVALID_PARAMETER_1);
|
/* Allocate the queue */
|
||||||
}
|
MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
|
||||||
if (NULL == ObjectAttributes)
|
sizeof(LPCP_NONPAGED_PORT_QUEUE),
|
||||||
{
|
TAG('P', 'o', 'r', 't'));
|
||||||
return (STATUS_INVALID_PARAMETER_2);
|
if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
|
||||||
}
|
|
||||||
if ((ObjectAttributes->Attributes & OBJ_OPENLINK)
|
/* Set it up */
|
||||||
|| (ObjectAttributes->Attributes & OBJ_OPENIF)
|
KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
|
||||||
|| (ObjectAttributes->Attributes & OBJ_EXCLUSIVE)
|
MessageQueue->BackPointer = Port;
|
||||||
|| (ObjectAttributes->Attributes & OBJ_PERMANENT)
|
|
||||||
|| (ObjectAttributes->Attributes & OBJ_INHERIT))
|
/* And link it with the Paged Pool part */
|
||||||
{
|
Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
|
||||||
return (STATUS_INVALID_PORT_ATTRIBUTES);
|
InitializeListHead(&Port->MsgQueue.ReceiveHead);
|
||||||
}
|
return STATUS_SUCCESS;
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
NTSTATUS
|
||||||
* NAME EXPORTED
|
NTAPI
|
||||||
* NtCreatePort/5
|
LpcpCreatePort(OUT PHANDLE PortHandle,
|
||||||
*
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
* DESCRIPTION
|
IN ULONG MaxConnectionInfoLength,
|
||||||
*
|
IN ULONG MaxMessageLength,
|
||||||
* ARGUMENTS
|
IN ULONG MaxPoolUsage,
|
||||||
* PortHandle,
|
IN BOOLEAN Waitable)
|
||||||
* ObjectAttributes,
|
|
||||||
* MaxConnectInfoLength,
|
|
||||||
* MaxDataLength,
|
|
||||||
* MaxPoolUsage: size of NP zone the NP part of msgs is kept in
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*/
|
|
||||||
/*EXPORTED*/ NTSTATUS STDCALL
|
|
||||||
NtCreatePort (PHANDLE PortHandle,
|
|
||||||
POBJECT_ATTRIBUTES ObjectAttributes,
|
|
||||||
ULONG MaxConnectInfoLength,
|
|
||||||
ULONG MaxDataLength,
|
|
||||||
ULONG MaxPoolUsage)
|
|
||||||
{
|
{
|
||||||
PEPORT Port;
|
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
|
||||||
NTSTATUS Status;
|
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,
|
||||||
/* Verify parameters */
|
|
||||||
Status = LpcpVerifyCreateParameters (PortHandle,
|
|
||||||
ObjectAttributes,
|
|
||||||
MaxConnectInfoLength,
|
|
||||||
MaxDataLength,
|
|
||||||
MaxPoolUsage);
|
|
||||||
if (STATUS_SUCCESS != Status)
|
|
||||||
{
|
|
||||||
return (Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Ask Ob to create the object */
|
|
||||||
Status = ObCreateObject (ExGetPreviousMode(),
|
|
||||||
LpcPortObjectType,
|
LpcPortObjectType,
|
||||||
ObjectAttributes,
|
ObjectAttributes,
|
||||||
ExGetPreviousMode(),
|
PreviousMode,
|
||||||
NULL,
|
NULL,
|
||||||
sizeof(EPORT),
|
sizeof(LPCP_PORT_OBJECT),
|
||||||
0,
|
0,
|
||||||
0,
|
0,
|
||||||
(PVOID*)&Port);
|
(PVOID*)&Port);
|
||||||
if (!NT_SUCCESS(Status))
|
if (!NT_SUCCESS(Status)) return Status;
|
||||||
|
|
||||||
|
/* Set up the Object */
|
||||||
|
RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
|
||||||
|
Port->ConnectionPort = Port;
|
||||||
|
Port->Creator = PsGetCurrentThread()->Cid;
|
||||||
|
InitializeListHead(&Port->LpcDataInfoChainHead);
|
||||||
|
InitializeListHead(&Port->LpcReplyChainHead);
|
||||||
|
|
||||||
|
/* Check if we don't have a name */
|
||||||
|
if (!ObjectAttributes->ObjectName->Buffer)
|
||||||
{
|
{
|
||||||
return (Status);
|
/* 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
Status = ObInsertObject ((PVOID)Port,
|
/* 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,
|
NULL,
|
||||||
PORT_ALL_ACCESS,
|
PORT_ALL_ACCESS,
|
||||||
0,
|
0,
|
||||||
NULL,
|
NULL,
|
||||||
PortHandle);
|
PortHandle);
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ObDereferenceObject (Port);
|
|
||||||
return (Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = LpcpInitializePort (Port, EPORT_TYPE_SERVER_RQST_PORT, NULL);
|
/* Return success or the error */
|
||||||
Port->MaxConnectInfoLength = LPC_MAX_DATA_LENGTH;
|
LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %lx\n", Port, *PortHandle);
|
||||||
Port->MaxDataLength = LPC_MAX_MESSAGE_LENGTH;
|
return Status;
|
||||||
Port->MaxPoolUsage = MaxPoolUsage;
|
|
||||||
|
|
||||||
return (Status);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**********************************************************************
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
* NAME EXPORTED
|
|
||||||
* NtCreateWaitablePort/5
|
/*
|
||||||
*
|
* @implemented
|
||||||
* 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
|
NTSTATUS
|
||||||
NtCreateWaitablePort (OUT PHANDLE PortHandle,
|
NTAPI
|
||||||
|
NtCreatePort(OUT PHANDLE PortHandle,
|
||||||
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
IN POBJECT_ATTRIBUTES ObjectAttributes,
|
||||||
IN ULONG MaxConnectInfoLength,
|
IN ULONG MaxConnectInfoLength,
|
||||||
IN ULONG MaxDataLength,
|
IN ULONG MaxDataLength,
|
||||||
IN ULONG MaxPoolUsage)
|
IN ULONG MaxPoolUsage)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
PAGED_CODE();
|
||||||
|
|
||||||
/* Verify parameters */
|
/* Call the internal API */
|
||||||
Status = LpcpVerifyCreateParameters (PortHandle,
|
return LpcpCreatePort(PortHandle,
|
||||||
ObjectAttributes,
|
ObjectAttributes,
|
||||||
MaxConnectInfoLength,
|
MaxConnectInfoLength,
|
||||||
MaxDataLength,
|
MaxDataLength,
|
||||||
MaxPoolUsage);
|
MaxPoolUsage,
|
||||||
if (STATUS_SUCCESS != Status)
|
FALSE);
|
||||||
{
|
}
|
||||||
return (Status);
|
|
||||||
}
|
/*
|
||||||
/* TODO */
|
* @implemented
|
||||||
return (STATUS_NOT_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 */
|
/* EOF */
|
||||||
|
|
|
@ -1,72 +1,52 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* PROJECT: ReactOS Kernel
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/lpc/listen.c
|
* FILE: ntoskrnl/lpc/listen.c
|
||||||
* PURPOSE: Communication mechanism
|
* PURPOSE: Local Procedure Call: Listening
|
||||||
*
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES ******************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include "lpc.h"
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
/**********************************************************************
|
/*
|
||||||
* NAME EXPORTED
|
* @implemented
|
||||||
* 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
|
|
||||||
*/
|
*/
|
||||||
/*EXPORTED*/ NTSTATUS STDCALL
|
NTSTATUS
|
||||||
NtListenPort (IN HANDLE PortHandle,
|
NTAPI
|
||||||
IN PPORT_MESSAGE ConnectMsg)
|
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. */
|
||||||
* Wait forever for a connection request.
|
|
||||||
*/
|
|
||||||
for (;;)
|
for (;;)
|
||||||
{
|
{
|
||||||
|
/* Do the wait */
|
||||||
Status = NtReplyWaitReceivePort(PortHandle,
|
Status = NtReplyWaitReceivePort(PortHandle,
|
||||||
NULL,
|
NULL,
|
||||||
NULL,
|
NULL,
|
||||||
ConnectMsg);
|
ConnectMessage);
|
||||||
/*
|
|
||||||
* Accept only LPC_CONNECTION_REQUEST requests.
|
/* Accept only LPC_CONNECTION_REQUEST requests. */
|
||||||
* Drop any other message.
|
if ((Status != STATUS_SUCCESS) ||
|
||||||
*/
|
(LpcpGetMessageType(ConnectMessage) == LPC_CONNECTION_REQUEST))
|
||||||
if (!NT_SUCCESS(Status) ||
|
|
||||||
LPC_CONNECTION_REQUEST == ConnectMsg->u2.s2.Type)
|
|
||||||
{
|
{
|
||||||
DPRINT("Got message (type %x)\n", LPC_CONNECTION_REQUEST);
|
/* Break out */
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
DPRINT("Got message (type %x)\n", ConnectMsg->u2.s2.Type);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return (Status);
|
/* 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$
|
/*
|
||||||
*
|
* PROJECT: ReactOS Kernel
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/lpc/port.c
|
* FILE: ntoskrnl/lpc/port.c
|
||||||
* PURPOSE: Communication mechanism
|
* PURPOSE: Local Procedure Call: Port Management
|
||||||
*
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include "lpc.h"
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
#if defined (ALLOC_PRAGMA)
|
|
||||||
#pragma alloc_text(INIT, LpcpInitSystem)
|
|
||||||
#endif
|
|
||||||
|
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* GLOBALS *******************************************************************/
|
||||||
|
|
||||||
POBJECT_TYPE LpcPortObjectType = 0;
|
POBJECT_TYPE LpcPortObjectType;
|
||||||
ULONG LpcpNextMessageId = 0; /* 0 is not a valid ID */
|
ULONG LpcpMaxMessageSize;
|
||||||
FAST_MUTEX LpcpLock; /* global internal sync in LPC facility */
|
PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
|
||||||
|
KGUARDED_MUTEX LpcpLock;
|
||||||
|
ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG;
|
||||||
|
ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;
|
||||||
|
|
||||||
static GENERIC_MAPPING LpcpPortMapping =
|
static GENERIC_MAPPING LpcpPortMapping =
|
||||||
{
|
{
|
||||||
|
@ -33,105 +30,60 @@ static GENERIC_MAPPING LpcpPortMapping =
|
||||||
PORT_ALL_ACCESS
|
PORT_ALL_ACCESS
|
||||||
};
|
};
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
INIT_FUNCTION
|
INIT_FUNCTION
|
||||||
NTAPI
|
NTAPI
|
||||||
LpcpInitSystem (VOID)
|
LpcpInitSystem(VOID)
|
||||||
{
|
{
|
||||||
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
|
||||||
UNICODE_STRING Name;
|
UNICODE_STRING Name;
|
||||||
|
|
||||||
DPRINT("Creating Port Object Type\n");
|
/* Setup the LPC Lock */
|
||||||
|
KeInitializeGuardedMutex(&LpcpLock);
|
||||||
|
|
||||||
/* Create the Port Object Type */
|
/* Create the Port Object Type */
|
||||||
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
|
||||||
RtlInitUnicodeString(&Name, L"Port");
|
RtlInitUnicodeString(&Name, L"Port");
|
||||||
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
|
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.GenericMapping = LpcpPortMapping;
|
||||||
ObjectTypeInitializer.PoolType = NonPagedPool;
|
ObjectTypeInitializer.PoolType = PagedPool;
|
||||||
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
ObjectTypeInitializer.UseDefaultObject = TRUE;
|
||||||
ObjectTypeInitializer.CloseProcedure = LpcpClosePort;
|
ObjectTypeInitializer.CloseProcedure = LpcpClosePort;
|
||||||
ObjectTypeInitializer.DeleteProcedure = LpcpDeletePort;
|
ObjectTypeInitializer.DeleteProcedure = LpcpDeletePort;
|
||||||
ObjectTypeInitializer.ValidAccessMask = PORT_ALL_ACCESS;
|
ObjectTypeInitializer.ValidAccessMask = PORT_ALL_ACCESS;
|
||||||
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &LpcPortObjectType);
|
ObjectTypeInitializer.MaintainTypeList = TRUE;
|
||||||
|
ObCreateObjectType(&Name,
|
||||||
|
&ObjectTypeInitializer,
|
||||||
|
NULL,
|
||||||
|
&LpcPortObjectType);
|
||||||
|
|
||||||
LpcpNextMessageId = 0;
|
/* Allocate the LPC lookaside list */
|
||||||
ExInitializeFastMutex (& LpcpLock);
|
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 **********************************************************/
|
||||||
|
|
||||||
/**********************************************************************
|
NTSTATUS
|
||||||
* NAME INTERNAL
|
NTAPI
|
||||||
* NiInitializePort/3
|
NtImpersonateClientOfPort(IN HANDLE PortHandle,
|
||||||
*
|
IN PPORT_MESSAGE ClientMessage)
|
||||||
* DESCRIPTION
|
|
||||||
* Initialize the EPORT object attributes. The Port
|
|
||||||
* object enters the inactive state.
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
* Port Pointer to an EPORT object to initialize.
|
|
||||||
* Type connect (RQST), or communication port (COMM)
|
|
||||||
* Parent OPTIONAL connect port a communication port
|
|
||||||
* is created from
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
* STATUS_SUCCESS if initialization succedeed. An error code
|
|
||||||
* otherwise.
|
|
||||||
*/
|
|
||||||
NTSTATUS STDCALL
|
|
||||||
LpcpInitializePort (IN OUT PEPORT Port,
|
|
||||||
IN USHORT Type,
|
|
||||||
IN PEPORT Parent OPTIONAL)
|
|
||||||
{
|
|
||||||
if ((Type != EPORT_TYPE_SERVER_RQST_PORT) &&
|
|
||||||
(Type != EPORT_TYPE_SERVER_COMM_PORT) &&
|
|
||||||
(Type != EPORT_TYPE_CLIENT_COMM_PORT))
|
|
||||||
{
|
|
||||||
return STATUS_INVALID_PARAMETER_2;
|
|
||||||
}
|
|
||||||
memset (Port, 0, sizeof(EPORT));
|
|
||||||
KeInitializeSpinLock (& Port->Lock);
|
|
||||||
KeInitializeSemaphore( &Port->Semaphore, 0, MAXLONG );
|
|
||||||
Port->RequestPort = Parent;
|
|
||||||
Port->OtherPort = NULL;
|
|
||||||
Port->QueueLength = 0;
|
|
||||||
Port->ConnectQueueLength = 0;
|
|
||||||
Port->Type = Type;
|
|
||||||
Port->State = EPORT_INACTIVE;
|
|
||||||
InitializeListHead (& Port->QueueListHead);
|
|
||||||
InitializeListHead (& Port->ConnectQueueListHead);
|
|
||||||
|
|
||||||
return (STATUS_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/* MISCELLANEA SYSTEM SERVICES */
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* NAME SYSTEM
|
|
||||||
* NtImpersonateClientOfPort/2
|
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
* PortHandle,
|
|
||||||
* ClientMessage
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*/
|
|
||||||
NTSTATUS STDCALL
|
|
||||||
NtImpersonateClientOfPort (HANDLE PortHandle,
|
|
||||||
PPORT_MESSAGE ClientMessage)
|
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
UNIMPLEMENTED;
|
||||||
return(STATUS_NOT_IMPLEMENTED);
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
|
@ -142,4 +94,16 @@ NtQueryPortInformationProcess(VOID)
|
||||||
return STATUS_UNSUCCESSFUL;
|
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 */
|
/* 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$
|
/*
|
||||||
*
|
* PROJECT: ReactOS Kernel
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/lpc/reply.c
|
* FILE: ntoskrnl/lpc/reply.c
|
||||||
* PURPOSE: Communication mechanism
|
* PURPOSE: Local Procedure Call: Receive (Replies)
|
||||||
*
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES ******************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include "lpc.h"
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
/* GLOBALS *******************************************************************/
|
/* PRIVATE FUNCTIONS *********************************************************/
|
||||||
|
|
||||||
/* FUNCTIONS *****************************************************************/
|
VOID
|
||||||
|
NTAPI
|
||||||
/**********************************************************************
|
LpcpFreeDataInfoMessage(IN PLPCP_PORT_OBJECT Port,
|
||||||
* NAME
|
IN ULONG MessageId,
|
||||||
*
|
IN ULONG CallbackId)
|
||||||
* DESCRIPTION
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*
|
|
||||||
* REVISIONS
|
|
||||||
*/
|
|
||||||
NTSTATUS STDCALL
|
|
||||||
EiReplyOrRequestPort (IN PEPORT Port,
|
|
||||||
IN PPORT_MESSAGE LpcReply,
|
|
||||||
IN ULONG MessageType,
|
|
||||||
IN PEPORT Sender)
|
|
||||||
{
|
{
|
||||||
KIRQL oldIrql;
|
PLPCP_MESSAGE Message;
|
||||||
PQUEUEDMESSAGE MessageReply;
|
PLIST_ENTRY ListHead, NextEntry;
|
||||||
ULONG Size;
|
|
||||||
|
|
||||||
if (Port == NULL)
|
/* Check if the port we want is the connection port */
|
||||||
|
if ((Port->Flags & LPCP_PORT_TYPE_MASK) > LPCP_UNCONNECTED_PORT)
|
||||||
{
|
{
|
||||||
KEBUGCHECK(0);
|
/* Use it */
|
||||||
|
Port = Port->ConnectionPort;
|
||||||
}
|
}
|
||||||
|
|
||||||
Size = sizeof(QUEUEDMESSAGE);
|
/* Loop the list */
|
||||||
if (LpcReply && LpcReply->u1.s1.TotalLength > (CSHORT)sizeof(PORT_MESSAGE))
|
ListHead = &Port->LpcDataInfoChainHead;
|
||||||
|
NextEntry = ListHead->Flink;
|
||||||
|
while (ListHead != NextEntry)
|
||||||
{
|
{
|
||||||
Size += LpcReply->u1.s1.TotalLength - sizeof(PORT_MESSAGE);
|
/* Get the message */
|
||||||
}
|
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
|
||||||
MessageReply = ExAllocatePoolWithTag(NonPagedPool, Size,
|
|
||||||
TAG_LPC_MESSAGE);
|
|
||||||
MessageReply->Sender = Sender;
|
|
||||||
|
|
||||||
if (LpcReply != NULL)
|
/* Make sure it matches */
|
||||||
|
if ((Message->Request.MessageId == MessageId) &&
|
||||||
|
(Message->Request.CallbackId == CallbackId))
|
||||||
{
|
{
|
||||||
memcpy(&MessageReply->Message, LpcReply, LpcReply->u1.s1.TotalLength);
|
/* 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
|
else
|
||||||
{
|
{
|
||||||
MessageReply->Message.u1.s1.TotalLength = sizeof(PORT_MESSAGE);
|
/* Otherwise, copy it */
|
||||||
MessageReply->Message.u1.s1.DataLength = 0;
|
Destination->ClientId.UniqueProcess = Origin->ClientId.UniqueProcess;
|
||||||
|
Destination->ClientId.UniqueThread = Origin->ClientId.UniqueThread;
|
||||||
}
|
}
|
||||||
|
|
||||||
MessageReply->Message.ClientId.UniqueProcess = PsGetCurrentProcessId();
|
/* Copy the MessageId and ClientViewSize */
|
||||||
MessageReply->Message.ClientId.UniqueThread = PsGetCurrentThreadId();
|
Destination->MessageId = Origin->MessageId;
|
||||||
MessageReply->Message.u2.s2.Type = (CSHORT)MessageType;
|
Destination->ClientViewSize = Origin->ClientViewSize;
|
||||||
MessageReply->Message.MessageId = InterlockedIncrementUL(&LpcpNextMessageId);
|
|
||||||
|
|
||||||
KeAcquireSpinLock(&Port->Lock, &oldIrql);
|
/* Copy the Message Data */
|
||||||
EiEnqueueMessagePort(Port, MessageReply);
|
RtlMoveMemory(Destination + 1,
|
||||||
KeReleaseSpinLock(&Port->Lock, oldIrql);
|
Data,
|
||||||
|
((Destination->u1.Length & 0xFFFF) + 3) &~3);
|
||||||
return(STATUS_SUCCESS);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
|
|
||||||
/**********************************************************************
|
/*
|
||||||
* NAME EXPORTED
|
* @unimplemented
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*
|
|
||||||
* REVISIONS
|
|
||||||
*/
|
*/
|
||||||
NTSTATUS STDCALL
|
NTSTATUS
|
||||||
NtReplyPort (IN HANDLE PortHandle,
|
NTAPI
|
||||||
|
NtReplyPort(IN HANDLE PortHandle,
|
||||||
IN PPORT_MESSAGE LpcReply)
|
IN PPORT_MESSAGE LpcReply)
|
||||||
{
|
|
||||||
NTSTATUS Status;
|
|
||||||
PEPORT Port;
|
|
||||||
|
|
||||||
DPRINT("NtReplyPort(PortHandle %x, LpcReply %x)\n", PortHandle, LpcReply);
|
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle(PortHandle,
|
|
||||||
PORT_ALL_ACCESS, /* AccessRequired */
|
|
||||||
LpcPortObjectType,
|
|
||||||
UserMode,
|
|
||||||
(PVOID*)&Port,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT("NtReplyPort() = %x\n", Status);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (EPORT_DISCONNECTED == Port->State)
|
|
||||||
{
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
return STATUS_PORT_DISCONNECTED;
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = EiReplyOrRequestPort(Port->OtherPort,
|
|
||||||
LpcReply,
|
|
||||||
LPC_REPLY,
|
|
||||||
Port);
|
|
||||||
KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1, FALSE);
|
|
||||||
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* 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)
|
|
||||||
{
|
|
||||||
PEPORT Port;
|
|
||||||
KIRQL oldIrql;
|
|
||||||
PQUEUEDMESSAGE Request;
|
|
||||||
BOOLEAN Disconnected;
|
|
||||||
LARGE_INTEGER to;
|
|
||||||
KPROCESSOR_MODE PreviousMode;
|
|
||||||
NTSTATUS Status = STATUS_SUCCESS;
|
|
||||||
|
|
||||||
PreviousMode = ExGetPreviousMode();
|
|
||||||
|
|
||||||
DPRINT("NtReplyWaitReceivePortEx(PortHandle %x, LpcReply %x, "
|
|
||||||
"LpcMessage %x)\n", PortHandle, ReplyMessage, ReceiveMessage);
|
|
||||||
|
|
||||||
if (PreviousMode != KernelMode)
|
|
||||||
{
|
|
||||||
_SEH_TRY
|
|
||||||
{
|
|
||||||
ProbeForWrite(ReceiveMessage,
|
|
||||||
sizeof(PORT_MESSAGE),
|
|
||||||
1);
|
|
||||||
}
|
|
||||||
_SEH_HANDLE
|
|
||||||
{
|
|
||||||
Status = _SEH_GetExceptionCode();
|
|
||||||
}
|
|
||||||
_SEH_END;
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
return Status;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle(PortHandle,
|
|
||||||
PORT_ALL_ACCESS,
|
|
||||||
LpcPortObjectType,
|
|
||||||
UserMode,
|
|
||||||
(PVOID*)&Port,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
if( Port->State == EPORT_DISCONNECTED )
|
|
||||||
{
|
|
||||||
/* If the port is disconnected, force the timeout to be 0
|
|
||||||
* so we don't wait for new messages, because there won't be
|
|
||||||
* any, only try to remove any existing messages
|
|
||||||
*/
|
|
||||||
Disconnected = TRUE;
|
|
||||||
to.QuadPart = 0;
|
|
||||||
Timeout = &to;
|
|
||||||
}
|
|
||||||
else Disconnected = FALSE;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Send the reply, only if port is connected
|
|
||||||
*/
|
|
||||||
if (ReplyMessage != NULL && !Disconnected)
|
|
||||||
{
|
|
||||||
Status = EiReplyOrRequestPort(Port->OtherPort,
|
|
||||||
ReplyMessage,
|
|
||||||
LPC_REPLY,
|
|
||||||
Port);
|
|
||||||
KeReleaseSemaphore(&Port->OtherPort->Semaphore, IO_NO_INCREMENT, 1,
|
|
||||||
FALSE);
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Want for a message to be received
|
|
||||||
*/
|
|
||||||
Status = KeWaitForSingleObject(&Port->Semaphore,
|
|
||||||
UserRequest,
|
|
||||||
UserMode,
|
|
||||||
FALSE,
|
|
||||||
Timeout);
|
|
||||||
if( Status == STATUS_TIMEOUT )
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* if the port is disconnected, and there are no remaining messages,
|
|
||||||
* return STATUS_PORT_DISCONNECTED
|
|
||||||
*/
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
return(Disconnected ? STATUS_PORT_DISCONNECTED : STATUS_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
if (STATUS_THREAD_IS_TERMINATING != Status)
|
|
||||||
{
|
|
||||||
DPRINT1("NtReplyWaitReceivePortEx() = %x\n", Status);
|
|
||||||
}
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dequeue the message
|
|
||||||
*/
|
|
||||||
KeAcquireSpinLock(&Port->Lock, &oldIrql);
|
|
||||||
Request = EiDequeueMessagePort(Port);
|
|
||||||
KeReleaseSpinLock(&Port->Lock, oldIrql);
|
|
||||||
|
|
||||||
if (Request == NULL)
|
|
||||||
{
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
return STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Request->Message.u2.s2.Type == LPC_CONNECTION_REQUEST)
|
|
||||||
{
|
|
||||||
PORT_MESSAGE Header;
|
|
||||||
PEPORT_CONNECT_REQUEST_MESSAGE CRequest;
|
|
||||||
|
|
||||||
CRequest = (PEPORT_CONNECT_REQUEST_MESSAGE)&Request->Message;
|
|
||||||
memcpy(&Header, &Request->Message, sizeof(PORT_MESSAGE));
|
|
||||||
Header.u1.s1.DataLength = (CSHORT)CRequest->ConnectDataLength;
|
|
||||||
Header.u1.s1.TotalLength = Header.u1.s1.DataLength + sizeof(PORT_MESSAGE);
|
|
||||||
|
|
||||||
if (PreviousMode != KernelMode)
|
|
||||||
{
|
|
||||||
_SEH_TRY
|
|
||||||
{
|
|
||||||
ProbeForWrite((PVOID)(ReceiveMessage + 1),
|
|
||||||
CRequest->ConnectDataLength,
|
|
||||||
1);
|
|
||||||
|
|
||||||
RtlCopyMemory(ReceiveMessage,
|
|
||||||
&Header,
|
|
||||||
sizeof(PORT_MESSAGE));
|
|
||||||
RtlCopyMemory((PVOID)(ReceiveMessage + 1),
|
|
||||||
CRequest->ConnectData,
|
|
||||||
CRequest->ConnectDataLength);
|
|
||||||
}
|
|
||||||
_SEH_HANDLE
|
|
||||||
{
|
|
||||||
Status = _SEH_GetExceptionCode();
|
|
||||||
}
|
|
||||||
_SEH_END;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RtlCopyMemory(ReceiveMessage,
|
|
||||||
&Header,
|
|
||||||
sizeof(PORT_MESSAGE));
|
|
||||||
RtlCopyMemory((PVOID)(ReceiveMessage + 1),
|
|
||||||
CRequest->ConnectData,
|
|
||||||
CRequest->ConnectDataLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
if (PreviousMode != KernelMode)
|
|
||||||
{
|
|
||||||
_SEH_TRY
|
|
||||||
{
|
|
||||||
ProbeForWrite(ReceiveMessage,
|
|
||||||
Request->Message.u1.s1.TotalLength,
|
|
||||||
1);
|
|
||||||
|
|
||||||
RtlCopyMemory(ReceiveMessage,
|
|
||||||
&Request->Message,
|
|
||||||
Request->Message.u1.s1.TotalLength);
|
|
||||||
}
|
|
||||||
_SEH_HANDLE
|
|
||||||
{
|
|
||||||
Status = _SEH_GetExceptionCode();
|
|
||||||
}
|
|
||||||
_SEH_END;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
RtlCopyMemory(ReceiveMessage,
|
|
||||||
&Request->Message,
|
|
||||||
Request->Message.u1.s1.TotalLength);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* Copying the message to the caller's buffer failed so
|
|
||||||
* undo what we did and return.
|
|
||||||
* FIXME: Also increment semaphore.
|
|
||||||
*/
|
|
||||||
KeAcquireSpinLock(&Port->Lock, &oldIrql);
|
|
||||||
EiEnqueueMessageAtHeadPort(Port, Request);
|
|
||||||
KeReleaseSpinLock(&Port->Lock, oldIrql);
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
if (Request->Message.u2.s2.Type == LPC_CONNECTION_REQUEST)
|
|
||||||
{
|
|
||||||
KeAcquireSpinLock(&Port->Lock, &oldIrql);
|
|
||||||
EiEnqueueConnectMessagePort(Port, Request);
|
|
||||||
KeReleaseSpinLock(&Port->Lock, oldIrql);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ExFreePool(Request);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* Dereference the port
|
|
||||||
*/
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
return(STATUS_SUCCESS);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* NAME EXPORTED
|
|
||||||
* NtReplyWaitReceivePort
|
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
* Can be used with waitable ports.
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
* PortHandle
|
|
||||||
* PortId
|
|
||||||
* LpcReply
|
|
||||||
* LpcMessage
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*
|
|
||||||
* REVISIONS
|
|
||||||
*/
|
|
||||||
NTSTATUS STDCALL
|
|
||||||
NtReplyWaitReceivePort(IN HANDLE PortHandle,
|
|
||||||
OUT PVOID *PortContext OPTIONAL,
|
|
||||||
IN PPORT_MESSAGE ReplyMessage OPTIONAL,
|
|
||||||
OUT PPORT_MESSAGE ReceiveMessage)
|
|
||||||
{
|
|
||||||
return NtReplyWaitReceivePortEx(PortHandle,
|
|
||||||
PortContext,
|
|
||||||
ReplyMessage,
|
|
||||||
ReceiveMessage,
|
|
||||||
NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* NAME
|
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*
|
|
||||||
* REVISIONS
|
|
||||||
*/
|
|
||||||
NTSTATUS STDCALL
|
|
||||||
NtReplyWaitReplyPort (HANDLE PortHandle,
|
|
||||||
PPORT_MESSAGE ReplyMessage)
|
|
||||||
{
|
{
|
||||||
UNIMPLEMENTED;
|
UNIMPLEMENTED;
|
||||||
return(STATUS_NOT_IMPLEMENTED);
|
return STATUS_NOT_IMPLEMENTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -423,36 +143,349 @@ NtReplyWaitReplyPort (HANDLE PortHandle,
|
||||||
*/
|
*/
|
||||||
NTSTATUS
|
NTSTATUS
|
||||||
NTAPI
|
NTAPI
|
||||||
LpcRequestWaitReplyPort(IN PVOID Port,
|
NtReplyWaitReceivePortEx(IN HANDLE PortHandle,
|
||||||
IN PPORT_MESSAGE LpcMessageRequest,
|
OUT PVOID *PortContext OPTIONAL,
|
||||||
OUT PPORT_MESSAGE LpcMessageReply)
|
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;
|
NTSTATUS Status;
|
||||||
UNICODE_STRING PortName;
|
PLPCP_MESSAGE Message;
|
||||||
ULONG ConnectInfoLength;
|
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 */
|
||||||
// OMG HAXX!
|
if (Thread->SystemThread) WaitMode = UserMode;
|
||||||
//
|
|
||||||
RtlInitUnicodeString(&PortName, L"\\Windows\\ApiPort");
|
|
||||||
ConnectInfoLength = 0;
|
|
||||||
Status = ZwConnectPort(&PortHandle,
|
|
||||||
&PortName,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
NULL,
|
|
||||||
&ConnectInfoLength);
|
|
||||||
|
|
||||||
Status = ZwRequestWaitReplyPort(PortHandle,
|
/* Check if caller has a reply message */
|
||||||
LpcMessageRequest,
|
if (ReplyMessage)
|
||||||
LpcMessageReply);
|
{
|
||||||
|
/* Validate its length */
|
||||||
|
if ((ReplyMessage->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
|
||||||
|
ReplyMessage->u1.s1.TotalLength)
|
||||||
|
{
|
||||||
|
/* Fail */
|
||||||
|
return STATUS_INVALID_PARAMETER;
|
||||||
|
}
|
||||||
|
|
||||||
/* Close the handle */
|
/* Make sure it has a valid ID */
|
||||||
ObCloseHandle(PortHandle, KernelMode);
|
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;
|
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 */
|
/* EOF */
|
||||||
|
|
|
@ -1,395 +1,426 @@
|
||||||
/* $Id$
|
/*
|
||||||
*
|
* PROJECT: ReactOS Kernel
|
||||||
* COPYRIGHT: See COPYING in the top level directory
|
* LICENSE: GPL - See COPYING in the top level directory
|
||||||
* PROJECT: ReactOS kernel
|
|
||||||
* FILE: ntoskrnl/lpc/send.c
|
* FILE: ntoskrnl/lpc/send.c
|
||||||
* PURPOSE: Communication mechanism
|
* PURPOSE: Local Procedure Call: Sending (Requests)
|
||||||
*
|
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
|
||||||
* PROGRAMMERS: David Welch (welch@cwcom.net)
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/* INCLUDES *****************************************************************/
|
/* INCLUDES ******************************************************************/
|
||||||
|
|
||||||
#include <ntoskrnl.h>
|
#include <ntoskrnl.h>
|
||||||
|
#include "lpc.h"
|
||||||
#define NDEBUG
|
#define NDEBUG
|
||||||
#include <internal/debug.h>
|
#include <internal/debug.h>
|
||||||
|
|
||||||
/**********************************************************************
|
/* PUBLIC FUNCTIONS **********************************************************/
|
||||||
* 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.
|
|
||||||
*
|
|
||||||
* @implemented
|
* @implemented
|
||||||
*/
|
*/
|
||||||
NTSTATUS STDCALL LpcRequestPort (IN PVOID PortObject,
|
NTSTATUS
|
||||||
|
NTAPI
|
||||||
|
LpcRequestPort(IN PVOID PortObject,
|
||||||
IN PPORT_MESSAGE LpcMessage)
|
IN PPORT_MESSAGE LpcMessage)
|
||||||
{
|
{
|
||||||
NTSTATUS Status;
|
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject, QueuePort;
|
||||||
PEPORT Port = (PEPORT)PortObject;
|
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__
|
/* Validate it */
|
||||||
/* Check the message's type */
|
if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))
|
||||||
if (LPC_NEW_MESSAGE == LpcMessage->u2.s2.Type)
|
|
||||||
{
|
|
||||||
LpcMessage->u2.s2.Type = LPC_DATAGRAM;
|
|
||||||
}
|
|
||||||
else if (LPC_DATAGRAM == LpcMessage->u2.s2.Type)
|
|
||||||
{
|
{
|
||||||
|
/* Fail */
|
||||||
return STATUS_INVALID_PARAMETER;
|
return STATUS_INVALID_PARAMETER;
|
||||||
}
|
}
|
||||||
else if (LpcMessage->u2.s2.Type > LPC_CLIENT_DIED)
|
|
||||||
|
/* Mark this as a kernel-mode message only if we really came from there */
|
||||||
|
if ((PreviousMode == KernelMode) &&
|
||||||
|
(LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))
|
||||||
{
|
{
|
||||||
return STATUS_INVALID_PARAMETER;
|
/* We did, this is a kernel mode message */
|
||||||
}
|
MessageType |= LPC_KERNELMODE_MESSAGE;
|
||||||
/* Check the range offset */
|
|
||||||
if (0 != LpcMessage->VirtualRangesOffset)
|
|
||||||
{
|
|
||||||
return STATUS_INVALID_PARAMETER;
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
Status = EiReplyOrRequestPort(Port,
|
|
||||||
LpcMessage,
|
|
||||||
LPC_DATAGRAM,
|
|
||||||
Port);
|
|
||||||
KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );
|
|
||||||
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* NAME
|
|
||||||
* NtRequestPort/2
|
|
||||||
*
|
|
||||||
* DESCRIPTION
|
|
||||||
*
|
|
||||||
* ARGUMENTS
|
|
||||||
*
|
|
||||||
* RETURN VALUE
|
|
||||||
*
|
|
||||||
* REVISIONS
|
|
||||||
*
|
|
||||||
* @implemented
|
|
||||||
*/
|
|
||||||
NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle,
|
|
||||||
IN PPORT_MESSAGE LpcMessage)
|
|
||||||
{
|
|
||||||
NTSTATUS Status;
|
|
||||||
PEPORT Port;
|
|
||||||
|
|
||||||
DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle,
|
|
||||||
LpcMessage);
|
|
||||||
|
|
||||||
Status = ObReferenceObjectByHandle(PortHandle,
|
|
||||||
PORT_ALL_ACCESS,
|
|
||||||
LpcPortObjectType,
|
|
||||||
UserMode,
|
|
||||||
(PVOID*)&Port,
|
|
||||||
NULL);
|
|
||||||
if (!NT_SUCCESS(Status))
|
|
||||||
{
|
|
||||||
DPRINT("NtRequestPort() = %x\n", Status);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
Status = LpcRequestPort(Port->OtherPort,
|
|
||||||
LpcMessage);
|
|
||||||
|
|
||||||
ObDereferenceObject(Port);
|
|
||||||
return(Status);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**********************************************************************
|
|
||||||
* 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
|
else
|
||||||
{
|
{
|
||||||
LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
|
/* This is a datagram */
|
||||||
|
MessageType = LPC_DATAGRAM;
|
||||||
}
|
}
|
||||||
|
|
||||||
DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
|
/* Can't have data information on this type of call */
|
||||||
"LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
|
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,
|
Status = ObReferenceObjectByHandle(PortHandle,
|
||||||
PORT_ALL_ACCESS,
|
0,
|
||||||
LpcPortObjectType,
|
LpcPortObjectType,
|
||||||
UserMode,
|
PreviousMode,
|
||||||
(PVOID*)&Port,
|
(PVOID*)&Port,
|
||||||
NULL);
|
NULL);
|
||||||
if (!NT_SUCCESS(Status))
|
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))
|
||||||
{
|
{
|
||||||
return(Status);
|
/* Fail */
|
||||||
|
ObDereferenceObject(Port);
|
||||||
|
return STATUS_PORT_MESSAGE_TOO_LONG;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (EPORT_DISCONNECTED == Port->State)
|
/* 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);
|
ObDereferenceObject(Port);
|
||||||
return STATUS_PORT_DISCONNECTED;
|
return STATUS_PORT_DISCONNECTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* win32k sometimes needs to KeAttach() the CSRSS process in order to make
|
/* This will be the rundown port */
|
||||||
the PortHandle valid. Now that we've got the EPORT structure from the
|
ReplyPort = QueuePort;
|
||||||
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)
|
/* Check if this is a communication port */
|
||||||
|
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
|
||||||
{
|
{
|
||||||
if (NULL != AttachedProcess)
|
/* Copy the port context and use the connection port */
|
||||||
{
|
Message->PortContext = ReplyPort->PortContext;
|
||||||
KeAttachProcess(AttachedProcess);
|
QueuePort = Port->ConnectionPort;
|
||||||
}
|
}
|
||||||
ObDereferenceObject(Port);
|
else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
|
||||||
return(STATUS_PORT_MESSAGE_TOO_LONG);
|
LPCP_COMMUNICATION_PORT)
|
||||||
}
|
|
||||||
LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
|
|
||||||
if (LpcRequest == NULL)
|
|
||||||
{
|
{
|
||||||
if (NULL != AttachedProcess)
|
/* Use the connection port for anything but communication ports */
|
||||||
{
|
QueuePort = Port->ConnectionPort;
|
||||||
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
|
else
|
||||||
{
|
{
|
||||||
RtlCopyMemory(LpcRequest,
|
/* Otherwise, for a connection port, use the same port object */
|
||||||
UnsafeLpcRequest,
|
QueuePort = ReplyPort = Port;
|
||||||
LpcRequestMessageSize);
|
|
||||||
LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
|
|
||||||
LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
|
/* 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)
|
||||||
{
|
{
|
||||||
ExFreePool(LpcRequest);
|
/* Wake it */
|
||||||
if (NULL != AttachedProcess)
|
KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
|
||||||
{
|
|
||||||
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,
|
/* Now release the semaphore */
|
||||||
LpcRequest,
|
LpcpCompleteWait(Semaphore);
|
||||||
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);
|
|
||||||
|
|
||||||
/*
|
/* And let's wait for the reply */
|
||||||
* Wait for a reply
|
LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);
|
||||||
*/
|
|
||||||
Status = KeWaitForSingleObject(&Port->Semaphore,
|
/* Acquire the LPC lock */
|
||||||
UserRequest,
|
KeAcquireGuardedMutex(&LpcpLock);
|
||||||
UserMode,
|
|
||||||
FALSE,
|
/* Get the LPC Message and clear our thread's reply data */
|
||||||
NULL);
|
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)
|
if (Status == STATUS_SUCCESS)
|
||||||
{
|
{
|
||||||
|
/* Check if we have a valid message */
|
||||||
/*
|
|
||||||
* Dequeue the reply
|
|
||||||
*/
|
|
||||||
KeAcquireSpinLock(&Port->Lock, &oldIrql);
|
|
||||||
Message = EiDequeueMessagePort(Port);
|
|
||||||
KeReleaseSpinLock(&Port->Lock, oldIrql);
|
|
||||||
if (Message)
|
if (Message)
|
||||||
{
|
{
|
||||||
DPRINT("Message->Message.u1.s1.TotalLength %d\n",
|
LPCTRACE(LPC_SEND_DEBUG,
|
||||||
Message->Message.u1.s1.TotalLength);
|
"Reply Messages: %p/%p\n",
|
||||||
if (PreviousMode != KernelMode)
|
&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))
|
||||||
{
|
{
|
||||||
_SEH_TRY
|
/* Save the data information */
|
||||||
{
|
LpcpSaveDataInfoMessage(Port, Message);
|
||||||
RtlCopyMemory(UnsafeLpcReply,
|
|
||||||
&Message->Message,
|
|
||||||
Message->Message.u1.s1.TotalLength);
|
|
||||||
}
|
|
||||||
_SEH_HANDLE
|
|
||||||
{
|
|
||||||
Status = _SEH_GetExceptionCode();
|
|
||||||
}
|
|
||||||
_SEH_END;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
RtlCopyMemory(UnsafeLpcReply,
|
/* Otherwise, just free it */
|
||||||
&Message->Message,
|
LpcpFreeToPortZone(Message, FALSE);
|
||||||
Message->Message.u1.s1.TotalLength);
|
|
||||||
}
|
}
|
||||||
ExFreePool(Message);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
Status = STATUS_UNSUCCESSFUL;
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (NT_SUCCESS(Status))
|
/* We don't have a reply */
|
||||||
|
Status = STATUS_LPC_REPLY_LOST;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
Status = STATUS_UNSUCCESSFUL;
|
/* The wait failed, free the message while holding the lock */
|
||||||
}
|
KeAcquireGuardedMutex(&LpcpLock);
|
||||||
}
|
LpcpFreeToPortZone(Message, TRUE);
|
||||||
if (NULL != AttachedProcess)
|
KeReleaseGuardedMutex(&LpcpLock);
|
||||||
{
|
|
||||||
KeAttachProcess(AttachedProcess);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* All done */
|
||||||
|
LPCTRACE(LPC_SEND_DEBUG,
|
||||||
|
"Port: %p. Status: %p\n",
|
||||||
|
Port,
|
||||||
|
Status);
|
||||||
ObDereferenceObject(Port);
|
ObDereferenceObject(Port);
|
||||||
|
return Status;
|
||||||
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 */
|
/* EOF */
|
||||||
|
|
|
@ -9,9 +9,6 @@
|
||||||
<define name="__NO_CTYPE_INLINES" />
|
<define name="__NO_CTYPE_INLINES" />
|
||||||
<define name="__USE_W32API" />
|
<define name="__USE_W32API" />
|
||||||
<define name="WIN9X_COMPAT_SPINLOCK" />
|
<define name="WIN9X_COMPAT_SPINLOCK" />
|
||||||
<if property="NTLPC" value="1">
|
|
||||||
<define name="NTLPC" />
|
|
||||||
</if>
|
|
||||||
<include base="cmlib">.</include>
|
<include base="cmlib">.</include>
|
||||||
<include base="ntoskrnl">include</include>
|
<include base="ntoskrnl">include</include>
|
||||||
<include base="ReactOS">include/reactos/drivers</include>
|
<include base="ReactOS">include/reactos/drivers</include>
|
||||||
|
@ -230,24 +227,7 @@
|
||||||
<file>loader.c</file>
|
<file>loader.c</file>
|
||||||
<file>rtl.c</file>
|
<file>rtl.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
<if property="NTLPC" value="0">
|
|
||||||
<directory name="lpc">
|
<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>close.c</file>
|
||||||
<file>complete.c</file>
|
<file>complete.c</file>
|
||||||
<file>connect.c</file>
|
<file>connect.c</file>
|
||||||
|
@ -257,8 +237,6 @@
|
||||||
<file>reply.c</file>
|
<file>reply.c</file>
|
||||||
<file>send.c</file>
|
<file>send.c</file>
|
||||||
</directory>
|
</directory>
|
||||||
</directory>
|
|
||||||
</if>
|
|
||||||
<directory name="mm">
|
<directory name="mm">
|
||||||
<if property="ARCH" value="i386">
|
<if property="ARCH" value="i386">
|
||||||
<directory name="i386">
|
<directory name="i386">
|
||||||
|
|
|
@ -1716,8 +1716,7 @@ ObpSetHandleAttributes(IN PHANDLE_TABLE HandleTable,
|
||||||
IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
|
IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
|
||||||
IN PVOID Context)
|
IN PVOID Context)
|
||||||
{
|
{
|
||||||
POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo =
|
POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = Context;
|
||||||
(POBP_SET_HANDLE_ATTRIBUTES_CONTEXT)Context;
|
|
||||||
POBJECT_HEADER ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry);
|
POBJECT_HEADER ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry);
|
||||||
PAGED_CODE();
|
PAGED_CODE();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue