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