mirror of https://github.com/tongzx/nt5src
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
410 lines
9.1 KiB
410 lines
9.1 KiB
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
lpcclose.c
|
|
|
|
Abstract:
|
|
|
|
Local Inter-Process Communication close procedures that are called when
|
|
a connection port or a communications port is closed.
|
|
|
|
Author:
|
|
|
|
Steve Wood (stevewo) 15-May-1989
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "lpcp.h"
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text(PAGE,LpcpClosePort)
|
|
#pragma alloc_text(PAGE,LpcpDeletePort)
|
|
#pragma alloc_text(PAGE,LpcExitThread)
|
|
#endif
|
|
|
|
|
|
VOID
|
|
LpcpClosePort (
|
|
IN PEPROCESS Process OPTIONAL,
|
|
IN PVOID Object,
|
|
IN ACCESS_MASK GrantedAccess,
|
|
IN ULONG ProcessHandleCount,
|
|
IN ULONG SystemHandleCount
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the callback used for closing a port object.
|
|
|
|
Arguments:
|
|
|
|
Process - Supplies an optional pointer to the process whose port is being
|
|
closed
|
|
|
|
Object - Supplies a pointer to the port object being closed
|
|
|
|
GrantedAccess - Supplies the access granted to the handle closing port
|
|
object
|
|
|
|
ProcessHandleCount - Supplies the number of process handles remaining to
|
|
the object
|
|
|
|
SystemHandleCount - Supplies the number of system handles remaining to
|
|
the object
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
//
|
|
// Translate the object to what it really is, an LPCP port object
|
|
//
|
|
|
|
PLPCP_PORT_OBJECT Port = Object;
|
|
|
|
UNREFERENCED_PARAMETER (Process);
|
|
UNREFERENCED_PARAMETER (GrantedAccess);
|
|
UNREFERENCED_PARAMETER (ProcessHandleCount);
|
|
|
|
//
|
|
// We only have work to do if the object is a server communication port
|
|
//
|
|
|
|
if ( (Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT ) {
|
|
|
|
//
|
|
// If this is a server communication port without any system handles
|
|
// then we can completely destroy the communication queue for the
|
|
// port
|
|
//
|
|
|
|
if ( SystemHandleCount == 0 ) {
|
|
|
|
LpcpDestroyPortQueue( Port, TRUE );
|
|
|
|
//
|
|
// If there is only one system handle left then we'll reset the
|
|
// communication queue for the port
|
|
//
|
|
|
|
} else if ( SystemHandleCount == 1 ) {
|
|
|
|
LpcpDestroyPortQueue( Port, FALSE );
|
|
}
|
|
|
|
//
|
|
// Otherwise we do nothing
|
|
//
|
|
}
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
LpcpDeletePort (
|
|
IN PVOID Object
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is the callback used for deleting a port object.
|
|
|
|
Arguments:
|
|
|
|
Object - Supplies a pointer to the port object being deleted
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PETHREAD CurrentThread;
|
|
PLPCP_PORT_OBJECT Port = Object;
|
|
PLPCP_PORT_OBJECT ConnectionPort;
|
|
LPC_CLIENT_DIED_MSG ClientPortClosedDatagram;
|
|
PLPCP_MESSAGE Msg;
|
|
PLIST_ENTRY Head, Next;
|
|
HANDLE CurrentProcessId;
|
|
|
|
PAGED_CODE();
|
|
|
|
CurrentThread = PsGetCurrentThread ();
|
|
|
|
//
|
|
// If the port is a server communication port then make sure that if
|
|
// there is a dangling client thread that we get rid of it. This
|
|
// handles the case of someone calling NtAcceptConnectPort and not
|
|
// calling NtCompleteConnectPort
|
|
//
|
|
|
|
if ((Port->Flags & PORT_TYPE) == SERVER_COMMUNICATION_PORT) {
|
|
|
|
PETHREAD ClientThread;
|
|
|
|
LpcpAcquireLpcpLockByThread(CurrentThread);
|
|
|
|
if ((ClientThread = Port->ClientThread) != NULL) {
|
|
|
|
Port->ClientThread = NULL;
|
|
|
|
LpcpReleaseLpcpLock();
|
|
|
|
ObDereferenceObject( ClientThread );
|
|
|
|
} else {
|
|
|
|
LpcpReleaseLpcpLock();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Send an LPC_PORT_CLOSED datagram to whoever is connected
|
|
// to this port so they know they are no longer connected.
|
|
//
|
|
|
|
if ((Port->Flags & PORT_TYPE) == CLIENT_COMMUNICATION_PORT) {
|
|
|
|
ClientPortClosedDatagram.PortMsg.u1.s1.TotalLength = sizeof( ClientPortClosedDatagram );
|
|
ClientPortClosedDatagram.PortMsg.u1.s1.DataLength = sizeof( ClientPortClosedDatagram.CreateTime );
|
|
|
|
ClientPortClosedDatagram.PortMsg.u2.s2.Type = LPC_PORT_CLOSED;
|
|
ClientPortClosedDatagram.PortMsg.u2.s2.DataInfoOffset = 0;
|
|
|
|
ClientPortClosedDatagram.CreateTime = PsGetCurrentProcess()->CreateTime;
|
|
|
|
LpcRequestPort( Port, (PPORT_MESSAGE)&ClientPortClosedDatagram );
|
|
}
|
|
|
|
//
|
|
// If connected, disconnect the port, and then scan the message queue
|
|
// for this port and dereference any messages in the queue.
|
|
//
|
|
|
|
LpcpDestroyPortQueue( Port, TRUE );
|
|
|
|
//
|
|
// If we had mapped sections into the server or client communication ports,
|
|
// we need to unmap them in the context of that process.
|
|
//
|
|
|
|
if ( (Port->ClientSectionBase != NULL) ||
|
|
(Port->ServerSectionBase != NULL) ) {
|
|
|
|
//
|
|
// If the client has a port memory view, then unmap it
|
|
//
|
|
|
|
if (Port->ClientSectionBase != NULL) {
|
|
|
|
MmUnmapViewOfSection( Port->MappingProcess,
|
|
Port->ClientSectionBase );
|
|
|
|
}
|
|
|
|
//
|
|
// If the server has a port memory view, then unmap it
|
|
//
|
|
|
|
if (Port->ServerSectionBase != NULL) {
|
|
|
|
MmUnmapViewOfSection( Port->MappingProcess,
|
|
Port->ServerSectionBase );
|
|
|
|
}
|
|
|
|
//
|
|
// Removing the reference added while mapping the section
|
|
//
|
|
|
|
ObDereferenceObject( Port->MappingProcess );
|
|
|
|
Port->MappingProcess = NULL;
|
|
}
|
|
|
|
//
|
|
// Dereference the pointer to the connection port if it is not
|
|
// this port.
|
|
//
|
|
|
|
LpcpAcquireLpcpLockByThread(CurrentThread);
|
|
|
|
ConnectionPort = Port->ConnectionPort;
|
|
|
|
if (ConnectionPort) {
|
|
|
|
CurrentProcessId = CurrentThread->Cid.UniqueProcess;
|
|
|
|
Head = &ConnectionPort->LpcDataInfoChainHead;
|
|
Next = Head->Flink;
|
|
|
|
while (Next != Head) {
|
|
|
|
Msg = CONTAINING_RECORD( Next, LPCP_MESSAGE, Entry );
|
|
Next = Next->Flink;
|
|
|
|
//
|
|
// Test whether the message come from the same port and process
|
|
//
|
|
|
|
if ((Msg->Request.ClientId.UniqueProcess == CurrentProcessId)
|
|
&&
|
|
((Msg->SenderPort == Port)
|
|
||
|
|
(Msg->SenderPort == Port->ConnectedPort)
|
|
||
|
|
(Msg->SenderPort == ConnectionPort))) {
|
|
|
|
LpcpTrace(( "%s Freeing DataInfo Message %lx (%u.%u) Port: %lx\n",
|
|
PsGetCurrentProcess()->ImageFileName,
|
|
Msg,
|
|
Msg->Request.MessageId,
|
|
Msg->Request.CallbackId,
|
|
ConnectionPort ));
|
|
|
|
RemoveEntryList( &Msg->Entry );
|
|
|
|
LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED );
|
|
|
|
//
|
|
// In LpcpFreeToPortZone the LPC lock is released and reacquired.
|
|
// Another thread might free the LPC message captured above
|
|
// in Next. We need to restart the search at the list head.
|
|
//
|
|
|
|
Next = Head->Flink;
|
|
}
|
|
}
|
|
|
|
LpcpReleaseLpcpLock();
|
|
|
|
if (ConnectionPort != Port) {
|
|
|
|
ObDereferenceObject( ConnectionPort );
|
|
}
|
|
|
|
} else {
|
|
|
|
LpcpReleaseLpcpLock();
|
|
}
|
|
|
|
if (((Port->Flags & PORT_TYPE) == SERVER_CONNECTION_PORT) &&
|
|
(ConnectionPort->ServerProcess != NULL)) {
|
|
|
|
ObDereferenceObject( ConnectionPort->ServerProcess );
|
|
|
|
ConnectionPort->ServerProcess = NULL;
|
|
}
|
|
|
|
//
|
|
// Free any static client security context
|
|
//
|
|
|
|
LpcpFreePortClientSecurity( Port );
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
VOID
|
|
LpcExitThread (
|
|
PETHREAD Thread
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine is called whenever a thread is exiting and need to cleanup the
|
|
lpc port for the thread.
|
|
|
|
Arguments:
|
|
|
|
Thread - Supplies the thread being terminated
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PLPCP_MESSAGE Msg;
|
|
|
|
//
|
|
// Acquire the mutex that protects the LpcReplyMessage field of
|
|
// the thread. Zero the field so nobody else tries to process it
|
|
// when we release the lock.
|
|
//
|
|
|
|
ASSERT (Thread == PsGetCurrentThread());
|
|
|
|
LpcpAcquireLpcpLockByThread(Thread);
|
|
|
|
if (!IsListEmpty( &Thread->LpcReplyChain )) {
|
|
|
|
RemoveEntryList( &Thread->LpcReplyChain );
|
|
}
|
|
|
|
//
|
|
// Indicate that this thread is exiting
|
|
//
|
|
|
|
Thread->LpcExitThreadCalled = TRUE;
|
|
Thread->LpcReplyMessageId = 0;
|
|
|
|
//
|
|
// If we need to reply to a message then if the thread that we need to reply
|
|
// to is still around we want to dereference the thread and free the message
|
|
//
|
|
|
|
Msg = LpcpGetThreadMessage(Thread);
|
|
|
|
if (Msg != NULL) {
|
|
|
|
Thread->LpcReplyMessage = NULL;
|
|
|
|
if (Msg->RepliedToThread != NULL) {
|
|
|
|
ObDereferenceObject( Msg->RepliedToThread );
|
|
|
|
Msg->RepliedToThread = NULL;
|
|
}
|
|
|
|
LpcpTrace(( "Cleanup Msg %lx (%d) for Thread %lx allocated\n", Msg, IsListEmpty( &Msg->Entry ), Thread ));
|
|
|
|
LpcpFreeToPortZone( Msg, LPCP_MUTEX_OWNED | LPCP_MUTEX_RELEASE_ON_RETURN );
|
|
}
|
|
else {
|
|
|
|
//
|
|
// Free the global lpc mutex.
|
|
//
|
|
|
|
LpcpReleaseLpcpLock();
|
|
}
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
return;
|
|
}
|