Home | Info | Community | Development | myReactOS | Contact Us
ReactOS Development > Doxygencomplete.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
1.7.6.1
|