From 64dd669749707d4476fa5ce602d785a8a2ea7b68 Mon Sep 17 00:00:00 2001 From: Alexander Lunev Date: Wed, 19 Jan 2022 11:02:33 +0300 Subject: [PATCH] net/tcp/sendfile: retransmit only one the earliest not acknowledged segment (according to RFC 6298 (5.4)). The issue is the same as it was in tcp_send_unbuffered.c. --- net/tcp/tcp.h | 3 ++- net/tcp/tcp_appsend.c | 46 +++++++++++++++++++++-------------- net/tcp/tcp_send_unbuffered.c | 6 +++++ net/tcp/tcp_sendfile.c | 45 +++++++++++++++++++++++++++++----- 4 files changed, 75 insertions(+), 25 deletions(-) diff --git a/net/tcp/tcp.h b/net/tcp/tcp.h index 3992d6be0e..60dd1e3b9f 100644 --- a/net/tcp/tcp.h +++ b/net/tcp/tcp.h @@ -172,7 +172,8 @@ struct tcp_conn_s uint8_t rcvseq[4]; /* The sequence number that we expect to * receive next */ uint8_t sndseq[4]; /* The sequence number that was last sent by us */ -#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) +#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || \ + defined(CONFIG_NET_SENDFILE) uint32_t rexmit_seq; /* The sequence number to be retrasmitted */ #endif uint8_t crefs; /* Reference counts on this instance */ diff --git a/net/tcp/tcp_appsend.c b/net/tcp/tcp_appsend.c index 82c7c9f6f7..1e8e58dbc2 100644 --- a/net/tcp/tcp_appsend.c +++ b/net/tcp/tcp_appsend.c @@ -322,26 +322,36 @@ void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn, * new data in it, we must send out a packet. */ -#ifdef CONFIG_NET_TCP_WRITE_BUFFERS +#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_NET_SENDFILE) + if (conn->sendfile) +#endif + { +#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || defined(CONFIG_NET_SENDFILE) + if ((result & TCP_REXMIT) != 0 && + dev->d_sndlen > 0 && conn->tx_unacked > 0) + { + uint32_t saveseq; + + /* According to RFC 6298 (5.4), retransmit the earliest segment + * that has not been acknowledged by the TCP receiver. + */ + + saveseq = tcp_getsequence(conn->sndseq); + tcp_setsequence(conn->sndseq, conn->rexmit_seq); + + tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen); + + tcp_setsequence(conn->sndseq, saveseq); + + return; + } +#endif + } + +#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) if (dev->d_sndlen > 0) #else - if ((result & TCP_REXMIT) != 0 && - dev->d_sndlen > 0 && conn->tx_unacked > 0) - { - uint32_t saveseq; - - /* According to RFC 6298 (5.4), retransmit the earliest segment - * that has not been acknowledged by the TCP receiver. - */ - - saveseq = tcp_getsequence(conn->sndseq); - tcp_setsequence(conn->sndseq, conn->rexmit_seq); - - tcp_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen); - - tcp_setsequence(conn->sndseq, saveseq); - } - else if (dev->d_sndlen > 0 && conn->tx_unacked > 0) + if (dev->d_sndlen > 0 && conn->tx_unacked > 0) #endif { uint32_t seq; diff --git a/net/tcp/tcp_send_unbuffered.c b/net/tcp/tcp_send_unbuffered.c index 26a11ed2d7..41d23023cf 100644 --- a/net/tcp/tcp_send_unbuffered.c +++ b/net/tcp/tcp_send_unbuffered.c @@ -311,6 +311,8 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev, if ((flags & TCP_REXMIT) != 0) { + nwarn("WARNING: TCP_REXMIT\n"); + /* According to RFC 6298 (5.4), retransmit the earliest segment * that has not been acknowledged by the TCP receiver. */ @@ -430,6 +432,10 @@ static uint16_t tcpsend_eventhandler(FAR struct net_driver_s *dev, ninfo("SEND: acked=%" PRId32 " sent=%zd buflen=%zd\n", pstate->snd_acked, pstate->snd_sent, pstate->snd_buflen); } + else + { + nwarn("WARNING: Window full, wait for ack\n"); + } } /* Continue waiting */ diff --git a/net/tcp/tcp_sendfile.c b/net/tcp/tcp_sendfile.c index 5f4a30275f..9406fa5313 100644 --- a/net/tcp/tcp_sendfile.c +++ b/net/tcp/tcp_sendfile.c @@ -276,14 +276,47 @@ static uint16_t sendfile_eventhandler(FAR struct net_driver_s *dev, { nwarn("WARNING: TCP_REXMIT\n"); - /* Yes.. in this case, reset the number of bytes that have been sent - * to the number of bytes that have been ACKed. + /* According to RFC 6298 (5.4), retransmit the earliest segment + * that has not been acknowledged by the TCP receiver. */ - pstate->snd_sent = pstate->snd_acked; -#ifndef CONFIG_NET_TCP_WRITE_BUFFERS - conn->rexmit_seq = pstate->snd_sent + pstate->snd_isn; -#endif + /* Reconstruct the length of the earliest segment to be retransmitted */ + + uint32_t sndlen = pstate->snd_flen - pstate->snd_acked; + + if (sndlen > conn->mss) + { + sndlen = conn->mss; + } + + conn->rexmit_seq = pstate->snd_isn + pstate->snd_acked; + + /* Then set-up to send that amount of data. (this won't actually + * happen until the polling cycle completes). + */ + + ret = file_seek(pstate->snd_file, + pstate->snd_foffset + pstate->snd_acked, SEEK_SET); + if (ret < 0) + { + nerr("ERROR: Failed to lseek: %d\n", ret); + pstate->snd_sent = ret; + goto end_wait; + } + + ret = file_read(pstate->snd_file, dev->d_appdata, sndlen); + if (ret < 0) + { + nerr("ERROR: Failed to read from input file: %d\n", (int)ret); + pstate->snd_sent = ret; + goto end_wait; + } + + dev->d_sndlen = sndlen; + + /* Continue waiting */ + + return flags; } /* Check for a loss of connection.