From d7a7a20e8bf6f74c4ba850a7bd7247cda12aa757 Mon Sep 17 00:00:00 2001 From: Cameron Gutman Date: Wed, 22 Jun 2011 00:17:19 +0000 Subject: [PATCH] [AFD] - 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 --- reactos/drivers/network/afd/afd/main.c | 166 +++++++++++++++------- reactos/drivers/network/afd/afd/write.c | 13 +- reactos/drivers/network/afd/include/afd.h | 6 +- 3 files changed, 131 insertions(+), 54 deletions(-) diff --git a/reactos/drivers/network/afd/afd/main.c b/reactos/drivers/network/afd/afd/main.c index 45daed79b15..0d211d0a811 100644 --- a/reactos/drivers/network/afd/afd/main.c +++ b/reactos/drivers/network/afd/afd/main.c @@ -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); diff --git a/reactos/drivers/network/afd/afd/write.c b/reactos/drivers/network/afd/afd/write.c index b706b044f6b..af699ae8583 100644 --- a/reactos/drivers/network/afd/afd/write.c +++ b/reactos/drivers/network/afd/afd/write.c @@ -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 ); } diff --git a/reactos/drivers/network/afd/include/afd.h b/reactos/drivers/network/afd/include/afd.h index 0780cf975ee..82ad98d6362 100644 --- a/reactos/drivers/network/afd/include/afd.h +++ b/reactos/drivers/network/afd/include/afd.h @@ -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 */