- 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 working on the \ntlpc directory. Leave this disabled unless you really know
what you're doing. what you're doing.
--> -->
<property name="NTLPC" value="0" /> <property name="NTLPC" value="1" />
</rbuild> </rbuild>

View file

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

View file

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

View file

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

File diff suppressed because it is too large Load diff

View file

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

View file

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

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

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

View file

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

View file

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

View file

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