From 1c6f8b95eb40be04d267fc733feb6c262cb7e016 Mon Sep 17 00:00:00 2001 From: Sergey Lyubka Date: Sat, 2 Mar 2024 15:44:08 +0000 Subject: [PATCH] Sending ACK when about to exhaust TCP WIN1 --- mongoose.c | 37 +++++++++++++++++++++---------------- src/net_builtin.c | 37 +++++++++++++++++++++---------------- 2 files changed, 42 insertions(+), 32 deletions(-) diff --git a/mongoose.c b/mongoose.c index 93b4ca35..bd1593d9 100644 --- a/mongoose.c +++ b/mongoose.c @@ -4894,10 +4894,12 @@ void mg_mgr_init(struct mg_mgr *mgr) { #define MIP_TCP_ARP_MS 100 // Timeout for ARP response #define MIP_TCP_SYN_MS 15000 // Timeout for connection establishment #define MIP_TCP_FIN_MS 1000 // Timeout for closing connection +#define MIP_TCP_WIN 16384 // TCP window size struct connstate { uint32_t seq, ack; // TCP seq/ack counters uint64_t timer; // TCP keep-alive / ACK timer + size_t noack; // Not ACK-ed received TCP bytes uint8_t mac[6]; // Peer MAC address uint8_t ttype; // Timer type. 0: ack, 1: keep-alive #define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive @@ -5280,11 +5282,12 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (msgtype == 6 && ifp->ip == ip) { // DHCPNACK, release IP ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; } else if (msgtype == 2 && ifp->state == MG_TCPIP_STATE_UP && ip && gw && - lease) { // DHCPOFFER + lease) { // DHCPOFFER // select IP, (4.4.1) (fallback to IP source addr on foul play) - tx_dhcp_request_sel(ifp, ip, pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); - ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state - } else if (msgtype == 5) { // DHCPACK + tx_dhcp_request_sel(ifp, ip, + pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); + ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state + } else if (msgtype == 5) { // DHCPACK if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP ifp->lease_expire = ifp->now + lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); @@ -5378,7 +5381,7 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip, tcp->seq = seq; tcp->ack = ack; tcp->flags = flags; - tcp->win = mg_htons(8192); + tcp->win = mg_htons(MIP_TCP_WIN); tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); uint32_t cs = 0; uint16_t n = (uint16_t) (sizeof(*tcp) + len); @@ -5533,17 +5536,18 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { MG_VERBOSE(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack)); // Advance ACK counter s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); -#if 0 - // Send ACK immediately - uint32_t rem_ip; - memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); - MG_DEBUG((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack)); - tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, c->loc.port, - c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); -#else - // if not already running, setup a timer to send an ACK later - if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); -#endif + s->noack += pkt->pay.len; + if (s->noack + 1500 >= MIP_TCP_WIN) { + // Send ACK immediately + MG_VERBOSE((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack)); + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", + 0); + s->noack = 0; + } else { + // if not already running, setup a timer to send an ACK later + if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); + } if (c->is_tls && c->is_tls_hs) { mg_tls_handshake(c); @@ -5787,6 +5791,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack)); tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); + s->noack = 0; } else if (s->ttype == MIP_TTYPE_ARP) { mg_error(c, "ARP timeout"); } else if (s->ttype == MIP_TTYPE_SYN) { diff --git a/src/net_builtin.c b/src/net_builtin.c index 23d15835..7b726cfc 100644 --- a/src/net_builtin.c +++ b/src/net_builtin.c @@ -12,10 +12,12 @@ #define MIP_TCP_ARP_MS 100 // Timeout for ARP response #define MIP_TCP_SYN_MS 15000 // Timeout for connection establishment #define MIP_TCP_FIN_MS 1000 // Timeout for closing connection +#define MIP_TCP_WIN 16384 // TCP window size struct connstate { uint32_t seq, ack; // TCP seq/ack counters uint64_t timer; // TCP keep-alive / ACK timer + size_t noack; // Not ACK-ed received TCP bytes uint8_t mac[6]; // Peer MAC address uint8_t ttype; // Timer type. 0: ack, 1: keep-alive #define MIP_TTYPE_KEEPALIVE 0 // Connection is idle for long, send keepalive @@ -398,11 +400,12 @@ static void rx_dhcp_client(struct mg_tcpip_if *ifp, struct pkt *pkt) { if (msgtype == 6 && ifp->ip == ip) { // DHCPNACK, release IP ifp->state = MG_TCPIP_STATE_UP, ifp->ip = 0; } else if (msgtype == 2 && ifp->state == MG_TCPIP_STATE_UP && ip && gw && - lease) { // DHCPOFFER + lease) { // DHCPOFFER // select IP, (4.4.1) (fallback to IP source addr on foul play) - tx_dhcp_request_sel(ifp, ip, pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); - ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state - } else if (msgtype == 5) { // DHCPACK + tx_dhcp_request_sel(ifp, ip, + pkt->dhcp->siaddr ? pkt->dhcp->siaddr : pkt->ip->src); + ifp->state = MG_TCPIP_STATE_REQ; // REQUESTING state + } else if (msgtype == 5) { // DHCPACK if (ifp->state == MG_TCPIP_STATE_REQ && ip && gw && lease) { // got an IP ifp->lease_expire = ifp->now + lease * 1000; MG_INFO(("Lease: %u sec (%lld)", lease, ifp->lease_expire / 1000)); @@ -496,7 +499,7 @@ static size_t tx_tcp(struct mg_tcpip_if *ifp, uint8_t *dst_mac, uint32_t dst_ip, tcp->seq = seq; tcp->ack = ack; tcp->flags = flags; - tcp->win = mg_htons(8192); + tcp->win = mg_htons(MIP_TCP_WIN); tcp->off = (uint8_t) (sizeof(*tcp) / 4 << 4); uint32_t cs = 0; uint16_t n = (uint16_t) (sizeof(*tcp) + len); @@ -651,17 +654,18 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { MG_VERBOSE(("%lu SEQ %x -> %x", c->id, mg_htonl(pkt->tcp->seq), s->ack)); // Advance ACK counter s->ack = (uint32_t) (mg_htonl(pkt->tcp->seq) + pkt->pay.len); -#if 0 - // Send ACK immediately - uint32_t rem_ip; - memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); - MG_DEBUG((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack)); - tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, c->loc.port, - c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); -#else - // if not already running, setup a timer to send an ACK later - if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); -#endif + s->noack += pkt->pay.len; + if (s->noack + 1500 >= MIP_TCP_WIN) { + // Send ACK immediately + MG_VERBOSE((" imm ACK", c->id, mg_htonl(pkt->tcp->seq), s->ack)); + tx_tcp((struct mg_tcpip_if *) c->mgr->priv, s->mac, rem_ip, TH_ACK, + c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", + 0); + s->noack = 0; + } else { + // if not already running, setup a timer to send an ACK later + if (s->ttype != MIP_TTYPE_ACK) settmout(c, MIP_TTYPE_ACK); + } if (c->is_tls && c->is_tls_hs) { mg_tls_handshake(c); @@ -905,6 +909,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t now) { MG_VERBOSE(("%lu ack %x %x", c->id, s->seq, s->ack)); tx_tcp(ifp, s->mac, rem_ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); + s->noack = 0; } else if (s->ttype == MIP_TTYPE_ARP) { mg_error(c, "ARP timeout"); } else if (s->ttype == MIP_TTYPE_SYN) {