- 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)

svn path=/trunk/; revision=52503
This commit is contained in:
Cameron Gutman 2011-07-02 20:36:35 +00:00
parent f828c2431c
commit 0669007af7
5 changed files with 147 additions and 15 deletions

View file

@ -1696,7 +1696,7 @@ WSPShutdown(SOCKET Handle,
break;
}
DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1);
DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1000000);
/* Send IOCTL */
Status = NtDeviceIoControlFile((HANDLE)Handle,

View file

@ -138,6 +138,7 @@ NTSTATUS TCPConnect(
NTSTATUS TCPDisconnect(
PCONNECTION_ENDPOINT Connection,
UINT Flags,
PLARGE_INTEGER Timeout,
PTDI_CONNECTION_INFORMATION ConnInfo,
PTDI_CONNECTION_INFORMATION ReturnInfo,
PTCP_COMPLETION_ROUTINE Complete,

View file

@ -270,6 +270,10 @@ typedef struct _CONNECTION_ENDPOINT {
/* 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;

View file

@ -549,6 +549,7 @@ NTSTATUS DispTdiDisconnect(
Status = TCPDisconnect(
TranContext->Handle.ConnectionContext,
DisReq->RequestFlags,
DisReq->RequestSpecific,
DisReq->RequestConnectionInformation,
DisReq->ReturnConnectionInformation,
DispDataRequestComplete,

View file

@ -278,6 +278,11 @@ VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection)
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 @@ VOID HandleSignalledConnection(PCONNECTION_ENDPOINT Connection)
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,11 +376,13 @@ PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
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 @@ NTSTATUS TCPTranslateError( int OskitError ) {
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 TCPConnect
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 @@ NTSTATUS TCPDisconnect
PTDI_BUCKET Bucket;
KIRQL OldIrql;
PLIST_ENTRY Entry;
LARGE_INTEGER ActualTimeout;
TI_DbgPrint(DEBUG_TCP,("started\n"));
@ -740,6 +831,28 @@ NTSTATUS TCPDisconnect
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 @@ NTSTATUS TCPDisconnect
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);