- Hold on to the disconnect IRP until all pending sending IRPs are sent to the transport driver if a controlled disconnect was requested

svn path=/trunk/; revision=52415
This commit is contained in:
Cameron Gutman 2011-06-22 00:17:19 +00:00
parent 379fa83099
commit d7a7a20e8b
3 changed files with 131 additions and 54 deletions

View file

@ -440,6 +440,7 @@ AfdCloseSocket(PDEVICE_OBJECT DeviceObject, PIRP Irp,
ASSERT(IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]));
ASSERT(IsListEmpty(&FCB->PendingIrpList[FUNCTION_RECV]));
ASSERT(IsListEmpty(&FCB->PendingIrpList[FUNCTION_PREACCEPT]));
ASSERT(IsListEmpty(&FCB->PendingIrpList[FUNCTION_DISCONNECT]))
while (!IsListEmpty(&FCB->PendingConnections))
{
@ -531,14 +532,108 @@ AfdCloseSocket(PDEVICE_OBJECT DeviceObject, PIRP Irp,
return STATUS_SUCCESS;
}
static
NTSTATUS
DoDisconnect(PAFD_FCB FCB, PIRP CurrentIrp)
{
PAFD_DISCONNECT_INFO DisReq;
IO_STATUS_BLOCK Iosb;
PTDI_CONNECTION_INFORMATION ConnectionReturnInfo;
PIO_STACK_LOCATION CurrentIrpSp;
USHORT Flags = 0;
NTSTATUS Status;
CurrentIrpSp = IoGetCurrentIrpStackLocation(CurrentIrp);
DisReq = GetLockedData(CurrentIrp, CurrentIrpSp);
if( DisReq->DisconnectType & AFD_DISCONNECT_SEND )
Flags |= TDI_DISCONNECT_RELEASE;
if( DisReq->DisconnectType & AFD_DISCONNECT_RECV ||
DisReq->DisconnectType & AFD_DISCONNECT_ABORT )
Flags |= TDI_DISCONNECT_ABORT;
Status = TdiBuildNullConnectionInfo(&ConnectionReturnInfo,
FCB->RemoteAddress->Address[0].AddressType);
if (NT_SUCCESS(Status))
{
FCB->ConnectInfo->UserData = FCB->DisconnectData;
FCB->ConnectInfo->UserDataLength = FCB->DisconnectDataSize;
FCB->ConnectInfo->Options = FCB->DisconnectOptions;
FCB->ConnectInfo->OptionsLength = FCB->DisconnectOptionsSize;
Status = TdiDisconnect(FCB->Connection.Object,
&DisReq->Timeout,
Flags,
&Iosb,
NULL,
NULL,
FCB->ConnectInfo,
ConnectionReturnInfo);
if (NT_SUCCESS(Status)) {
FCB->FilledDisconnectData = MIN(FCB->DisconnectDataSize, ConnectionReturnInfo->UserDataLength);
if (FCB->FilledDisconnectData)
{
RtlCopyMemory(FCB->DisconnectData,
ConnectionReturnInfo->UserData,
FCB->FilledDisconnectData);
}
FCB->FilledDisconnectOptions = MIN(FCB->DisconnectOptionsSize, ConnectionReturnInfo->OptionsLength);
if (FCB->FilledDisconnectOptions)
{
RtlCopyMemory(FCB->DisconnectOptions,
ConnectionReturnInfo->Options,
FCB->FilledDisconnectOptions);
}
}
ExFreePool( ConnectionReturnInfo );
if (Flags & TDI_DISCONNECT_RELEASE)
FCB->PollState |= AFD_EVENT_DISCONNECT;
else
FCB->PollState |= AFD_EVENT_ABORT;
FCB->PollStatus[FD_CLOSE_BIT] = Status;
PollReeval( FCB->DeviceExt, FCB->FileObject );
}
CurrentIrp->IoStatus.Status = Status;
CurrentIrp->IoStatus.Information = 0;
UnlockRequest(CurrentIrp, CurrentIrpSp);
(void)IoSetCancelRoutine(CurrentIrp, NULL);
IoCompleteRequest(CurrentIrp, IO_NETWORK_INCREMENT);
return Status;
}
VOID
RetryDisconnectCompletion(PAFD_FCB FCB)
{
if (IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]))
{
PIRP CurrentIrp;
PLIST_ENTRY CurrentEntry;
ASSERT(FCB->RemoteAddress);
while (!IsListEmpty(&FCB->PendingIrpList[FUNCTION_DISCONNECT]))
{
CurrentEntry = RemoveHeadList(&FCB->PendingIrpList[FUNCTION_DISCONNECT]);
CurrentIrp = CONTAINING_RECORD(CurrentEntry, IRP, Tail.Overlay.ListEntry);
DoDisconnect(FCB, CurrentIrp);
}
}
}
static NTSTATUS NTAPI
AfdDisconnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
PIO_STACK_LOCATION IrpSp) {
PFILE_OBJECT FileObject = IrpSp->FileObject;
PAFD_FCB FCB = FileObject->FsContext;
PAFD_DISCONNECT_INFO DisReq;
IO_STATUS_BLOCK Iosb;
PTDI_CONNECTION_INFORMATION ConnectionReturnInfo;
NTSTATUS Status = STATUS_SUCCESS;
USHORT Flags = 0;
@ -559,56 +654,23 @@ AfdDisconnect(PDEVICE_OBJECT DeviceObject, PIRP Irp,
if( !FCB->ConnectInfo )
return UnlockAndMaybeComplete( FCB, STATUS_INVALID_PARAMETER,
Irp, 0 );
ASSERT(FCB->RemoteAddress);
Status = TdiBuildNullConnectionInfo
( &ConnectionReturnInfo, FCB->RemoteAddress->Address[0].AddressType );
if( !NT_SUCCESS(Status) )
return UnlockAndMaybeComplete( FCB, Status,
Irp, 0 );
FCB->ConnectInfo->UserData = FCB->DisconnectData;
FCB->ConnectInfo->UserDataLength = FCB->DisconnectDataSize;
FCB->ConnectInfo->Options = FCB->DisconnectOptions;
FCB->ConnectInfo->OptionsLength = FCB->DisconnectOptionsSize;
Status = TdiDisconnect( FCB->Connection.Object,
&DisReq->Timeout,
Flags,
&Iosb,
NULL,
NULL,
FCB->ConnectInfo,
ConnectionReturnInfo);
if (NT_SUCCESS(Status)) {
FCB->FilledDisconnectData = MIN(FCB->DisconnectDataSize, ConnectionReturnInfo->UserDataLength);
if (FCB->FilledDisconnectData)
{
RtlCopyMemory(FCB->DisconnectData,
ConnectionReturnInfo->UserData,
FCB->FilledDisconnectData);
}
FCB->FilledDisconnectOptions = MIN(FCB->DisconnectOptionsSize, ConnectionReturnInfo->OptionsLength);
if (FCB->FilledDisconnectOptions)
{
RtlCopyMemory(FCB->DisconnectOptions,
ConnectionReturnInfo->Options,
FCB->FilledDisconnectOptions);
}
if (IsListEmpty(&FCB->PendingIrpList[FUNCTION_SEND]) || (Flags & TDI_DISCONNECT_ABORT))
{
/* Go ahead an execute the disconnect because we're ready for it */
Status = DoDisconnect(FCB, Irp);
/* DoDisconnect takes care of the IRP */
SocketStateUnlock(FCB);
return Status;
}
else
{
/* We have a graceful disconnect waiting on pending sends to complete */
return LeaveIrpUntilLater(FCB, Irp, FUNCTION_DISCONNECT);
}
ExFreePool( ConnectionReturnInfo );
if (Flags & TDI_DISCONNECT_RELEASE)
FCB->PollState |= AFD_EVENT_DISCONNECT;
else
FCB->PollState |= AFD_EVENT_ABORT;
FCB->PollStatus[FD_CLOSE_BIT] = STATUS_SUCCESS;
PollReeval( FCB->DeviceExt, FCB->FileObject );
}
else
{
@ -924,6 +986,10 @@ AfdCancelHandler(PDEVICE_OBJECT DeviceObject,
DbgPrint("WARNING!!! IRP cancellation race could lead to a process hang! (IOCTL_AFD_SELECT)\n");
return;
case IOCTL_AFD_DISCONNECT:
Function = FUNCTION_DISCONNECT;
break;
default:
ASSERT(FALSE);
UnlockAndMaybeComplete(FCB, STATUS_CANCELLED, Irp, 0);

View file

@ -59,8 +59,11 @@ static NTSTATUS NTAPI SendComplete
(void)IoSetCancelRoutine(NextIrp, NULL);
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
}
SocketStateUnlock( FCB );
return STATUS_FILE_CLOSED;
RetryDisconnectCompletion(FCB);
SocketStateUnlock( FCB );
return STATUS_FILE_CLOSED;
}
if( !NT_SUCCESS(Status) ) {
@ -85,6 +88,8 @@ static NTSTATUS NTAPI SendComplete
(void)IoSetCancelRoutine(NextIrp, NULL);
IoCompleteRequest( NextIrp, IO_NETWORK_INCREMENT );
}
RetryDisconnectCompletion(FCB);
SocketStateUnlock( FCB );
@ -164,6 +169,8 @@ static NTSTATUS NTAPI SendComplete
&FCB->SendIrp.Iosb,
SendComplete,
FCB );
RetryDisconnectCompletion(FCB);
} else {
FCB->PollState |= AFD_EVENT_SEND;
FCB->PollStatus[FD_WRITE_BIT] = STATUS_SUCCESS;
@ -410,6 +417,8 @@ AfdConnectedSocketWriteData(PDEVICE_OBJECT DeviceObject, PIRP Irp,
Status, TotalBytesCopied));
}
RetryDisconnectCompletion(FCB);
return UnlockAndMaybeComplete
( FCB, Status, Irp, TotalBytesCopied );
}

View file

@ -99,8 +99,9 @@ typedef struct IPADDR_ENTRY {
#define FUNCTION_SEND 2
#define FUNCTION_PREACCEPT 3
#define FUNCTION_ACCEPT 4
#define FUNCTION_CLOSE 5
#define MAX_FUNCTIONS 6
#define FUNCTION_DISCONNECT 5
#define FUNCTION_CLOSE 6
#define MAX_FUNCTIONS 7
#define IN_FLIGHT_REQUESTS 4
@ -309,6 +310,7 @@ NTSTATUS LeaveIrpUntilLater( PAFD_FCB FCB, PIRP Irp, UINT Function );
VOID DestroySocket( PAFD_FCB FCB );
VOID NTAPI AfdCancelHandler(PDEVICE_OBJECT DeviceObject,
PIRP Irp);
VOID RetryDisconnectCompletion(PAFD_FCB FCB);
/* read.c */