mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2025-02-05 06:39:52 +00:00
task #14433: TCP: combine unsent/unacked queue loops in tcp_receive()
This commit is contained in:
parent
39316bb9de
commit
778206798e
@ -1000,6 +1000,42 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next)
|
|||||||
}
|
}
|
||||||
#endif /* TCP_QUEUE_OOSEQ */
|
#endif /* TCP_QUEUE_OOSEQ */
|
||||||
|
|
||||||
|
/** Remove segments from a list if the incoming ACK acknowledges them */
|
||||||
|
static struct tcp_seg *
|
||||||
|
tcp_free_acked_segments(struct tcp_pcb *pcb, struct tcp_seg *seg_list, const char* dbg_list_name,
|
||||||
|
struct tcp_seg *dbg_other_seg_list)
|
||||||
|
{
|
||||||
|
struct tcp_seg *next;
|
||||||
|
u16_t clen;
|
||||||
|
while (seg_list != NULL &&
|
||||||
|
TCP_SEQ_LEQ(lwip_ntohl(seg_list->tcphdr->seqno) +
|
||||||
|
TCP_TCPLEN(seg_list), ackno)) {
|
||||||
|
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->%s\n",
|
||||||
|
dbg_list_name, lwip_ntohl(seg_list->tcphdr->seqno),
|
||||||
|
lwip_ntohl(seg_list->tcphdr->seqno) + TCP_TCPLEN(seg_list)));
|
||||||
|
|
||||||
|
next = seg_list;
|
||||||
|
seg_list = seg_list->next;
|
||||||
|
|
||||||
|
clen = pbuf_clen(next->p);
|
||||||
|
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ",
|
||||||
|
(tcpwnd_size_t)pcb->snd_queuelen));
|
||||||
|
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= clen));
|
||||||
|
|
||||||
|
pcb->snd_queuelen -= clen;
|
||||||
|
recv_acked += next->len;
|
||||||
|
tcp_seg_free(next);
|
||||||
|
|
||||||
|
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing %s)\n", dbg_list_name,
|
||||||
|
(tcpwnd_size_t)pcb->snd_queuelen));
|
||||||
|
if (pcb->snd_queuelen != 0) {
|
||||||
|
LWIP_ASSERT("tcp_receive: valid queue length",
|
||||||
|
seg_list != NULL || dbg_other_seg_list != NULL);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return seg_list;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Called by tcp_process. Checks if the given segment is an ACK for outstanding
|
* Called by tcp_process. Checks if the given segment is an ACK for outstanding
|
||||||
* data, and if so frees the memory of the buffered data. Next, it places the
|
* data, and if so frees the memory of the buffered data. Next, it places the
|
||||||
@ -1185,30 +1221,14 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
|
|
||||||
/* Remove segment from the unacknowledged list if the incoming
|
/* Remove segment from the unacknowledged list if the incoming
|
||||||
ACK acknowledges them. */
|
ACK acknowledges them. */
|
||||||
while (pcb->unacked != NULL &&
|
pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent);
|
||||||
TCP_SEQ_LEQ(lwip_ntohl(pcb->unacked->tcphdr->seqno) +
|
/* We go through the ->unsent list to see if any of the segments
|
||||||
TCP_TCPLEN(pcb->unacked), ackno)) {
|
on the list are acknowledged by the ACK. This may seem
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n",
|
strange since an "unsent" segment shouldn't be acked. The
|
||||||
lwip_ntohl(pcb->unacked->tcphdr->seqno),
|
rationale is that lwIP puts all outstanding segments on the
|
||||||
lwip_ntohl(pcb->unacked->tcphdr->seqno) +
|
->unsent list after a retransmission, so these segments may
|
||||||
TCP_TCPLEN(pcb->unacked)));
|
in fact have been sent once. */
|
||||||
|
pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked);
|
||||||
next = pcb->unacked;
|
|
||||||
pcb->unacked = pcb->unacked->next;
|
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen));
|
|
||||||
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
|
|
||||||
|
|
||||||
pcb->snd_queuelen -= pbuf_clen(next->p);
|
|
||||||
recv_acked += next->len;
|
|
||||||
tcp_seg_free(next);
|
|
||||||
|
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unacked)\n", (tcpwnd_size_t)pcb->snd_queuelen));
|
|
||||||
if (pcb->snd_queuelen != 0) {
|
|
||||||
LWIP_ASSERT("tcp_receive: valid queue length", pcb->unacked != NULL ||
|
|
||||||
pcb->unsent != NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* If there's nothing left to acknowledge, stop the retransmit
|
/* If there's nothing left to acknowledge, stop the retransmit
|
||||||
timer, otherwise reset it to start again */
|
timer, otherwise reset it to start again */
|
||||||
@ -1220,6 +1240,12 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
|
|
||||||
pcb->polltmr = 0;
|
pcb->polltmr = 0;
|
||||||
|
|
||||||
|
#if TCP_OVERSIZE
|
||||||
|
if (pcb->unsent == NULL) {
|
||||||
|
pcb->unsent_oversize = 0;
|
||||||
|
}
|
||||||
|
#endif /* TCP_OVERSIZE */
|
||||||
|
|
||||||
#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
|
#if LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS
|
||||||
if (ip_current_is_v6()) {
|
if (ip_current_is_v6()) {
|
||||||
/* Inform neighbor reachability of forward progress. */
|
/* Inform neighbor reachability of forward progress. */
|
||||||
@ -1227,38 +1253,6 @@ tcp_receive(struct tcp_pcb *pcb)
|
|||||||
}
|
}
|
||||||
#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
|
#endif /* LWIP_IPV6 && LWIP_ND6_TCP_REACHABILITY_HINTS*/
|
||||||
|
|
||||||
/* We go through the ->unsent list to see if any of the segments
|
|
||||||
on the list are acknowledged by the ACK. This may seem
|
|
||||||
strange since an "unsent" segment shouldn't be acked. The
|
|
||||||
rationale is that lwIP puts all outstanding segments on the
|
|
||||||
->unsent list after a retransmission, so these segments may
|
|
||||||
in fact have been sent once. */
|
|
||||||
while (pcb->unsent != NULL &&
|
|
||||||
TCP_SEQ_LEQ(lwip_ntohl(pcb->unsent->tcphdr->seqno) +
|
|
||||||
TCP_TCPLEN(pcb->unsent), ackno)) {
|
|
||||||
LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unsent\n",
|
|
||||||
lwip_ntohl(pcb->unsent->tcphdr->seqno), lwip_ntohl(pcb->unsent->tcphdr->seqno) +
|
|
||||||
TCP_TCPLEN(pcb->unsent)));
|
|
||||||
|
|
||||||
next = pcb->unsent;
|
|
||||||
pcb->unsent = pcb->unsent->next;
|
|
||||||
#if TCP_OVERSIZE
|
|
||||||
if (pcb->unsent == NULL) {
|
|
||||||
pcb->unsent_oversize = 0;
|
|
||||||
}
|
|
||||||
#endif /* TCP_OVERSIZE */
|
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_receive: queuelen %"TCPWNDSIZE_F" ... ", (tcpwnd_size_t)pcb->snd_queuelen));
|
|
||||||
LWIP_ASSERT("pcb->snd_queuelen >= pbuf_clen(next->p)", (pcb->snd_queuelen >= pbuf_clen(next->p)));
|
|
||||||
/* Prevent ACK for FIN to generate a sent event */
|
|
||||||
pcb->snd_queuelen -= pbuf_clen(next->p);
|
|
||||||
recv_acked += next->len;
|
|
||||||
tcp_seg_free(next);
|
|
||||||
LWIP_DEBUGF(TCP_QLEN_DEBUG, ("%"TCPWNDSIZE_F" (after freeing unsent)\n", (tcpwnd_size_t)pcb->snd_queuelen));
|
|
||||||
if (pcb->snd_queuelen != 0) {
|
|
||||||
LWIP_ASSERT("tcp_receive: valid queue length",
|
|
||||||
pcb->unacked != NULL || pcb->unsent != NULL);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
pcb->snd_buf += recv_acked;
|
pcb->snd_buf += recv_acked;
|
||||||
/* check if this ACK ends our retransmission of in-flight data */
|
/* check if this ACK ends our retransmission of in-flight data */
|
||||||
if (pcb->flags & TF_RTO) {
|
if (pcb->flags & TF_RTO) {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user