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:
parent
f75f100954
commit
669fb83706
@ -175,10 +175,7 @@ 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) || \
|
||||
defined(CONFIG_NET_SENDFILE)
|
||||
uint32_t rexmit_seq; /* The sequence number to be retrasmitted */
|
||||
#endif
|
||||
uint8_t crefs; /* Reference counts on this instance */
|
||||
#if defined(CONFIG_NET_IPv4) && defined(CONFIG_NET_IPv6)
|
||||
uint8_t domain; /* IP domain: PF_INET or PF_INET6 */
|
||||
|
@ -322,30 +322,23 @@ 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.
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS) && defined(CONFIG_NET_SENDFILE)
|
||||
if (conn->sendfile)
|
||||
#endif
|
||||
if ((result & TCP_REXMIT) != 0 &&
|
||||
dev->d_sndlen > 0 && conn->tx_unacked > 0)
|
||||
{
|
||||
#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;
|
||||
uint32_t saveseq;
|
||||
|
||||
/* According to RFC 6298 (5.4), retransmit the earliest segment
|
||||
* that has not been acknowledged by the TCP receiver.
|
||||
*/
|
||||
/* 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);
|
||||
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_send(dev, conn, TCP_ACK | TCP_PSH, dev->d_sndlen + hdrlen);
|
||||
|
||||
tcp_setsequence(conn->sndseq, saveseq);
|
||||
tcp_setsequence(conn->sndseq, saveseq);
|
||||
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_NET_TCP_WRITE_BUFFERS)
|
||||
|
@ -323,7 +323,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
||||
*/
|
||||
|
||||
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
|
||||
* the corresponding TCP socket.
|
||||
@ -501,12 +503,9 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
||||
{
|
||||
/* Do fast retransmit */
|
||||
|
||||
rexmit = true;
|
||||
}
|
||||
else if ((TCP_WBNACK(wrb) > TCP_FAST_RETRANSMISSION_THRESH) &&
|
||||
TCP_WBNACK(wrb) == sq_count(&conn->unacked_q) - 1)
|
||||
{
|
||||
/* Reset the duplicate ack counter */
|
||||
rexmitno = ackno;
|
||||
|
||||
/* Reset counter */
|
||||
|
||||
TCP_WBNACK(wrb) = 0;
|
||||
}
|
||||
@ -573,14 +572,77 @@ static uint16_t psock_send_eventhandler(FAR struct net_driver_s *dev,
|
||||
return flags;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_NET_TCP_FAST_RETRANSMIT
|
||||
if (rexmitno != 0)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
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 */
|
||||
|
||||
else if ((flags & TCP_REXMIT) != 0)
|
||||
{
|
||||
rexmit = true;
|
||||
}
|
||||
|
||||
if (rexmit)
|
||||
if ((flags & TCP_REXMIT) != 0)
|
||||
{
|
||||
FAR struct tcp_wrbuffer_s *wrb;
|
||||
FAR sq_entry_t *entry;
|
||||
|
Loading…
Reference in New Issue
Block a user