From 48afbe321eddfb68966a4436884c022e64c3e166 Mon Sep 17 00:00:00 2001 From: Stefano Brivio Date: Sun, 25 Apr 2021 10:46:42 +0200 Subject: [PATCH] tcp: Preserve data sent during SOCK_SYN_SENT state Seen with iperf3 server on tap side: connection state is SOCK_SYN_SENT, we haven't got an ACK from the tap yet (that's why we're not in ESTABLISHED), but a data packet comes. Don't read this data until we reach the ESTABLISHED state, by keeping EPOLLIN disabled until that point. Signed-off-by: Stefano Brivio --- tcp.c | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/tcp.c b/tcp.c index 3d47f35..1713dbc 100644 --- a/tcp.c +++ b/tcp.c @@ -954,7 +954,7 @@ static void tcp_conn_from_tap(struct ctx *c, int af, void *addr, tcp_act_set(s); - ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP; + ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP; ev.data.fd = s; tc[s].seq_init_from_tap = ntohl(th->seq); @@ -1059,7 +1059,7 @@ static void tcp_conn_from_sock(struct ctx *c, int fd) tcp_act_set(s); - ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP; + ev.events = EPOLLRDHUP | EPOLLHUP; ev.data.fd = s; epoll_ctl(c->epollfd, EPOLL_CTL_ADD, s, &ev); @@ -1209,6 +1209,7 @@ int tcp_tap_handler(struct ctx *c, int af, void *addr, { /* TODO: Implement message batching for TCP */ struct tcphdr *th = (struct tcphdr *)msg[0].l4h; + struct epoll_event ev = { 0 }; size_t len = msg[0].l4_len; size_t off, skip = 0; @@ -1272,6 +1273,16 @@ int tcp_tap_handler(struct ctx *c, int af, void *addr, tcp_set_state(s, ESTABLISHED); tcp_send_to_tap(c, s, ACK, NULL, 0); + + /* The client might have sent data already, which we didn't + * dequeue waiting for SYN,ACK from tap -- check now. + */ + tcp_data_from_sock(c, s); + + ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP; + ev.data.fd = s; + epoll_ctl(c->epollfd, EPOLL_CTL_MOD, s, &ev); + break; case TAP_SYN_RCVD: if (th->fin) { @@ -1379,7 +1390,7 @@ static void tcp_connect_finish(struct ctx *c, int s) return; /* Drop EPOLLOUT, only used to wait for connect() to complete */ - ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLERR | EPOLLHUP; + ev.events = EPOLLIN | EPOLLET | EPOLLRDHUP | EPOLLHUP; ev.data.fd = s; epoll_ctl(c->epollfd, EPOLL_CTL_MOD, s, &ev); @@ -1403,6 +1414,12 @@ void tcp_sock_handler(struct ctx *c, int s, uint32_t events) return; } + if (tc[s].s == SOCK_SYN_SENT) { + /* This can only be a socket error or a shutdown from remote */ + tcp_rst(c, s); + return; + } + sl = sizeof(so); if ((events & EPOLLERR) || getsockopt(s, SOL_SOCKET, SO_ACCEPTCONN, &so, &sl)) {