Author: cgutman Date: Sun Aug 26 22:24:49 2012 New Revision: 57169
URL: http://svn.reactos.org/svn/reactos?rev=57169&view=rev Log: [LWIP] - Fix broken handling of partial receives
Modified: trunk/reactos/lib/drivers/lwip/src/include/rosip.h trunk/reactos/lib/drivers/lwip/src/rostcp.c
Modified: trunk/reactos/lib/drivers/lwip/src/include/rosip.h URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/lwip/src/includ... ============================================================================== --- trunk/reactos/lib/drivers/lwip/src/include/rosip.h [iso-8859-1] (original) +++ trunk/reactos/lib/drivers/lwip/src/include/rosip.h [iso-8859-1] Sun Aug 26 22:24:49 2012 @@ -15,6 +15,7 @@ typedef struct _QUEUE_ENTRY { struct pbuf *p; + ULONG Offset; LIST_ENTRY ListEntry; } QUEUE_ENTRY, *PQUEUE_ENTRY;
Modified: trunk/reactos/lib/drivers/lwip/src/rostcp.c URL: http://svn.reactos.org/svn/reactos/trunk/reactos/lib/drivers/lwip/src/rostcp... ============================================================================== --- trunk/reactos/lib/drivers/lwip/src/rostcp.c [iso-8859-1] (original) +++ trunk/reactos/lib/drivers/lwip/src/rostcp.c [iso-8859-1] Sun Aug 26 22:24:49 2012 @@ -60,6 +60,7 @@
qp = (PQUEUE_ENTRY)ExAllocateFromNPagedLookasideList(&QueueEntryLookasideList); qp->p = p; + qp->Offset = 0;
ExInterlockedInsertTailList(&Connection->PacketQueue, &qp->ListEntry, &Connection->Lock); } @@ -82,9 +83,10 @@ { PQUEUE_ENTRY qp; struct pbuf* p; - NTSTATUS Status = STATUS_PENDING; - UINT ReadLength, ExistingDataLength; + NTSTATUS Status; + UINT ReadLength, PayloadLength; KIRQL OldIrql; + PUCHAR Payload;
(*Received) = 0;
@@ -95,49 +97,53 @@ while ((qp = LibTCPDequeuePacket(Connection)) != NULL) { p = qp->p; - ExistingDataLength = (*Received); + + /* Calculate the payload first */ + Payload = p->payload; + Payload += qp->Offset; + PayloadLength = p->len; + PayloadLength -= qp->Offset; + + /* Check if we're reading the whole buffer */ + ReadLength = MIN(PayloadLength, RecvLen); + if (ReadLength != PayloadLength) + { + /* Save this one for later */ + qp->Offset += ReadLength; + InsertHeadList(&Connection->PacketQueue, &qp->ListEntry); + qp = NULL; + } + + UnlockObject(Connection, OldIrql); + + /* Return to a lower IRQL because the receive buffer may be pageable memory */ + RtlCopyMemory(RecvBuffer, + Payload, + ReadLength); + + LockObject(Connection, &OldIrql); + + /* Update trackers */ + RecvLen -= ReadLength; + RecvBuffer += ReadLength; + (*Received) += ReadLength; + + if (qp != NULL) + { + /* Use this special pbuf free callback function because we're outside tcpip thread */ + pbuf_free_callback(qp->p); + + ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp); + } + else + { + /* If we get here, it means we've filled the buffer */ + ASSERT(RecvLen == 0); + }
Status = STATUS_SUCCESS;
- ReadLength = MIN(p->tot_len, RecvLen); - if (ReadLength != p->tot_len) - { - if (ExistingDataLength) - { - /* The packet was too big but we used some data already so give it another shot later */ - InsertHeadList(&Connection->PacketQueue, &qp->ListEntry); - break; - } - else - { - /* The packet is just too big to fit fully in our buffer, even when empty so - * return an informative status but still copy all the data we can fit. - */ - Status = STATUS_BUFFER_OVERFLOW; - } - } - - UnlockObject(Connection, OldIrql); - - /* Return to a lower IRQL because the receive buffer may be pageable memory */ - for (; (*Received) < ReadLength + ExistingDataLength; (*Received) += p->len, p = p->next) - { - RtlCopyMemory(RecvBuffer + (*Received), p->payload, p->len); - } - - LockObject(Connection, &OldIrql); - - RecvLen -= ReadLength; - - /* Use this special pbuf free callback function because we're outside tcpip thread */ - pbuf_free_callback(qp->p); - - ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp); - if (!RecvLen) - break; - - if (Status != STATUS_SUCCESS) break; } } @@ -196,6 +202,8 @@ InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t err) { PCONNECTION_ENDPOINT Connection = arg; + struct pbuf *pb; + ULONG RecvLen;
/* Make sure the socket didn't get closed */ if (!arg) @@ -208,9 +216,19 @@
if (p) { - LibTCPEnqueuePacket(Connection, p); - - tcp_recved(pcb, p->tot_len); + pb = p; + RecvLen = 0; + while (pb != NULL) + { + /* Enqueue this buffer */ + LibTCPEnqueuePacket(Connection, pb); + RecvLen += pb->len; + + /* Advance and unchain the buffer */ + pb = pbuf_dechain(pb);; + } + + tcp_recved(pcb, RecvLen);
TCPRecvEventHandler(arg); }