mirror of
https://github.com/apache/nuttx.git
synced 2026-06-01 16:59:28 +08:00
net/tcp(buffered): retransmit only one the earliest not acknowledged segment
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 and tcp_sendfile.c. Signed-off-by: chao.an <anchao@xiaomi.com>
This commit is contained in:
@@ -175,10 +175,7 @@ struct tcp_conn_s
|
|||||||
uint8_t rcvseq[4]; /* The sequence number that we expect to
|
uint8_t rcvseq[4]; /* The sequence number that we expect to
|
||||||
* receive next */
|
* receive next */
|
||||||
uint8_t sndseq[4]; /* The sequence number that was last sent by us */
|
uint8_t sndseq[4]; /* The sequence number that was last sent by us */
|
||||||
#if !defined(CONFIG_NET_TCP_WRITE_BUFFERS) || \
|
|
||||||
defined(CONFIG_NET_SENDFILE)
|
|
||||||
uint32_t rexmit_seq; /* The sequence number to be retrasmitted */
|
uint32_t rexmit_seq; /* The sequence number to be retrasmitted */
|
||||||
#endif
|
|
||||||
uint8_t crefs; /* Reference counts on this instance */
|
uint8_t crefs; /* Reference counts on this instance */
|
||||||
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
||||||
uint8_t domain; /* IP domain: PF_INET or PF_INET6 */
|
uint8_t domain; /* IP domain: PF_INET or PF_INET6 */
|
||||||
|
|||||||
@@ -322,11 +322,6 @@ 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.
|
* new data in it, we must send out a packet.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#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 &&
|
if ((result & TCP_REXMIT) != 0 &&
|
||||||
dev->d_sndlen > 0 && conn->tx_unacked > 0)
|
dev->d_sndlen > 0 && conn->tx_unacked > 0)
|
||||||
{
|
{
|
||||||
@@ -345,8 +340,6 @@ void tcp_rexmit(FAR struct net_driver_s *dev, FAR struct tcp_conn_s *conn,
|
|||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS)
|
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS)
|
||||||
if (dev->d_sndlen > 0)
|
if (dev->d_sndlen > 0)
|
||||||
|
|||||||
+74
-12
@@ -323,7 +323,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
FAR struct tcp_conn_s *conn = pvpriv;
|
FAR struct tcp_conn_s *conn = pvpriv;
|
||||||
bool rexmit = false;
|
#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
|
||||||
|
uint32_t rexmitno = 0;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* Get the TCP connection pointer reliably from
|
/* Get the TCP connection pointer reliably from
|
||||||
* the corresponding TCP socket.
|
* the corresponding TCP socket.
|
||||||
@@ -501,12 +503,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
{
|
{
|
||||||
/* Do fast retransmit */
|
/* Do fast retransmit */
|
||||||
|
|
||||||
rexmit = true;
|
rexmitno = ackno;
|
||||||
}
|
|
||||||
else if ((TCP_WBNACK(wrb) > TCP_FAST_RETRANSMISSION_THRESH) &&
|
/* Reset counter */
|
||||||
TCP_WBNACK(wrb) == sq_count(&conn->unacked_q) - 1)
|
|
||||||
{
|
|
||||||
/* Reset the duplicate ack counter */
|
|
||||||
|
|
||||||
TCP_WBNACK(wrb) = 0;
|
TCP_WBNACK(wrb) = 0;
|
||||||
}
|
}
|
||||||
@@ -573,14 +572,77 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
|||||||
return flags;
|
return flags;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Check if we are being asked to retransmit data */
|
#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
|
||||||
|
if (rexmitno != 0)
|
||||||
else if ((flags & TCP_REXMIT) != 0)
|
|
||||||
{
|
{
|
||||||
rexmit = true;
|
FAR struct tcp_wrbuffer_s *wrb;
|
||||||
|
FAR sq_entry_t *entry;
|
||||||
|
FAR sq_entry_t *next;
|
||||||
|
size_t sndlen;
|
||||||
|
|
||||||
|
/* According to RFC 6298 (5.4), retransmit the earliest segment
|
||||||
|
* that has not been acknowledged by the TCP receiver.
|
||||||
|
*/
|
||||||
|
|
||||||
|
for (entry = sq_peek(&conn->unacked_q); entry; entry = next)
|
||||||
|
{
|
||||||
|
wrb = (FAR struct tcp_wrbuffer_s *)entry;
|
||||||
|
next = sq_next(entry);
|
||||||
|
|
||||||
|
if (rexmitno != TCP_WBSEQNO(wrb))
|
||||||
|
{
|
||||||
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (rexmit)
|
conn->rexmit_seq = rexmitno;
|
||||||
|
|
||||||
|
/* Reconstruct the length of the earliest segment to be
|
||||||
|
* retransmitted.
|
||||||
|
*/
|
||||||
|
|
||||||
|
sndlen = TCP_WBPKTLEN(wrb);
|
||||||
|
|
||||||
|
if (sndlen > conn->mss)
|
||||||
|
{
|
||||||
|
sndlen = conn->mss;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* As we are retransmitting, the sequence number is expected
|
||||||
|
* already set for this write buffer.
|
||||||
|
*/
|
||||||
|
|
||||||
|
DEBUGASSERT(TCP_WBSEQNO(wrb) != (unsigned)-1);
|
||||||
|
conn->rexmit_seq = TCP_WBSEQNO(wrb);
|
||||||
|
|
||||||
|
#ifdef NEED_IPDOMAIN_SUPPORT
|
||||||
|
/* If both IPv4 and IPv6 support are enabled, then we will need to
|
||||||
|
* select which one to use when generating the outgoing packet.
|
||||||
|
* If only one domain is selected, then the setup is already in
|
||||||
|
* place and we need do nothing.
|
||||||
|
*/
|
||||||
|
|
||||||
|
send_ipselect(dev, conn);
|
||||||
|
#endif
|
||||||
|
/* Then set-up to send that amount of data. (this won't actually
|
||||||
|
* happen until the polling cycle completes).
|
||||||
|
*/
|
||||||
|
|
||||||
|
devif_iob_send(dev, TCP_WBIOB(wrb), sndlen, 0);
|
||||||
|
|
||||||
|
/* Reset the retransmission timer. */
|
||||||
|
|
||||||
|
tcp_update_retrantimer(conn, conn->rto);
|
||||||
|
|
||||||
|
/* Continue waiting */
|
||||||
|
|
||||||
|
return flags;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* Check if we are being asked to retransmit data */
|
||||||
|
|
||||||
|
if ((flags & TCP_REXMIT) != 0)
|
||||||
{
|
{
|
||||||
FAR struct tcp_wrbuffer_s *wrb;
|
FAR struct tcp_wrbuffer_s *wrb;
|
||||||
FAR sq_entry_t *entry;
|
FAR sq_entry_t *entry;
|
||||||
|
|||||||
Reference in New Issue
Block a user