Author: ion
Date: Mon Oct 30 17:44:05 2006
New Revision: 24670
URL:
http://svn.reactos.org/svn/reactos?rev=24670&view=rev
Log:
- Implement NtAcceptConnectPort. This is a naive implementation that doesn't support
memory-mapped LPC yet (since it's not used by SMSS). Such LPC messages will hit an
ASSERT for now (when they do, I'll implement the missing functionalitY).
Modified:
trunk/reactos/ntoskrnl/lpc/ntlpc/complete.c
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/complete.c
URL:
http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/complet…
==============================================================================
--- trunk/reactos/ntoskrnl/lpc/ntlpc/complete.c (original)
+++ trunk/reactos/ntoskrnl/lpc/ntlpc/complete.c Mon Oct 30 17:44:05 2006
@@ -29,8 +29,234 @@
IN PPORT_VIEW ClientView,
IN PREMOTE_PORT_VIEW ServerView)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ PLPCP_PORT_OBJECT ConnectionPort, ServerPort, ClientPort;
+ PVOID ClientSectionToMap = NULL;
+ HANDLE Handle;
+ KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
+ NTSTATUS Status;
+ ULONG ConnectionInfoLength;
+ PLPCP_MESSAGE Msg;
+ PLPCP_CONNECTION_MESSAGE ConnectMsg;
+ PEPROCESS ClientProcess;
+ PETHREAD ClientThread;
+ 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 */
+ Msg = ClientThread->LpcReplyMessage;
+ ConnectMsg = (PLPCP_CONNECTION_MESSAGE)(Msg + 1);
+
+ /* Get the client and connection port as well */
+ ClientPort = ConnectMsg->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 */
+ ConnectMsg->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 */
+ Msg->Request.u1.s1.DataLength = sizeof(LPCP_CONNECTION_MESSAGE) +
+ ConnectionInfoLength;
+ Msg->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
+ Msg->Request.u1.s1.DataLength;
+
+ /* Setup the reply message */
+ Msg->Request.u2.s2.Type = LPC_REPLY;
+ Msg->Request.u2.s2.DataInfoOffset = 0;
+ Msg->Request.ClientId = ReplyMessage->ClientId;
+ Msg->Request.MessageId = ReplyMessage->MessageId;
+ Msg->Request.ClientViewSize = 0;
+ RtlMoveMemory(ConnectMsg + 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 = Msg->Request.ClientId;
+
+ /* Get the section associated and then clear it, while inside the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+ ClientSectionToMap = ConnectMsg->SectionToMap;
+ ConnectMsg->SectionToMap = NULL;
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Now check if there's a client section */
+ if (ClientSectionToMap)
+ {
+ /* FIXME: TODO */
+ ASSERT(FALSE);
+ }
+
+ /* 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 = ConnectMsg->ClientView.ViewRemoteBase;
+ ClientView->ViewSize = ConnectMsg->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,
+ Msg,
+ ConnectMsg,
+ 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 = Msg;
+ 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;
}
/*