mirror of
https://github.com/reactos/reactos.git
synced 2025-08-02 06:15:52 +00:00
[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) svn path=/trunk/; revision=52503
This commit is contained in:
parent
f828c2431c
commit
0669007af7
5 changed files with 147 additions and 15 deletions
|
@ -1696,7 +1696,7 @@ WSPShutdown(SOCKET Handle,
|
|||
break;
|
||||
}
|
||||
|
||||
DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1);
|
||||
DisconnectInfo.Timeout = RtlConvertLongToLargeInteger(-1000000);
|
||||
|
||||
/* Send IOCTL */
|
||||
Status = NtDeviceIoControlFile((HANDLE)Handle,
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -549,6 +549,7 @@ NTSTATUS DispTdiDisconnect(
|
|||
Status = TCPDisconnect(
|
||||
TranContext->Handle.ConnectionContext,
|
||||
DisReq->RequestFlags,
|
||||
DisReq->RequestSpecific,
|
||||
DisReq->RequestConnectionInformation,
|
||||
DisReq->ReturnConnectionInformation,
|
||||
DispDataRequestComplete,
|
||||
|
|
|
@ -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);
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue