Let oskit tell us when sending should be blocked 'cause its stuffed upto its
nose with data waiting to be sent. Bug 1232.
Modified: trunk/reactos/drivers/lib/ip/transport/tcp/event.c
Modified: trunk/reactos/drivers/lib/ip/transport/tcp/tcp.c
Modified: trunk/reactos/drivers/lib/oskittcp/oskittcp/interface.c
Modified: trunk/reactos/drivers/lib/oskittcp/oskittcp/sleep.c
Modified: trunk/reactos/drivers/net/afd/afd/write.c
Modified: trunk/reactos/drivers/net/tcpip/include/tcp.h
Modified: trunk/reactos/drivers/net/tcpip/include/titypes.h
Modified: trunk/reactos/drivers/net/tcpip/tcpip/dispatch.c

Modified: trunk/reactos/drivers/lib/ip/transport/tcp/event.c
--- trunk/reactos/drivers/lib/ip/transport/tcp/event.c	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/lib/ip/transport/tcp/event.c	2006-01-04 22:40:48 UTC (rev 20562)
@@ -121,6 +121,11 @@
 	KeInitializeEvent( &SleepingThread->Event, NotificationEvent, FALSE );
 	SleepingThread->SleepToken = token;
 
+	/* We're going to sleep and need to release the lock, otherwise
+           it's impossible to re-enter oskittcp to deliver the event that's
+           going to wake us */
+	TcpipRecursiveMutexLeave( &TCPLock );
+
 	TcpipAcquireFastMutex( &SleepingThreadsLock );
 	InsertTailList( &SleepingThreadsList, &SleepingThread->Entry );
 	TcpipReleaseFastMutex( &SleepingThreadsLock );
@@ -136,6 +141,8 @@
 	RemoveEntryList( &SleepingThread->Entry );
 	TcpipReleaseFastMutex( &SleepingThreadsLock );
 
+	TcpipRecursiveMutexEnter( &TCPLock, TRUE );
+
 	PoolFreeBuffer( SleepingThread );
     }
     TI_DbgPrint(DEBUG_TCP,("Waiting finished: %x\n", token));

Modified: trunk/reactos/drivers/lib/ip/transport/tcp/tcp.c
--- trunk/reactos/drivers/lib/ip/transport/tcp/tcp.c	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/lib/ip/transport/tcp/tcp.c	2006-01-04 22:40:48 UTC (rev 20562)
@@ -153,7 +153,64 @@
 	    }
 	}
     }
+    if( NewState & SEL_WRITE ) {
+	TI_DbgPrint(DEBUG_TCP,("Writeable: irp list %s\n",
+			       IsListEmpty(&Connection->ReceiveRequest) ?
+			       "empty" : "nonempty"));
 
+	while( !IsListEmpty( &Connection->SendRequest ) ) {
+	    OSK_UINT SendLen = 0, Sent = 0;
+	    OSK_PCHAR SendBuffer = 0;
+
+	    Entry = RemoveHeadList( &Connection->SendRequest );
+	    Bucket = CONTAINING_RECORD( Entry, TDI_BUCKET, Entry );
+	    Complete = Bucket->Request.RequestNotifyObject;
+
+	    Irp = Bucket->Request.RequestContext;
+	    Mdl = Irp->MdlAddress;
+
+	    TI_DbgPrint(DEBUG_TCP,
+			("Getting the user buffer from %x\n", Mdl));
+
+	    NdisQueryBuffer( Mdl, &SendBuffer, &SendLen );
+
+	    TI_DbgPrint(DEBUG_TCP,
+			("Writing %d bytes to %x\n", SendLen, SendBuffer));
+
+	    TI_DbgPrint(DEBUG_TCP, ("Connection: %x\n", Connection));
+	    TI_DbgPrint
+		(DEBUG_TCP,
+		 ("Connection->SocketContext: %x\n",
+		  Connection->SocketContext));
+
+	    Status = TCPTranslateError
+		( OskitTCPSend( Connection->SocketContext,
+				SendBuffer,
+				SendLen,
+				&Sent,
+				0 ) );
+
+	    TI_DbgPrint(DEBUG_TCP,("TCP Bytes: %d\n", Sent));
+
+	    if( Status == STATUS_SUCCESS ) {
+		TI_DbgPrint(DEBUG_TCP,("Sent %d bytes with status %x\n",
+				       Sent, Status));
+
+		Complete( Bucket->Request.RequestContext,
+			  STATUS_SUCCESS, Sent );
+	    } else if( Status == STATUS_PENDING ) {
+		InsertHeadList
+		    ( &Connection->SendRequest, &Bucket->Entry );
+		break;
+	    } else {
+		TI_DbgPrint(DEBUG_TCP,
+			    ("Completing Send request: %x %x\n",
+			     Bucket->Request, Status));
+		Complete( Bucket->Request.RequestContext, Status, 0 );
+	    }
+	}
+    }
+
     if( NewState & SEL_FIN ) {
         PLIST_ENTRY ListsToErase[4];
         NTSTATUS    IrpStatus[4];
@@ -209,6 +266,7 @@
     InitializeListHead(&Connection->ConnectRequest);
     InitializeListHead(&Connection->ListenRequest);
     InitializeListHead(&Connection->ReceiveRequest);
+    InitializeListHead(&Connection->SendRequest);
 
     /* Save client context pointer */
     Connection->ClientContext = ClientContext;
@@ -656,11 +714,18 @@
 NTSTATUS TCPSendData
 ( PCONNECTION_ENDPOINT Connection,
   PCHAR BufferData,
-  ULONG PacketSize,
-  PULONG DataUsed,
-  ULONG Flags) {
+  ULONG SendLength,
+  PULONG BytesSent,
+  ULONG Flags,
+  PTCP_COMPLETION_ROUTINE Complete,
+  PVOID Context ) {
+    UINT Sent = 0;
     NTSTATUS Status;
+    PTDI_BUCKET Bucket;
 
+    TI_DbgPrint(DEBUG_TCP,("Called for %d bytes (on socket %x)\n",
+                           SendLength, Connection->SocketContext));
+
     ASSERT_KM_POINTER(Connection->SocketContext);
 
     TcpipRecursiveMutexEnter( &TCPLock, TRUE );
@@ -669,12 +734,38 @@
     TI_DbgPrint(DEBUG_TCP,("Connection->SocketContext = %x\n",
 			   Connection->SocketContext));
 
-    Status = OskitTCPSend( Connection->SocketContext,
-			   (OSK_PCHAR)BufferData, PacketSize,
-			   (PUINT)DataUsed, 0 );
+    Status = TCPTranslateError
+	( OskitTCPSend( Connection->SocketContext,
+			(OSK_PCHAR)BufferData, SendLength,
+			&Sent, 0 ) );
 
+    TI_DbgPrint(DEBUG_TCP,("OskitTCPSend: %x, %d\n", Status, Sent));
+
+    /* Keep this request around ... there was no data yet */
+    if( Status == STATUS_PENDING ) {
+	/* Freed in TCPSocketState */
+	Bucket = ExAllocatePool( NonPagedPool, sizeof(*Bucket) );
+	if( !Bucket ) {
+	    TI_DbgPrint(DEBUG_TCP,("Failed to allocate bucket\n"));
+	    TcpipRecursiveMutexLeave( &TCPLock );
+	    return STATUS_NO_MEMORY;
+	}
+
+	Bucket->Request.RequestNotifyObject = Complete;
+	Bucket->Request.RequestContext = Context;
+	*BytesSent = 0;
+
+	InsertHeadList( &Connection->SendRequest, &Bucket->Entry );
+	TI_DbgPrint(DEBUG_TCP,("Queued write irp\n"));
+    } else {
+	TI_DbgPrint(DEBUG_TCP,("Got status %x, bytes %d\n", Status, Sent));
+	*BytesSent = Sent;
+    }
+
     TcpipRecursiveMutexLeave( &TCPLock );
 
+    TI_DbgPrint(DEBUG_TCP,("Status %x\n", Status));
+
     return Status;
 }
 
@@ -729,14 +820,14 @@
     PTDI_BUCKET Bucket;
     UINT i = 0;
 
-    ListHead[0] = &Endpoint->ReceiveRequest;
-    ListHead[1] = &Endpoint->ConnectRequest;
-    ListHead[2] = &Endpoint->ListenRequest;
-    ListHead[3] = 0;
+    ListHead[0] = &Endpoint->SendRequest;
+    ListHead[1] = &Endpoint->ReceiveRequest;
+    ListHead[2] = &Endpoint->ConnectRequest;
+    ListHead[3] = &Endpoint->ListenRequest;
 
     TcpipAcquireSpinLock( &Endpoint->Lock, &OldIrql );
 
-    for( i = 0; ListHead[i]; i++ ) {
+    for( i = 0; i < sizeof( ListHead ) / sizeof( ListHead[0] ); i++ ) {
 	for( Entry = ListHead[i]->Flink;
 	     Entry != ListHead[i];
 	     Entry = Entry->Flink ) {

Modified: trunk/reactos/drivers/lib/oskittcp/oskittcp/interface.c
--- trunk/reactos/drivers/lib/oskittcp/oskittcp/interface.c	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/lib/oskittcp/oskittcp/interface.c	2006-01-04 22:40:48 UTC (rev 20562)
@@ -256,12 +256,26 @@
 
 int OskitTCPSend( void *socket, OSK_PCHAR Data, OSK_UINT Len,
 		  OSK_UINT *OutLen, OSK_UINT flags ) {
-    struct mbuf* m = m_devget( Data, Len, 0, NULL, NULL );
-    int error = 0;
-	if ( !m )
-		return ENOBUFS;
-    error = sosend( socket, NULL, NULL, m, NULL, 0 );
-    *OutLen = Len;
+    int error;
+    struct uio uio;
+    struct iovec iov;
+
+    iov.iov_len = Len;
+    iov.iov_base = Data;
+    uio.uio_iov = &iov;
+    uio.uio_iovcnt = 1;
+    uio.uio_offset = 0;
+    uio.uio_resid = Len;
+    uio.uio_segflg = UIO_SYSSPACE;
+    uio.uio_rw = UIO_WRITE;
+    uio.uio_procp = NULL;
+
+    error = sosend( socket, NULL, &uio, NULL, NULL, 0 );
+    if (OSK_EWOULDBLOCK == error) {
+	((struct socket *) socket)->so_snd.sb_flags |= SB_WAIT;
+    }
+    *OutLen = uio.uio_offset;
+
     return error;
 }
 

Modified: trunk/reactos/drivers/lib/oskittcp/oskittcp/sleep.c
--- trunk/reactos/drivers/lib/oskittcp/oskittcp/sleep.c	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/lib/oskittcp/oskittcp/sleep.c	2006-01-04 22:40:48 UTC (rev 20562)
@@ -35,6 +35,10 @@
 	OS_DbgPrint(OSK_MID_TRACE,("Socket readable\n"));
 	flags |= SEL_READ;
     }
+    if( 0 < sbspace(&so->so_snd) ) {
+	OS_DbgPrint(OSK_MID_TRACE,("Socket writeable\n"));
+	flags |= SEL_WRITE;
+    }
     if( so->so_state & SS_CANTRCVMORE ) {
 	OS_DbgPrint(OSK_MID_TRACE,("Socket can't be read any longer\n"));
 	flags |= SEL_FIN;

Modified: trunk/reactos/drivers/net/afd/afd/write.c
--- trunk/reactos/drivers/net/afd/afd/write.c	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/net/afd/afd/write.c	2006-01-04 22:40:48 UTC (rev 20562)
@@ -1,4 +1,4 @@
-/* $Id$
+/*
  * COPYRIGHT:        See COPYING in the top level directory
  * PROJECT:          ReactOS kernel
  * FILE:             drivers/net/afd/afd/write.c
@@ -17,7 +17,6 @@
   PIRP Irp,
   PVOID Context ) {
     NTSTATUS Status = Irp->IoStatus.Status;
-    PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation(Irp);
     PAFD_FCB FCB = (PAFD_FCB)Context;
     PLIST_ENTRY NextIrpEntry;
     PIRP NextIrp = NULL;
@@ -26,6 +25,15 @@
     PAFD_MAPBUF Map;
     UINT TotalBytesCopied = 0, SpaceAvail, i, CopySize = 0;
 
+    /*
+     * The Irp parameter passed in is the IRP of the stream between AFD and
+     * TDI driver. It's not very usefull to us. We need the IRPs of the stream
+     * between usermode and AFD. Those are chained from
+     * FCB->PendingIrpList[FUNCTION_SEND] and you'll see them in the code
+     * below as "NextIrp" ('cause they are the next usermode IRP to be
+     * processed).
+     */
+
     AFD_DbgPrint(MID_TRACE,("Called, status %x, %d bytes used\n",
 			    Irp->IoStatus.Status,
 			    Irp->IoStatus.Information));
@@ -78,7 +86,7 @@
 	!IsListEmpty( &FCB->PendingIrpList[FUNCTION_SEND] ) &&
 	NT_SUCCESS(Status) ) {
 	NextIrpEntry =
-	    RemoveHeadList(&FCB->PendingIrpList[FUNCTION_RECV]);
+	    RemoveHeadList(&FCB->PendingIrpList[FUNCTION_SEND]);
 	NextIrp =
 	    CONTAINING_RECORD(NextIrpEntry, IRP, Tail.Overlay.ListEntry);
 	NextIrpSp = IoGetCurrentIrpStackLocation( NextIrp );
@@ -89,8 +97,7 @@
 
 	SpaceAvail = FCB->Send.Size - FCB->Send.BytesUsed;
 
-	for( i = 0; FCB->Send.BytesUsed < FCB->Send.Content &&
-		 i < SendReq->BufferCount; i++ ) {
+	for( i = 0; i < SendReq->BufferCount; i++ ) {
 	    Map[i].BufferAddress =
 		MmMapLockedPages( Map[i].Mdl, KernelMode );
 
@@ -101,7 +108,7 @@
 			   Map[i].BufferAddress,
 			   CopySize );
 
-	    MmUnmapLockedPages( Map[i].Mdl, KernelMode );
+	    MmUnmapLockedPages( Map[i].BufferAddress, Map[i].Mdl );
 
 	    FCB->Send.BytesUsed += CopySize;
 	    TotalBytesCopied += CopySize;
@@ -116,7 +123,7 @@
 	SocketCalloutEnter( FCB );
 
 	Status = TdiSend( &FCB->SendIrp.InFlightRequest,
-			  IrpSp->FileObject,
+			  FCB->Connection.Object,
 			  0,
 			  FCB->Send.Window,
 			  FCB->Send.BytesUsed,
@@ -138,13 +145,13 @@
 
 	AFD_DbgPrint(MID_TRACE,("Dismissing request: %x\n", Status));
 
-	return UnlockAndMaybeComplete( FCB, Status, Irp, TotalBytesCopied,
+	return UnlockAndMaybeComplete( FCB, Status, NextIrp, TotalBytesCopied,
 				       NULL, TRUE );
     } else if( NextIrp ) {
 	AFD_DbgPrint(MID_TRACE,("Could not do any more with Irp %x\n",
 				NextIrp));
 	InsertHeadList( &FCB->PendingIrpList[FUNCTION_SEND],
-			&Irp->Tail.Overlay.ListEntry );
+			&NextIrp->Tail.Overlay.ListEntry );
     }
 
     SocketStateUnlock( FCB );

Modified: trunk/reactos/drivers/net/tcpip/include/tcp.h
--- trunk/reactos/drivers/net/tcpip/include/tcp.h	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/net/tcpip/include/tcp.h	2006-01-04 22:40:48 UTC (rev 20562)
@@ -150,7 +150,9 @@
   PCHAR Buffer,
   ULONG DataSize,
   PULONG DataUsed,
-  ULONG Flags);
+  ULONG Flags,
+  PTCP_COMPLETION_ROUTINE Complete,
+  PVOID Context);
 
 NTSTATUS TCPClose( PCONNECTION_ENDPOINT Connection );
 

Modified: trunk/reactos/drivers/net/tcpip/include/titypes.h
--- trunk/reactos/drivers/net/tcpip/include/titypes.h	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/net/tcpip/include/titypes.h	2006-01-04 22:40:48 UTC (rev 20562)
@@ -302,6 +302,7 @@
     LIST_ENTRY ConnectRequest; /* Queued connect rqueusts */
     LIST_ENTRY ListenRequest;  /* Queued listen requests */
     LIST_ENTRY ReceiveRequest; /* Queued receive requests */
+    LIST_ENTRY SendRequest;    /* Queued send requests */
 
     /* Signals */
     LIST_ENTRY SignalList;     /* Entry in the list of sockets waiting for

Modified: trunk/reactos/drivers/net/tcpip/tcpip/dispatch.c
--- trunk/reactos/drivers/net/tcpip/tcpip/dispatch.c	2006-01-04 20:45:58 UTC (rev 20561)
+++ trunk/reactos/drivers/net/tcpip/tcpip/dispatch.c	2006-01-04 22:40:48 UTC (rev 20562)
@@ -898,15 +898,15 @@
  */
 {
   PIO_STACK_LOCATION IrpSp;
-  PTDI_REQUEST_KERNEL_RECEIVE ReceiveInfo;
+  PTDI_REQUEST_KERNEL_SEND SendInfo;
   PTRANSPORT_CONTEXT TranContext;
   NTSTATUS Status;
-  ULONG BytesReceived;
+  ULONG BytesSent;
 
   TI_DbgPrint(DEBUG_IRP, ("Called.\n"));
 
   IrpSp = IoGetCurrentIrpStackLocation(Irp);
-  ReceiveInfo = (PTDI_REQUEST_KERNEL_RECEIVE)&(IrpSp->Parameters);
+  SendInfo = (PTDI_REQUEST_KERNEL_SEND)&(IrpSp->Parameters);
 
   TranContext = IrpSp->FileObject->FsContext;
   if (TranContext == NULL)
@@ -938,12 +938,14 @@
 	Status = TCPSendData(
 	    TranContext->Handle.ConnectionContext,
 	    Data,
-	    ReceiveInfo->ReceiveLength,
-	    &BytesReceived,
-	    ReceiveInfo->ReceiveFlags);
+	    SendInfo->SendLength,
+	    &BytesSent,
+	    SendInfo->SendFlags,
+	    DispDataRequestComplete,
+	    Irp);
 	if (Status != STATUS_PENDING)
 	{
-	    DispDataRequestComplete(Irp, Status, BytesReceived);
+	    DispDataRequestComplete(Irp, Status, BytesSent);
 	} else
 	    IoMarkIrpPending( Irp );
     }