- 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:
Alex Ionescu 2007-01-10 04:27:40 +00:00
parent d8160f0676
commit 6af685313a
25 changed files with 2554 additions and 5332 deletions

View file

@ -75,6 +75,6 @@
working on the \ntlpc directory. Leave this disabled unless you really know
what you're doing.
-->
<property name="NTLPC" value="0" />
<property name="NTLPC" value="1" />
</rbuild>

View file

@ -1,91 +1,56 @@
#ifndef __INCLUDE_INTERNAL_PORT_H
#define __INCLUDE_INTERNAL_PORT_H
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/include/lpc.h
* PURPOSE: Internal header for the Local Procedure Call
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* EPORT.Type */
//
// Define this if you want debugging support
//
#define _LPC_DEBUG_ 0x01
#define EPORT_TYPE_SERVER_RQST_PORT (0)
#define EPORT_TYPE_SERVER_COMM_PORT (1)
#define EPORT_TYPE_CLIENT_COMM_PORT (2)
//
// These define the Debug Masks Supported
//
#define LPC_CREATE_DEBUG 0x01
#define LPC_CLOSE_DEBUG 0x02
#define LPC_CONNECT_DEBUG 0x04
#define LPC_LISTEN_DEBUG 0x08
#define LPC_REPLY_DEBUG 0x10
#define LPC_COMPLETE_DEBUG 0x20
#define LPC_SEND_DEBUG 0x40
/* EPORT.State */
#define EPORT_INACTIVE (0)
#define EPORT_WAIT_FOR_CONNECT (1)
#define EPORT_WAIT_FOR_ACCEPT (2)
#define EPORT_WAIT_FOR_COMPLETE_SRV (3)
#define EPORT_WAIT_FOR_COMPLETE_CLT (4)
#define EPORT_CONNECTED_CLIENT (5)
#define EPORT_CONNECTED_SERVER (6)
#define EPORT_DISCONNECTED (7)
extern POBJECT_TYPE LpcPortObjectType;
extern ULONG LpcpNextMessageId;
#ifndef NTLPC
extern FAST_MUTEX LpcpLock;
//
// Debug/Tracing support
//
#if _LPC_DEBUG_
#ifdef NEW_DEBUG_SYSTEM_IMPLEMENTED // enable when Debug Filters are implemented
#define LPCTRACE(x, ...) \
{ \
DbgPrintEx("%s [%.16s] - ", \
__FUNCTION__, \
PsGetCurrentProcess()->ImageFileName); \
DbgPrintEx(__VA_ARGS__); \
}
#else
#define LPCTRACE(x, ...) \
if (x & LpcpTraceLevel) \
{ \
DbgPrint("%s [%.16s:%lx] - ", \
__FUNCTION__, \
PsGetCurrentProcess()->ImageFileName, \
PsGetCurrentThreadId()); \
DbgPrint(__VA_ARGS__); \
}
#endif
#endif
typedef struct _EPORT_LISTENER
{
HANDLE ListenerPid;
LIST_ENTRY ListenerListEntry;
} EPORT_LISTENER, *PEPORT_LISTENER;
typedef struct _EPORT
{
KSPIN_LOCK Lock;
KSEMAPHORE Semaphore;
USHORT Type;
USHORT State;
struct _EPORT *RequestPort;
struct _EPORT *OtherPort;
ULONG QueueLength;
LIST_ENTRY QueueListHead;
ULONG ConnectQueueLength;
LIST_ENTRY ConnectQueueListHead;
ULONG MaxDataLength;
ULONG MaxConnectInfoLength;
ULONG MaxPoolUsage; /* size of NP zone */
} EPORT, *PEPORT;
typedef struct _EPORT_CONNECT_REQUEST_MESSAGE
{
PORT_MESSAGE MessageHeader;
PEPROCESS ConnectingProcess;
struct _SECTION_OBJECT* SendSectionObject;
LARGE_INTEGER SendSectionOffset;
ULONG SendViewSize;
ULONG ConnectDataLength;
UCHAR ConnectData[0];
} EPORT_CONNECT_REQUEST_MESSAGE, *PEPORT_CONNECT_REQUEST_MESSAGE;
typedef struct _EPORT_CONNECT_REPLY_MESSAGE
{
PORT_MESSAGE MessageHeader;
PVOID SendServerViewBase;
ULONG ReceiveClientViewSize;
PVOID ReceiveClientViewBase;
ULONG MaximumMessageSize;
ULONG ConnectDataLength;
UCHAR ConnectData[0];
} EPORT_CONNECT_REPLY_MESSAGE, *PEPORT_CONNECT_REPLY_MESSAGE;
typedef struct _QUEUEDMESSAGE
{
PEPORT Sender;
LIST_ENTRY QueueListEntry;
PORT_MESSAGE Message;
} QUEUEDMESSAGE, *PQUEUEDMESSAGE;
NTSTATUS
NTAPI
LpcSendTerminationPort(
PEPORT Port,
LARGE_INTEGER CreationTime
);
/* Code in ntoskrnl/lpc/close.c */
VOID
//
// Internal Port Management
//
VOID
NTAPI
LpcpClosePort(
IN PEPROCESS Process OPTIONAL,
@ -97,66 +62,69 @@ LpcpClosePort(
VOID
NTAPI
LpcpDeletePort(IN PVOID ObjectBody);
VOID
NTAPI
LpcExitThread(IN PETHREAD Thread);
/* Code in ntoskrnl/lpc/queue.c */
VOID
NTAPI
EiEnqueueConnectMessagePort(
IN OUT PEPORT Port,
IN PQUEUEDMESSAGE Message
);
VOID
NTAPI
EiEnqueueMessagePort(
IN OUT PEPORT Port,
IN PQUEUEDMESSAGE Message
);
VOID
NTAPI
EiEnqueueMessageAtHeadPort(
IN OUT PEPORT Port,
IN PQUEUEDMESSAGE Message
);
PQUEUEDMESSAGE
NTAPI
EiDequeueConnectMessagePort(IN OUT PEPORT Port);
PQUEUEDMESSAGE
NTAPI
EiDequeueMessagePort(IN OUT PEPORT Port);
/* Code in ntoskrnl/lpc/port.c */
NTSTATUS
NTAPI
LpcpInitializePort(
IN OUT PEPORT Port,
IN USHORT Type,
IN PEPORT Parent OPTIONAL
LpcpDeletePort(
IN PVOID ObjectBody
);
NTSTATUS
NTAPI
LpcpInitSystem (VOID);
LpcpInitializePortQueue(
IN PLPCP_PORT_OBJECT Port
);
/* Code in ntoskrnl/lpc/reply.c */
NTSTATUS
VOID
NTAPI
EiReplyOrRequestPort(
IN PEPORT Port,
IN PPORT_MESSAGE LpcReply,
LpcpFreeToPortZone(
IN PLPCP_MESSAGE Message,
IN ULONG Flags
);
VOID
NTAPI
LpcpMoveMessage(
IN PPORT_MESSAGE Destination,
IN PPORT_MESSAGE Origin,
IN PVOID Data,
IN ULONG MessageType,
IN PEPORT Sender
IN PCLIENT_ID ClientId
);
#endif /* __INCLUDE_INTERNAL_PORT_H */
VOID
NTAPI
LpcpSaveDataInfoMessage(
IN PLPCP_PORT_OBJECT Port,
IN PLPCP_MESSAGE Message
);
//
// Module-external utlity functions
//
VOID
NTAPI
LpcExitThread(
IN PETHREAD Thread
);
//
// Initialization functions
//
NTSTATUS
NTAPI
LpcpInitSystem(
VOID
);
//
// Global data inside the Process Manager
//
extern POBJECT_TYPE LpcPortObjectType;
extern ULONG LpcpNextMessageId, LpcpNextCallbackId;
extern KGUARDED_MUTEX LpcpLock;
extern PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
extern ULONG LpcpMaxMessageSize;
extern ULONG LpcpTraceLevel;
//
// Inlined Functions
//
#include "lpc_x.h"

View file

@ -1,122 +1,122 @@
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/include/lpc_x.h
* PURPOSE: Intenral Inlined Functions for Local Procedure Call
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
//
// Gets the message type, removing the kernel-mode flag
//
#define LpcpGetMessageType(x) \
((x)->u2.s2.Type &~ LPC_KERNELMODE_MESSAGE)
//
// Waits on an LPC semaphore for a receive operation
//
#define LpcpReceiveWait(s, w) \
{ \
LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \
Status = KeWaitForSingleObject(s, \
WrLpcReceive, \
w, \
FALSE, \
NULL); \
LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \
}
//
// Waits on an LPC semaphore for a reply operation
//
#define LpcpReplyWait(s, w) \
{ \
LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \
Status = KeWaitForSingleObject(s, \
WrLpcReply, \
w, \
FALSE, \
NULL); \
LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \
if (Status == STATUS_USER_APC) \
{ \
/* We were preempted by an APC */ \
if (KeReadStateSemaphore(s)) \
{ \
/* It's still signaled, so wait on it */ \
KeWaitForSingleObject(s, \
Executive, \
KernelMode, \
FALSE, \
NULL); \
Status = STATUS_SUCCESS; \
} \
} \
}
//
// Waits on an LPC semaphore for a connect operation
//
#define LpcpConnectWait(s, w) \
{ \
LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \
Status = KeWaitForSingleObject(s, \
Executive, \
w, \
FALSE, \
NULL); \
LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\
if (Status == STATUS_USER_APC) \
{ \
/* We were preempted by an APC */ \
if (KeReadStateSemaphore(s)) \
{ \
/* It's still signaled, so wait on it */ \
KeWaitForSingleObject(s, \
Executive, \
KernelMode, \
FALSE, \
NULL); \
Status = STATUS_SUCCESS; \
} \
} \
}
//
// Releases an LPC Semaphore to complete a wait
//
#define LpcpCompleteWait(s) \
{ \
/* Release the semaphore */ \
LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \
KeReleaseSemaphore(s, 1, 1, FALSE); \
}
//
// Allocates a new message
//
PLPCP_MESSAGE
FORCEINLINE
LpcpAllocateFromPortZone(VOID)
{
PLPCP_MESSAGE Message;
/* Allocate a message from the port zone while holding the lock */
KeAcquireGuardedMutex(&LpcpLock);
Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);
if (!Message)
{
/* Fail, and let caller cleanup */
KeReleaseGuardedMutex(&LpcpLock);
return NULL;
}
/* Initialize it */
InitializeListHead(&Message->Entry);
Message->RepliedToThread = NULL;
Message->Request.u2.ZeroInit = 0;
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
return Message;
}
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/include/lpc_x.h
* PURPOSE: Intenral Inlined Functions for Local Procedure Call
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
//
// Gets the message type, removing the kernel-mode flag
//
#define LpcpGetMessageType(x) \
((x)->u2.s2.Type &~ LPC_KERNELMODE_MESSAGE)
//
// Waits on an LPC semaphore for a receive operation
//
#define LpcpReceiveWait(s, w) \
{ \
LPCTRACE(LPC_REPLY_DEBUG, "Wait: %p\n", s); \
Status = KeWaitForSingleObject(s, \
WrLpcReceive, \
w, \
FALSE, \
NULL); \
LPCTRACE(LPC_REPLY_DEBUG, "Wait done: %lx\n", Status); \
}
//
// Waits on an LPC semaphore for a reply operation
//
#define LpcpReplyWait(s, w) \
{ \
LPCTRACE(LPC_SEND_DEBUG, "Wait: %p\n", s); \
Status = KeWaitForSingleObject(s, \
WrLpcReply, \
w, \
FALSE, \
NULL); \
LPCTRACE(LPC_SEND_DEBUG, "Wait done: %lx\n", Status); \
if (Status == STATUS_USER_APC) \
{ \
/* We were preempted by an APC */ \
if (KeReadStateSemaphore(s)) \
{ \
/* It's still signaled, so wait on it */ \
KeWaitForSingleObject(s, \
Executive, \
KernelMode, \
FALSE, \
NULL); \
Status = STATUS_SUCCESS; \
} \
} \
}
//
// Waits on an LPC semaphore for a connect operation
//
#define LpcpConnectWait(s, w) \
{ \
LPCTRACE(LPC_CONNECT_DEBUG, "Wait: %p\n", s); \
Status = KeWaitForSingleObject(s, \
Executive, \
w, \
FALSE, \
NULL); \
LPCTRACE(LPC_CONNECT_DEBUG, "Wait done: %lx\n", Status);\
if (Status == STATUS_USER_APC) \
{ \
/* We were preempted by an APC */ \
if (KeReadStateSemaphore(s)) \
{ \
/* It's still signaled, so wait on it */ \
KeWaitForSingleObject(s, \
Executive, \
KernelMode, \
FALSE, \
NULL); \
Status = STATUS_SUCCESS; \
} \
} \
}
//
// Releases an LPC Semaphore to complete a wait
//
#define LpcpCompleteWait(s) \
{ \
/* Release the semaphore */ \
LPCTRACE(LPC_SEND_DEBUG, "Release: %p\n", s); \
KeReleaseSemaphore(s, 1, 1, FALSE); \
}
//
// Allocates a new message
//
PLPCP_MESSAGE
FORCEINLINE
LpcpAllocateFromPortZone(VOID)
{
PLPCP_MESSAGE Message;
/* Allocate a message from the port zone while holding the lock */
KeAcquireGuardedMutex(&LpcpLock);
Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);
if (!Message)
{
/* Fail, and let caller cleanup */
KeReleaseGuardedMutex(&LpcpLock);
return NULL;
}
/* Initialize it */
InitializeListHead(&Message->Entry);
Message->RepliedToThread = NULL;
Message->Request.u2.ZeroInit = 0;
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
return Message;
}

View file

@ -1,25 +1,29 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/close.c
* PURPOSE: Communication mechanism
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
* PURPOSE: Local Procedure Call: Rundown, Cleanup, Deletion
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS *****************************************************************/
/* PRIVATE FUNCTIONS *********************************************************/
VOID
NTAPI
LpcExitThread(IN PETHREAD Thread)
{
PLPCP_MESSAGE Message;
/* Acquire the lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Make sure that the Reply Chain is empty */
if (!IsListEmpty(&Thread->LpcReplyChain))
{
@ -31,104 +35,361 @@ LpcExitThread(IN PETHREAD Thread)
Thread->LpcExitThreadCalled = TRUE;
Thread->LpcReplyMessageId = 0;
/* FIXME: Reply to the LpcReplyMessage */
}
/**********************************************************************
* NAME
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*/
VOID STDCALL
LpcpClosePort (IN PEPROCESS Process OPTIONAL,
IN PVOID ObjectBody,
IN ACCESS_MASK GrantedAccess,
IN ULONG HandleCount,
IN ULONG SystemHandleCount)
{
PEPORT Port = (PEPORT)ObjectBody;
PORT_MESSAGE Message;
/* FIXME Race conditions here! */
/*
* If the client has just closed its handle then tell the server what
* happened and disconnect this port.
*/
if (!(HandleCount)&& (Port->State == EPORT_CONNECTED_CLIENT))
/* Check if there's a reply message */
Message = Thread->LpcReplyMessage;
if (Message)
{
DPRINT("Informing server\n");
Message.u1.s1.TotalLength = sizeof(PORT_MESSAGE);
Message.u1.s1.DataLength = 0;
EiReplyOrRequestPort (Port->OtherPort,
&Message,
LPC_PORT_CLOSED,
Port);
Port->OtherPort->OtherPort = NULL;
Port->OtherPort->State = EPORT_DISCONNECTED;
KeReleaseSemaphore( &Port->OtherPort->Semaphore,
IO_NO_INCREMENT,
1,
FALSE );
ObDereferenceObject (Port);
/* FIXME: TODO */
KEBUGCHECK(0);
}
/*
* If the server has closed all of its handles then disconnect the port,
* don't actually notify the client until it attempts an operation.
*/
if (!(HandleCount)&& (Port->State == EPORT_CONNECTED_SERVER))
{
DPRINT("Cleaning up server\n");
Port->OtherPort->OtherPort = NULL;
Port->OtherPort->State = EPORT_DISCONNECTED;
ObDereferenceObject(Port->OtherPort);
}
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
}
/**********************************************************************
* NAME
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*/
VOID STDCALL
LpcpDeletePort (PVOID ObjectBody)
VOID
NTAPI
LpcpFreeToPortZone(IN PLPCP_MESSAGE Message,
IN ULONG Flags)
{
PLIST_ENTRY Entry;
PQUEUEDMESSAGE Message;
PLPCP_CONNECTION_MESSAGE ConnectMessage;
PLPCP_PORT_OBJECT ClientPort = NULL;
PETHREAD Thread = NULL;
BOOLEAN LockHeld = Flags & 1;
PAGED_CODE();
LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. Flags: %lx\n", Message, Flags);
PEPORT Port = (PEPORT)ObjectBody;
/* Acquire the lock if not already */
if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock);
DPRINT("Deleting port %x\n", Port);
/* Check if the queue list is empty */
if (!IsListEmpty(&Message->Entry))
{
/* Remove and re-initialize */
RemoveEntryList(&Message->Entry);
InitializeListHead(&Message->Entry);
}
/* Free all waiting messages */
while (!IsListEmpty(&Port->QueueListHead))
{
Entry = RemoveHeadList(&Port->QueueListHead);
Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry);
ExFreePool(Message);
}
/* Check if we've already replied */
if (Message->RepliedToThread)
{
/* Set thread to dereference and clean up */
Thread = Message->RepliedToThread;
Message->RepliedToThread = NULL;
}
while (!IsListEmpty(&Port->ConnectQueueListHead))
{
Entry = RemoveHeadList(&Port->ConnectQueueListHead);
Message = CONTAINING_RECORD (Entry, QUEUEDMESSAGE, QueueListEntry);
ExFreePool(Message);
}
/* Check if this is a connection request */
if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
{
/* Get the connection message */
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
/* Clear the client port */
ClientPort = ConnectMessage->ClientPort;
if (ClientPort) ConnectMessage->ClientPort = NULL;
}
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
/* Check if we had anything to dereference */
if (Thread) ObDereferenceObject(Thread);
if (ClientPort) ObDereferenceObject(ClientPort);
/* Free the entry */
ExFreeToPagedLookasideList(&LpcpMessagesLookaside, Message);
/* Reacquire the lock if needed */
if ((LockHeld) && !(Flags & 2)) KeAcquireGuardedMutex(&LpcpLock);
}
VOID
NTAPI
LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port,
IN BOOLEAN Destroy)
{
PLIST_ENTRY ListHead, NextEntry;
PETHREAD Thread;
PLPCP_MESSAGE Message;
PLPCP_CONNECTION_MESSAGE ConnectMessage;
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
/* Hold the lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Disconnect the port to which this port is connected */
if (Port->ConnectedPort) Port->ConnectedPort->ConnectedPort = NULL;
/* Check if this is a connection port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
{
/* Delete the name */
Port->Flags |= LPCP_NAME_DELETED;
}
/* Walk all the threads waiting and signal them */
ListHead = &Port->LpcReplyChainHead;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Get the Thread */
Thread = CONTAINING_RECORD(NextEntry, ETHREAD, LpcReplyChain);
/* Make sure we're not in exit */
if (Thread->LpcExitThreadCalled) break;
/* Move to the next entry */
NextEntry = NextEntry->Flink;
/* Remove and reinitialize the List */
RemoveEntryList(&Thread->LpcReplyChain);
InitializeListHead(&Thread->LpcReplyChain);
/* Check if someone is waiting */
if (!KeReadStateSemaphore(&Thread->LpcReplySemaphore))
{
/* Get the message and check if it's a connection request */
Message = Thread->LpcReplyMessage;
if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST)
{
/* Get the connection message */
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
/* Check if it had a section */
if (ConnectMessage->SectionToMap)
{
/* Dereference it */
ObDereferenceObject(ConnectMessage->SectionToMap);
}
}
/* Clear the reply message */
Thread->LpcReplyMessage = NULL;
/* And remove the message from the port zone */
LpcpFreeToPortZone(Message, TRUE);
}
/* Release the semaphore and reset message id count */
Thread->LpcReplyMessageId = 0;
LpcpCompleteWait(&Thread->LpcReplySemaphore);
}
/* Reinitialize the list head */
InitializeListHead(&Port->LpcReplyChainHead);
/* Loop queued messages */
ListHead = &Port->MsgQueue.ReceiveHead;
NextEntry = ListHead->Flink;
while (ListHead != NextEntry)
{
/* Get the message */
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
NextEntry = NextEntry->Flink;
/* Free and reinitialize it's list head */
InitializeListHead(&Message->Entry);
/* Remove it from the port zone */
LpcpFreeToPortZone(Message, TRUE);
}
/* Reinitialize the message queue list head */
InitializeListHead(&Port->MsgQueue.ReceiveHead);
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
/* Check if we have to free the port entirely */
if (Destroy)
{
/* Check if the semaphore exists */
if (Port->MsgQueue.Semaphore)
{
/* Use the semaphore to find the port queue and free it */
ExFreePool(CONTAINING_RECORD(Port->MsgQueue.Semaphore,
LPCP_NONPAGED_PORT_QUEUE,
Semaphore));
}
}
}
VOID
NTAPI
LpcpClosePort(IN PEPROCESS Process OPTIONAL,
IN PVOID Object,
IN ACCESS_MASK GrantedAccess,
IN ULONG ProcessHandleCount,
IN ULONG SystemHandleCount)
{
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object;
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
/* Only Server-side Connection Ports need clean up*/
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT)
{
/* Check the handle count */
switch (SystemHandleCount)
{
/* No handles left */
case 0:
/* Destroy the port queue */
LpcpDestroyPortQueue(Port, TRUE);
break;
/* Last handle remaining */
case 1:
/* Reset the queue only */
LpcpDestroyPortQueue(Port, FALSE);
/* More handles remain, do nothing */
default:
break;
}
}
}
VOID
NTAPI
LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port)
{
/* Check if this is a client port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
{
/* Check if security is static */
if (!(Port->Flags & LPCP_SECURITY_DYNAMIC))
{
/* Check if we have a token */
if (Port->StaticSecurity.ClientToken)
{
/* Free security */
SeDeleteClientSecurity(&Port->StaticSecurity);
}
}
}
}
VOID
NTAPI
LpcpDeletePort(IN PVOID ObjectBody)
{
LARGE_INTEGER Timeout;
PETHREAD Thread;
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody;
PLPCP_PORT_OBJECT ConnectionPort;
PLPCP_MESSAGE Message;
PLIST_ENTRY ListHead, NextEntry;
HANDLE Pid;
CLIENT_DIED_MSG ClientDiedMsg;
Timeout.QuadPart = -1000000;
PAGED_CODE();
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags);
/* Check if this is a communication port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT)
{
/* Acquire the lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Get the thread */
Thread = Port->ClientThread;
if (Thread)
{
/* Clear it */
Port->ClientThread = NULL;
/* Release the lock and dereference */
KeReleaseGuardedMutex(&LpcpLock);
ObDereferenceObject(Thread);
}
else
{
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
}
}
/* Check if this is a client-side port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
{
/* Setup the client died message */
ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg);
ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime);
ClientDiedMsg.h.u2.ZeroInit = LPC_PORT_CLOSED;
ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime;
/* Send it */
for (;;)
{
/* Send the message */
if (LpcRequestPort(Port,
&ClientDiedMsg.h) != STATUS_NO_MEMORY) break;
/* Wait until trying again */
KeDelayExecutionThread(KernelMode, FALSE, &Timeout);
}
}
/* Destroy the port queue */
LpcpDestroyPortQueue(Port, TRUE);
/* Check if we had a client view */
if (Port->ClientSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
Port->ClientSectionBase);
/* Check for a server view */
if (Port->ServerSectionBase) MmUnmapViewOfSection(PsGetCurrentProcess(),
Port->ServerSectionBase);
/* Get the connection port */
ConnectionPort = Port->ConnectionPort;
if (ConnectionPort)
{
/* Get the PID */
Pid = PsGetCurrentProcessId();
/* Acquire the lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Loop the data lists */
ListHead = &ConnectionPort->LpcDataInfoChainHead;
NextEntry = ListHead->Flink;
while (NextEntry != ListHead)
{
/* Get the message */
Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry);
NextEntry = NextEntry->Flink;
/* Check if the PID matches */
if (Message->Request.ClientId.UniqueProcess == Pid)
{
/* Remove it */
RemoveEntryList(&Message->Entry);
LpcpFreeToPortZone(Message, TRUE);
}
}
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
/* Dereference the object unless it's the same port */
if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort);
}
/* Check if this is a connection port with a server process*/
if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) &&
(ConnectionPort->ServerProcess))
{
/* Dereference the server process */
ObDereferenceObject(ConnectionPort->ServerProcess);
ConnectionPort->ServerProcess = NULL;
}
/* Free client security */
LpcpFreePortClientSecurity(Port);
LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port);
}
/* EOF */

View file

@ -1,82 +1,376 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
* FILE: ntoskrnl/lpc/complete.c
* PURPOSE: Communication mechanism
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
*/
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/complete.c
* PURPOSE: Local Procedure Call: Connection Completion
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS *****************************************************************/
/* PRIVATE FUNCTIONS *********************************************************/
/***********************************************************************
* NAME EXPORTED
* NtCompleteConnectPort/1
*
* DESCRIPTION
* Wake up the client thread that issued the NtConnectPort call
* this server-side port was created for communicating with.
* To be used in LPC servers processes on reply ports only.
*
* ARGUMENTS
* hServerSideCommPort: a reply port handle returned by
* NtAcceptConnectPort.
*
* RETURN VALUE
* STATUS_SUCCESS or an error code from Ob.
*/
NTSTATUS STDCALL
NtCompleteConnectPort (HANDLE hServerSideCommPort)
VOID
NTAPI
LpcpPrepareToWakeClient(IN PETHREAD Thread)
{
NTSTATUS Status;
PEPORT ReplyPort;
PAGED_CODE();
DPRINT("NtCompleteConnectPort(hServerSideCommPort %x)\n", hServerSideCommPort);
/*
* Ask Ob to translate the port handle to EPORT
*/
Status = ObReferenceObjectByHandle (hServerSideCommPort,
PORT_ALL_ACCESS,
LpcPortObjectType,
UserMode,
(PVOID*)&ReplyPort,
NULL);
if (!NT_SUCCESS(Status))
/* Make sure the thread isn't dying and it has a valid chain */
if (!(Thread->LpcExitThreadCalled) &&
!(IsListEmpty(&Thread->LpcReplyChain)))
{
return (Status);
/* Remove it from the list and reinitialize it */
RemoveEntryList(&Thread->LpcReplyChain);
InitializeListHead(&Thread->LpcReplyChain);
}
/*
* Verify EPORT type is a server-side reply port;
* otherwise tell the caller the port handle is not
* valid.
*/
if (ReplyPort->Type != EPORT_TYPE_SERVER_COMM_PORT)
{
ObDereferenceObject (ReplyPort);
return STATUS_INVALID_PORT_HANDLE;
}
ReplyPort->State = EPORT_CONNECTED_SERVER;
/*
* Wake up the client thread that issued NtConnectPort.
*/
KeReleaseSemaphore(&ReplyPort->OtherPort->Semaphore, IO_NO_INCREMENT, 1,
FALSE);
/*
* Tell Ob we are no more interested in ReplyPort
*/
ObDereferenceObject (ReplyPort);
return (STATUS_SUCCESS);
}
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
NTSTATUS
NTAPI
NtAcceptConnectPort(OUT PHANDLE PortHandle,
IN PVOID PortContext OPTIONAL,
IN PPORT_MESSAGE ReplyMessage,
IN BOOLEAN AcceptConnection,
IN PPORT_VIEW ServerView,
IN PREMOTE_PORT_VIEW ClientView)
{
PLPCP_PORT_OBJECT ConnectionPort, ServerPort, ClientPort;
PVOID ClientSectionToMap = NULL;
HANDLE Handle;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
NTSTATUS Status;
ULONG ConnectionInfoLength;
PLPCP_MESSAGE Message;
PLPCP_CONNECTION_MESSAGE ConnectMessage;
PEPROCESS ClientProcess;
PETHREAD ClientThread;
LARGE_INTEGER SectionOffset;
PAGED_CODE();
LPCTRACE(LPC_COMPLETE_DEBUG,
"Context: %p. Message: %p. Accept: %lx. Views: %p/%p\n",
PortContext,
ReplyMessage,
AcceptConnection,
ClientView,
ServerView);
/* Validate the size of the server view */
if ((ServerView) && (ServerView->Length != sizeof(PORT_VIEW)))
{
/* Invalid size */
return STATUS_INVALID_PARAMETER;
}
/* Validate the size of the client view */
if ((ClientView) && (ClientView->Length != sizeof(REMOTE_PORT_VIEW)))
{
/* Invalid size */
return STATUS_INVALID_PARAMETER;
}
/* Get the client process and thread */
Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
&ClientProcess,
&ClientThread);
if (!NT_SUCCESS(Status)) return Status;
/* Acquire the LPC Lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Make sure that the client wants a reply, and this is the right one */
if (!(ClientThread->LpcReplyMessage) ||
!(ReplyMessage->MessageId) ||
(ClientThread->LpcReplyMessageId != ReplyMessage->MessageId))
{
/* Not the reply asked for, or no reply wanted, fail */
KeReleaseGuardedMutex(&LpcpLock);
ObDereferenceObject(ClientProcess);
ObDereferenceObject(ClientThread);
return STATUS_REPLY_MESSAGE_MISMATCH;
}
/* Now get the message and connection message */
Message = ClientThread->LpcReplyMessage;
ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
/* Get the client and connection port as well */
ClientPort = ConnectMessage->ClientPort;
ConnectionPort = ClientPort->ConnectionPort;
/* Make sure that the reply is being sent to the proper server process */
if (ConnectionPort->ServerProcess != PsGetCurrentProcess())
{
/* It's not, so fail */
KeReleaseGuardedMutex(&LpcpLock);
ObDereferenceObject(ClientProcess);
ObDereferenceObject(ClientThread);
return STATUS_REPLY_MESSAGE_MISMATCH;
}
/* At this point, don't let other accept attempts happen */
ClientThread->LpcReplyMessage = NULL;
ClientThread->LpcReplyMessageId = 0;
/* Clear the client port for now as well, then release the lock */
ConnectMessage->ClientPort = NULL;
KeReleaseGuardedMutex(&LpcpLock);
/* Get the connection information length */
ConnectionInfoLength = ReplyMessage->u1.s1.DataLength;
if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength)
{
/* Normalize it since it's too large */
ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength;
}
/* Set the sizes of our reply message */
Message->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
ConnectionInfoLength;
Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
Message->Request.u1.s1.DataLength;
/* Setup the reply message */
Message->Request.u2.s2.Type = LPC_REPLY;
Message->Request.u2.s2.DataInfoOffset = 0;
Message->Request.ClientId = ReplyMessage->ClientId;
Message->Request.MessageId = ReplyMessage->MessageId;
Message->Request.ClientViewSize = 0;
RtlMoveMemory(ConnectMessage + 1, ReplyMessage + 1, ConnectionInfoLength);
/* At this point, if the caller refused the connection, go to cleanup */
if (!AcceptConnection) goto Cleanup;
/* Otherwise, create the actual port */
Status = ObCreateObject(PreviousMode,
LpcPortObjectType,
NULL,
PreviousMode,
NULL,
sizeof(LPCP_PORT_OBJECT),
0,
0,
(PVOID*)&ServerPort);
if (!NT_SUCCESS(Status)) goto Cleanup;
/* Set it up */
RtlZeroMemory(ServerPort, sizeof(LPCP_PORT_OBJECT));
ServerPort->PortContext = PortContext;
ServerPort->Flags = LPCP_COMMUNICATION_PORT;
ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength;
InitializeListHead(&ServerPort->LpcReplyChainHead);
InitializeListHead(&ServerPort->LpcDataInfoChainHead);
/* Reference the connection port until we're fully setup */
ObReferenceObject(ConnectionPort);
/* Link the ports together */
ServerPort->ConnectionPort = ConnectionPort;
ServerPort->ConnectedPort = ClientPort;
ClientPort->ConnectedPort = ServerPort;
/* Also set the creator CID */
ServerPort->Creator = PsGetCurrentThread()->Cid;
ClientPort->Creator = Message->Request.ClientId;
/* Get the section associated and then clear it, while inside the lock */
KeAcquireGuardedMutex(&LpcpLock);
ClientSectionToMap = ConnectMessage->SectionToMap;
ConnectMessage->SectionToMap = NULL;
KeReleaseGuardedMutex(&LpcpLock);
/* Now check if there's a client section */
if (ClientSectionToMap)
{
/* Setup the offset */
SectionOffset.QuadPart = ConnectMessage->ClientView.SectionOffset;
/* Map the section */
Status = MmMapViewOfSection(ClientSectionToMap,
PsGetCurrentProcess(),
&ServerPort->ClientSectionBase,
0,
0,
&SectionOffset,
&ConnectMessage->ClientView.ViewSize,
ViewUnmap,
0,
PAGE_READWRITE);
/* Update the offset and check for mapping status */
ConnectMessage->ClientView.SectionOffset = SectionOffset.LowPart;
if (NT_SUCCESS(Status))
{
/* Set the view base */
ConnectMessage->ClientView.ViewRemoteBase = ServerPort->
ClientSectionBase;
}
else
{
/* Otherwise, quit */
ObDereferenceObject(ServerPort);
goto Cleanup;
}
}
/* Check if there's a server section */
if (ServerView)
{
/* FIXME: TODO */
ASSERT(FALSE);
}
/* Reference the server port until it's fully inserted */
ObReferenceObject(ServerPort);
/* Insert the server port in the namespace */
Status = ObInsertObject(ServerPort,
NULL,
PORT_ALL_ACCESS,
0,
NULL,
&Handle);
if (!NT_SUCCESS(Status))
{
/* We failed, remove the extra reference and cleanup */
ObDereferenceObject(ServerPort);
goto Cleanup;
}
/* Check if the caller gave a client view */
if (ClientView)
{
/* Fill it out */
ClientView->ViewBase = ConnectMessage->ClientView.ViewRemoteBase;
ClientView->ViewSize = ConnectMessage->ClientView.ViewSize;
}
/* Return the handle to user mode */
*PortHandle = Handle;
LPCTRACE(LPC_COMPLETE_DEBUG,
"Handle: %lx. Messages: %p/%p. Ports: %p/%p/%p\n",
Handle,
Message,
ConnectMessage,
ServerPort,
ClientPort,
ConnectionPort);
/* If there was no port context, use the handle by default */
if (!PortContext) ServerPort->PortContext = Handle;
ServerPort->ClientThread = ClientThread;
/* Set this message as the LPC Reply message while holding the lock */
KeAcquireGuardedMutex(&LpcpLock);
ClientThread->LpcReplyMessage = Message;
KeReleaseGuardedMutex(&LpcpLock);
/* Clear the thread pointer so it doesn't get cleaned later */
ClientThread = NULL;
/* Remove the extra reference we had added */
ObDereferenceObject(ServerPort);
Cleanup:
/* If there was a section, dereference it */
if (ClientSectionToMap) ObDereferenceObject(ClientSectionToMap);
/* Check if we got here while still having a client thread */
if (ClientThread)
{
/* FIXME: Complex cleanup code */
ASSERT(FALSE);
}
/* Dereference the client port if we have one, and the process */
LPCTRACE(LPC_COMPLETE_DEBUG,
"Status: %lx. Thread: %p. Process: [%.16s]\n",
Status,
ClientThread,
ClientProcess->ImageFileName);
if (ClientPort) ObDereferenceObject(ClientPort);
ObDereferenceObject(ClientProcess);
return Status;
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtCompleteConnectPort(IN HANDLE PortHandle)
{
NTSTATUS Status;
PLPCP_PORT_OBJECT Port;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PETHREAD Thread;
PAGED_CODE();
LPCTRACE(LPC_COMPLETE_DEBUG, "Handle: %lx\n", PortHandle);
/* Get the Port Object */
Status = ObReferenceObjectByHandle(PortHandle,
PORT_ALL_ACCESS,
LpcPortObjectType,
PreviousMode,
(PVOID*)&Port,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Make sure this is a connection port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
{
/* It isn't, fail */
ObDereferenceObject(Port);
return STATUS_INVALID_PORT_HANDLE;
}
/* Acquire the lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Make sure we have a client thread */
if (!Port->ClientThread)
{
/* We don't, fail */
KeReleaseGuardedMutex(&LpcpLock);
ObDereferenceObject(Port);
return STATUS_INVALID_PARAMETER;
}
/* Get the thread */
Thread = Port->ClientThread;
/* Make sure it has a reply message */
if (!Thread->LpcReplyMessage)
{
/* It doesn't, fail */
KeReleaseGuardedMutex(&LpcpLock);
ObDereferenceObject(Port);
return STATUS_PORT_DISCONNECTED;
}
/* Clear the client thread and wake it up */
Port->ClientThread = NULL;
LpcpPrepareToWakeClient(Thread);
/* Release the lock and wait for an answer */
KeReleaseGuardedMutex(&LpcpLock);
LpcpCompleteWait(&Thread->LpcReplySemaphore);
/* Dereference the Thread and Port and return */
ObDereferenceObject(Port);
ObDereferenceObject(Thread);
LPCTRACE(LPC_COMPLETE_DEBUG, "Port: %p. Thread: %p\n", Port, Thread);
return Status;
}
/* EOF */

File diff suppressed because it is too large Load diff

View file

@ -1,180 +1,195 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/create.c
* PURPOSE: Communication mechanism
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
* PURPOSE: Local Procedure Call: Port/Queue/Message Creation
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
/**********************************************************************
* NAME
* LpcpVerifyCreateParameters/5
*
* DESCRIPTION
* Verify user parameters in NtCreatePort and in
* NtCreateWaitablePort.
*
* ARGUMENTS
*
* RETURN VALUE
*/
static NTSTATUS STDCALL
LpcpVerifyCreateParameters (IN PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectInfoLength,
IN ULONG MaxDataLength,
IN ULONG MaxPoolUsage)
/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUS
NTAPI
LpcpInitializePortQueue(IN PLPCP_PORT_OBJECT Port)
{
if (NULL == PortHandle)
{
return (STATUS_INVALID_PARAMETER_1);
}
if (NULL == ObjectAttributes)
{
return (STATUS_INVALID_PARAMETER_2);
}
if ((ObjectAttributes->Attributes & OBJ_OPENLINK)
|| (ObjectAttributes->Attributes & OBJ_OPENIF)
|| (ObjectAttributes->Attributes & OBJ_EXCLUSIVE)
|| (ObjectAttributes->Attributes & OBJ_PERMANENT)
|| (ObjectAttributes->Attributes & OBJ_INHERIT))
{
return (STATUS_INVALID_PORT_ATTRIBUTES);
}
if (MaxConnectInfoLength > LPC_MAX_DATA_LENGTH)
{
return (STATUS_INVALID_PARAMETER_3);
}
if (MaxDataLength > LPC_MAX_MESSAGE_LENGTH)
{
return (STATUS_INVALID_PARAMETER_4);
}
/* TODO: some checking is done also on MaxPoolUsage
* to avoid choking the executive */
return (STATUS_SUCCESS);
PLPCP_NONPAGED_PORT_QUEUE MessageQueue;
/* Allocate the queue */
MessageQueue = ExAllocatePoolWithTag(NonPagedPool,
sizeof(LPCP_NONPAGED_PORT_QUEUE),
TAG('P', 'o', 'r', 't'));
if (!MessageQueue) return STATUS_INSUFFICIENT_RESOURCES;
/* Set it up */
KeInitializeSemaphore(&MessageQueue->Semaphore, 0, MAXLONG);
MessageQueue->BackPointer = Port;
/* And link it with the Paged Pool part */
Port->MsgQueue.Semaphore = &MessageQueue->Semaphore;
InitializeListHead(&Port->MsgQueue.ReceiveHead);
return STATUS_SUCCESS;
}
/**********************************************************************
* NAME EXPORTED
* NtCreatePort/5
*
* DESCRIPTION
*
* ARGUMENTS
* PortHandle,
* ObjectAttributes,
* MaxConnectInfoLength,
* MaxDataLength,
* MaxPoolUsage: size of NP zone the NP part of msgs is kept in
*
* RETURN VALUE
*/
/*EXPORTED*/ NTSTATUS STDCALL
NtCreatePort (PHANDLE PortHandle,
POBJECT_ATTRIBUTES ObjectAttributes,
ULONG MaxConnectInfoLength,
ULONG MaxDataLength,
ULONG MaxPoolUsage)
NTSTATUS
NTAPI
LpcpCreatePort(OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectionInfoLength,
IN ULONG MaxMessageLength,
IN ULONG MaxPoolUsage,
IN BOOLEAN Waitable)
{
PEPORT Port;
NTSTATUS Status;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
NTSTATUS Status;
PLPCP_PORT_OBJECT Port;
LPCTRACE(LPC_CREATE_DEBUG, "Name: %wZ\n", ObjectAttributes->ObjectName);
DPRINT("NtCreatePort() Name %x\n", ObjectAttributes->ObjectName->Buffer);
/* Create the Object */
Status = ObCreateObject(PreviousMode,
LpcPortObjectType,
ObjectAttributes,
PreviousMode,
NULL,
sizeof(LPCP_PORT_OBJECT),
0,
0,
(PVOID*)&Port);
if (!NT_SUCCESS(Status)) return Status;
/* Verify parameters */
Status = LpcpVerifyCreateParameters (PortHandle,
ObjectAttributes,
MaxConnectInfoLength,
MaxDataLength,
MaxPoolUsage);
if (STATUS_SUCCESS != Status)
/* Set up the Object */
RtlZeroMemory(Port, sizeof(LPCP_PORT_OBJECT));
Port->ConnectionPort = Port;
Port->Creator = PsGetCurrentThread()->Cid;
InitializeListHead(&Port->LpcDataInfoChainHead);
InitializeListHead(&Port->LpcReplyChainHead);
/* Check if we don't have a name */
if (!ObjectAttributes->ObjectName->Buffer)
{
return (Status);
/* Set up for an unconnected port */
Port->Flags = LPCP_UNCONNECTED_PORT;
Port->ConnectedPort = Port;
Port->ServerProcess = NULL;
}
else
{
/* Set up for a named connection port */
Port->Flags = LPCP_CONNECTION_PORT;
Port->ServerProcess = PsGetCurrentProcess();
/* Don't let the process die on us */
ObReferenceObject(Port->ServerProcess);
}
/* Ask Ob to create the object */
Status = ObCreateObject (ExGetPreviousMode(),
LpcPortObjectType,
ObjectAttributes,
ExGetPreviousMode(),
NULL,
sizeof(EPORT),
0,
0,
(PVOID*)&Port);
if (!NT_SUCCESS(Status))
/* Check if this is a waitable port */
if (Waitable) Port->Flags |= LPCP_WAITABLE_PORT;
/* Setup the port queue */
Status = LpcpInitializePortQueue(Port);
if (!NT_SUCCESS(Status))
{
return (Status);
/* Fail */
ObDereferenceObject(Port);
return Status;
}
Status = ObInsertObject ((PVOID)Port,
NULL,
PORT_ALL_ACCESS,
0,
NULL,
PortHandle);
if (!NT_SUCCESS(Status))
/* Check if this is a waitable port */
if (Port->Flags & LPCP_WAITABLE_PORT)
{
ObDereferenceObject (Port);
return (Status);
/* Setup the wait event */
KeInitializeEvent(&Port->WaitEvent, NotificationEvent, FALSE);
}
Status = LpcpInitializePort (Port, EPORT_TYPE_SERVER_RQST_PORT, NULL);
Port->MaxConnectInfoLength = LPC_MAX_DATA_LENGTH;
Port->MaxDataLength = LPC_MAX_MESSAGE_LENGTH;
Port->MaxPoolUsage = MaxPoolUsage;
/* Set the maximum message size allowed */
Port->MaxMessageLength = LpcpMaxMessageSize -
FIELD_OFFSET(LPCP_MESSAGE, Request);
return (Status);
/* Now subtract the actual message structures and get the data size */
Port->MaxConnectionInfoLength = Port->MaxMessageLength -
sizeof(PORT_MESSAGE) -
sizeof(LPCP_CONNECTION_MESSAGE);
/* Validate the sizes */
if (Port->MaxConnectionInfoLength < MaxConnectionInfoLength)
{
/* Not enough space for your request */
ObDereferenceObject(Port);
return STATUS_INVALID_PARAMETER_3;
}
else if (Port->MaxMessageLength < MaxMessageLength)
{
/* Not enough space for your request */
ObDereferenceObject(Port);
return STATUS_INVALID_PARAMETER_4;
}
/* Now set the custom setting */
Port->MaxMessageLength = MaxMessageLength;
/* Insert it now */
Status = ObInsertObject((PVOID)Port,
NULL,
PORT_ALL_ACCESS,
0,
NULL,
PortHandle);
/* Return success or the error */
LPCTRACE(LPC_CREATE_DEBUG, "Port: %p. Handle: %lx\n", Port, *PortHandle);
return Status;
}
/**********************************************************************
* NAME EXPORTED
* NtCreateWaitablePort/5
*
* DESCRIPTION
* Waitable ports can be connected to with NtSecureConnectPort.
* No port interface can be used with waitable ports but
* NtReplyWaitReceivePort and NtReplyWaitReceivePortEx.
* Present only in w2k+.
*
* ARGUMENTS
* PortHandle,
* ObjectAttributes,
* MaxConnectInfoLength,
* MaxDataLength,
* MaxPoolUsage
*
* RETURN VALUE
*/
/*EXPORTED*/ NTSTATUS STDCALL
NtCreateWaitablePort (OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectInfoLength,
IN ULONG MaxDataLength,
IN ULONG MaxPoolUsage)
{
NTSTATUS Status;
/* PUBLIC FUNCTIONS **********************************************************/
/* Verify parameters */
Status = LpcpVerifyCreateParameters (PortHandle,
ObjectAttributes,
MaxConnectInfoLength,
MaxDataLength,
MaxPoolUsage);
if (STATUS_SUCCESS != Status)
{
return (Status);
}
/* TODO */
return (STATUS_NOT_IMPLEMENTED);
/*
* @implemented
*/
NTSTATUS
NTAPI
NtCreatePort(OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectInfoLength,
IN ULONG MaxDataLength,
IN ULONG MaxPoolUsage)
{
PAGED_CODE();
/* Call the internal API */
return LpcpCreatePort(PortHandle,
ObjectAttributes,
MaxConnectInfoLength,
MaxDataLength,
MaxPoolUsage,
FALSE);
}
/*
* @implemented
*/
NTSTATUS
NTAPI
NtCreateWaitablePort(OUT PHANDLE PortHandle,
IN POBJECT_ATTRIBUTES ObjectAttributes,
IN ULONG MaxConnectInfoLength,
IN ULONG MaxDataLength,
IN ULONG MaxPoolUsage)
{
PAGED_CODE();
/* Call the internal API */
return LpcpCreatePort(PortHandle,
ObjectAttributes,
MaxConnectInfoLength,
MaxDataLength,
MaxPoolUsage,
TRUE);
}
/* EOF */

View file

@ -1,72 +1,52 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/listen.c
* PURPOSE: Communication mechanism
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
* PURPOSE: Local Procedure Call: Listening
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
/* FUNCTIONS *****************************************************************/
/* PUBLIC FUNCTIONS **********************************************************/
/**********************************************************************
* NAME EXPORTED
* NtListenPort@8
*
* DESCRIPTION
* Listen on a named port and wait for a connection attempt.
*
* ARGUMENTS
* PortHandle [IN] LPC port to listen on.
*
* ConnectMsg [IN] User provided storage for a
* possible connection request LPC message.
*
* RETURN VALUE
* STATUS_SUCCESS if a connection request is received
* successfully; otherwise an error code.
*
* The buffer ConnectMessage is filled with the connection
* request message queued by NtConnectPort() in PortHandle.
*
* NOTE
/*
* @implemented
*/
/*EXPORTED*/ NTSTATUS STDCALL
NtListenPort (IN HANDLE PortHandle,
IN PPORT_MESSAGE ConnectMsg)
NTSTATUS
NTAPI
NtListenPort(IN HANDLE PortHandle,
OUT PPORT_MESSAGE ConnectMessage)
{
NTSTATUS Status;
NTSTATUS Status;
PAGED_CODE();
LPCTRACE(LPC_LISTEN_DEBUG, "Handle: %lx\n", PortHandle);
/*
* Wait forever for a connection request.
*/
for (;;)
{
Status = NtReplyWaitReceivePort(PortHandle,
NULL,
NULL,
ConnectMsg);
/*
* Accept only LPC_CONNECTION_REQUEST requests.
* Drop any other message.
*/
if (!NT_SUCCESS(Status) ||
LPC_CONNECTION_REQUEST == ConnectMsg->u2.s2.Type)
{
DPRINT("Got message (type %x)\n", LPC_CONNECTION_REQUEST);
break;
}
DPRINT("Got message (type %x)\n", ConnectMsg->u2.s2.Type);
}
/* Wait forever for a connection request. */
for (;;)
{
/* Do the wait */
Status = NtReplyWaitReceivePort(PortHandle,
NULL,
NULL,
ConnectMessage);
return (Status);
/* Accept only LPC_CONNECTION_REQUEST requests. */
if ((Status != STATUS_SUCCESS) ||
(LpcpGetMessageType(ConnectMessage) == LPC_CONNECTION_REQUEST))
{
/* Break out */
break;
}
}
/* Return status */
return Status;
}

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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"

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -1,29 +1,26 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/port.c
* PURPOSE: Communication mechanism
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
* PURPOSE: Local Procedure Call: Port Management
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
#if defined (ALLOC_PRAGMA)
#pragma alloc_text(INIT, LpcpInitSystem)
#endif
/* GLOBALS *******************************************************************/
POBJECT_TYPE LpcPortObjectType = 0;
ULONG LpcpNextMessageId = 0; /* 0 is not a valid ID */
FAST_MUTEX LpcpLock; /* global internal sync in LPC facility */
POBJECT_TYPE LpcPortObjectType;
ULONG LpcpMaxMessageSize;
PAGED_LOOKASIDE_LIST LpcpMessagesLookaside;
KGUARDED_MUTEX LpcpLock;
ULONG LpcpTraceLevel = LPC_CLOSE_DEBUG;
ULONG LpcpNextMessageId = 1, LpcpNextCallbackId = 1;
static GENERIC_MAPPING LpcpPortMapping =
{
@ -33,105 +30,60 @@ static GENERIC_MAPPING LpcpPortMapping =
PORT_ALL_ACCESS
};
/* FUNCTIONS *****************************************************************/
/* PRIVATE FUNCTIONS *********************************************************/
NTSTATUS
INIT_FUNCTION
NTAPI
LpcpInitSystem (VOID)
LpcpInitSystem(VOID)
{
OBJECT_TYPE_INITIALIZER ObjectTypeInitializer;
UNICODE_STRING Name;
DPRINT("Creating Port Object Type\n");
/* Setup the LPC Lock */
KeInitializeGuardedMutex(&LpcpLock);
/* Create the Port Object Type */
RtlZeroMemory(&ObjectTypeInitializer, sizeof(ObjectTypeInitializer));
RtlInitUnicodeString(&Name, L"Port");
ObjectTypeInitializer.Length = sizeof(ObjectTypeInitializer);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(EPORT);
ObjectTypeInitializer.DefaultNonPagedPoolCharge = sizeof(LPCP_PORT_OBJECT);
ObjectTypeInitializer.DefaultPagedPoolCharge = sizeof(LPCP_NONPAGED_PORT_QUEUE);
ObjectTypeInitializer.GenericMapping = LpcpPortMapping;
ObjectTypeInitializer.PoolType = NonPagedPool;
ObjectTypeInitializer.PoolType = PagedPool;
ObjectTypeInitializer.UseDefaultObject = TRUE;
ObjectTypeInitializer.CloseProcedure = LpcpClosePort;
ObjectTypeInitializer.DeleteProcedure = LpcpDeletePort;
ObjectTypeInitializer.ValidAccessMask = PORT_ALL_ACCESS;
ObCreateObjectType(&Name, &ObjectTypeInitializer, NULL, &LpcPortObjectType);
ObjectTypeInitializer.MaintainTypeList = TRUE;
ObCreateObjectType(&Name,
&ObjectTypeInitializer,
NULL,
&LpcPortObjectType);
LpcpNextMessageId = 0;
ExInitializeFastMutex (& LpcpLock);
/* Allocate the LPC lookaside list */
LpcpMaxMessageSize = LPCP_MAX_MESSAGE_SIZE;
ExInitializePagedLookasideList(&LpcpMessagesLookaside,
NULL,
NULL,
0,
LpcpMaxMessageSize,
TAG('L', 'p', 'c', 'M'),
32);
return(STATUS_SUCCESS);
/* We're done */
return STATUS_SUCCESS;
}
/* PUBLIC FUNCTIONS **********************************************************/
/**********************************************************************
* NAME INTERNAL
* NiInitializePort/3
*
* DESCRIPTION
* Initialize the EPORT object attributes. The Port
* object enters the inactive state.
*
* ARGUMENTS
* Port Pointer to an EPORT object to initialize.
* Type connect (RQST), or communication port (COMM)
* Parent OPTIONAL connect port a communication port
* is created from
*
* RETURN VALUE
* STATUS_SUCCESS if initialization succedeed. An error code
* otherwise.
*/
NTSTATUS STDCALL
LpcpInitializePort (IN OUT PEPORT Port,
IN USHORT Type,
IN PEPORT Parent OPTIONAL)
NTSTATUS
NTAPI
NtImpersonateClientOfPort(IN HANDLE PortHandle,
IN PPORT_MESSAGE ClientMessage)
{
if ((Type != EPORT_TYPE_SERVER_RQST_PORT) &&
(Type != EPORT_TYPE_SERVER_COMM_PORT) &&
(Type != EPORT_TYPE_CLIENT_COMM_PORT))
{
return STATUS_INVALID_PARAMETER_2;
}
memset (Port, 0, sizeof(EPORT));
KeInitializeSpinLock (& Port->Lock);
KeInitializeSemaphore( &Port->Semaphore, 0, MAXLONG );
Port->RequestPort = Parent;
Port->OtherPort = NULL;
Port->QueueLength = 0;
Port->ConnectQueueLength = 0;
Port->Type = Type;
Port->State = EPORT_INACTIVE;
InitializeListHead (& Port->QueueListHead);
InitializeListHead (& Port->ConnectQueueListHead);
return (STATUS_SUCCESS);
}
/* MISCELLANEA SYSTEM SERVICES */
/**********************************************************************
* NAME SYSTEM
* NtImpersonateClientOfPort/2
*
* DESCRIPTION
*
* ARGUMENTS
* PortHandle,
* ClientMessage
*
* RETURN VALUE
*/
NTSTATUS STDCALL
NtImpersonateClientOfPort (HANDLE PortHandle,
PPORT_MESSAGE ClientMessage)
{
UNIMPLEMENTED;
return(STATUS_NOT_IMPLEMENTED);
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
NTSTATUS
@ -142,4 +94,16 @@ NtQueryPortInformationProcess(VOID)
return STATUS_UNSUCCESSFUL;
}
NTSTATUS
NTAPI
NtQueryInformationPort(IN HANDLE PortHandle,
IN PORT_INFORMATION_CLASS PortInformationClass,
OUT PVOID PortInformation,
IN ULONG PortInformationLength,
OUT PULONG ReturnLength)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/* EOF */

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

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

View file

@ -1,395 +1,426 @@
/* $Id$
*
* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS kernel
/*
* PROJECT: ReactOS Kernel
* LICENSE: GPL - See COPYING in the top level directory
* FILE: ntoskrnl/lpc/send.c
* PURPOSE: Communication mechanism
*
* PROGRAMMERS: David Welch (welch@cwcom.net)
* PURPOSE: Local Procedure Call: Sending (Requests)
* PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES *****************************************************************/
/* INCLUDES ******************************************************************/
#include <ntoskrnl.h>
#include "lpc.h"
#define NDEBUG
#include <internal/debug.h>
/**********************************************************************
* NAME
* LpcRequestPort/2
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
* 2002-03-01 EA
* I investigated this function a bit more in depth.
* It looks like the legal values for the MessageType field in the
* message to send are in the range LPC_NEW_MESSAGE .. LPC_CLIENT_DIED,
* but LPC_DATAGRAM is explicitly forbidden.
*
/* PUBLIC FUNCTIONS **********************************************************/
/*
* @implemented
*/
NTSTATUS STDCALL LpcRequestPort (IN PVOID PortObject,
IN PPORT_MESSAGE LpcMessage)
NTSTATUS
NTAPI
LpcRequestPort(IN PVOID PortObject,
IN PPORT_MESSAGE LpcMessage)
{
NTSTATUS Status;
PEPORT Port = (PEPORT)PortObject;
PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)PortObject, QueuePort;
ULONG MessageType;
PLPCP_MESSAGE Message;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
PAGED_CODE();
LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", Port, LpcMessage);
DPRINT("LpcRequestPort(PortHandle %08x, LpcMessage %08x)\n", Port, LpcMessage);
/* Check if this is a non-datagram message */
if (LpcMessage->u2.s2.Type)
{
/* Get the message type */
MessageType = LpcpGetMessageType(LpcMessage);
#ifdef __USE_NT_LPC__
/* Check the message's type */
if (LPC_NEW_MESSAGE == LpcMessage->u2.s2.Type)
{
LpcMessage->u2.s2.Type = LPC_DATAGRAM;
}
else if (LPC_DATAGRAM == LpcMessage->u2.s2.Type)
{
return STATUS_INVALID_PARAMETER;
}
else if (LpcMessage->u2.s2.Type > LPC_CLIENT_DIED)
{
return STATUS_INVALID_PARAMETER;
}
/* Check the range offset */
if (0 != LpcMessage->VirtualRangesOffset)
{
return STATUS_INVALID_PARAMETER;
}
#endif
/* Validate it */
if ((MessageType < LPC_DATAGRAM) || (MessageType > LPC_CLIENT_DIED))
{
/* Fail */
return STATUS_INVALID_PARAMETER;
}
Status = EiReplyOrRequestPort(Port,
LpcMessage,
LPC_DATAGRAM,
Port);
KeReleaseSemaphore( &Port->Semaphore, IO_NO_INCREMENT, 1, FALSE );
/* Mark this as a kernel-mode message only if we really came from there */
if ((PreviousMode == KernelMode) &&
(LpcMessage->u2.s2.Type & LPC_KERNELMODE_MESSAGE))
{
/* We did, this is a kernel mode message */
MessageType |= LPC_KERNELMODE_MESSAGE;
}
}
else
{
/* This is a datagram */
MessageType = LPC_DATAGRAM;
}
return(Status);
/* Can't have data information on this type of call */
if (LpcMessage->u2.s2.DataInfoOffset) return STATUS_INVALID_PARAMETER;
/* Validate message sizes */
if ((LpcMessage->u1.s1.TotalLength > Port->MaxMessageLength) ||
(LpcMessage->u1.s1.TotalLength <= LpcMessage->u1.s1.DataLength))
{
/* Fail */
return STATUS_PORT_MESSAGE_TOO_LONG;
}
/* Allocate a new message */
Message = LpcpAllocateFromPortZone();
if (!Message) return STATUS_NO_MEMORY;
/* Clear the context */
Message->PortContext = NULL;
/* Copy the message */
LpcpMoveMessage(&Message->Request,
LpcMessage,
LpcMessage + 1,
MessageType,
&PsGetCurrentThread()->Cid);
/* Acquire the LPC lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Check if this is anything but a connection port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
{
/* The queue port is the connected port */
QueuePort = Port->ConnectedPort;
if (QueuePort)
{
/* Check if this is a client port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
{
/* Then copy the context */
Message->PortContext = QueuePort->PortContext;
QueuePort = Port->ConnectionPort;
}
else if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
{
/* Any other kind of port, use the connection port */
QueuePort = Port->ConnectionPort;
}
}
}
else
{
/* For connection ports, use the port itself */
QueuePort = PortObject;
}
/* Make sure we have a port */
if (QueuePort)
{
/* Generate the Message ID and set it */
Message->Request.MessageId = LpcpNextMessageId++;
if (!LpcpNextMessageId) LpcpNextMessageId = 1;
Message->Request.CallbackId = 0;
/* No Message ID for the thread */
PsGetCurrentThread()->LpcReplyMessageId = 0;
/* Insert the message in our chain */
InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
/* Release the lock and release the semaphore */
KeReleaseGuardedMutex(&LpcpLock);
LpcpCompleteWait(QueuePort->MsgQueue.Semaphore);
/* If this is a waitable port, wake it up */
if (QueuePort->Flags & LPCP_WAITABLE_PORT)
{
/* Wake it */
KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
}
/* We're done */
LPCTRACE(LPC_SEND_DEBUG, "Port: %p. Message: %p\n", QueuePort, Message);
return STATUS_SUCCESS;
}
/* If we got here, then free the message and fail */
LpcpFreeToPortZone(Message, TRUE);
KeReleaseGuardedMutex(&LpcpLock);
return STATUS_PORT_DISCONNECTED;
}
/*
* @unimplemented
*/
NTSTATUS
NTAPI
LpcRequestWaitReplyPort(IN PVOID Port,
IN PPORT_MESSAGE LpcMessageRequest,
OUT PPORT_MESSAGE LpcMessageReply)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/**********************************************************************
* NAME
* NtRequestPort/2
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
/*
* @unimplemented
*/
NTSTATUS
NTAPI
NtRequestPort(IN HANDLE PortHandle,
IN PPORT_MESSAGE LpcMessage)
{
UNIMPLEMENTED;
return STATUS_NOT_IMPLEMENTED;
}
/*
* @implemented
*/
NTSTATUS STDCALL NtRequestPort (IN HANDLE PortHandle,
IN PPORT_MESSAGE LpcMessage)
NTSTATUS
NTAPI
NtRequestWaitReplyPort(IN HANDLE PortHandle,
IN PPORT_MESSAGE LpcRequest,
IN OUT PPORT_MESSAGE LpcReply)
{
NTSTATUS Status;
PEPORT Port;
PLPCP_PORT_OBJECT Port, QueuePort, ReplyPort;
KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
NTSTATUS Status;
PLPCP_MESSAGE Message;
PETHREAD Thread = PsGetCurrentThread();
BOOLEAN Callback;
PKSEMAPHORE Semaphore;
ULONG MessageType;
PAGED_CODE();
LPCTRACE(LPC_SEND_DEBUG,
"Handle: %lx. Messages: %p/%p. Type: %lx\n",
PortHandle,
LpcRequest,
LpcReply,
LpcpGetMessageType(LpcRequest));
DPRINT("NtRequestPort(PortHandle %x LpcMessage %x)\n", PortHandle,
LpcMessage);
/* Check if the thread is dying */
if (Thread->LpcExitThreadCalled) return STATUS_THREAD_IS_TERMINATING;
Status = ObReferenceObjectByHandle(PortHandle,
PORT_ALL_ACCESS,
LpcPortObjectType,
UserMode,
(PVOID*)&Port,
NULL);
if (!NT_SUCCESS(Status))
{
DPRINT("NtRequestPort() = %x\n", Status);
return(Status);
}
/* Check if this is an LPC Request */
if (LpcpGetMessageType(LpcRequest) == LPC_REQUEST)
{
/* Then it's a callback */
Callback = TRUE;
}
else if (LpcpGetMessageType(LpcRequest))
{
/* This is a not kernel-mode message */
return STATUS_INVALID_PARAMETER;
}
else
{
/* This is a kernel-mode message without a callback */
LpcRequest->u2.s2.Type |= LPC_REQUEST;
Callback = FALSE;
}
Status = LpcRequestPort(Port->OtherPort,
LpcMessage);
/* Get the message type */
MessageType = LpcRequest->u2.s2.Type;
ObDereferenceObject(Port);
return(Status);
/* Validate the length */
if ((LpcRequest->u1.s1.DataLength + sizeof(PORT_MESSAGE)) >
LpcRequest->u1.s1.TotalLength)
{
/* Fail */
return STATUS_INVALID_PARAMETER;
}
/* Reference the object */
Status = ObReferenceObjectByHandle(PortHandle,
0,
LpcPortObjectType,
PreviousMode,
(PVOID*)&Port,
NULL);
if (!NT_SUCCESS(Status)) return Status;
/* Validate the message length */
if ((LpcRequest->u1.s1.TotalLength > Port->MaxMessageLength) ||
(LpcRequest->u1.s1.TotalLength <= LpcRequest->u1.s1.DataLength))
{
/* Fail */
ObDereferenceObject(Port);
return STATUS_PORT_MESSAGE_TOO_LONG;
}
/* Allocate a message from the port zone */
Message = LpcpAllocateFromPortZone();
if (!Message)
{
/* Fail if we couldn't allocate a message */
ObDereferenceObject(Port);
return STATUS_NO_MEMORY;
}
/* Check if this is a callback */
if (Callback)
{
/* FIXME: TODO */
Semaphore = NULL; // we'd use the Thread Semaphore here
ASSERT(FALSE);
}
else
{
/* No callback, just copy the message */
LpcpMoveMessage(&Message->Request,
LpcRequest,
LpcRequest + 1,
MessageType,
&Thread->Cid);
/* Acquire the LPC lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Right now clear the port context */
Message->PortContext = NULL;
/* Check if this is a not connection port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_CONNECTION_PORT)
{
/* We want the connected port */
QueuePort = Port->ConnectedPort;
if (!QueuePort)
{
/* We have no connected port, fail */
LpcpFreeToPortZone(Message, TRUE);
KeReleaseGuardedMutex(&LpcpLock);
ObDereferenceObject(Port);
return STATUS_PORT_DISCONNECTED;
}
/* This will be the rundown port */
ReplyPort = QueuePort;
/* Check if this is a communication port */
if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT)
{
/* Copy the port context and use the connection port */
Message->PortContext = ReplyPort->PortContext;
QueuePort = Port->ConnectionPort;
}
else if ((Port->Flags & LPCP_PORT_TYPE_MASK) !=
LPCP_COMMUNICATION_PORT)
{
/* Use the connection port for anything but communication ports */
QueuePort = Port->ConnectionPort;
}
}
else
{
/* Otherwise, for a connection port, use the same port object */
QueuePort = ReplyPort = Port;
}
/* No reply thread */
Message->RepliedToThread = NULL;
/* Generate the Message ID and set it */
Message->Request.MessageId = LpcpNextMessageId++;
if (!LpcpNextMessageId) LpcpNextMessageId = 1;
Message->Request.CallbackId = 0;
/* Set the message ID for our thread now */
Thread->LpcReplyMessageId = Message->Request.MessageId;
Thread->LpcReplyMessage = NULL;
/* Insert the message in our chain */
InsertTailList(&QueuePort->MsgQueue.ReceiveHead, &Message->Entry);
InsertTailList(&ReplyPort->LpcReplyChainHead, &Thread->LpcReplyChain);
/* Release the lock and get the semaphore we'll use later */
KeReleaseGuardedMutex(&LpcpLock);
Semaphore = QueuePort->MsgQueue.Semaphore;
/* If this is a waitable port, wake it up */
if (QueuePort->Flags & LPCP_WAITABLE_PORT)
{
/* Wake it */
KeSetEvent(&QueuePort->WaitEvent, IO_NO_INCREMENT, FALSE);
}
}
/* Now release the semaphore */
LpcpCompleteWait(Semaphore);
/* And let's wait for the reply */
LpcpReplyWait(&Thread->LpcReplySemaphore, PreviousMode);
/* Acquire the LPC lock */
KeAcquireGuardedMutex(&LpcpLock);
/* Get the LPC Message and clear our thread's reply data */
Message = Thread->LpcReplyMessage;
Thread->LpcReplyMessage = NULL;
Thread->LpcReplyMessageId = 0;
/* Check if we have anything on the reply chain*/
if (!IsListEmpty(&Thread->LpcReplyChain))
{
/* Remove this thread and reinitialize the list */
RemoveEntryList(&Thread->LpcReplyChain);
InitializeListHead(&Thread->LpcReplyChain);
}
/* Release the lock */
KeReleaseGuardedMutex(&LpcpLock);
/* Check if we got a reply */
if (Status == STATUS_SUCCESS)
{
/* Check if we have a valid message */
if (Message)
{
LPCTRACE(LPC_SEND_DEBUG,
"Reply Messages: %p/%p\n",
&Message->Request,
(&Message->Request) + 1);
/* Move the message */
LpcpMoveMessage(LpcReply,
&Message->Request,
(&Message->Request) + 1,
0,
NULL);
/* Check if this is an LPC request with data information */
if ((LpcpGetMessageType(&Message->Request) == LPC_REQUEST) &&
(Message->Request.u2.s2.DataInfoOffset))
{
/* Save the data information */
LpcpSaveDataInfoMessage(Port, Message);
}
else
{
/* Otherwise, just free it */
LpcpFreeToPortZone(Message, FALSE);
}
}
else
{
/* We don't have a reply */
Status = STATUS_LPC_REPLY_LOST;
}
}
else
{
/* The wait failed, free the message while holding the lock */
KeAcquireGuardedMutex(&LpcpLock);
LpcpFreeToPortZone(Message, TRUE);
KeReleaseGuardedMutex(&LpcpLock);
}
/* All done */
LPCTRACE(LPC_SEND_DEBUG,
"Port: %p. Status: %p\n",
Port,
Status);
ObDereferenceObject(Port);
return Status;
}
/**********************************************************************
* NAME
* NtRequestWaitReplyPort/3
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*
* @implemented
*/
NTSTATUS STDCALL
NtRequestWaitReplyPort (IN HANDLE PortHandle,
PPORT_MESSAGE UnsafeLpcRequest,
PPORT_MESSAGE UnsafeLpcReply)
{
PETHREAD CurrentThread;
struct _KPROCESS *AttachedProcess;
PEPORT Port;
PQUEUEDMESSAGE Message;
KIRQL oldIrql;
PPORT_MESSAGE LpcRequest;
USHORT LpcRequestMessageSize = 0, LpcRequestDataSize = 0;
KPROCESSOR_MODE PreviousMode;
NTSTATUS Status = STATUS_SUCCESS;
PreviousMode = ExGetPreviousMode();
if (PreviousMode != KernelMode)
{
_SEH_TRY
{
ProbeForRead(UnsafeLpcRequest,
sizeof(PORT_MESSAGE),
1);
ProbeForWrite(UnsafeLpcReply,
sizeof(PORT_MESSAGE),
1);
LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
return Status;
}
}
else
{
LpcRequestMessageSize = UnsafeLpcRequest->u1.s1.TotalLength;
}
DPRINT("NtRequestWaitReplyPort(PortHandle %x, LpcRequest %x, "
"LpcReply %x)\n", PortHandle, UnsafeLpcRequest, UnsafeLpcReply);
Status = ObReferenceObjectByHandle(PortHandle,
PORT_ALL_ACCESS,
LpcPortObjectType,
UserMode,
(PVOID*)&Port,
NULL);
if (!NT_SUCCESS(Status))
{
return(Status);
}
if (EPORT_DISCONNECTED == Port->State)
{
ObDereferenceObject(Port);
return STATUS_PORT_DISCONNECTED;
}
/* win32k sometimes needs to KeAttach() the CSRSS process in order to make
the PortHandle valid. Now that we've got the EPORT structure from the
handle we can undo this, so everything is normal again. Need to
re-KeAttach() before returning though */
CurrentThread = PsGetCurrentThread();
if (&CurrentThread->ThreadsProcess->Pcb == CurrentThread->Tcb.ApcState.Process)
{
AttachedProcess = NULL;
}
else
{
AttachedProcess = CurrentThread->Tcb.ApcState.Process;
KeDetachProcess();
}
if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
{
if (NULL != AttachedProcess)
{
KeAttachProcess(AttachedProcess);
}
ObDereferenceObject(Port);
return(STATUS_PORT_MESSAGE_TOO_LONG);
}
LpcRequest = ExAllocatePool(NonPagedPool, LpcRequestMessageSize);
if (LpcRequest == NULL)
{
if (NULL != AttachedProcess)
{
KeAttachProcess(AttachedProcess);
}
ObDereferenceObject(Port);
return(STATUS_NO_MEMORY);
}
if (PreviousMode != KernelMode)
{
_SEH_TRY
{
RtlCopyMemory(LpcRequest,
UnsafeLpcRequest,
LpcRequestMessageSize);
LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
if (!NT_SUCCESS(Status))
{
ExFreePool(LpcRequest);
if (NULL != AttachedProcess)
{
KeAttachProcess(AttachedProcess);
}
ObDereferenceObject(Port);
return(Status);
}
}
else
{
RtlCopyMemory(LpcRequest,
UnsafeLpcRequest,
LpcRequestMessageSize);
LpcRequestMessageSize = LpcRequest->u1.s1.TotalLength;
LpcRequestDataSize = LpcRequest->u1.s1.DataLength;
}
if (LpcRequestMessageSize > LPC_MAX_MESSAGE_LENGTH)
{
ExFreePool(LpcRequest);
if (NULL != AttachedProcess)
{
KeAttachProcess(AttachedProcess);
}
ObDereferenceObject(Port);
return(STATUS_PORT_MESSAGE_TOO_LONG);
}
if (LpcRequestDataSize > LPC_MAX_DATA_LENGTH)
{
ExFreePool(LpcRequest);
if (NULL != AttachedProcess)
{
KeAttachProcess(AttachedProcess);
}
ObDereferenceObject(Port);
return(STATUS_PORT_MESSAGE_TOO_LONG);
}
Status = EiReplyOrRequestPort(Port->OtherPort,
LpcRequest,
LpcRequest->u2.s2.Type == LPC_ERROR_EVENT ? LPC_ERROR_EVENT : LPC_REQUEST,
Port);
if (!NT_SUCCESS(Status))
{
DPRINT1("Enqueue failed\n");
ExFreePool(LpcRequest);
if (NULL != AttachedProcess)
{
KeAttachProcess(AttachedProcess);
}
ObDereferenceObject(Port);
return(Status);
}
ExFreePool(LpcRequest);
KeReleaseSemaphore (&Port->OtherPort->Semaphore, IO_NO_INCREMENT,
1, FALSE);
/*
* Wait for a reply
*/
Status = KeWaitForSingleObject(&Port->Semaphore,
UserRequest,
UserMode,
FALSE,
NULL);
if (Status == STATUS_SUCCESS)
{
/*
* Dequeue the reply
*/
KeAcquireSpinLock(&Port->Lock, &oldIrql);
Message = EiDequeueMessagePort(Port);
KeReleaseSpinLock(&Port->Lock, oldIrql);
if (Message)
{
DPRINT("Message->Message.u1.s1.TotalLength %d\n",
Message->Message.u1.s1.TotalLength);
if (PreviousMode != KernelMode)
{
_SEH_TRY
{
RtlCopyMemory(UnsafeLpcReply,
&Message->Message,
Message->Message.u1.s1.TotalLength);
}
_SEH_HANDLE
{
Status = _SEH_GetExceptionCode();
}
_SEH_END;
}
else
{
RtlCopyMemory(UnsafeLpcReply,
&Message->Message,
Message->Message.u1.s1.TotalLength);
}
ExFreePool(Message);
}
else
Status = STATUS_UNSUCCESSFUL;
}
else
{
if (NT_SUCCESS(Status))
{
Status = STATUS_UNSUCCESSFUL;
}
}
if (NULL != AttachedProcess)
{
KeAttachProcess(AttachedProcess);
}
ObDereferenceObject(Port);
return(Status);
}
/**********************************************************************
* NAME
* NtWriteRequestData/6
*
* DESCRIPTION
*
* ARGUMENTS
*
* RETURN VALUE
*
* REVISIONS
*/
NTSTATUS STDCALL NtWriteRequestData (HANDLE PortHandle,
PPORT_MESSAGE Message,
ULONG Index,
PVOID Buffer,
ULONG BufferLength,
PULONG ReturnLength)
{
UNIMPLEMENTED;
return(STATUS_NOT_IMPLEMENTED);
}
/* EOF */

View file

@ -9,9 +9,6 @@
<define name="__NO_CTYPE_INLINES" />
<define name="__USE_W32API" />
<define name="WIN9X_COMPAT_SPINLOCK" />
<if property="NTLPC" value="1">
<define name="NTLPC" />
</if>
<include base="cmlib">.</include>
<include base="ntoskrnl">include</include>
<include base="ReactOS">include/reactos/drivers</include>
@ -230,35 +227,16 @@
<file>loader.c</file>
<file>rtl.c</file>
</directory>
<if property="NTLPC" value="0">
<directory name="lpc">
<file>close.c</file>
<file>complete.c</file>
<file>connect.c</file>
<file>create.c</file>
<file>listen.c</file>
<file>port.c</file>
<file>query.c</file>
<file>queue.c</file>
<file>receive.c</file>
<file>reply.c</file>
<file>send.c</file>
</directory>
</if>
<if property="NTLPC" value="1">
<directory name="lpc">
<directory name="ntlpc">
<file>close.c</file>
<file>complete.c</file>
<file>connect.c</file>
<file>create.c</file>
<file>listen.c</file>
<file>port.c</file>
<file>reply.c</file>
<file>send.c</file>
</directory>
</directory>
</if>
<directory name="lpc">
<file>close.c</file>
<file>complete.c</file>
<file>connect.c</file>
<file>create.c</file>
<file>listen.c</file>
<file>port.c</file>
<file>reply.c</file>
<file>send.c</file>
</directory>
<directory name="mm">
<if property="ARCH" value="i386">
<directory name="i386">

View file

@ -1716,8 +1716,7 @@ ObpSetHandleAttributes(IN PHANDLE_TABLE HandleTable,
IN OUT PHANDLE_TABLE_ENTRY HandleTableEntry,
IN PVOID Context)
{
POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo =
(POBP_SET_HANDLE_ATTRIBUTES_CONTEXT)Context;
POBP_SET_HANDLE_ATTRIBUTES_CONTEXT SetHandleInfo = Context;
POBJECT_HEADER ObjectHeader = EX_HTE_TO_HDR(HandleTableEntry);
PAGED_CODE();