From 79be888b6fc9c52a440e6bc642c2635a4d5ca0c8 Mon Sep 17 00:00:00 2001 From: kieranm Date: Thu, 12 Apr 2007 14:56:07 +0000 Subject: [PATCH] * tcp.c, tcp_in.c, tcp_out.c, tcp.h: Modify way the retransmission timer is reset to fix bug#19434, with help from Oleg Tyshev. --- src/core/tcp.c | 26 ++++++++++++++++++-------- src/core/tcp_in.c | 25 +++++++++++++++++++------ src/core/tcp_out.c | 5 +++-- src/include/lwip/tcp.h | 4 ++-- 4 files changed, 42 insertions(+), 18 deletions(-) diff --git a/src/core/tcp.c b/src/core/tcp.c index 3bc87f98..c4bb9bb9 100644 --- a/src/core/tcp.c +++ b/src/core/tcp.c @@ -500,18 +500,24 @@ tcp_slowtmr(void) ++pcb_remove; LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n")); } else { - ++pcb->rtime; - if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { + /* Increase the retransmission timer if it is running */ + if(pcb->rtime >= 0) + ++pcb->rtime; + if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) { /* Time for a retransmission. */ - LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"U16_F" pcb->rto %"U16_F"\n", - pcb->rtime, pcb->rto)); + LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F" pcb->rto %"S16_F"\n", + pcb->rtime, pcb->rto)); /* Double retransmission time-out unless we are trying to * connect to somebody (i.e., we are in SYN_SENT). */ if (pcb->state != SYN_SENT) { pcb->rto = ((pcb->sa >> 3) + pcb->sv) << tcp_backoff[pcb->nrtx]; } + + /* Reset the retransmission timer. */ + pcb->rtime = 0; + /* Reduce congestion window and ssthresh. */ eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd); pcb->ssthresh = eff_wnd >> 1; @@ -520,11 +526,11 @@ tcp_slowtmr(void) } pcb->cwnd = pcb->mss; LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n", - pcb->cwnd, pcb->ssthresh)); + pcb->cwnd, pcb->ssthresh)); /* The following needs to be called AFTER cwnd is set to one mss - STJ */ tcp_rexmit_rto(pcb); - } + } } /* Check if this PCB has stayed too long in FIN-WAIT-2 */ if (pcb->state == FIN_WAIT_2) { @@ -844,7 +850,7 @@ tcp_alloc(u8_t prio) pcb->rto = 3000 / TCP_SLOW_INTERVAL; pcb->sa = 0; pcb->sv = 3000 / TCP_SLOW_INTERVAL; - pcb->rtime = 0; + pcb->rtime = -1; pcb->cwnd = 1; iss = tcp_next_iss(); pcb->snd_wl2 = iss; @@ -993,7 +999,11 @@ tcp_pcb_purge(struct tcp_pcb *pcb) if (pcb->ooseq != NULL) { LWIP_DEBUGF(TCP_DEBUG, ("tcp_pcb_purge: data left on ->ooseq\n")); } - + + /* Stop the retransmission timer as it will expect data on unacked + queue if it fires */ + pcb->rtime = -1; + tcp_segs_free(pcb->ooseq); pcb->ooseq = NULL; #endif /* TCP_QUEUE_OOSEQ */ diff --git a/src/core/tcp_in.c b/src/core/tcp_in.c index 5ab48682..96d76e5b 100644 --- a/src/core/tcp_in.c +++ b/src/core/tcp_in.c @@ -282,12 +282,12 @@ tcp_input(struct pbuf *p, struct netif *inp) TCP_EVENT_ERR(pcb->errf, pcb->callback_arg, ERR_RST); tcp_pcb_remove(&tcp_active_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); - } else if (recv_flags & TF_CLOSED) { + } else if (recv_flags & TF_CLOSED) { /* The connection has been closed and we will deallocate the PCB. */ tcp_pcb_remove(&tcp_active_pcbs, pcb); memp_free(MEMP_TCP_PCB, pcb); - } else { + } else { err = ERR_OK; /* If the application has registered a "sent" function to be called when new send buffer space is available, we call it @@ -504,6 +504,14 @@ tcp_process(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_QLEN_DEBUG, ("tcp_process: SYN-SENT --queuelen %"U16_F"\n", (u16_t)pcb->snd_queuelen)); rseg = pcb->unacked; pcb->unacked = rseg->next; + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if(pcb->unacked == NULL) + pcb->rtime = -1; + else + pcb->rtime = 0; + tcp_seg_free(rseg); /* Parse any options in the SYNACK. */ @@ -700,10 +708,7 @@ tcp_receive(struct tcp_pcb *pcb) LWIP_DEBUGF(TCP_FR_DEBUG, ("tcp_receive: dupack averted %"U32_F" %"U32_F"\n", pcb->snd_wl1 + pcb->snd_wnd, right_wnd_edge)); } - } else - /*if (TCP_SEQ_LT(pcb->lastack, ackno) && - TCP_SEQ_LEQ(ackno, pcb->snd_max)) { */ - if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){ + } else if (TCP_SEQ_BETWEEN(ackno, pcb->lastack+1, pcb->snd_max)){ /* We come here when the ACK acknowledges new data. */ /* Reset the "IN Fast Retransmit" flag, since we are no longer @@ -775,6 +780,14 @@ tcp_receive(struct tcp_pcb *pcb) pcb->unsent != NULL); } } + + /* If there's nothing left to acknowledge, stop the retransmit + timer, otherwise reset it to start again */ + if(pcb->unacked == NULL) + pcb->rtime = -1; + else + pcb->rtime = 0; + pcb->polltmr = 0; } diff --git a/src/core/tcp_out.c b/src/core/tcp_out.c index 9b865d83..a8be31fd 100644 --- a/src/core/tcp_out.c +++ b/src/core/tcp_out.c @@ -551,7 +551,9 @@ tcp_output_segment(struct tcp_seg *seg, struct tcp_pcb *pcb) ip_addr_set(&(pcb->local_ip), &(netif->ip_addr)); } - pcb->rtime = 0; + /* Set retransmission timer running if it is not currently enabled */ + if(pcb->rtime == -1) + pcb->rtime = 0; if (pcb->rttest == 0) { pcb->rttest = tcp_ticks; @@ -674,7 +676,6 @@ tcp_rexmit(struct tcp_pcb *pcb) /* Do the actual retransmission. */ snmp_inc_tcpretranssegs(); tcp_output(pcb); - } diff --git a/src/include/lwip/tcp.h b/src/include/lwip/tcp.h index 1aaeb370..dbf4ef47 100644 --- a/src/include/lwip/tcp.h +++ b/src/include/lwip/tcp.h @@ -253,7 +253,7 @@ struct tcp_pcb { u8_t polltmr, pollinterval; /* Retransmission timer. */ - u16_t rtime; + s16_t rtime; u16_t mss; /* maximum segment size */ @@ -262,7 +262,7 @@ struct tcp_pcb { u32_t rtseq; /* sequence number being timed */ s16_t sa, sv; /* @todo document this */ - u16_t rto; /* retransmission time-out */ + s16_t rto; /* retransmission time-out */ u8_t nrtx; /* number of retransmissions */ /* fast retransmit/recovery */