1 /* 2 * PROJECT: ReactOS Kernel 3 * LICENSE: GPL - See COPYING in the top level directory 4 * FILE: ntoskrnl/lpc/close.c 5 * PURPOSE: Local Procedure Call: Rundown, Cleanup, Deletion 6 * PROGRAMMERS: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include <ntoskrnl.h> 12 #define NDEBUG 13 #include <debug.h> 14 15 /* PRIVATE FUNCTIONS *********************************************************/ 16 17 VOID 18 NTAPI 19 LpcExitThread(IN PETHREAD Thread) 20 { 21 PLPCP_MESSAGE Message; 22 ASSERT(Thread == PsGetCurrentThread()); 23 24 /* Acquire the lock */ 25 KeAcquireGuardedMutex(&LpcpLock); 26 27 /* Make sure that the Reply Chain is empty */ 28 if (!IsListEmpty(&Thread->LpcReplyChain)) 29 { 30 /* It's not, remove the entry */ 31 RemoveEntryList(&Thread->LpcReplyChain); 32 } 33 34 /* Set the thread in exit mode */ 35 Thread->LpcExitThreadCalled = TRUE; 36 Thread->LpcReplyMessageId = 0; 37 38 /* Check if there's a reply message */ 39 Message = LpcpGetMessageFromThread(Thread); 40 if (Message) 41 { 42 /* FIXME: TODO */ 43 ASSERT(FALSE); 44 } 45 46 /* Release the lock */ 47 KeReleaseGuardedMutex(&LpcpLock); 48 } 49 50 VOID 51 NTAPI 52 LpcpFreeToPortZone(IN PLPCP_MESSAGE Message, 53 IN ULONG LockFlags) 54 { 55 PLPCP_CONNECTION_MESSAGE ConnectMessage; 56 PLPCP_PORT_OBJECT ClientPort = NULL; 57 PETHREAD Thread = NULL; 58 BOOLEAN LockHeld = (LockFlags & LPCP_LOCK_HELD); 59 BOOLEAN ReleaseLock = (LockFlags & LPCP_LOCK_RELEASE); 60 61 PAGED_CODE(); 62 63 LPCTRACE(LPC_CLOSE_DEBUG, "Message: %p. LockFlags: %lx\n", Message, LockFlags); 64 65 /* Acquire the lock if not already */ 66 if (!LockHeld) KeAcquireGuardedMutex(&LpcpLock); 67 68 /* Check if the queue list is empty */ 69 if (!IsListEmpty(&Message->Entry)) 70 { 71 /* Remove and re-initialize */ 72 RemoveEntryList(&Message->Entry); 73 InitializeListHead(&Message->Entry); 74 } 75 76 /* Check if we've already replied */ 77 if (Message->RepliedToThread) 78 { 79 /* Set thread to dereference and clean up */ 80 Thread = Message->RepliedToThread; 81 Message->RepliedToThread = NULL; 82 } 83 84 /* Check if this is a connection request */ 85 if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST) 86 { 87 /* Get the connection message */ 88 ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1); 89 90 /* Clear the client port */ 91 ClientPort = ConnectMessage->ClientPort; 92 if (ClientPort) ConnectMessage->ClientPort = NULL; 93 } 94 95 /* Release the lock */ 96 KeReleaseGuardedMutex(&LpcpLock); 97 98 /* Check if we had anything to dereference */ 99 if (Thread) ObDereferenceObject(Thread); 100 if (ClientPort) ObDereferenceObject(ClientPort); 101 102 /* Free the entry */ 103 ExFreeToPagedLookasideList(&LpcpMessagesLookaside, Message); 104 105 /* Reacquire the lock if needed */ 106 if ((LockHeld) && !(ReleaseLock)) KeAcquireGuardedMutex(&LpcpLock); 107 } 108 109 VOID 110 NTAPI 111 LpcpDestroyPortQueue(IN PLPCP_PORT_OBJECT Port, 112 IN BOOLEAN Destroy) 113 { 114 PLIST_ENTRY ListHead, NextEntry; 115 PETHREAD Thread; 116 PLPCP_MESSAGE Message; 117 PLPCP_PORT_OBJECT ConnectionPort = NULL; 118 PLPCP_CONNECTION_MESSAGE ConnectMessage; 119 PLPCP_NONPAGED_PORT_QUEUE MessageQueue; 120 121 PAGED_CODE(); 122 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags); 123 124 /* Hold the lock */ 125 KeAcquireGuardedMutex(&LpcpLock); 126 127 /* Check if we have a connected port */ 128 if (((Port->Flags & LPCP_PORT_TYPE_MASK) != LPCP_UNCONNECTED_PORT) && 129 (Port->ConnectedPort)) 130 { 131 /* Disconnect it */ 132 Port->ConnectedPort->ConnectedPort = NULL; 133 ConnectionPort = Port->ConnectedPort->ConnectionPort; 134 if (ConnectionPort) 135 { 136 /* Clear connection port */ 137 Port->ConnectedPort->ConnectionPort = NULL; 138 } 139 } 140 141 /* Check if this is a connection port */ 142 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) 143 { 144 /* Delete the name */ 145 Port->Flags |= LPCP_NAME_DELETED; 146 } 147 148 /* Walk all the threads waiting and signal them */ 149 ListHead = &Port->LpcReplyChainHead; 150 NextEntry = ListHead->Flink; 151 while ((NextEntry) && (NextEntry != ListHead)) 152 { 153 /* Get the Thread */ 154 Thread = CONTAINING_RECORD(NextEntry, ETHREAD, LpcReplyChain); 155 156 /* Make sure we're not in exit */ 157 if (Thread->LpcExitThreadCalled) break; 158 159 /* Move to the next entry */ 160 NextEntry = NextEntry->Flink; 161 162 /* Remove and reinitialize the List */ 163 RemoveEntryList(&Thread->LpcReplyChain); 164 InitializeListHead(&Thread->LpcReplyChain); 165 166 /* Check if someone is waiting */ 167 if (!KeReadStateSemaphore(&Thread->LpcReplySemaphore)) 168 { 169 /* Get the message */ 170 Message = LpcpGetMessageFromThread(Thread); 171 if (Message) 172 { 173 /* Check if it's a connection request */ 174 if (Message->Request.u2.s2.Type == LPC_CONNECTION_REQUEST) 175 { 176 /* Get the connection message */ 177 ConnectMessage = (PLPCP_CONNECTION_MESSAGE)(Message + 1); 178 179 /* Check if it had a section */ 180 if (ConnectMessage->SectionToMap) 181 { 182 /* Dereference it */ 183 ObDereferenceObject(ConnectMessage->SectionToMap); 184 } 185 } 186 187 /* Clear the reply message */ 188 Thread->LpcReplyMessage = NULL; 189 190 /* And remove the message from the port zone */ 191 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); 192 NextEntry = Port->LpcReplyChainHead.Flink; 193 } 194 195 /* Release the semaphore and reset message id count */ 196 Thread->LpcReplyMessageId = 0; 197 KeReleaseSemaphore(&Thread->LpcReplySemaphore, 0, 1, FALSE); 198 } 199 } 200 201 /* Reinitialize the list head */ 202 InitializeListHead(&Port->LpcReplyChainHead); 203 204 /* Loop queued messages */ 205 while ((Port->MsgQueue.ReceiveHead.Flink) && 206 !(IsListEmpty(&Port->MsgQueue.ReceiveHead))) 207 { 208 /* Get the message */ 209 Message = CONTAINING_RECORD(Port->MsgQueue.ReceiveHead.Flink, 210 LPCP_MESSAGE, 211 Entry); 212 213 /* Free and reinitialize it's list head */ 214 RemoveEntryList(&Message->Entry); 215 InitializeListHead(&Message->Entry); 216 217 /* Remove it from the port zone */ 218 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); 219 } 220 221 /* Release the lock */ 222 KeReleaseGuardedMutex(&LpcpLock); 223 224 /* Dereference the connection port */ 225 if (ConnectionPort) ObDereferenceObject(ConnectionPort); 226 227 /* Check if we have to free the port entirely */ 228 if (Destroy) 229 { 230 /* Check if the semaphore exists */ 231 if (Port->MsgQueue.Semaphore) 232 { 233 /* Use the semaphore to find the port queue and free it */ 234 MessageQueue = CONTAINING_RECORD(Port->MsgQueue.Semaphore, 235 LPCP_NONPAGED_PORT_QUEUE, 236 Semaphore); 237 ExFreePoolWithTag(MessageQueue, 'troP'); 238 } 239 } 240 } 241 242 VOID 243 NTAPI 244 LpcpClosePort(IN PEPROCESS Process OPTIONAL, 245 IN PVOID Object, 246 IN ACCESS_MASK GrantedAccess, 247 IN ULONG ProcessHandleCount, 248 IN ULONG SystemHandleCount) 249 { 250 PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)Object; 251 252 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags); 253 254 /* Only Server-side Connection Ports need clean up*/ 255 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) 256 { 257 /* Check the handle count */ 258 switch (SystemHandleCount) 259 { 260 /* No handles left */ 261 case 0: 262 263 /* Destroy the port queue */ 264 LpcpDestroyPortQueue(Port, TRUE); 265 break; 266 267 /* Last handle remaining */ 268 case 1: 269 270 /* Reset the queue only */ 271 LpcpDestroyPortQueue(Port, FALSE); 272 273 /* More handles remain, do nothing */ 274 default: 275 break; 276 } 277 } 278 } 279 280 VOID 281 NTAPI 282 LpcpFreePortClientSecurity(IN PLPCP_PORT_OBJECT Port) 283 { 284 /* Check if this is a client port */ 285 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT) 286 { 287 /* Check if security is static */ 288 if (!(Port->Flags & LPCP_SECURITY_DYNAMIC)) 289 { 290 /* Check if we have a token */ 291 if (Port->StaticSecurity.ClientToken) 292 { 293 /* Free security */ 294 SeDeleteClientSecurity(&Port->StaticSecurity); 295 } 296 } 297 } 298 } 299 300 VOID 301 NTAPI 302 LpcpDeletePort(IN PVOID ObjectBody) 303 { 304 LARGE_INTEGER Timeout; 305 PETHREAD Thread; 306 PLPCP_PORT_OBJECT Port = (PLPCP_PORT_OBJECT)ObjectBody; 307 PLPCP_PORT_OBJECT ConnectionPort; 308 PLPCP_MESSAGE Message; 309 PLIST_ENTRY ListHead, NextEntry; 310 HANDLE Pid; 311 CLIENT_DIED_MSG ClientDiedMsg; 312 313 PAGED_CODE(); 314 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p. Flags: %lx\n", Port, Port->Flags); 315 316 Timeout.QuadPart = -1000000; 317 318 /* Check if this is a communication port */ 319 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_COMMUNICATION_PORT) 320 { 321 /* Acquire the lock */ 322 KeAcquireGuardedMutex(&LpcpLock); 323 324 /* Get the thread */ 325 Thread = Port->ClientThread; 326 if (Thread) 327 { 328 /* Clear it */ 329 Port->ClientThread = NULL; 330 331 /* Release the lock and dereference */ 332 KeReleaseGuardedMutex(&LpcpLock); 333 ObDereferenceObject(Thread); 334 } 335 else 336 { 337 /* Release the lock */ 338 KeReleaseGuardedMutex(&LpcpLock); 339 } 340 } 341 342 /* Check if this is a client-side port */ 343 if ((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CLIENT_PORT) 344 { 345 /* Setup the client died message */ 346 ClientDiedMsg.h.u1.s1.TotalLength = sizeof(ClientDiedMsg); 347 ClientDiedMsg.h.u1.s1.DataLength = sizeof(ClientDiedMsg.CreateTime); 348 ClientDiedMsg.h.u2.ZeroInit = 0; 349 ClientDiedMsg.h.u2.s2.Type = LPC_PORT_CLOSED; 350 ClientDiedMsg.CreateTime = PsGetCurrentProcess()->CreateTime; 351 352 /* Send it */ 353 for (;;) 354 { 355 /* Send the message */ 356 if (LpcRequestPort(Port, &ClientDiedMsg.h) != STATUS_NO_MEMORY) 357 break; 358 359 /* Wait until trying again */ 360 KeDelayExecutionThread(KernelMode, FALSE, &Timeout); 361 } 362 } 363 364 /* Destroy the port queue */ 365 LpcpDestroyPortQueue(Port, TRUE); 366 367 /* Check if we had views */ 368 if ((Port->ClientSectionBase) || (Port->ServerSectionBase)) 369 { 370 /* Check if we had a client view */ 371 if (Port->ClientSectionBase) 372 { 373 /* Unmap it */ 374 MmUnmapViewOfSection(Port->MappingProcess, 375 Port->ClientSectionBase); 376 } 377 378 /* Check for a server view */ 379 if (Port->ServerSectionBase) 380 { 381 /* Unmap it */ 382 MmUnmapViewOfSection(Port->MappingProcess, 383 Port->ServerSectionBase); 384 } 385 386 /* Dereference the mapping process */ 387 ObDereferenceObject(Port->MappingProcess); 388 Port->MappingProcess = NULL; 389 } 390 391 /* Acquire the lock */ 392 KeAcquireGuardedMutex(&LpcpLock); 393 394 /* Get the connection port */ 395 ConnectionPort = Port->ConnectionPort; 396 if (ConnectionPort) 397 { 398 /* Get the PID */ 399 Pid = PsGetCurrentProcessId(); 400 401 /* Loop the data lists */ 402 ListHead = &ConnectionPort->LpcDataInfoChainHead; 403 NextEntry = ListHead->Flink; 404 while (NextEntry != ListHead) 405 { 406 /* Get the message */ 407 Message = CONTAINING_RECORD(NextEntry, LPCP_MESSAGE, Entry); 408 NextEntry = NextEntry->Flink; 409 410 /* Check if this is the connection port */ 411 if (Port == ConnectionPort) 412 { 413 /* Free queued messages */ 414 RemoveEntryList(&Message->Entry); 415 InitializeListHead(&Message->Entry); 416 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); 417 418 /* Restart at the head */ 419 NextEntry = ListHead->Flink; 420 } 421 else if ((Message->Request.ClientId.UniqueProcess == Pid) && 422 ((Message->SenderPort == Port) || 423 (Message->SenderPort == Port->ConnectedPort) || 424 (Message->SenderPort == ConnectionPort))) 425 { 426 /* Remove it */ 427 RemoveEntryList(&Message->Entry); 428 InitializeListHead(&Message->Entry); 429 LpcpFreeToPortZone(Message, LPCP_LOCK_HELD); 430 431 /* Restart at the head */ 432 NextEntry = ListHead->Flink; 433 } 434 } 435 436 /* Release the lock */ 437 KeReleaseGuardedMutex(&LpcpLock); 438 439 /* Dereference the object unless it's the same port */ 440 if (ConnectionPort != Port) ObDereferenceObject(ConnectionPort); 441 442 /* Check if this is a connection port with a server process */ 443 if (((Port->Flags & LPCP_PORT_TYPE_MASK) == LPCP_CONNECTION_PORT) && 444 (ConnectionPort->ServerProcess)) 445 { 446 /* Dereference the server process */ 447 ObDereferenceObject(ConnectionPort->ServerProcess); 448 ConnectionPort->ServerProcess = NULL; 449 } 450 } 451 else 452 { 453 /* Release the lock */ 454 KeReleaseGuardedMutex(&LpcpLock); 455 } 456 457 /* Free client security */ 458 LpcpFreePortClientSecurity(Port); 459 LPCTRACE(LPC_CLOSE_DEBUG, "Port: %p deleted\n", Port); 460 } 461 462 /* EOF */ 463