- Rework our oskittcp signalling
[reactos.git] / reactos / lib / drivers / ip / transport / tcp / tcp.c
index 5500db0..1641718 100644 (file)
@@ -22,7 +22,7 @@ FAST_MUTEX SleepingThreadsLock;
 RECURSIVE_MUTEX TCPLock;
 PORT_SET TCPPorts;
 
-static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
+ULONG HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
     NTSTATUS Status = STATUS_SUCCESS;
     PTCP_COMPLETION_ROUTINE Complete;
     PTDI_BUCKET Bucket;
@@ -38,46 +38,31 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
     if( Connection->SignalState & SEL_FIN ) {
         TI_DbgPrint(DEBUG_TCP, ("EOF From socket\n"));
 
+        Connection->SignalState &= ~SEL_READ;
         while ((Entry = ExInterlockedRemoveHeadList( &Connection->ReceiveRequest,
                                                      &Connection->Lock )) != NULL)
         {
            Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
            Complete = Bucket->Request.RequestNotifyObject;
 
-           /* We have to notify oskittcp of the abortion */
-           TCPDisconnect
-            ( Connection,
-              TDI_DISCONNECT_RELEASE | TDI_DISCONNECT_ABORT,
-              NULL,
-              NULL,
-              Bucket->Request.RequestNotifyObject,
-              (PIRP)Bucket->Request.RequestContext );
-
            Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
 
            exFreePool(Bucket);
         }
 
+        Connection->SignalState &= ~SEL_WRITE;
         while ((Entry = ExInterlockedRemoveHeadList( &Connection->SendRequest,
                                                      &Connection->Lock )) != NULL)
         {
            Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
            Complete = Bucket->Request.RequestNotifyObject;
 
-           /* We have to notify oskittcp of the abortion */
-           TCPDisconnect
-            ( Connection,
-              TDI_DISCONNECT_RELEASE,
-              NULL,
-              NULL,
-              Bucket->Request.RequestNotifyObject,
-              (PIRP)Bucket->Request.RequestContext );
-
            Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
 
            exFreePool(Bucket);
         }
 
+        Connection->SignalState &= ~SEL_ACCEPT;
         while ((Entry = ExInterlockedRemoveHeadList( &Connection->ListenRequest,
                                                      &Connection->Lock )) != NULL)
         {
@@ -89,8 +74,11 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
                                Connection);
 
            Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
+
+           exFreePool(Bucket);
         }
 
+        Connection->SignalState &= ~SEL_CONNECT;
         while ((Entry = ExInterlockedRemoveHeadList( &Connection->ConnectRequest,
                                                      &Connection->Lock )) != NULL)
         {
@@ -98,13 +86,14 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
            Complete = Bucket->Request.RequestNotifyObject;
 
            Complete( Bucket->Request.RequestContext, STATUS_CANCELLED, 0 );
-        }
 
-        Connection->SignalState = 0;
+           exFreePool(Bucket);
+        }
     }
 
     /* Things that can happen when we try the initial connection */
     if( Connection->SignalState & SEL_CONNECT ) {
+        Connection->SignalState &= ~SEL_CONNECT;
         while( (Entry = ExInterlockedRemoveHeadList( &Connection->ConnectRequest,
                                                      &Connection->Lock )) != NULL ) {
             
@@ -132,6 +121,7 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
                                IsListEmpty(&Connection->ListenRequest) ?
                                "empty" : "nonempty"));
 
+        Connection->SignalState &= ~SEL_ACCEPT;
         while( (Entry = ExInterlockedRemoveHeadList( &Connection->ListenRequest,
                                                      &Connection->Lock )) != NULL ) {
             PIO_STACK_LOCATION IrpSp;
@@ -151,6 +141,7 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
             TI_DbgPrint(DEBUG_TCP,("Socket: Status: %x\n"));
 
             if( Status == STATUS_PENDING ) {
+                Connection->SignalState |= SEL_ACCEPT;
                 ExInterlockedInsertHeadList( &Connection->ListenRequest, &Bucket->Entry, &Connection->Lock );
                 break;
             } else {
@@ -166,6 +157,7 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
                                IsListEmpty(&Connection->ReceiveRequest) ?
                                "empty" : "nonempty"));
 
+        Connection->SignalState &= ~SEL_READ;
         while( (Entry = ExInterlockedRemoveHeadList( &Connection->ReceiveRequest,
                                                      &Connection->Lock )) != NULL ) {
             OSK_UINT RecvLen = 0, Received = 0;
@@ -211,6 +203,7 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
             } else if( Status == STATUS_PENDING ) {
                 ExInterlockedInsertHeadList
                     ( &Connection->ReceiveRequest, &Bucket->Entry, &Connection->Lock );
+                Connection->SignalState |= SEL_READ;
                 break;
             } else {
                 TI_DbgPrint(DEBUG_TCP,
@@ -226,6 +219,7 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
                                IsListEmpty(&Connection->SendRequest) ?
                                "empty" : "nonempty"));
 
+        Connection->SignalState &= ~SEL_WRITE;
         while( (Entry = ExInterlockedRemoveHeadList( &Connection->SendRequest,
                                                      &Connection->Lock )) != NULL ) {
             OSK_UINT SendLen = 0, Sent = 0;
@@ -270,6 +264,7 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
             } else if( Status == STATUS_PENDING ) {
                 ExInterlockedInsertHeadList
                     ( &Connection->SendRequest, &Bucket->Entry, &Connection->Lock );
+                Connection->SignalState |= SEL_WRITE;
                 break;
             } else {
                 TI_DbgPrint(DEBUG_TCP,
@@ -281,20 +276,35 @@ static VOID HandleSignalledConnection( PCONNECTION_ENDPOINT Connection ) {
         }
     }
 
-    Connection->SignalState = 0;
-    Connection->Signalled = FALSE;
+    return Connection->SignalState;
 }
 
-VOID DrainSignals() {
+static VOID DrainSignals() {
     PCONNECTION_ENDPOINT Connection;
-    PLIST_ENTRY ListEntry;
+    PLIST_ENTRY CurrentEntry, NextEntry;
+    ULONG NewState;
+    KIRQL OldIrql;
 
-    while( (ListEntry = ExInterlockedRemoveHeadList(&SignalledConnectionsList,
-                                                    &SignalledConnectionsLock)) != NULL) {
-        Connection = CONTAINING_RECORD( ListEntry, CONNECTION_ENDPOINT,
+    KeAcquireSpinLock(&SignalledConnectionsLock, &OldIrql);
+    CurrentEntry = SignalledConnectionsList.Flink;
+    while (CurrentEntry != &SignalledConnectionsList)
+    {
+        NextEntry = CurrentEntry->Flink;
+        Connection = CONTAINING_RECORD( CurrentEntry, CONNECTION_ENDPOINT,
                                         SignalList );
-        HandleSignalledConnection( Connection );
+
+        KeReleaseSpinLock(&SignalledConnectionsLock, OldIrql);
+        NewState = HandleSignalledConnection(Connection);
+        KeAcquireSpinLock(&SignalledConnectionsLock, &OldIrql);
+
+        if (NewState == SEL_FIN || NewState == 0)
+        {
+            RemoveEntryList(CurrentEntry);
+        }
+
+        CurrentEntry = NextEntry;
     }
+    KeReleaseSpinLock(&SignalledConnectionsLock, OldIrql);
 }
 
 PCONNECTION_ENDPOINT TCPAllocateConnectionEndpoint( PVOID ClientContext ) {
@@ -368,8 +378,6 @@ VOID TCPReceive(PIP_INTERFACE Interface, PIP_PACKET IPPacket)
                              IPPacket->TotalSize,
                              IPPacket->HeaderSize );
 
-    DrainSignals();
-
     TcpipRecursiveMutexLeave( &TCPLock );
 }
 
@@ -559,12 +567,20 @@ NTSTATUS TCPTranslateError( int OskitError ) {
 
     switch( OskitError ) {
     case 0: Status = STATUS_SUCCESS; break;
-    case OSK_EADDRNOTAVAIL:
+    case OSK_EADDRNOTAVAIL: Status = STATUS_INVALID_ADDRESS; break;
     case OSK_EAFNOSUPPORT: Status = STATUS_INVALID_CONNECTION; break;
     case OSK_ECONNREFUSED:
     case OSK_ECONNRESET: Status = STATUS_REMOTE_NOT_LISTENING; break;
-    case OSK_EINPROGRESS:
-    case OSK_EAGAIN: Status = STATUS_PENDING; break;
+    case OSK_EWOULDBLOCK:
+    case OSK_EINPROGRESS: Status = STATUS_PENDING; break;
+    case OSK_EINVAL: Status = STATUS_INVALID_PARAMETER; 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;
     default:
        DbgPrint("OskitTCP returned unhandled error code: %d\n", OskitError);
        Status = STATUS_INVALID_CONNECTION;
@@ -607,11 +623,6 @@ NTSTATUS TCPConnect
         return STATUS_NETWORK_UNREACHABLE;
     }
 
-    if (Connection->State & SEL_FIN)
-    {
-        return STATUS_REMOTE_DISCONNECT;
-    }
-
     /* Freed in TCPSocketState */
     TI_DbgPrint(DEBUG_TCP,
                 ("Connecting to address %x:%x\n",
@@ -663,29 +674,17 @@ NTSTATUS TCPDisconnect
   PTDI_CONNECTION_INFORMATION ReturnInfo,
   PTCP_COMPLETION_ROUTINE Complete,
   PVOID Context ) {
-    NTSTATUS Status;
+    NTSTATUS Status = STATUS_INVALID_PARAMETER;
 
     ASSERT_LOCKED(&TCPLock);
 
     TI_DbgPrint(DEBUG_TCP,("started\n"));
 
-    switch( Flags & (TDI_DISCONNECT_ABORT | TDI_DISCONNECT_RELEASE) ) {
-    case 0:
-    case TDI_DISCONNECT_ABORT:
-        Flags = 0;
-        break;
-
-    case TDI_DISCONNECT_ABORT | TDI_DISCONNECT_RELEASE:
-        Flags = 2;
-        break;
-
-    case TDI_DISCONNECT_RELEASE:
-        Flags = 1;
-        break;
-    }
+    if (Flags & TDI_DISCONNECT_RELEASE)
+        Status = TCPTranslateError(OskitTCPDisconnect(Connection->SocketContext));
 
-    Status = TCPTranslateError
-        ( OskitTCPShutdown( Connection->SocketContext, Flags ) );
+    if ((Flags & TDI_DISCONNECT_ABORT) || !Flags)
+        Status = TCPTranslateError(OskitTCPShutdown(Connection->SocketContext, FWRITE | FREAD));
 
     TI_DbgPrint(DEBUG_TCP,("finished %x\n", Status));
 
@@ -701,8 +700,8 @@ NTSTATUS TCPClose
     ASSERT_LOCKED(&TCPLock);
 
     /* Make our code remove all pending IRPs */
-    Connection->State |= SEL_FIN;
-    DrainSignals();
+    Connection->SignalState |= SEL_FIN;
+    HandleSignalledConnection(Connection);
 
     Status = TCPTranslateError( OskitTCPClose( Connection->SocketContext ) );
     if (Status == STATUS_SUCCESS)
@@ -733,13 +732,6 @@ NTSTATUS TCPReceiveData
 
     ASSERT_KM_POINTER(Connection->SocketContext);
 
-    /* Closing */
-    if (Connection->State & SEL_FIN)
-    {
-        *BytesReceived = 0;
-        return STATUS_REMOTE_DISCONNECT;
-    }
-
     NdisQueryBuffer( Buffer, &DataBuffer, &DataLen );
 
     TI_DbgPrint(DEBUG_TCP,("TCP>|< Got an MDL %x (%x:%d)\n", Buffer, DataBuffer, DataLen));
@@ -804,12 +796,6 @@ NTSTATUS TCPSendData
     TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
                            Connection->SocketContext));
 
-    /* Closing */
-    if (Connection->State & SEL_FIN)
-    {
-        *BytesSent = 0;
-        return STATUS_REMOTE_DISCONNECT;
-    }
 
     Status = TCPTranslateError
         ( OskitTCPSend( Connection->SocketContext,