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/complete... ============================================================================== --- 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; }
/*