ReactOS Fundraising Campaign 2012
 
€ 4,410 / € 30,000

Information | Donate

Home | Info | Community | Development | myReactOS | Contact Us

  1. Home
  2. Community
  3. Development
  4. myReactOS
  5. Fundraiser 2012

  1. Main Page
  2. Alphabetical List
  3. Data Structures
  4. Directories
  5. File List
  6. Data Fields
  7. Globals
  8. Related Pages

ReactOS Development > Doxygen

complete.c
Go to the documentation of this file.
00001 /*
00002 * PROJECT:         ReactOS Kernel
00003 * LICENSE:         GPL - See COPYING in the top level directory
00004 * FILE:            ntoskrnl/lpc/complete.c
00005 * PURPOSE:         Local Procedure Call: Connection Completion
00006 * PROGRAMMERS:     Alex Ionescu (alex.ionescu@reactos.org)
00007 */
00008 
00009 /* INCLUDES ******************************************************************/
00010 
00011 #include <ntoskrnl.h>
00012 #define NDEBUG
00013 #include <debug.h>
00014 
00015 /* PRIVATE FUNCTIONS *********************************************************/
00016 
00017 VOID
00018 NTAPI
00019 LpcpPrepareToWakeClient(IN PETHREAD Thread)
00020 {
00021     PAGED_CODE();
00022 
00023     /* Make sure the thread isn't dying and it has a valid chain */
00024     if (!(Thread->LpcExitThreadCalled) &&
00025         !(IsListEmpty(&Thread->LpcReplyChain)))
00026     {
00027         /* Remove it from the list and reinitialize it */
00028         RemoveEntryList(&Thread->LpcReplyChain);
00029         InitializeListHead(&Thread->LpcReplyChain);
00030     }
00031 }
00032 
00033 /* PUBLIC FUNCTIONS **********************************************************/
00034 
00035 /*
00036  * @implemented
00037  */
00038 NTSTATUS
00039 NTAPI
00040 NtAcceptConnectPort(OUT PHANDLE PortHandle,
00041                     IN PVOID PortContext OPTIONAL,
00042                     IN PPORT_MESSAGE ReplyMessage,
00043                     IN BOOLEAN AcceptConnection,
00044                     IN PPORT_VIEW ServerView,
00045                     IN PREMOTE_PORT_VIEW ClientView)
00046 {
00047     PLPCP_PORT_OBJECT ConnectionPort, ServerPort, ClientPort;
00048     PVOID ClientSectionToMap = NULL;
00049     HANDLE Handle;
00050     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
00051     NTSTATUS Status;
00052     ULONG ConnectionInfoLength;
00053     PLPCP_MESSAGE Message;
00054     PLPCP_CONNECTION_MESSAGE ConnectMessage;
00055     PEPROCESS ClientProcess;
00056     PETHREAD ClientThread;
00057     LARGE_INTEGER SectionOffset;
00058     PAGED_CODE();
00059     LPCTRACE(LPC_COMPLETE_DEBUG,
00060              "Context: %p. Message: %p. Accept: %lx. Views: %p/%p\n",
00061              PortContext,
00062              ReplyMessage,
00063              AcceptConnection,
00064              ClientView,
00065              ServerView);
00066 
00067     /* Validate the size of the server view */
00068     if ((ServerView) && (ServerView->Length != sizeof(PORT_VIEW)))
00069     {
00070         /* Invalid size */
00071         return STATUS_INVALID_PARAMETER;
00072     }
00073 
00074     /* Validate the size of the client view */
00075     if ((ClientView) && (ClientView->Length != sizeof(REMOTE_PORT_VIEW)))
00076     {
00077         /* Invalid size */
00078         return STATUS_INVALID_PARAMETER;
00079     }
00080 
00081     /* Get the client process and thread */
00082     Status = PsLookupProcessThreadByCid(&ReplyMessage->ClientId,
00083                                         &ClientProcess,
00084                                         &ClientThread);
00085     if (!NT_SUCCESS(Status)) return Status;
00086 
00087     /* Acquire the LPC Lock */
00088     KeAcquireGuardedMutex(&LpcpLock);
00089 
00090     /* Make sure that the client wants a reply, and this is the right one */
00091     if (!(LpcpGetMessageFromThread(ClientThread)) ||
00092         !(ReplyMessage->MessageId) ||
00093         (ClientThread->LpcReplyMessageId != ReplyMessage->MessageId))
00094     {
00095         /* Not the reply asked for, or no reply wanted, fail */
00096         KeReleaseGuardedMutex(&LpcpLock);
00097         ObDereferenceObject(ClientProcess);
00098         ObDereferenceObject(ClientThread);
00099         return STATUS_REPLY_MESSAGE_MISMATCH;
00100     }
00101 
00102     /* Now get the message and connection message */
00103     Message = LpcpGetMessageFromThread(ClientThread);
00104     ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1);
00105 
00106     /* Get the client and connection port as well */
00107     ClientPort = ConnectMessage->ClientPort;
00108     ConnectionPort = ClientPort->ConnectionPort;
00109 
00110     /* Make sure that the reply is being sent to the proper server process */
00111     if (ConnectionPort->ServerProcess != PsGetCurrentProcess())
00112     {
00113         /* It's not, so fail */
00114         KeReleaseGuardedMutex(&LpcpLock);
00115         ObDereferenceObject(ClientProcess);
00116         ObDereferenceObject(ClientThread);
00117         return STATUS_REPLY_MESSAGE_MISMATCH;
00118     }
00119 
00120     /* At this point, don't let other accept attempts happen */
00121     ClientThread->LpcReplyMessage = NULL;
00122     ClientThread->LpcReplyMessageId = 0;
00123 
00124     /* Clear the client port for now as well, then release the lock */
00125     ConnectMessage->ClientPort = NULL;
00126     KeReleaseGuardedMutex(&LpcpLock);
00127 
00128     /* Get the connection information length */
00129     ConnectionInfoLength = ReplyMessage->u1.s1.DataLength;
00130     if (ConnectionInfoLength > ConnectionPort->MaxConnectionInfoLength)
00131     {
00132         /* Normalize it since it's too large */
00133         ConnectionInfoLength = ConnectionPort->MaxConnectionInfoLength;
00134     }
00135 
00136     /* Set the sizes of our reply message */
00137     Message->Request.u1.s1.DataLength = (CSHORT)ConnectionInfoLength +
00138                                          sizeof(LPCP_CONNECTION_MESSAGE);
00139     Message->Request.u1.s1.TotalLength = sizeof(LPCP_MESSAGE) +
00140                                      Message->Request.u1.s1.DataLength;
00141 
00142     /* Setup the reply message */
00143     Message->Request.u2.s2.Type = LPC_REPLY;
00144     Message->Request.u2.s2.DataInfoOffset = 0;
00145     Message->Request.ClientId = ReplyMessage->ClientId;
00146     Message->Request.MessageId = ReplyMessage->MessageId;
00147     Message->Request.ClientViewSize = 0;
00148     RtlCopyMemory(ConnectMessage + 1, ReplyMessage + 1, ConnectionInfoLength);
00149 
00150     /* At this point, if the caller refused the connection, go to cleanup */
00151     if (!AcceptConnection)
00152     {
00153         DPRINT1("LPC connection was refused\n");
00154         goto Cleanup;   
00155     }
00156 
00157     /* Otherwise, create the actual port */
00158     Status = ObCreateObject(PreviousMode,
00159                             LpcPortObjectType,
00160                             NULL,
00161                             PreviousMode,
00162                             NULL,
00163                             sizeof(LPCP_PORT_OBJECT),
00164                             0,
00165                             0,
00166                             (PVOID*)&ServerPort);
00167     if (!NT_SUCCESS(Status)) goto Cleanup;
00168 
00169     /* Set it up */
00170     RtlZeroMemory(ServerPort, sizeof(LPCP_PORT_OBJECT));
00171     ServerPort->PortContext = PortContext;
00172     ServerPort->Flags = LPCP_COMMUNICATION_PORT;
00173     ServerPort->MaxMessageLength = ConnectionPort->MaxMessageLength;
00174     InitializeListHead(&ServerPort->LpcReplyChainHead);
00175     InitializeListHead(&ServerPort->LpcDataInfoChainHead);
00176 
00177     /* Reference the connection port until we're fully setup */
00178     ObReferenceObject(ConnectionPort);
00179 
00180     /* Link the ports together */
00181     ServerPort->ConnectionPort = ConnectionPort;
00182     ServerPort->ConnectedPort = ClientPort;
00183     ClientPort->ConnectedPort = ServerPort;
00184 
00185     /* Also set the creator CID */
00186     ServerPort->Creator = PsGetCurrentThread()->Cid;
00187     ClientPort->Creator = Message->Request.ClientId;
00188 
00189     /* Get the section associated and then clear it, while inside the lock */
00190     KeAcquireGuardedMutex(&LpcpLock);
00191     ClientSectionToMap = ConnectMessage->SectionToMap;
00192     ConnectMessage->SectionToMap = NULL;
00193     KeReleaseGuardedMutex(&LpcpLock);
00194 
00195     /* Now check if there's a client section */
00196     if (ClientSectionToMap)
00197     {
00198         /* Setup the offset */
00199         SectionOffset.QuadPart = ConnectMessage->ClientView.SectionOffset;
00200 
00201         /* Map the section */
00202         Status = MmMapViewOfSection(ClientSectionToMap,
00203                                     PsGetCurrentProcess(),
00204                                     &ServerPort->ClientSectionBase,
00205                                     0,
00206                                     0,
00207                                     &SectionOffset,
00208                                     &ConnectMessage->ClientView.ViewSize,
00209                                     ViewUnmap,
00210                                     0,
00211                                     PAGE_READWRITE);
00212 
00213         /* Update the offset and check for mapping status */
00214         ConnectMessage->ClientView.SectionOffset = SectionOffset.LowPart;
00215         if (NT_SUCCESS(Status))
00216         {
00217             /* Set the view base */
00218             ConnectMessage->ClientView.ViewRemoteBase = ServerPort->
00219                                                         ClientSectionBase;
00220 
00221             /* Save and reference the mapping process */
00222             ServerPort->MappingProcess = PsGetCurrentProcess();
00223             ObReferenceObject(ServerPort->MappingProcess);
00224         }
00225         else
00226         {
00227             /* Otherwise, quit */
00228             ObDereferenceObject(ServerPort);
00229             DPRINT1("Client section mapping failed: %lx\n", Status);
00230             DPRINT1("View base, offset, size: %lx %lx %lx\n",
00231                     ServerPort->ClientSectionBase,
00232                     ConnectMessage->ClientView.ViewSize,
00233                     SectionOffset);
00234             goto Cleanup;
00235         }
00236     }
00237 
00238     /* Check if there's a server section */
00239     if (ServerView)
00240     {
00241         /* FIXME: TODO */
00242         ASSERT(FALSE);
00243     }
00244 
00245     /* Reference the server port until it's fully inserted */
00246     ObReferenceObject(ServerPort);
00247 
00248     /* Insert the server port in the namespace */
00249     Status = ObInsertObject(ServerPort,
00250                             NULL,
00251                             PORT_ALL_ACCESS,
00252                             0,
00253                             NULL,
00254                             &Handle);
00255     if (!NT_SUCCESS(Status))
00256     {
00257         /* We failed, remove the extra reference and cleanup */
00258         ObDereferenceObject(ServerPort);
00259         goto Cleanup;
00260     }
00261 
00262     /* Check if the caller gave a client view */
00263     if (ClientView)
00264     {
00265         /* Fill it out */
00266         ClientView->ViewBase = ConnectMessage->ClientView.ViewRemoteBase;
00267         ClientView->ViewSize = ConnectMessage->ClientView.ViewSize;
00268     }
00269 
00270     /* Return the handle to user mode */
00271     *PortHandle = Handle;
00272     LPCTRACE(LPC_COMPLETE_DEBUG,
00273              "Handle: %lx. Messages: %p/%p. Ports: %p/%p/%p\n",
00274              Handle,
00275              Message,
00276              ConnectMessage,
00277              ServerPort,
00278              ClientPort,
00279              ConnectionPort);
00280 
00281     /* If there was no port context, use the handle by default */
00282     if (!PortContext) ServerPort->PortContext = Handle;
00283     ServerPort->ClientThread = ClientThread;
00284 
00285     /* Set this message as the LPC Reply message while holding the lock */
00286     KeAcquireGuardedMutex(&LpcpLock);
00287     ClientThread->LpcReplyMessage = Message;
00288     KeReleaseGuardedMutex(&LpcpLock);
00289 
00290     /* Clear the thread pointer so it doesn't get cleaned later */
00291     ClientThread = NULL;
00292 
00293     /* Remove the extra reference we had added */
00294     ObDereferenceObject(ServerPort);
00295 
00296 Cleanup:
00297     /* If there was a section, dereference it */
00298     if (ClientSectionToMap) ObDereferenceObject(ClientSectionToMap);
00299 
00300     /* Check if we got here while still having a client thread */
00301     if (ClientThread)
00302     {
00303         /* FIXME: Complex cleanup code */
00304         ASSERT(FALSE);
00305     }
00306 
00307     /* Dereference the client port if we have one, and the process */
00308     LPCTRACE(LPC_COMPLETE_DEBUG,
00309              "Status: %lx. Thread: %p. Process: [%.16s]\n",
00310              Status,
00311              ClientThread,
00312              ClientProcess->ImageFileName);
00313     if (ClientPort) ObDereferenceObject(ClientPort);
00314     ObDereferenceObject(ClientProcess);
00315     return Status;
00316 }
00317 
00318 /*
00319  * @implemented
00320  */
00321 NTSTATUS
00322 NTAPI
00323 NtCompleteConnectPort(IN HANDLE PortHandle)
00324 {
00325     NTSTATUS Status;
00326     PLPCP_PORT_OBJECT Port;
00327     KPROCESSOR_MODE PreviousMode = KeGetPreviousMode();
00328     PETHREAD Thread;
00329     PAGED_CODE();
00330     LPCTRACE(LPC_COMPLETE_DEBUG, "Handle: %lx\n", PortHandle);
00331 
00332     /* Get the Port Object */
00333     Status = ObReferenceObjectByHandle(PortHandle,
00334                                        PORT_ALL_ACCESS,
00335                                        LpcPortObjectType,
00336                                        PreviousMode,
00337                                        (PVOID*)&Port,
00338                                        NULL);
00339     if (!NT_SUCCESS(Status)) return Status;
00340 
00341     /* Make sure this is a connection port */
00342     if ((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_COMMUNICATION_PORT)
00343     {
00344         /* It isn't, fail */
00345         ObDereferenceObject(Port);
00346         return STATUS_INVALID_PORT_HANDLE;
00347     }
00348 
00349     /* Acquire the lock */
00350     KeAcquireGuardedMutex(&LpcpLock);
00351 
00352     /* Make sure we have a client thread */
00353     if (!Port->ClientThread)
00354     {
00355         /* We don't, fail */
00356         KeReleaseGuardedMutex(&LpcpLock);
00357         ObDereferenceObject(Port);
00358         return STATUS_INVALID_PARAMETER;
00359     }
00360 
00361     /* Get the thread */
00362     Thread = Port->ClientThread;
00363 
00364     /* Make sure it has a reply message */
00365     if (!LpcpGetMessageFromThread(Thread))
00366     {
00367         /* It doesn't, quit */
00368         KeReleaseGuardedMutex(&LpcpLock);
00369         ObDereferenceObject(Port);
00370         return STATUS_SUCCESS;
00371     }
00372 
00373     /* Clear the client thread and wake it up */
00374     Port->ClientThread = NULL;
00375     LpcpPrepareToWakeClient(Thread);
00376 
00377     /* Release the lock and wait for an answer */
00378     KeReleaseGuardedMutex(&LpcpLock);
00379     LpcpCompleteWait(&Thread->LpcReplySemaphore);
00380 
00381     /* Dereference the Thread and Port  and return */
00382     ObDereferenceObject(Port);
00383     ObDereferenceObject(Thread);
00384     LPCTRACE(LPC_COMPLETE_DEBUG, "Port: %p. Thread: %p\n", Port, Thread);
00385     return Status;
00386 }
00387 
00388 /* EOF */

Generated on Sun May 27 2012 04:37:33 for ReactOS by doxygen 1.7.6.1

ReactOS is a registered trademark or a trademark of ReactOS Foundation in the United States and other countries.