Author: ion
Date: Mon Oct 30 17:50:31 2006
New Revision: 24673
URL: http://svn.reactos.org/svn/reactos?rev=24673&view=rev
Log:
- Implement NtRequestWaitReplyPort. This is a simple implementation that doesn't support Callback LPC Messages yet (Since we don't make use of them). SMSS can now send API messages on the Sb Port.
- With these APIs we now have a skeleton NTLPC that is fully NT-compatible. Thanks to ea's (Emanuele)'s smss work which he strived to make portable, building with NTLPC = 1 will also build a compatible smss that now works.
- CSRSS requires some changes since it was not written to be NTLPC portable.
Modified:
trunk/reactos/ntoskrnl/lpc/ntlpc/send.c
Modified: trunk/reactos/ntoskrnl/lpc/ntlpc/send.c
URL: http://svn.reactos.org/svn/reactos/trunk/reactos/ntoskrnl/lpc/ntlpc/send.c?…
==============================================================================
--- trunk/reactos/ntoskrnl/lpc/ntlpc/send.c (original)
+++ trunk/reactos/ntoskrnl/lpc/ntlpc/send.c Mon Oct 30 17:50:31 2006
@@ -61,8 +61,251 @@
IN PPORT_MESSAGE LpcRequest,
IN OUT PPORT_MESSAGE LpcReply)
{
- UNIMPLEMENTED;
- return STATUS_NOT_IMPLEMENTED;
+ 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;
+ }
+
+ /* Acquire the lock */
+ KeAcquireGuardedMutex(&LpcpLock);
+
+ /* Allocate a message */
+ Message = ExAllocateFromPagedLookasideList(&LpcpMessagesLookaside);
+ KeReleaseGuardedMutex(&LpcpLock);
+
+ /* Check if allocation worked */
+ if (!Message)
+ {
+ /* Fail */
+ 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 */
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;
}
/*