From 778206798ecafc5e1ef1d313147effd7f9534dfb Mon Sep 17 00:00:00 2001 From: goldsimon Date: Wed, 3 May 2017 12:32:01 +0200 Subject: [PATCH] task #14433: TCP: combine unsent/unacked queue loops in tcp_receive() --- src/core/tcp_in.c | 106 ++++++++++++++++++++++------------------------ 1 file changed, 50 insertions(+), 56 deletions(-) diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 1a33d2fb..7f32fcb3 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -1000,6 +1000,42 @@ tcp_oos_insert_segment(struct tcp_seg *cseg, struct tcp_seg *next) } #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 * 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 ACK acknowledges them. */ - while (pcb->unacked != NULL && - TCP_SEQ_LEQ(lwip_ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(pcb->unacked), ackno)) { - LWIP_DEBUGF(TCP_INPUT_DEBUG, ("tcp_receive: removing %"U32_F":%"U32_F" from pcb->unacked\n", - lwip_ntohl(pcb->unacked->tcphdr->seqno), - lwip_ntohl(pcb->unacked->tcphdr->seqno) + - TCP_TCPLEN(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); - } - } + pcb->unacked = tcp_free_acked_segments(pcb, pcb->unacked, "unacked", pcb->unsent); + /* 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. */ + pcb->unsent = tcp_free_acked_segments(pcb, pcb->unsent, "unsent", pcb->unacked); /* If there's nothing left to acknowledge, stop the retransmit timer, otherwise reset it to start again */ @@ -1220,6 +1240,12 @@ tcp_receive(struct tcp_pcb *pcb) 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 (ip_current_is_v6()) { /* Inform neighbor reachability of forward progress. */ @@ -1227,38 +1253,6 @@ tcp_receive(struct tcp_pcb *pcb) } #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; /* check if this ACK ends our retransmission of in-flight data */ if (pcb->flags & TF_RTO) {