489 lines
14 KiB
C
489 lines
14 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
close.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains code for cleanup and close IRPs.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David Treadwell (davidtr) 18-Mar-1992
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "afdp.h"
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text( PAGE, AfdClose )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdCleanup )
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdCleanup (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the routine that handles Cleanup IRPs in AFD.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Pointer to I/O request packet.
|
|||
|
|
|||
|
IrpSp - pointer to the IO stack location to use for this request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
KIRQL oldIrql1, oldIrql2;
|
|||
|
KIRQL cancelIrql;
|
|||
|
PLIST_ENTRY listEntry;
|
|||
|
LARGE_INTEGER processExitTime;
|
|||
|
|
|||
|
endpoint = IrpSp->FileObject->FsContext;
|
|||
|
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
|||
|
|
|||
|
IF_DEBUG(OPEN_CLOSE) {
|
|||
|
KdPrint((
|
|||
|
"AfdCleanup: cleanup on file object %lx, endpoint %lx, connection %lx\n",
|
|||
|
IrpSp->FileObject,
|
|||
|
endpoint,
|
|||
|
AFD_CONNECTION_FROM_ENDPOINT( endpoint )
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Get the process exit time while still at low IRQL.
|
|||
|
//
|
|||
|
|
|||
|
processExitTime = PsGetProcessExitTime( );
|
|||
|
|
|||
|
//
|
|||
|
// Indicate that there was a local close on this endpoint. If there
|
|||
|
// are any outstanding polls on this endpoint, they will be
|
|||
|
// completed now.
|
|||
|
//
|
|||
|
AfdIndicatePollEvent(
|
|||
|
endpoint,
|
|||
|
AFD_POLL_LOCAL_CLOSE_BIT,
|
|||
|
STATUS_SUCCESS
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Remember that the endpoint has been cleaned up. This is important
|
|||
|
// because it allows AfdRestartAccept to know that the endpoint has
|
|||
|
// been cleaned up and that it should toss the connection.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql1 );
|
|||
|
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql2 );
|
|||
|
|
|||
|
ASSERT( endpoint->EndpointCleanedUp == FALSE );
|
|||
|
endpoint->EndpointCleanedUp = TRUE;
|
|||
|
|
|||
|
connection = AFD_CONNECTION_FROM_ENDPOINT( endpoint );
|
|||
|
ASSERT( connection == NULL || connection->Type == AfdBlockTypeConnection );
|
|||
|
|
|||
|
//
|
|||
|
// Complete any outstanding wait for listen IRPs on the endpoint.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->Type == AfdBlockTypeVcListening ) {
|
|||
|
|
|||
|
while ( !IsListEmpty( &endpoint->Common.VcListening.ListeningIrpListHead ) ) {
|
|||
|
|
|||
|
PIRP waitForListenIrp;
|
|||
|
|
|||
|
listEntry = RemoveHeadList( &endpoint->Common.VcListening.ListeningIrpListHead );
|
|||
|
waitForListenIrp = CONTAINING_RECORD(
|
|||
|
listEntry,
|
|||
|
IRP,
|
|||
|
Tail.Overlay.ListEntry
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Release the AFD spin lock so that we can complete the
|
|||
|
// wait for listen IRP.
|
|||
|
//
|
|||
|
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
AfdReleaseSpinLock( &AfdSpinLock, oldIrql1 );
|
|||
|
|
|||
|
//
|
|||
|
// Cancel the IRP.
|
|||
|
//
|
|||
|
|
|||
|
waitForListenIrp->IoStatus.Status = STATUS_CANCELLED;
|
|||
|
waitForListenIrp->IoStatus.Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Reset the cancel routine in the IRP.
|
|||
|
//
|
|||
|
|
|||
|
IoAcquireCancelSpinLock( &cancelIrql );
|
|||
|
IoSetCancelRoutine( waitForListenIrp, NULL );
|
|||
|
IoReleaseCancelSpinLock( cancelIrql );
|
|||
|
|
|||
|
IoCompleteRequest( waitForListenIrp, AfdPriorityBoost );
|
|||
|
|
|||
|
//
|
|||
|
// Reacquire the AFD spin lock for the next pass through the
|
|||
|
// loop.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql1 );
|
|||
|
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql2 );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free all queued (free, unaccepted, and returned) connections
|
|||
|
// on the endpoint.
|
|||
|
//
|
|||
|
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
AfdReleaseSpinLock( &AfdSpinLock, oldIrql1 );
|
|||
|
AfdFreeQueuedConnections( endpoint );
|
|||
|
AfdAcquireSpinLock( &AfdSpinLock, &oldIrql1 );
|
|||
|
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql2 );
|
|||
|
endpoint->Common.VcListening.FailedConnectionAdds = 0;
|
|||
|
}
|
|||
|
|
|||
|
UPDATE_CONN( connection, 0 );
|
|||
|
|
|||
|
//
|
|||
|
// If this is a connected non-datagram socket and the send side has
|
|||
|
// not been disconnected and there is no outstanding data to be
|
|||
|
// received, begin a graceful disconnect on the connection. If there
|
|||
|
// is unreceived data out outstanding IO, abort the connection.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->State == AfdEndpointStateConnected && connection != NULL
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
!IS_DGRAM_ENDPOINT(endpoint)
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
( (endpoint->DisconnectMode & AFD_ABORTIVE_DISCONNECT) == 0)
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
( (endpoint->DisconnectMode & AFD_PARTIAL_DISCONNECT_SEND) == 0 ||
|
|||
|
( !endpoint->TdiBufferring &&
|
|||
|
connection->Common.NonBufferring.ReceiveBytesInTransport > 0 ) )
|
|||
|
|
|||
|
&&
|
|||
|
|
|||
|
!connection->AbortIndicated ) {
|
|||
|
|
|||
|
ASSERT( endpoint->Type == AfdBlockTypeVcConnecting );
|
|||
|
|
|||
|
if ( IS_DATA_ON_CONNECTION( connection )
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
IS_EXPEDITED_DATA_ON_CONNECTION( connection )
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
processExitTime.QuadPart != 0
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
endpoint->OutstandingIrpCount != 0
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
( !endpoint->TdiBufferring &&
|
|||
|
(!IsListEmpty( &connection->VcReceiveIrpListHead ) ||
|
|||
|
!IsListEmpty( &connection->VcSendIrpListHead )) )
|
|||
|
|
|||
|
) {
|
|||
|
|
|||
|
#if DBG
|
|||
|
if ( IS_DATA_ON_CONNECTION( connection ) ) {
|
|||
|
KdPrint(( "AfdCleanup: unrecv'd data on endp %lx, aborting. "
|
|||
|
"%ld ind, %ld taken, %ld out\n",
|
|||
|
endpoint,
|
|||
|
connection->Common.Bufferring.ReceiveBytesIndicated,
|
|||
|
connection->Common.Bufferring.ReceiveBytesTaken,
|
|||
|
connection->Common.Bufferring.ReceiveBytesOutstanding ));
|
|||
|
}
|
|||
|
|
|||
|
if ( IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
|
|||
|
KdPrint(( "AfdCleanup: unrecv'd exp data on endp %lx, aborting. "
|
|||
|
"%ld ind, %ld taken, %ld out\n",
|
|||
|
endpoint,
|
|||
|
connection->Common.Bufferring.ReceiveExpeditedBytesIndicated,
|
|||
|
connection->Common.Bufferring.ReceiveExpeditedBytesTaken,
|
|||
|
connection->Common.Bufferring.ReceiveExpeditedBytesOutstanding ));
|
|||
|
}
|
|||
|
|
|||
|
if ( processExitTime.QuadPart != 0 ) {
|
|||
|
KdPrint(( "AfdCleanup: process exiting w/o closesocket, "
|
|||
|
"aborting endp %lx\n", endpoint ));
|
|||
|
}
|
|||
|
|
|||
|
if ( endpoint->OutstandingIrpCount != 0 ) {
|
|||
|
KdPrint(( "AfdCleanup: 3 IRPs outstanding on endpoint %lx, "
|
|||
|
"aborting.\n", endpoint ));
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
AfdReleaseSpinLock( &AfdSpinLock, oldIrql1 );
|
|||
|
|
|||
|
(VOID)AfdBeginAbort( connection );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
endpoint->DisconnectMode |= AFD_PARTIAL_DISCONNECT_RECEIVE;
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
AfdReleaseSpinLock( &AfdSpinLock, oldIrql1 );
|
|||
|
|
|||
|
(VOID)AfdBeginDisconnect( endpoint, NULL, NULL );
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
AfdReleaseSpinLock( &AfdSpinLock, oldIrql1 );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this a datagram endpoint, cancel all IRPs and free any buffers
|
|||
|
// of data. Note that if the state of the endpoint is just "open"
|
|||
|
// (not bound, etc.) then we can't have any pended IRPs or datagrams
|
|||
|
// on the endpoint. Also, the lists of IRPs and datagrams may not
|
|||
|
// yet been initialized if the state is just open.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->State != AfdEndpointStateOpen &&
|
|||
|
endpoint->Type == AfdBlockTypeDatagram ) {
|
|||
|
|
|||
|
//
|
|||
|
// Reset the counts of datagrams bufferred on the endpoint.
|
|||
|
// This prevents anyone from thinking that there is bufferred
|
|||
|
// data on the endpoint.
|
|||
|
//
|
|||
|
|
|||
|
endpoint->BufferredDatagramCount = 0;
|
|||
|
endpoint->BufferredDatagramBytes = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Cancel all receive datagram and peek datagram IRPs on the
|
|||
|
// endpoint.
|
|||
|
//
|
|||
|
|
|||
|
AfdCompleteIrpList(
|
|||
|
&endpoint->ReceiveDatagramIrpListHead,
|
|||
|
&endpoint->SpinLock,
|
|||
|
STATUS_CANCELLED,
|
|||
|
AfdCleanupReceiveDatagramIrp
|
|||
|
);
|
|||
|
|
|||
|
AfdCompleteIrpList(
|
|||
|
&endpoint->PeekDatagramIrpListHead,
|
|||
|
&endpoint->SpinLock,
|
|||
|
STATUS_CANCELLED,
|
|||
|
AfdCleanupReceiveDatagramIrp
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is a datagram endpoint, return the process quota which we
|
|||
|
// charged when the endpoint was created.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->Type == AfdBlockTypeDatagram ) {
|
|||
|
|
|||
|
PsReturnPoolQuota(
|
|||
|
endpoint->OwningProcess,
|
|||
|
NonPagedPool,
|
|||
|
endpoint->Common.Datagram.MaxBufferredSendBytes +
|
|||
|
endpoint->Common.Datagram.MaxBufferredReceiveBytes
|
|||
|
);
|
|||
|
AfdRecordQuotaHistory(
|
|||
|
endpoint->OwningProcess,
|
|||
|
-(LONG)(endpoint->Common.Datagram.MaxBufferredSendBytes +
|
|||
|
endpoint->Common.Datagram.MaxBufferredReceiveBytes),
|
|||
|
"Cleanup dgrm",
|
|||
|
endpoint
|
|||
|
);
|
|||
|
AfdRecordPoolQuotaReturned(
|
|||
|
endpoint->Common.Datagram.MaxBufferredSendBytes +
|
|||
|
endpoint->Common.Datagram.MaxBufferredReceiveBytes
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If this is a connected VC endpoint on a nonbufferring TDI provider,
|
|||
|
// cancel all outstanding send and receive IRPs.
|
|||
|
//
|
|||
|
|
|||
|
if ( connection != NULL ) {
|
|||
|
|
|||
|
if ( !endpoint->TdiBufferring ) {
|
|||
|
|
|||
|
AfdCompleteIrpList(
|
|||
|
&connection->VcReceiveIrpListHead,
|
|||
|
&endpoint->SpinLock,
|
|||
|
STATUS_CANCELLED,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
AfdCompleteIrpList(
|
|||
|
&connection->VcSendIrpListHead,
|
|||
|
&endpoint->SpinLock,
|
|||
|
STATUS_CANCELLED,
|
|||
|
NULL
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remember that we have started cleanup on this connection.
|
|||
|
// We know that we'll never get a request on the connection
|
|||
|
// after we start cleanup on the connection.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql2 );
|
|||
|
connection->CleanupBegun = TRUE;
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
|
|||
|
//
|
|||
|
// Attempt to remove the connected reference.
|
|||
|
//
|
|||
|
|
|||
|
AfdDeleteConnectedReference( connection, FALSE );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// If there is a transmit IRP on the endpoint, cancel it.
|
|||
|
//
|
|||
|
|
|||
|
IoAcquireCancelSpinLock( &cancelIrql );
|
|||
|
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql2 );
|
|||
|
|
|||
|
if ( endpoint->TransmitIrp != NULL ) {
|
|||
|
endpoint->TransmitIrp->CancelIrql = cancelIrql;
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
AfdCancelTransmit( NULL, endpoint->TransmitIrp );
|
|||
|
} else {
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql2 );
|
|||
|
IoReleaseCancelSpinLock( cancelIrql );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Remember the new state of the endpoint.
|
|||
|
//
|
|||
|
|
|||
|
//endpoint->State = AfdEndpointStateCleanup;
|
|||
|
|
|||
|
//
|
|||
|
// Reset relevent event handlers on the endpoint. This prevents
|
|||
|
// getting indications after we free the endpoint and connection
|
|||
|
// objects. We should not be able to get new connects after this
|
|||
|
// handle has been cleaned up.
|
|||
|
//
|
|||
|
// Note that these calls can fail if, for example, DHCP changes the
|
|||
|
// host's IP address while the endpoint is active.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->AddressHandle != NULL ) {
|
|||
|
|
|||
|
if ( endpoint->State == AfdEndpointStateListening ) {
|
|||
|
status = AfdSetEventHandler(
|
|||
|
endpoint->AddressFileObject,
|
|||
|
TDI_EVENT_CONNECT,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
//ASSERT( NT_SUCCESS(status) );
|
|||
|
}
|
|||
|
|
|||
|
if ( IS_DGRAM_ENDPOINT(endpoint) ) {
|
|||
|
status = AfdSetEventHandler(
|
|||
|
endpoint->AddressFileObject,
|
|||
|
TDI_EVENT_RECEIVE_DATAGRAM,
|
|||
|
NULL,
|
|||
|
NULL
|
|||
|
);
|
|||
|
//ASSERT( NT_SUCCESS(status) );
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&AfdEndpointsCleanedUp
|
|||
|
);
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // AfdCleanup
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdClose (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This is the routine that handles Close IRPs in AFD. It
|
|||
|
dereferences the endpoint specified in the IRP, which will result in
|
|||
|
the endpoint being freed when all other references go away.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - Pointer to I/O request packet.
|
|||
|
|
|||
|
IrpSp - pointer to the IO stack location to use for this request.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
NTSTATUS -- Indicates whether the request was successfully queued.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
endpoint = IrpSp->FileObject->FsContext;
|
|||
|
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
|||
|
|
|||
|
IF_DEBUG(OPEN_CLOSE) {
|
|||
|
KdPrint(( "AfdClose: closing file object %lx, endpoint %lx\n",
|
|||
|
IrpSp->FileObject, endpoint ));
|
|||
|
}
|
|||
|
|
|||
|
AfdCloseEndpoint( endpoint );
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // AfdClose
|