Author: cgutman Date: Sat Jul 2 20:36:35 2011 New Revision: 52503
URL: http://svn.reactos.org/svn/reactos?rev=52503&view=rev Log: [TCPIP] - Implement support for timing out disconnects - Add debug prints for oskittcp errors [MSAFD] - Set a disconnect timeout value that actually makes sense (1 second vs 100 nanoseconds)
Modified: trunk/reactos/dll/win32/msafd/misc/dllmain.c trunk/reactos/drivers/network/tcpip/include/tcp.h trunk/reactos/drivers/network/tcpip/include/titypes.h trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c trunk/reactos/lib/drivers/ip/transport/tcp/tcp.c
Modified: trunk/reactos/dll/win32/msafd/misc/dllmain.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/dll/win32/msafd/misc/dllmai... ============================================================================== --- trunk/reactos/dll/win32/msafd/misc/dllmain.c [iso-8859-1] (original) +++ trunk/reactos/dll/win32/msafd/misc/dllmain.c [iso-8859-1] Sat Jul 2 20:36:35 2011 @@ -1696,7 +1696,7 @@ break; }
- DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1); + DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1000000);
/* Send IOCTL */ Status = NtDeviceIoControlFile((HANDLE)Handle,
Modified: trunk/reactos/drivers/network/tcpip/include/tcp.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/network/tcpip/inclu... ============================================================================== --- trunk/reactos/drivers/network/tcpip/include/tcp.h [iso-8859-1] (original) +++ trunk/reactos/drivers/network/tcpip/include/tcp.h [iso-8859-1] Sat Jul 2 20:36:35 2011 @@ -138,6 +138,7 @@ NTSTATUS TCPDisconnect( PCONNECTION_ENDPOINT Connection, UINT Flags, + PLARGE_INTEGER Timeout, PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete,
Modified: trunk/reactos/drivers/network/tcpip/include/titypes.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/network/tcpip/inclu... ============================================================================== --- trunk/reactos/drivers/network/tcpip/include/titypes.h [iso-8859-1] (original) +++ trunk/reactos/drivers/network/tcpip/include/titypes.h [iso-8859-1] Sat Jul 2 20:36:35 2011 @@ -270,6 +270,10 @@
/* Signals */ UINT SignalState; /* Active signals from oskit */ + + /* Disconnect Timer */ + KTIMER DisconnectTimer; + KDPC DisconnectDpc;
struct _CONNECTION_ENDPOINT *Next; /* Next connection in address file list */ } CONNECTION_ENDPOINT, *PCONNECTION_ENDPOINT;
Modified: trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/drivers/network/tcpip/tcpip... ============================================================================== --- trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c [iso-8859-1] (original) +++ trunk/reactos/drivers/network/tcpip/tcpip/dispatch.c [iso-8859-1] Sat Jul 2 20:36:35 2011 @@ -549,6 +549,7 @@ Status = TCPDisconnect( TranContext->Handle.ConnectionContext, DisReq->RequestFlags, + DisReq->RequestSpecific, DisReq->RequestConnectionInformation, DisReq->ReturnConnectionInformation, DispDataRequestComplete,
Modified: trunk/reactos/lib/drivers/ip/transport/tcp/tcp.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/ip/transport/tc... ============================================================================== --- trunk/reactos/lib/drivers/ip/transport/tcp/tcp.c [iso-8859-1] (original) +++ trunk/reactos/lib/drivers/ip/transport/tcp/tcp.c [iso-8859-1] Sat Jul 2 20:36:35 2011 @@ -278,6 +278,11 @@ TI_DbgPrint(DEBUG_TCP, ("Completing shutdown request: %x %x\n", Bucket->Request, Status)); + + if (KeCancelTimer(&Connection->DisconnectTimer)) + { + DereferenceObject(Connection); + }
Bucket->Status = Status; Bucket->Information = 0; @@ -297,6 +302,49 @@ UnlockObjectFromDpcLevel(Connection); }
+VOID NTAPI +DisconnectTimeoutDpc(PKDPC Dpc, + PVOID DeferredContext, + PVOID SystemArgument1, + PVOID SystemArgument2) +{ + PCONNECTION_ENDPOINT Connection = DeferredContext; + PLIST_ENTRY Entry; + PTDI_BUCKET Bucket; + + LockObjectAtDpcLevel(Connection); + + /* We timed out waiting for pending sends so force it to shutdown */ + OskitTCPShutdown(Connection->SocketContext, FWRITE); + + while (!IsListEmpty(&Connection->SendRequest)) + { + Entry = RemoveHeadList(&Connection->SendRequest); + + Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); + + Bucket->Information = 0; + Bucket->Status = STATUS_FILE_CLOSED; + + CompleteBucket(Connection, Bucket); + } + + while (!IsListEmpty(&Connection->ShutdownRequest)) { + Entry = RemoveHeadList( &Connection->ShutdownRequest ); + + Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry ); + + Bucket->Status = STATUS_TIMEOUT; + Bucket->Information = 0; + + CompleteBucket(Connection, Bucket); + } + + UnlockObjectFromDpcLevel(Connection); + + DereferenceObject(Connection); +} + VOID ConnectionFree(PVOID Object) { PCONNECTION_ENDPOINT Connection = Object; KIRQL OldIrql; @@ -328,10 +376,12 @@ InitializeListHead(&Connection->ReceiveRequest); InitializeListHead(&Connection->SendRequest); InitializeListHead(&Connection->ShutdownRequest); + + KeInitializeTimer(&Connection->DisconnectTimer); + KeInitializeDpc(&Connection->DisconnectDpc, DisconnectTimeoutDpc, Connection);
/* Save client context pointer */ Connection->ClientContext = ClientContext; -
Connection->RefCount = 2; Connection->Free = ConnectionFree; @@ -569,22 +619,61 @@
switch( OskitError ) { case 0: Status = STATUS_SUCCESS; break; - case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break; - case OSK_EADDRINUSE: Status = STATUS_ADDRESS_ALREADY_EXISTS; break; - case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break; - case OSK_ECONNREFUSED: Status = STATUS_REMOTE_NOT_LISTENING; break; - case OSK_ECONNRESET: Status = STATUS_REMOTE_DISCONNECT; break; - case OSK_ECONNABORTED: Status = STATUS_LOCAL_DISCONNECT; break; + case OSK_EADDRNOTAVAIL: + Status = STATUS_INVALID_ADDRESS; + DbgPrint("OskitTCP: EADDRNOTAVAIL\n"); + break; + case OSK_EADDRINUSE: + Status = STATUS_ADDRESS_ALREADY_EXISTS; + DbgPrint("OskitTCP: EADDRINUSE\n"); + break; + case OSK_EAFNOSUPPORT: + Status = STATUS_INVALID_CONNECTION; + DbgPrint("OskitTCP: EAFNOSUPPORT\n"); + break; + case OSK_ECONNREFUSED: + Status = STATUS_REMOTE_NOT_LISTENING; + DbgPrint("OskitTCP: ECONNREFUSED\n"); + break; + case OSK_ECONNRESET: + Status = STATUS_REMOTE_DISCONNECT; + DbgPrint("OskitTCP: ECONNRESET\n"); + break; + case OSK_ECONNABORTED: + Status = STATUS_LOCAL_DISCONNECT; + DbgPrint("OskitTCP: ECONNABORTED\n"); + break; case OSK_EWOULDBLOCK: case OSK_EINPROGRESS: Status = STATUS_PENDING; break; - case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; break; + case OSK_EINVAL: + Status = STATUS_INVALID_PARAMETER; + DbgPrint("OskitTCP: EINVAL\n"); + break; case OSK_ENOMEM: - case OSK_ENOBUFS: Status = STATUS_INSUFFICIENT_RESOURCES; break; - case OSK_ESHUTDOWN: Status = STATUS_FILE_CLOSED; break; - case OSK_EMSGSIZE: Status = STATUS_BUFFER_TOO_SMALL; break; - case OSK_ETIMEDOUT: Status = STATUS_TIMEOUT; break; - case OSK_ENETUNREACH: Status = STATUS_NETWORK_UNREACHABLE; break; - case OSK_EFAULT: Status = STATUS_ACCESS_VIOLATION; break; + case OSK_ENOBUFS: + Status = STATUS_INSUFFICIENT_RESOURCES; + DbgPrint("OskitTCP: ENOMEM/ENOBUFS\n"); + break; + case OSK_ESHUTDOWN: + Status = STATUS_FILE_CLOSED; + DbgPrint("OskitTCP: ESHUTDOWN\n"); + break; + case OSK_EMSGSIZE: + Status = STATUS_BUFFER_TOO_SMALL; + DbgPrint("OskitTCP: EMSGSIZE\n"); + break; + case OSK_ETIMEDOUT: + Status = STATUS_TIMEOUT; + DbgPrint("OskitTCP: ETIMEDOUT\n"); + break; + case OSK_ENETUNREACH: + Status = STATUS_NETWORK_UNREACHABLE; + DbgPrint("OskitTCP: ENETUNREACH\n"); + break; + case OSK_EFAULT: + Status = STATUS_ACCESS_VIOLATION; + DbgPrint("OskitTCP: EFAULT\n"); + break; default: DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError); Status = STATUS_INVALID_CONNECTION; @@ -714,6 +803,7 @@ NTSTATUS TCPDisconnect ( PCONNECTION_ENDPOINT Connection, UINT Flags, + PLARGE_INTEGER Timeout, PTDI_CONNECTION_INFORMATION ConnInfo, PTDI_CONNECTION_INFORMATION ReturnInfo, PTCP_COMPLETION_ROUTINE Complete, @@ -722,6 +812,7 @@ PTDI_BUCKET Bucket; KIRQL OldIrql; PLIST_ENTRY Entry; + LARGE_INTEGER ActualTimeout;
TI_DbgPrint(DEBUG_TCP,("started\n"));
@@ -740,6 +831,28 @@ return Status; }
+ /* Check if the timeout was 0 */ + if (Timeout && Timeout->QuadPart == 0) + { + OskitTCPShutdown(Connection->SocketContext, FWRITE); + + while (!IsListEmpty(&Connection->SendRequest)) + { + Entry = RemoveHeadList(&Connection->SendRequest); + + Bucket = CONTAINING_RECORD(Entry, TDI_BUCKET, Entry); + + Bucket->Information = 0; + Bucket->Status = STATUS_FILE_CLOSED; + + CompleteBucket(Connection, Bucket); + } + + UnlockObject(Connection, OldIrql); + + return STATUS_TIMEOUT; + } + /* Otherwise we wait for the send queue to be empty */ }
@@ -803,6 +916,19 @@ Bucket->Request.RequestContext = Context;
InsertTailList(&Connection->ShutdownRequest, &Bucket->Entry); + + /* Use the timeout specified or 1 second if none was specified */ + if (Timeout) + { + ActualTimeout = *Timeout; + } + else + { + ActualTimeout.QuadPart = -1000000; + } + + ReferenceObject(Connection); + KeSetTimer(&Connection->DisconnectTimer, ActualTimeout, &Connection->DisconnectDpc);
UnlockObject(Connection, OldIrql);