mirror of
https://github.com/reactos/reactos.git
synced 2025-07-04 19:11:22 +00:00
[LWIP]
- Fix broken handling of partial receives svn path=/trunk/; revision=57169
This commit is contained in:
parent
44356bb773
commit
aa6611286c
2 changed files with 50 additions and 31 deletions
|
@ -15,6 +15,7 @@ typedef struct tcp_pcb* PTCP_PCB;
|
||||||
typedef struct _QUEUE_ENTRY
|
typedef struct _QUEUE_ENTRY
|
||||||
{
|
{
|
||||||
struct pbuf *p;
|
struct pbuf *p;
|
||||||
|
ULONG Offset;
|
||||||
LIST_ENTRY ListEntry;
|
LIST_ENTRY ListEntry;
|
||||||
} QUEUE_ENTRY, *PQUEUE_ENTRY;
|
} QUEUE_ENTRY, *PQUEUE_ENTRY;
|
||||||
|
|
||||||
|
|
|
@ -60,6 +60,7 @@ void LibTCPEnqueuePacket(PCONNECTION_ENDPOINT Connection, struct pbuf *p)
|
||||||
|
|
||||||
qp = (PQUEUE_ENTRY)ExAllocateFromNPagedLookasideList(&QueueEntryLookasideList);
|
qp = (PQUEUE_ENTRY)ExAllocateFromNPagedLookasideList(&QueueEntryLookasideList);
|
||||||
qp->p = p;
|
qp->p = p;
|
||||||
|
qp->Offset = 0;
|
||||||
|
|
||||||
ExInterlockedInsertTailList(&Connection->PacketQueue, &qp->ListEntry, &Connection->Lock);
|
ExInterlockedInsertTailList(&Connection->PacketQueue, &qp->ListEntry, &Connection->Lock);
|
||||||
}
|
}
|
||||||
|
@ -82,9 +83,10 @@ NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHA
|
||||||
{
|
{
|
||||||
PQUEUE_ENTRY qp;
|
PQUEUE_ENTRY qp;
|
||||||
struct pbuf* p;
|
struct pbuf* p;
|
||||||
NTSTATUS Status = STATUS_PENDING;
|
NTSTATUS Status;
|
||||||
UINT ReadLength, ExistingDataLength;
|
UINT ReadLength, PayloadLength;
|
||||||
KIRQL OldIrql;
|
KIRQL OldIrql;
|
||||||
|
PUCHAR Payload;
|
||||||
|
|
||||||
(*Received) = 0;
|
(*Received) = 0;
|
||||||
|
|
||||||
|
@ -95,50 +97,54 @@ NTSTATUS LibTCPGetDataFromConnectionQueue(PCONNECTION_ENDPOINT Connection, PUCHA
|
||||||
while ((qp = LibTCPDequeuePacket(Connection)) != NULL)
|
while ((qp = LibTCPDequeuePacket(Connection)) != NULL)
|
||||||
{
|
{
|
||||||
p = qp->p;
|
p = qp->p;
|
||||||
ExistingDataLength = (*Received);
|
|
||||||
|
|
||||||
Status = STATUS_SUCCESS;
|
/* Calculate the payload first */
|
||||||
|
Payload = p->payload;
|
||||||
|
Payload += qp->Offset;
|
||||||
|
PayloadLength = p->len;
|
||||||
|
PayloadLength -= qp->Offset;
|
||||||
|
|
||||||
ReadLength = MIN(p->tot_len, RecvLen);
|
/* Check if we're reading the whole buffer */
|
||||||
if (ReadLength != p->tot_len)
|
ReadLength = MIN(PayloadLength, RecvLen);
|
||||||
|
if (ReadLength != PayloadLength)
|
||||||
{
|
{
|
||||||
if (ExistingDataLength)
|
/* Save this one for later */
|
||||||
{
|
qp->Offset += ReadLength;
|
||||||
/* The packet was too big but we used some data already so give it another shot later */
|
|
||||||
InsertHeadList(&Connection->PacketQueue, &qp->ListEntry);
|
InsertHeadList(&Connection->PacketQueue, &qp->ListEntry);
|
||||||
break;
|
qp = NULL;
|
||||||
}
|
|
||||||
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);
|
UnlockObject(Connection, OldIrql);
|
||||||
|
|
||||||
/* Return to a lower IRQL because the receive buffer may be pageable memory */
|
/* 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,
|
||||||
{
|
Payload,
|
||||||
RtlCopyMemory(RecvBuffer + (*Received), p->payload, p->len);
|
ReadLength);
|
||||||
}
|
|
||||||
|
|
||||||
LockObject(Connection, &OldIrql);
|
LockObject(Connection, &OldIrql);
|
||||||
|
|
||||||
|
/* Update trackers */
|
||||||
RecvLen -= ReadLength;
|
RecvLen -= ReadLength;
|
||||||
|
RecvBuffer += ReadLength;
|
||||||
|
(*Received) += ReadLength;
|
||||||
|
|
||||||
|
if (qp != NULL)
|
||||||
|
{
|
||||||
/* Use this special pbuf free callback function because we're outside tcpip thread */
|
/* Use this special pbuf free callback function because we're outside tcpip thread */
|
||||||
pbuf_free_callback(qp->p);
|
pbuf_free_callback(qp->p);
|
||||||
|
|
||||||
ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp);
|
ExFreeToNPagedLookasideList(&QueueEntryLookasideList, qp);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* If we get here, it means we've filled the buffer */
|
||||||
|
ASSERT(RecvLen == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
Status = STATUS_SUCCESS;
|
||||||
|
|
||||||
if (!RecvLen)
|
if (!RecvLen)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
if (Status != STATUS_SUCCESS)
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
|
@ -196,6 +202,8 @@ err_t
|
||||||
InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t err)
|
InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t err)
|
||||||
{
|
{
|
||||||
PCONNECTION_ENDPOINT Connection = arg;
|
PCONNECTION_ENDPOINT Connection = arg;
|
||||||
|
struct pbuf *pb;
|
||||||
|
ULONG RecvLen;
|
||||||
|
|
||||||
/* Make sure the socket didn't get closed */
|
/* Make sure the socket didn't get closed */
|
||||||
if (!arg)
|
if (!arg)
|
||||||
|
@ -208,9 +216,19 @@ InternalRecvEventHandler(void *arg, PTCP_PCB pcb, struct pbuf *p, const err_t er
|
||||||
|
|
||||||
if (p)
|
if (p)
|
||||||
{
|
{
|
||||||
LibTCPEnqueuePacket(Connection, p);
|
pb = p;
|
||||||
|
RecvLen = 0;
|
||||||
|
while (pb != NULL)
|
||||||
|
{
|
||||||
|
/* Enqueue this buffer */
|
||||||
|
LibTCPEnqueuePacket(Connection, pb);
|
||||||
|
RecvLen += pb->len;
|
||||||
|
|
||||||
tcp_recved(pcb, p->tot_len);
|
/* Advance and unchain the buffer */
|
||||||
|
pb = pbuf_dechain(pb);;
|
||||||
|
}
|
||||||
|
|
||||||
|
tcp_recved(pcb, RecvLen);
|
||||||
|
|
||||||
TCPRecvEventHandler(arg);
|
TCPRecvEventHandler(arg);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue