From 0017bc3c3e3f666bb190f2c1f808e447e96a10aa Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Wed, 4 Aug 2021 01:29:59 +0200 Subject: tcp: Always allow ACKs when pending, fixes for no_snd_wnd and closing states We won't necessarily have another choice to ACK in a timely fashion if we skip ACKs from a number of states (including ESTABLISHED) when there's enough window left. Check for ACKed bytes as soon as it makes sense. If the sending window is not reported by the kernel, ACK as soon as we queue onto the socket, given that we're forced to use a rather small window. In FIN_WAIT_1_SOCK_FIN, we also have to account for the FIN flag sent by the peer in the sequence. Signed-off-by: Stefano Brivio --- tcp.c | 33 +++++++++++++++++++++++---------- 1 file changed, 23 insertions(+), 10 deletions(-) (limited to 'tcp.c') diff --git a/tcp.c b/tcp.c index 65a9aff..5f9d5f6 100644 --- a/tcp.c +++ b/tcp.c @@ -1081,15 +1081,17 @@ static int tcp_send_to_tap(struct ctx *c, struct tcp_tap_conn *conn, uint32_t ack_offset = conn->seq_from_tap - conn->seq_ack_to_tap; char buf[USHRT_MAX] = { 0 }, *data; struct tcp_info info = { 0 }; + int ws = 0, err, ack_pending; socklen_t sl = sizeof(info); struct tcphdr *th; - int ws = 0, err; - if (ack_offset < conn->tcpi_snd_wnd / 10 && !flags) { + if (!ack_offset && !flags) { err = 0; info.tcpi_bytes_acked = conn->tcpi_acked_last; info.tcpi_snd_wnd = conn->tcpi_snd_wnd; info.tcpi_snd_wscale = conn->ws; + } else if (conn->no_snd_wnd && !(flags & SYN)) { + err = 0; } else { err = getsockopt(conn->sock, SOL_TCP, TCP_INFO, &info, &sl); if (err && !(flags & RST)) { @@ -1135,21 +1137,32 @@ static int tcp_send_to_tap(struct ctx *c, struct tcp_tap_conn *conn, conn->seq_to_tap += len; } - if (!err && ((info.tcpi_bytes_acked > conn->tcpi_acked_last) || - (flags & ACK) || len)) { + if (conn->no_snd_wnd) { + ack_pending = (conn->seq_from_tap - conn->seq_ack_to_tap) < + MAX_WINDOW; + } else { + ack_pending = info.tcpi_bytes_acked > conn->tcpi_acked_last; + } + + if (!err && (ack_pending || (flags & ACK) || len)) { th->ack = 1; - conn->seq_ack_to_tap = info.tcpi_bytes_acked + - conn->seq_init_from_tap; + if (conn->no_snd_wnd) { + conn->seq_ack_to_tap = conn->seq_from_tap; + } else { + conn->seq_ack_to_tap = info.tcpi_bytes_acked + + conn->seq_init_from_tap; + conn->tcpi_acked_last = info.tcpi_bytes_acked; + } - if (conn->state == LAST_ACK) { + if (conn->state == LAST_ACK || + conn->state == FIN_WAIT_1_SOCK_FIN) conn->seq_ack_to_tap = conn->seq_from_tap + 1; + + if (conn->state == LAST_ACK) th->seq = htonl(ntohl(th->seq) + 1); - } th->ack_seq = htonl(conn->seq_ack_to_tap); - - conn->tcpi_acked_last = info.tcpi_bytes_acked; } else { if (!len && !flags) return 0; -- cgit v1.2.3