Add persist timer

This commit is contained in:
kieranm 2007-12-31 13:34:47 +00:00
parent 22e2540eb6
commit 99afb15ced
5 changed files with 161 additions and 37 deletions

View File

@ -18,6 +18,8 @@ HISTORY
* [Enter new changes just after this line - do not remove this line]
++ New features:
2007-12-31 Kieran Mansley (based on patch from Per-Henrik Lundbolm)
* tcp.c, tcp_in.c, tcp_out.c, tcp.h: Add TCP persist timer
2007-12-31 Frédéric Bernon, Luca Ceresoli
* autoip.c, etharp.c: ip_addr.h: Integrate patch #6348: "Broadcast ARP packets

View File

@ -56,6 +56,8 @@
u32_t tcp_ticks;
const u8_t tcp_backoff[13] =
{ 1, 2, 3, 4, 5, 6, 7, 7, 7, 7, 7, 7, 7};
/* Times per slowtmr hits */
const u8_t tcp_persist_backoff[7] = { 3, 6, 12, 24, 48, 96, 120 };
/* The TCP PCB lists. */
@ -572,36 +574,52 @@ tcp_slowtmr(void)
++pcb_remove;
LWIP_DEBUGF(TCP_DEBUG, ("tcp_slowtmr: max DATA retries reached\n"));
} else {
/* 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 %"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];
if (pcb->persist_backoff > 0) {
/* If snd_wnd is zero, use persist timer to send 1 byte probes
* instead of using the standard retransmission mechanism. */
pcb->persist_cnt++;
if (pcb->persist_cnt >= tcp_persist_backoff[pcb->persist_backoff-1]) {
pcb->persist_cnt = 0;
if (pcb->persist_backoff < sizeof(tcp_persist_backoff)) {
pcb->persist_backoff++;
}
tcp_zero_window_probe(pcb);
}
} else {
/* Increase the retransmission timer if it is running */
if(pcb->rtime >= 0)
++pcb->rtime;
/* Reset the retransmission timer. */
pcb->rtime = 0;
if (pcb->unacked != NULL && pcb->rtime >= pcb->rto) {
/* Time for a retransmission. */
LWIP_DEBUGF(TCP_RTO_DEBUG, ("tcp_slowtmr: rtime %"S16_F
" pcb->rto %"S16_F"\n",
pcb->rtime, pcb->rto));
/* Reduce congestion window and ssthresh. */
eff_wnd = LWIP_MIN(pcb->cwnd, pcb->snd_wnd);
pcb->ssthresh = eff_wnd >> 1;
if (pcb->ssthresh < pcb->mss) {
pcb->ssthresh = pcb->mss * 2;
}
pcb->cwnd = pcb->mss;
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F" ssthresh %"U16_F"\n",
pcb->cwnd, pcb->ssthresh));
/* 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;
if (pcb->ssthresh < pcb->mss) {
pcb->ssthresh = pcb->mss * 2;
}
pcb->cwnd = pcb->mss;
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_slowtmr: cwnd %"U16_F
" ssthresh %"U16_F"\n",
pcb->cwnd, pcb->ssthresh));
/* The following needs to be called AFTER cwnd is set to one mss - STJ */
tcp_rexmit_rto(pcb);
/* 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 */

View File

@ -707,6 +707,9 @@ tcp_receive(struct tcp_pcb *pcb)
pcb->snd_wnd = tcphdr->wnd;
pcb->snd_wl1 = seqno;
pcb->snd_wl2 = ackno;
if (pcb->snd_wnd > 0 && pcb->persist_backoff > 0) {
pcb->persist_backoff = 0;
}
LWIP_DEBUGF(TCP_WND_DEBUG, ("tcp_receive: window update %"U16_F"\n", pcb->snd_wnd));
#if TCP_WND_DEBUG
} else {

View File

@ -491,25 +491,34 @@ tcp_output(struct tcp_pcb *pcb)
#if TCP_OUTPUT_DEBUG
if (seg == NULL) {
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n", (void*)pcb->unsent));
LWIP_DEBUGF(TCP_OUTPUT_DEBUG, ("tcp_output: nothing to send (%p)\n",
(void*)pcb->unsent));
}
#endif /* TCP_OUTPUT_DEBUG */
#if TCP_CWND_DEBUG
if (seg == NULL) {
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", seg == NULL, ack %"U32_F"\n",
pcb->snd_wnd, pcb->cwnd, wnd,
pcb->lastack));
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F
", cwnd %"U16_F", wnd %"U32_F
", seg == NULL, ack %"U32_F"\n",
pcb->snd_wnd, pcb->cwnd, wnd, pcb->lastack));
} else {
LWIP_DEBUGF(TCP_CWND_DEBUG, ("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
pcb->snd_wnd, pcb->cwnd, wnd,
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
ntohl(seg->tcphdr->seqno), pcb->lastack));
LWIP_DEBUGF(TCP_CWND_DEBUG,
("tcp_output: snd_wnd %"U16_F", cwnd %"U16_F", wnd %"U32_F
", effwnd %"U32_F", seq %"U32_F", ack %"U32_F"\n",
pcb->snd_wnd, pcb->cwnd, wnd,
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len,
ntohl(seg->tcphdr->seqno), pcb->lastack));
}
#endif /* TCP_CWND_DEBUG */
/* data available and window allows it to be sent? */
if (seg != NULL && pcb->snd_wnd == 0 && pcb->persist_backoff == 0) {
/* prepare for persist timer */
pcb->persist_cnt = 0;
pcb->persist_backoff = 1;
} /* data available and window allows it to be sent? */
while (seg != NULL &&
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
LWIP_ASSERT("RST not expected here!", (TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
ntohl(seg->tcphdr->seqno) - pcb->lastack + seg->len <= wnd) {
LWIP_ASSERT("RST not expected here!",
(TCPH_FLAGS(seg->tcphdr) & TCP_RST) == 0);
/* Stop sending if the nagle algorithm would prevent it
* Don't stop:
* - if tcp_enqueue had a memory error before (prevent delayed ACK timeout) or
@ -851,4 +860,90 @@ tcp_keepalive(struct tcp_pcb *pcb)
pcb->snd_nxt - 1, pcb->rcv_nxt));
}
/**
* Send persist timer zero-window probes to keep a connection active
* when a window update is lost.
*
* Called by tcp_slowtmr()
*
* @param pcb the tcp_pcb for which to send a zero-window probe packet
*/
void
tcp_zero_window_probe(struct tcp_pcb *pcb)
{
struct pbuf *p;
struct tcp_hdr *tcphdr;
struct tcp_seg *seg;
LWIP_DEBUGF(TCP_DEBUG,
("tcp_zero_window_probe: sending ZERO WINDOW probe to %"
U16_F".%"U16_F".%"U16_F".%"U16_F"\n",
ip4_addr1(&pcb->remote_ip), ip4_addr2(&pcb->remote_ip),
ip4_addr3(&pcb->remote_ip), ip4_addr4(&pcb->remote_ip)));
LWIP_DEBUGF(TCP_DEBUG,
("tcp_zero_window_probe: tcp_ticks %"U32_F
" pcb->tmr %"U32_F" pcb->keep_cnt_sent %"U16_F"\n",
tcp_ticks, pcb->tmr, pcb->keep_cnt_sent));
seg = pcb->unacked;
if(seg == NULL)
seg = pcb->unsent;
if(seg == NULL)
return;
p = pbuf_alloc(PBUF_IP, TCP_HLEN + 1, PBUF_RAM);
if(p == NULL) {
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: no memory for pbuf\n"));
return;
}
LWIP_ASSERT("check that first pbuf can hold struct tcp_hdr",
(p->len >= sizeof(struct tcp_hdr)));
tcphdr = p->payload;
tcphdr->src = htons(pcb->local_port);
tcphdr->dest = htons(pcb->remote_port);
tcphdr->seqno = seg->tcphdr->seqno;
tcphdr->ackno = htonl(pcb->rcv_nxt);
TCPH_FLAGS_SET(tcphdr, 0);
tcphdr->wnd = htons(pcb->rcv_ann_wnd);
tcphdr->urgp = 0;
TCPH_HDRLEN_SET(tcphdr, 5);
/* Copy in one byte from the head of the unacked queue */
*((char *)p->payload + sizeof(struct tcp_hdr)) = *(char *)seg->dataptr;
tcphdr->chksum = 0;
#if CHECKSUM_GEN_TCP
tcphdr->chksum = inet_chksum_pseudo(p, &pcb->local_ip, &pcb->remote_ip,
IP_PROTO_TCP, p->tot_len);
#endif
TCP_STATS_INC(tcp.xmit);
/* Send output to IP */
#if LWIP_NETIF_HWADDRHINT
{
struct netif *netif;
netif = ip_route(&pcb->remote_ip);
if(netif != NULL){
netif->addr_hint = &(pcb->addr_hint);
ip_output_if(p, &(pcb->local_ip), &(pcb->remote_ip), pcb->ttl,
0, IP_PROTO_TCP, netif);
netif->addr_hint = NULL;
}
}
#else /* LWIP_NETIF_HWADDRHINT*/
ip_output(p, &pcb->local_ip, &pcb->remote_ip, pcb->ttl, 0, IP_PROTO_TCP);
#endif /* LWIP_NETIF_HWADDRHINT*/
pbuf_free(p);
LWIP_DEBUGF(TCP_DEBUG, ("tcp_zero_window_probe: seqno %"U32_F
" ackno %"U32_F".\n",
pcb->snd_nxt - 1, pcb->rcv_nxt));
}
#endif /* LWIP_TCP */

View File

@ -397,6 +397,11 @@ struct tcp_pcb {
u32_t keep_cnt;
#endif /* LWIP_TCP_KEEPALIVE */
/* Persist timer counter */
u32_t persist_cnt;
/* Persist timer back-off */
u8_t persist_backoff;
/* KEEPALIVE counter */
u8_t keep_cnt_sent;
};
@ -517,6 +522,7 @@ void tcp_rst(u32_t seqno, u32_t ackno,
u32_t tcp_next_iss(void);
void tcp_keepalive(struct tcp_pcb *pcb);
void tcp_zero_window_probe(struct tcp_pcb *pcb);
#if LWIP_CALCULATE_EFF_SEND_MSS
u16_t tcp_eff_send_mss(u16_t sendmss, struct ip_addr *addr);