1474 lines
36 KiB
C
1474 lines
36 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
accept.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module contains the handling code for IOCTL_AFD_ACCEPT.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
David Treadwell (davidtr) 21-Feb-1992
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "afdp.h"
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdAcceptCore (
|
|||
|
IN PAFD_ENDPOINT ListenEndpoint,
|
|||
|
IN PAFD_ENDPOINT AcceptEndpoint,
|
|||
|
IN ULONG Sequence
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AfdDoListenBacklogReplenish (
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
VOID
|
|||
|
AfdReplenishListenBacklog (
|
|||
|
IN PAFD_ENDPOINT Endpoint
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptGetAddress (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptListen (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptReceive (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
);
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text( PAGE, AfdAccept )
|
|||
|
#pragma alloc_text( PAGE, AfdSuperAccept )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdDeferAccept )
|
|||
|
#pragma alloc_text( PAGE, AfdDoListenBacklogReplenish )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdAcceptCore )
|
|||
|
#pragma alloc_text( PAGE, AfdReplenishListenBacklog )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdInitiateListenBacklogReplenish )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptListen )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptGetAddress )
|
|||
|
#pragma alloc_text( PAGEAFD, AfdRestartSuperAcceptReceive )
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Accepts an incoming connection. The connection is identified by the
|
|||
|
sequence number returned in the wait for listen IRP, and then
|
|||
|
associated with the endpoint specified in this request. When this
|
|||
|
request completes, the connection is fully established and ready for
|
|||
|
data transfer.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - a pointer to a transmit file IRP.
|
|||
|
|
|||
|
IrpSp - Our stack location for this IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the request was completed successfully, or a
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PAFD_ACCEPT_INFO acceptInfo;
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
PFILE_OBJECT acceptEndpointFileObject;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
//
|
|||
|
// Set up local variables.
|
|||
|
//
|
|||
|
|
|||
|
endpoint = IrpSp->FileObject->FsContext;
|
|||
|
ASSERT( endpoint->Type == AfdBlockTypeVcListening );
|
|||
|
acceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that this request is valid.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->Type != AfdBlockTypeVcListening ||
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_ACCEPT_INFO) ) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Add another free connection to replace the one we're accepting.
|
|||
|
// Also, add extra to account for past failures in calls to
|
|||
|
// AfdAddFreeConnection().
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
AfdReplenishListenBacklog( endpoint );
|
|||
|
|
|||
|
//
|
|||
|
// Obtain a pointer to the endpoint on which we're going to
|
|||
|
// accept the connection.
|
|||
|
//
|
|||
|
|
|||
|
status = ObReferenceObjectByHandle(
|
|||
|
acceptInfo->AcceptHandle,
|
|||
|
0L, // DesiredAccess
|
|||
|
*IoFileObjectType,
|
|||
|
KernelMode,
|
|||
|
(PVOID *)&acceptEndpointFileObject,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
acceptEndpoint = acceptEndpointFileObject->FsContext;
|
|||
|
|
|||
|
//
|
|||
|
// We may have a file object that is not an AFD endpoint. Make sure
|
|||
|
// that this is an actual AFD endpoint.
|
|||
|
//
|
|||
|
|
|||
|
if ( acceptEndpoint->Type != AfdBlockTypeEndpoint ) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
ObDereferenceObject( acceptEndpointFileObject );
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
|
|||
|
|
|||
|
IF_DEBUG(ACCEPT) {
|
|||
|
KdPrint(( "AfdAccept: file object %lx, accept endpoint %lx, "
|
|||
|
"listen endpoint %lx\n",
|
|||
|
acceptEndpointFileObject, acceptEndpoint, endpoint ));
|
|||
|
}
|
|||
|
|
|||
|
status = AfdAcceptCore( endpoint, acceptEndpoint, acceptInfo->Sequence );
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( acceptEndpointFileObject );
|
|||
|
|
|||
|
complete:
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
ASSERT( Irp->CancelRoutine == NULL );
|
|||
|
|
|||
|
IoCompleteRequest( Irp, AfdPriorityBoost );
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
} // AfdAccept
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdAcceptCore (
|
|||
|
IN PAFD_ENDPOINT ListenEndpoint,
|
|||
|
IN PAFD_ENDPOINT AcceptEndpoint,
|
|||
|
IN ULONG Sequence
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Performs the key functions of associating a connection accepted
|
|||
|
on a listening endpoint with a new endpoint.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ListenEndpoint - the listening endpoint for the connection.
|
|||
|
|
|||
|
AcceptEndpoint - the new endpoint with which to associate the
|
|||
|
connectuion.
|
|||
|
|
|||
|
Sequence - the sequence number which identifies the accepted
|
|||
|
connection.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the operation was completed successfully, or a
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
KIRQL oldIrql;
|
|||
|
ULONG eventsActive;
|
|||
|
|
|||
|
//
|
|||
|
// Fail if the accepting endpoint is not in the correct state.
|
|||
|
//
|
|||
|
|
|||
|
if ( AcceptEndpoint->State != AfdEndpointStateOpen ) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Store the local address of the accept endpoint from the listening
|
|||
|
// endpoint. This keeps the address unusable as long as the accept
|
|||
|
// endpoint is active.
|
|||
|
//
|
|||
|
// If the endpoint already has a local address structure that is
|
|||
|
// sufficiently large, reuse it.
|
|||
|
//
|
|||
|
|
|||
|
if ( AcceptEndpoint->LocalAddress != NULL &&
|
|||
|
AcceptEndpoint->LocalAddressLength <
|
|||
|
ListenEndpoint->LocalAddressLength ) {
|
|||
|
|
|||
|
AFD_FREE_POOL(
|
|||
|
AcceptEndpoint->LocalAddress,
|
|||
|
AFD_LOCAL_ADDRESS_POOL_TAG
|
|||
|
);
|
|||
|
AcceptEndpoint->LocalAddress = NULL;
|
|||
|
}
|
|||
|
|
|||
|
if ( AcceptEndpoint->LocalAddress == NULL ) {
|
|||
|
|
|||
|
AcceptEndpoint->LocalAddress = AFD_ALLOCATE_POOL(
|
|||
|
NonPagedPool,
|
|||
|
ListenEndpoint->LocalAddressLength,
|
|||
|
AFD_LOCAL_ADDRESS_POOL_TAG
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
AcceptEndpoint->LocalAddressLength = ListenEndpoint->LocalAddressLength;
|
|||
|
|
|||
|
|
|||
|
if ( AcceptEndpoint->LocalAddress == NULL ) {
|
|||
|
return STATUS_INSUFFICIENT_RESOURCES;
|
|||
|
}
|
|||
|
|
|||
|
RtlCopyMemory(
|
|||
|
AcceptEndpoint->LocalAddress,
|
|||
|
ListenEndpoint->LocalAddress,
|
|||
|
ListenEndpoint->LocalAddressLength
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Find the connection on which the accept is being performed.
|
|||
|
//
|
|||
|
|
|||
|
connection = AfdGetReturnedConnection( ListenEndpoint, Sequence );
|
|||
|
|
|||
|
if ( connection == NULL ) {
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( connection->Type == AfdBlockTypeConnection );
|
|||
|
|
|||
|
//
|
|||
|
// Reenable the accept event bit, and if there are additional
|
|||
|
// unaccepted connections on the endpoint, post another event.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock( &ListenEndpoint->SpinLock, &oldIrql );
|
|||
|
|
|||
|
ListenEndpoint->EventsActive &= ~AFD_POLL_ACCEPT;
|
|||
|
|
|||
|
IF_DEBUG(EVENT_SELECT) {
|
|||
|
KdPrint((
|
|||
|
"AfdAcceptCore: Endp %08lX, Active %08lX\n",
|
|||
|
ListenEndpoint,
|
|||
|
ListenEndpoint->EventsActive
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
if( !IsListEmpty( &ListenEndpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
|
|||
|
|
|||
|
AfdIndicateEventSelectEvent(
|
|||
|
ListenEndpoint,
|
|||
|
AFD_POLL_ACCEPT_BIT,
|
|||
|
STATUS_SUCCESS
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
AfdReleaseSpinLock( &ListenEndpoint->SpinLock, oldIrql );
|
|||
|
|
|||
|
//
|
|||
|
// Recheck the state of the accepting endpoint under the guard
|
|||
|
// of the endpoint's spinlock.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock( &AcceptEndpoint->SpinLock, &oldIrql );
|
|||
|
|
|||
|
if ( AcceptEndpoint->State != AfdEndpointStateOpen ||
|
|||
|
AcceptEndpoint->EndpointCleanedUp ) {
|
|||
|
AfdReleaseSpinLock( &AcceptEndpoint->SpinLock, oldIrql );
|
|||
|
|
|||
|
//
|
|||
|
// The accepted endpoint has been closed, so go ahead and
|
|||
|
// abort the incoming connection.
|
|||
|
//
|
|||
|
|
|||
|
AfdAbortConnection( connection );
|
|||
|
return STATUS_INVALID_PARAMETER;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Note that the returned connection structure already has a
|
|||
|
// referenced pointer to the listening endpoint. Rather than
|
|||
|
// removing the reference here, only to re-add it later, we'll
|
|||
|
// just not touch the reference count.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( connection->Endpoint == ListenEndpoint );
|
|||
|
|
|||
|
//
|
|||
|
// Set up the accept endpoint's type, and remember blocking
|
|||
|
// characteristics of the TDI provider.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->Type = AfdBlockTypeVcConnecting;
|
|||
|
AcceptEndpoint->TdiBufferring = ListenEndpoint->TdiBufferring;
|
|||
|
|
|||
|
//
|
|||
|
// Place the connection on the endpoint we'll accept it on. It is
|
|||
|
// still referenced from when it was created.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->Common.VcConnecting.Connection = connection;
|
|||
|
|
|||
|
//
|
|||
|
// Set up a referenced pointer from the connection to the accept
|
|||
|
// endpoint.
|
|||
|
//
|
|||
|
|
|||
|
REFERENCE_ENDPOINT( AcceptEndpoint );
|
|||
|
connection->Endpoint = AcceptEndpoint;
|
|||
|
|
|||
|
//
|
|||
|
// Set up a referenced pointer to the listening endpoint. This is
|
|||
|
// necessary so that the endpoint does not go away until all
|
|||
|
// accepted endpoints have gone away. Without this, a connect
|
|||
|
// indication could occur on a TDI address object held open
|
|||
|
// by an accepted endpoint after the listening endpoint has
|
|||
|
// been closed and the memory for it deallocated.
|
|||
|
//
|
|||
|
// Note that, since we didn't remove the reference above, we don't
|
|||
|
// need to add it here.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->Common.VcConnecting.ListenEndpoint = ListenEndpoint;
|
|||
|
|
|||
|
//
|
|||
|
// Set the endpoint to the connected state.
|
|||
|
//
|
|||
|
|
|||
|
AcceptEndpoint->State = AfdEndpointStateConnected;
|
|||
|
|
|||
|
//
|
|||
|
// Set up a referenced pointer in the accepted endpoint to the
|
|||
|
// TDI address object.
|
|||
|
//
|
|||
|
|
|||
|
ObReferenceObject( ListenEndpoint->AddressFileObject );
|
|||
|
AfdRecordAddrRef();
|
|||
|
|
|||
|
AcceptEndpoint->AddressFileObject = ListenEndpoint->AddressFileObject;
|
|||
|
AcceptEndpoint->AddressDeviceObject = ListenEndpoint->AddressDeviceObject;
|
|||
|
|
|||
|
//
|
|||
|
// Setup the active event bits on the accepted endpoint. We'll start with
|
|||
|
// the ones in the listening endpoint, as these are the OR of all active
|
|||
|
// bits for the listening endpoint and all unaccepted connections.
|
|||
|
//
|
|||
|
// Note that we don't actually signal the events here, as the DLL will
|
|||
|
// invoke WSAEventSelect() if necessary on the socket while processing
|
|||
|
// the accept() API.
|
|||
|
//
|
|||
|
|
|||
|
eventsActive = ListenEndpoint->EventsActive;
|
|||
|
|
|||
|
if( eventsActive & AFD_POLL_RECEIVE ) {
|
|||
|
|
|||
|
if( !IS_DATA_ON_CONNECTION( connection ) &&
|
|||
|
( !AcceptEndpoint->InLine ||
|
|||
|
!IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) ) {
|
|||
|
|
|||
|
eventsActive &= ~AFD_POLL_RECEIVE;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( eventsActive & AFD_POLL_RECEIVE_EXPEDITED ) {
|
|||
|
|
|||
|
if( AcceptEndpoint->InLine ||
|
|||
|
!IS_EXPEDITED_DATA_ON_CONNECTION( connection ) ) {
|
|||
|
|
|||
|
eventsActive &= ~AFD_POLL_RECEIVE_EXPEDITED;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( eventsActive & AFD_POLL_DISCONNECT ) {
|
|||
|
|
|||
|
if( !connection->DisconnectIndicated ) {
|
|||
|
|
|||
|
eventsActive &= ~AFD_POLL_DISCONNECT;
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
if( eventsActive & AFD_POLL_ABORT ) {
|
|||
|
|
|||
|
if( !connection->AbortIndicated ) {
|
|||
|
|
|||
|
eventsActive &= ~AFD_POLL_ABORT;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
AcceptEndpoint->EventsActive = eventsActive | AFD_POLL_SEND;
|
|||
|
|
|||
|
IF_DEBUG(EVENT_SELECT) {
|
|||
|
KdPrint((
|
|||
|
"AfdAcceptCore: Endp %08lX, Active %08lX\n",
|
|||
|
AcceptEndpoint,
|
|||
|
AcceptEndpoint->EventsActive
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
AfdReleaseSpinLock( &AcceptEndpoint->SpinLock, oldIrql );
|
|||
|
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // AfdAcceptCore
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdInitiateListenBacklogReplenish (
|
|||
|
IN PAFD_ENDPOINT Endpoint
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Queues a work item to begin replenishing the listen backlog
|
|||
|
on a listening endpoint.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - the listening endpoint on which to replenish the
|
|||
|
backlog.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_WORK_ITEM afdWorkItem;
|
|||
|
|
|||
|
//
|
|||
|
// Reference the endpoint so that it won't go away until we're
|
|||
|
// done with it.
|
|||
|
//
|
|||
|
|
|||
|
REFERENCE_ENDPOINT( Endpoint );
|
|||
|
|
|||
|
//
|
|||
|
// Queue a work item to an executive worker thread.
|
|||
|
//
|
|||
|
|
|||
|
afdWorkItem = AfdAllocateWorkItem();
|
|||
|
ASSERT( afdWorkItem != NULL );
|
|||
|
|
|||
|
afdWorkItem->Context = Endpoint;
|
|||
|
|
|||
|
AfdQueueWorkItem(
|
|||
|
AfdDoListenBacklogReplenish,
|
|||
|
afdWorkItem
|
|||
|
);
|
|||
|
|
|||
|
} // AfdInitiateListenBacklogReplenish
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdDoListenBacklogReplenish (
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The worker routine for replenishing the listen backlog on a
|
|||
|
listening endpoint. This routine only runs in the context of
|
|||
|
an executive worker thread.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Context - Points to an AFD_WORK_ITEM structure. The Context field
|
|||
|
of this structure points to the endpoint on which to replenish
|
|||
|
the listen backlog.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
PAFD_WORK_ITEM afdWorkItem;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
ASSERT( Context != NULL );
|
|||
|
|
|||
|
afdWorkItem = Context;
|
|||
|
endpoint = (PAFD_ENDPOINT)afdWorkItem->Context;
|
|||
|
|
|||
|
AfdFreeWorkItem( afdWorkItem );
|
|||
|
|
|||
|
ASSERT( endpoint->Type == AfdBlockTypeVcListening );
|
|||
|
|
|||
|
//
|
|||
|
// If the endpoint's state changed, don't replenish the backlog.
|
|||
|
//
|
|||
|
|
|||
|
if ( endpoint->State != AfdEndpointStateListening ) {
|
|||
|
DEREFERENCE_ENDPOINT( endpoint );
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fill up the free connection backlog.
|
|||
|
//
|
|||
|
|
|||
|
AfdReplenishListenBacklog( endpoint );
|
|||
|
|
|||
|
//
|
|||
|
// Clean up and return.
|
|||
|
//
|
|||
|
|
|||
|
DEREFERENCE_ENDPOINT( endpoint );
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // AfdDoListenBacklogReplenish
|
|||
|
|
|||
|
|
|||
|
VOID
|
|||
|
AfdReplenishListenBacklog (
|
|||
|
IN PAFD_ENDPOINT Endpoint
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Does the actual work of filling up the listen backlog on a listening
|
|||
|
endpoint.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Endpoint - the listening endpoint on which to replenish the
|
|||
|
listen backlog.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
None--any errors are ignored and the backlog may be refilled
|
|||
|
at a later time.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
LONG result;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
ASSERT( Endpoint->Type == AfdBlockTypeVcListening );
|
|||
|
|
|||
|
|
|||
|
//
|
|||
|
// Decrement the count of failed connection additions.
|
|||
|
//
|
|||
|
|
|||
|
result = InterlockedDecrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Continue opening new free conections until we've hit the
|
|||
|
// backlog or a connection open fails.
|
|||
|
//
|
|||
|
// If the result of the decrement is negative, then we are either
|
|||
|
// all set on the connection count or else have available extra
|
|||
|
// connection objects on the listening endpoint. These connections
|
|||
|
// have been reused from prior connections which have now
|
|||
|
// terminated.
|
|||
|
//
|
|||
|
|
|||
|
while ( result >= 0 ) {
|
|||
|
|
|||
|
status = AfdAddFreeConnection( Endpoint );
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
IF_DEBUG(ACCEPT) {
|
|||
|
KdPrint(( "AfdReplenishListenBacklog: AfdAddFreeConnection failed: %X, "
|
|||
|
"fail count = %ld\n", status,
|
|||
|
Endpoint->Common.VcListening.FailedConnectionAdds ));
|
|||
|
}
|
|||
|
|
|||
|
return;
|
|||
|
}
|
|||
|
|
|||
|
result = InterlockedDecrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Correct the counter to reflect the number of connections
|
|||
|
// we have available. Then just return from here.
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&Endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
return;
|
|||
|
|
|||
|
} // AfdReplenishListenBacklog
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdSuperAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Initial entrypoint for handling super accept IRPs. A super accept
|
|||
|
combines several operations for high-performance connection
|
|||
|
acceptance. The combined operations are waiting for an incoming
|
|||
|
connection, accepting it, retrieving the local and remote socket
|
|||
|
addresses, and receiving the first chunk of data on the connection.
|
|||
|
|
|||
|
This routine verifies parameters, initializes data structures to be
|
|||
|
used for the request, and initiates the I/O.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - a pointer to a transmit file IRP.
|
|||
|
|
|||
|
IrpSp - Our stack location for this IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_PENDING if the request was initiated successfully, or a
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PAFD_SUPER_ACCEPT_INFO superAcceptInfo = NULL;
|
|||
|
NTSTATUS status;
|
|||
|
PIO_STACK_LOCATION nextIrpSp;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
//
|
|||
|
// Set up local variables.
|
|||
|
//
|
|||
|
|
|||
|
listenEndpoint = IrpSp->FileObject->FsContext;
|
|||
|
superAcceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
//
|
|||
|
// Validate the input information. The input buffer must be large
|
|||
|
// enough to hold all the input information, plus some extra to use
|
|||
|
// here to hold the local address. The output buffer must be
|
|||
|
// non-NULL and large enough to hold the specified information.
|
|||
|
//
|
|||
|
//
|
|||
|
|
|||
|
if ( listenEndpoint->Type != AfdBlockTypeVcListening
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_SUPER_ACCEPT_INFO)
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_SUPER_ACCEPT_INFO) + superAcceptInfo->LocalAddressLength
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
Irp->MdlAddress == NULL
|
|||
|
|
|||
|
||
|
|||
|
|
|||
|
IrpSp->Parameters.DeviceIoControl.OutputBufferLength <
|
|||
|
superAcceptInfo->ReceiveDataLength +
|
|||
|
superAcceptInfo->LocalAddressLength +
|
|||
|
superAcceptInfo->RemoteAddressLength ) {
|
|||
|
|
|||
|
#if DBG
|
|||
|
if( listenEndpoint->Type != AfdBlockTypeVcListening ) {
|
|||
|
KdPrint((
|
|||
|
"AfdSuperAccept: non-listening endpoint @ %08lX\n",
|
|||
|
listenEndpoint
|
|||
|
));
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
superAcceptInfo = NULL;
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Obtain a pointer to the endpoint on which we're going to
|
|||
|
// accept the connection.
|
|||
|
//
|
|||
|
|
|||
|
status = ObReferenceObjectByHandle(
|
|||
|
superAcceptInfo->AcceptHandle,
|
|||
|
0L, // DesiredAccess
|
|||
|
*IoFileObjectType,
|
|||
|
KernelMode,
|
|||
|
&superAcceptInfo->AcceptFileObject,
|
|||
|
NULL
|
|||
|
);
|
|||
|
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
superAcceptInfo = NULL;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
acceptFileObject = superAcceptInfo->AcceptFileObject;
|
|||
|
acceptEndpoint = acceptFileObject->FsContext;
|
|||
|
|
|||
|
superAcceptInfo->AcceptEndpoint = acceptEndpoint;
|
|||
|
|
|||
|
//
|
|||
|
// We may have a file object that is not an AFD endpoint. Make sure
|
|||
|
// that this is an actual AFD endpoint.
|
|||
|
//
|
|||
|
|
|||
|
if ( acceptEndpoint->Type != AfdBlockTypeEndpoint ) {
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( InterlockedIncrement( &acceptEndpoint->ObReferenceBias ) > 0 );
|
|||
|
|
|||
|
//
|
|||
|
// Add another free connection to replace the one we're accepting.
|
|||
|
// Also, add extra to account for past failures in calls to
|
|||
|
// AfdAddFreeConnection().
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
AfdReplenishListenBacklog( listenEndpoint );
|
|||
|
|
|||
|
//
|
|||
|
// Start off by building a AFD_WAIT_FOR_LISTEN_LIFO IRP, using the current
|
|||
|
// IRP and the next stack location on it.
|
|||
|
//
|
|||
|
|
|||
|
nextIrpSp = IoGetNextIrpStackLocation( Irp );
|
|||
|
|
|||
|
Irp->AssociatedIrp.SystemBuffer = &superAcceptInfo->ListenResponseInfo;
|
|||
|
nextIrpSp->FileObject = IrpSp->FileObject;
|
|||
|
nextIrpSp->DeviceObject = IoGetRelatedDeviceObject( IrpSp->FileObject );
|
|||
|
nextIrpSp->MajorFunction = IRP_MJ_DEVICE_CONTROL;
|
|||
|
|
|||
|
|
|||
|
nextIrpSp->Parameters.DeviceIoControl.OutputBufferLength =
|
|||
|
sizeof(AFD_LISTEN_RESPONSE_INFO) + superAcceptInfo->RemoteAddressLength;
|
|||
|
nextIrpSp->Parameters.DeviceIoControl.InputBufferLength = 0;
|
|||
|
nextIrpSp->Parameters.DeviceIoControl.IoControlCode = IOCTL_AFD_WAIT_FOR_LISTEN_LIFO;
|
|||
|
|
|||
|
IoSetCompletionRoutine(
|
|||
|
Irp,
|
|||
|
AfdRestartSuperAcceptListen,
|
|||
|
superAcceptInfo,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Perform the listen wait. We'll continue processing from the
|
|||
|
// completion routine.
|
|||
|
//
|
|||
|
|
|||
|
IoCallDriver( IrpSp->DeviceObject, Irp );
|
|||
|
|
|||
|
return STATUS_PENDING;
|
|||
|
|
|||
|
complete:
|
|||
|
|
|||
|
if ( superAcceptInfo != NULL ) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
}
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
IoCompleteRequest( Irp, 0 );
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
} // AfdSuperAccept
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptListen (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD wait for listen IRP portion
|
|||
|
of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Context - points to the super accept request information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_ENDPOINT listenEndpoint;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
PAFD_SUPER_ACCEPT_INFO superAcceptInfo;
|
|||
|
NTSTATUS status;
|
|||
|
PIO_STACK_LOCATION irpSp;
|
|||
|
ULONG bytesCopied;
|
|||
|
PMDL mdl;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
superAcceptInfo = Context;
|
|||
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|||
|
listenEndpoint = irpSp->FileObject->FsContext;
|
|||
|
acceptEndpoint = superAcceptInfo->AcceptEndpoint;
|
|||
|
|
|||
|
//
|
|||
|
// If pending has been returned for this irp then mark the current
|
|||
|
// stack as pending.
|
|||
|
//
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Fix up the system buffer pointer in the IRP.
|
|||
|
//
|
|||
|
|
|||
|
ASSERT( Irp->AssociatedIrp.SystemBuffer == &superAcceptInfo->ListenResponseInfo );
|
|||
|
Irp->AssociatedIrp.SystemBuffer = superAcceptInfo;
|
|||
|
|
|||
|
//
|
|||
|
// If the IRP failed, quit processing.
|
|||
|
//
|
|||
|
|
|||
|
if ( !NT_SUCCESS(Irp->IoStatus.Status) ) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
InterlockedDecrement(
|
|||
|
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
return Irp->IoStatus.Status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Copy over the address information to the user's buffer.
|
|||
|
//
|
|||
|
|
|||
|
status = TdiCopyBufferToMdl(
|
|||
|
&superAcceptInfo->ListenResponseInfo.RemoteAddress,
|
|||
|
0,
|
|||
|
superAcceptInfo->RemoteAddressLength,
|
|||
|
Irp->MdlAddress,
|
|||
|
superAcceptInfo->ReceiveDataLength +
|
|||
|
superAcceptInfo->LocalAddressLength,
|
|||
|
&bytesCopied
|
|||
|
);
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
InterlockedDecrement(
|
|||
|
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
return status;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now do the actual connection acceptance.
|
|||
|
//
|
|||
|
|
|||
|
status = AfdAcceptCore(
|
|||
|
listenEndpoint,
|
|||
|
acceptEndpoint,
|
|||
|
superAcceptInfo->ListenResponseInfo.Sequence
|
|||
|
);
|
|||
|
if ( !NT_SUCCESS(status) ) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
InterlockedDecrement(
|
|||
|
&listenEndpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// The AFD connection object should now be in the endpoiont.
|
|||
|
//
|
|||
|
|
|||
|
connection = AFD_CONNECTION_FROM_ENDPOINT( acceptEndpoint );
|
|||
|
ASSERT( connection != NULL );
|
|||
|
|
|||
|
//
|
|||
|
// The endpoint is now connected and ready to go. Get the local
|
|||
|
// address for the connection. We'll need an MDL to map the portion
|
|||
|
// of the user buffer that will receive the local address.
|
|||
|
//
|
|||
|
|
|||
|
mdl = IoAllocateMdl(
|
|||
|
(PCHAR)MmGetMdlVirtualAddress( Irp->MdlAddress ) + superAcceptInfo->ReceiveDataLength,
|
|||
|
superAcceptInfo->LocalAddressLength,
|
|||
|
FALSE,
|
|||
|
FALSE,
|
|||
|
NULL
|
|||
|
);
|
|||
|
if ( mdl == NULL ) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Set up this new MDL to describe the appropriate portion of the
|
|||
|
// buffer.
|
|||
|
//
|
|||
|
|
|||
|
IoBuildPartialMdl(
|
|||
|
Irp->MdlAddress,
|
|||
|
mdl,
|
|||
|
(PCHAR)MmGetMdlVirtualAddress( Irp->MdlAddress ) + superAcceptInfo->ReceiveDataLength,
|
|||
|
superAcceptInfo->LocalAddressLength
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Set up the IRP to query the local address of this endpoint. We'll
|
|||
|
// hold on to the original MDL value in the AcceptHandle field, which
|
|||
|
// we don't need any longer.
|
|||
|
//
|
|||
|
|
|||
|
superAcceptInfo->AcceptHandle = (HANDLE)Irp->MdlAddress;
|
|||
|
Irp->MdlAddress = mdl;
|
|||
|
|
|||
|
TdiBuildQueryInformation(
|
|||
|
Irp,
|
|||
|
connection->DeviceObject,
|
|||
|
connection->FileObject,
|
|||
|
AfdRestartSuperAcceptGetAddress,
|
|||
|
superAcceptInfo,
|
|||
|
TDI_QUERY_ADDRESS_INFO,
|
|||
|
Irp->MdlAddress
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Perform the local address query. We'll continue processing from
|
|||
|
// the completion routine.
|
|||
|
//
|
|||
|
|
|||
|
IoCallDriver( connection->DeviceObject, Irp );
|
|||
|
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
|
|||
|
} // AfdRestartSuperAcceptListen
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptGetAddress (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD wait for query local address
|
|||
|
portion of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Context - points to the super accept request information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_SUPER_ACCEPT_INFO superAcceptInfo;
|
|||
|
PAFD_ENDPOINT acceptEndpoint;
|
|||
|
PIO_STACK_LOCATION nextIrpSp;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
PMDL partialMdl;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
superAcceptInfo = Context;
|
|||
|
acceptEndpoint = superAcceptInfo->AcceptEndpoint;
|
|||
|
acceptFileObject = superAcceptInfo->AcceptFileObject;
|
|||
|
|
|||
|
//
|
|||
|
// If pending has been returned for this irp then mark the current
|
|||
|
// stack as pending.
|
|||
|
//
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the MDL we temporarily allocated and fix up the MDL pointer
|
|||
|
// in the IRP.
|
|||
|
//
|
|||
|
|
|||
|
IoFreeMdl( Irp->MdlAddress );
|
|||
|
|
|||
|
Irp->MdlAddress = (PMDL)superAcceptInfo->AcceptHandle;
|
|||
|
|
|||
|
//
|
|||
|
// If the caller didn't want to receive any data on the connection,
|
|||
|
// or if the query for the local address failed, then we're done
|
|||
|
// now.
|
|||
|
//
|
|||
|
|
|||
|
if ( superAcceptInfo->ReceiveDataLength == 0 ||
|
|||
|
!NT_SUCCESS( Irp->IoStatus.Status ) ) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Create a partial MDL describing the portion of the user's buffer
|
|||
|
// to be used for receive data. Note that we cannot use the entire
|
|||
|
// user's buffer, as the end of the buffer is used for the local and
|
|||
|
// remote addresses.
|
|||
|
//
|
|||
|
|
|||
|
partialMdl = IoAllocateMdl(
|
|||
|
MmGetMdlVirtualAddress( Irp->MdlAddress ),
|
|||
|
superAcceptInfo->ReceiveDataLength,
|
|||
|
FALSE, // SecondaryBuffer
|
|||
|
FALSE, // ChargeQuota
|
|||
|
NULL // Irp
|
|||
|
);
|
|||
|
|
|||
|
if( partialMdl == NULL ) {
|
|||
|
ASSERT( InterlockedDecrement( &acceptEndpoint->ObReferenceBias ) >= 0 );
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
return STATUS_SUCCESS;
|
|||
|
}
|
|||
|
|
|||
|
IoBuildPartialMdl(
|
|||
|
Irp->MdlAddress,
|
|||
|
partialMdl,
|
|||
|
MmGetMdlVirtualAddress( Irp->MdlAddress ),
|
|||
|
superAcceptInfo->ReceiveDataLength
|
|||
|
);
|
|||
|
|
|||
|
Irp->MdlAddress = partialMdl;
|
|||
|
|
|||
|
//
|
|||
|
// Prepare the IRP to be used to receive the first chunk of data on
|
|||
|
// the connection.
|
|||
|
//
|
|||
|
// Also note that we send ourselves an IRP_MJ_READ IRP because
|
|||
|
// the I/O subsystem has already probed & locked the output buffer,
|
|||
|
// which just happens to look just like an IRP_MJ_READ IRP.
|
|||
|
//
|
|||
|
|
|||
|
nextIrpSp = IoGetNextIrpStackLocation( Irp );
|
|||
|
|
|||
|
nextIrpSp->FileObject = acceptFileObject;
|
|||
|
nextIrpSp->DeviceObject = IoGetRelatedDeviceObject( acceptFileObject );
|
|||
|
nextIrpSp->MajorFunction = IRP_MJ_READ;
|
|||
|
|
|||
|
nextIrpSp->Parameters.Read.Length = superAcceptInfo->ReceiveDataLength;
|
|||
|
nextIrpSp->Parameters.Read.Key = 0;
|
|||
|
nextIrpSp->Parameters.Read.ByteOffset.QuadPart = 0;
|
|||
|
|
|||
|
IoSetCompletionRoutine(
|
|||
|
Irp,
|
|||
|
AfdRestartSuperAcceptReceive,
|
|||
|
superAcceptInfo,
|
|||
|
TRUE,
|
|||
|
TRUE,
|
|||
|
TRUE
|
|||
|
);
|
|||
|
|
|||
|
//
|
|||
|
// Perform the receive. We'll continue processing from
|
|||
|
// the completion routine.
|
|||
|
//
|
|||
|
|
|||
|
IoCallDriver( nextIrpSp->DeviceObject, Irp );
|
|||
|
|
|||
|
return STATUS_MORE_PROCESSING_REQUIRED;
|
|||
|
|
|||
|
} // AfdRestartSuperAcceptGetAddress
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdRestartSuperAcceptReceive (
|
|||
|
IN PDEVICE_OBJECT DeviceObject,
|
|||
|
IN PIRP Irp,
|
|||
|
IN PVOID Context
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
The completion routine for the AFD receive portion of a super accept.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
DeviceObject - the devoce object on which the request is completing.
|
|||
|
|
|||
|
Irp - The super accept IRP.
|
|||
|
|
|||
|
Context - points to the super accept request information.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the I/O system should complete the super accept
|
|||
|
request, or STATUS_MORE_PROCESSING_REQUIRED if the super accept
|
|||
|
request is still being processed.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
PAFD_SUPER_ACCEPT_INFO superAcceptInfo;
|
|||
|
PIO_STACK_LOCATION nextIrpSp;
|
|||
|
PFILE_OBJECT acceptFileObject;
|
|||
|
|
|||
|
//
|
|||
|
// Initialize some locals.
|
|||
|
//
|
|||
|
|
|||
|
superAcceptInfo = Context;
|
|||
|
acceptFileObject = superAcceptInfo->AcceptFileObject;
|
|||
|
|
|||
|
//
|
|||
|
// If pending has been returned for this irp then mark the current
|
|||
|
// stack as pending.
|
|||
|
//
|
|||
|
|
|||
|
if ( Irp->PendingReturned ) {
|
|||
|
IoMarkIrpPending( Irp );
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Free the partial MDL we temporarily allocated and fix up the
|
|||
|
// MDL pointer in the IRP.
|
|||
|
//
|
|||
|
|
|||
|
IoFreeMdl( Irp->MdlAddress );
|
|||
|
|
|||
|
Irp->MdlAddress = (PMDL)superAcceptInfo->AcceptHandle;
|
|||
|
|
|||
|
//
|
|||
|
// Dereference the accept file object and tell IO to complete this IRP.
|
|||
|
//
|
|||
|
|
|||
|
#if DBG
|
|||
|
{
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
|
|||
|
endpoint = ((PFILE_OBJECT)superAcceptInfo->AcceptFileObject)->FsContext;
|
|||
|
ASSERT( endpoint != NULL );
|
|||
|
ASSERT( IS_AFD_ENDPOINT_TYPE( endpoint ) );
|
|||
|
|
|||
|
ASSERT( InterlockedDecrement( &endpoint->ObReferenceBias ) >= 0 );
|
|||
|
}
|
|||
|
#endif
|
|||
|
|
|||
|
ObDereferenceObject( superAcceptInfo->AcceptFileObject );
|
|||
|
return STATUS_SUCCESS;
|
|||
|
|
|||
|
} // AfdRestartSuperAcceptReceive
|
|||
|
|
|||
|
|
|||
|
NTSTATUS
|
|||
|
AfdDeferAccept (
|
|||
|
IN PIRP Irp,
|
|||
|
IN PIO_STACK_LOCATION IrpSp
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
Defers acceptance of an incoming connection for which an
|
|||
|
AFD_WAIT_FOR_LISTEN IOCTL has already completed. The caller
|
|||
|
may specify that the connection be deferred for later acceptance
|
|||
|
or rejected totally.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
Irp - a pointer to a transmit file IRP.
|
|||
|
|
|||
|
IrpSp - Our stack location for this IRP.
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
STATUS_SUCCESS if the request was completed successfully, or a
|
|||
|
failure status code if there was an error.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
NTSTATUS status;
|
|||
|
PAFD_DEFER_ACCEPT_INFO deferAcceptInfo;
|
|||
|
PAFD_ENDPOINT endpoint;
|
|||
|
PAFD_CONNECTION connection;
|
|||
|
KIRQL oldIrql;
|
|||
|
|
|||
|
PAGED_CODE( );
|
|||
|
|
|||
|
//
|
|||
|
// Set up local variables.
|
|||
|
//
|
|||
|
|
|||
|
endpoint = IrpSp->FileObject->FsContext;
|
|||
|
ASSERT( endpoint->Type == AfdBlockTypeVcListening );
|
|||
|
deferAcceptInfo = Irp->AssociatedIrp.SystemBuffer;
|
|||
|
|
|||
|
Irp->IoStatus.Information = 0;
|
|||
|
|
|||
|
//
|
|||
|
// Make sure that this request is valid.
|
|||
|
//
|
|||
|
|
|||
|
if( endpoint->Type != AfdBlockTypeVcListening ||
|
|||
|
IrpSp->Parameters.DeviceIoControl.InputBufferLength <
|
|||
|
sizeof(AFD_DEFER_ACCEPT_INFO) ) {
|
|||
|
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Find the specified connection. If it cannot be found, then this
|
|||
|
// is a bogus request.
|
|||
|
//
|
|||
|
|
|||
|
connection = AfdGetReturnedConnection(
|
|||
|
endpoint,
|
|||
|
deferAcceptInfo->Sequence
|
|||
|
);
|
|||
|
|
|||
|
if( connection == NULL ) {
|
|||
|
|
|||
|
status = STATUS_INVALID_PARAMETER;
|
|||
|
goto complete;
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
ASSERT( connection->Type == AfdBlockTypeConnection );
|
|||
|
|
|||
|
//
|
|||
|
// If this is a request to reject the accepted connection, then
|
|||
|
// abort the connection. Otherwise (this is a request to defer
|
|||
|
// acceptance until later) then insert the connection at the *head*
|
|||
|
// of the endpoint's unaccepted connection queue.
|
|||
|
//
|
|||
|
|
|||
|
if( deferAcceptInfo->Reject ) {
|
|||
|
|
|||
|
//
|
|||
|
// Abort the connection.
|
|||
|
//
|
|||
|
|
|||
|
AfdAbortConnection( connection );
|
|||
|
|
|||
|
//
|
|||
|
// Reenable the accept event bit, and if there are additional
|
|||
|
// unaccepted connections on the endpoint, post another event.
|
|||
|
//
|
|||
|
|
|||
|
AfdAcquireSpinLock( &endpoint->SpinLock, &oldIrql );
|
|||
|
|
|||
|
endpoint->EventsActive &= ~AFD_POLL_ACCEPT;
|
|||
|
|
|||
|
IF_DEBUG(EVENT_SELECT) {
|
|||
|
KdPrint((
|
|||
|
"AfdDeferAccept: Endp %08lX, Active %08lX\n",
|
|||
|
endpoint,
|
|||
|
endpoint->EventsActive
|
|||
|
));
|
|||
|
}
|
|||
|
|
|||
|
if( !IsListEmpty( &endpoint->Common.VcListening.UnacceptedConnectionListHead ) ) {
|
|||
|
|
|||
|
AfdIndicateEventSelectEvent(
|
|||
|
endpoint,
|
|||
|
AFD_POLL_ACCEPT_BIT,
|
|||
|
STATUS_SUCCESS
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
AfdReleaseSpinLock( &endpoint->SpinLock, oldIrql );
|
|||
|
|
|||
|
//
|
|||
|
// Add another free connection to replace the one we're rejecting.
|
|||
|
// Also, add extra to account for past failures in calls to
|
|||
|
// AfdAddFreeConnection().
|
|||
|
//
|
|||
|
|
|||
|
InterlockedIncrement(
|
|||
|
&endpoint->Common.VcListening.FailedConnectionAdds
|
|||
|
);
|
|||
|
|
|||
|
AfdReplenishListenBacklog( endpoint );
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
//
|
|||
|
// Restore the connection's state before putting it back
|
|||
|
// on the queue.
|
|||
|
//
|
|||
|
|
|||
|
connection->State = AfdConnectionStateUnaccepted;
|
|||
|
|
|||
|
ExInterlockedInsertHeadList(
|
|||
|
&endpoint->Common.VcListening.UnacceptedConnectionListHead,
|
|||
|
&connection->ListEntry,
|
|||
|
&AfdSpinLock
|
|||
|
);
|
|||
|
|
|||
|
}
|
|||
|
|
|||
|
status = STATUS_SUCCESS;
|
|||
|
|
|||
|
complete:
|
|||
|
|
|||
|
Irp->IoStatus.Status = status;
|
|||
|
ASSERT( Irp->CancelRoutine == NULL );
|
|||
|
|
|||
|
IoCompleteRequest( Irp, AfdPriorityBoost );
|
|||
|
|
|||
|
return status;
|
|||
|
|
|||
|
} // AfdDeferAccept
|
|||
|
|