mirror of
https://github.com/lwip-tcpip/lwip.git
synced 2024-11-04 14:29:39 +00:00
Add persist timer
This commit is contained in:
parent
22e2540eb6
commit
99afb15ced
@ -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
|
||||
|
@ -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 */
|
||||
|
@ -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 {
|
||||
|
@ -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 */
|
||||
|
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user