diff --git a/mongoose.c b/mongoose.c index 2801a185e24..0e6e37c0f43 100644 --- a/mongoose.c +++ b/mongoose.c @@ -8122,6 +8122,7 @@ struct mg_tcpip_driver mg_tcpip_driver_w5500 = {w5500_init, w5500_tx, w5500_rx, #define MIP_TCP_ACK_MS 150 // Timeout for ACKing #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 100 // Timeout for closing connection struct connstate { uint32_t seq, ack; // TCP seq/ack counters @@ -8132,6 +8133,8 @@ struct connstate { #define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon #define MIP_TTYPE_ARP 2 // ARP resolve sent, waiting for response #define MIP_TTYPE_SYN 3 // SYN sent, waiting for response +#define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection +#define MIP_TTYPE_CLOSED 5 // Connection is closed uint8_t tmiss; // Number of keep-alive misses struct mg_iobuf raw; // For TLS only. Incoming raw data }; @@ -8271,6 +8274,7 @@ static void settmout(struct mg_connection *c, uint8_t type) { unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS : type == MIP_TTYPE_ARP ? MIP_TCP_ARP_MS : type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS + : type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS : MIP_TCP_KEEPALIVE_MS; s->timer = ifp->now + n; s->ttype = type; @@ -8694,8 +8698,15 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { struct mg_iobuf *io = c->is_tls ? &s->raw : &c->recv; uint32_t seq = mg_ntohl(pkt->tcp->seq); s->raw.align = c->recv.align; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); if (pkt->tcp->flags & TH_FIN) { s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack); + if (c->is_closing) + // We initiated FIN so when we receive FIN, we will have to ACK it + 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); c->is_closing = 1; } else if (pkt->pay.len == 0) { // TODO(cpq): handle this peer's ACK @@ -8704,8 +8715,6 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { if (s->ack == ack) { MG_VERBOSE(("ignoring duplicate pkt")); } else { - uint32_t rem_ip; - memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, 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), "", @@ -8973,6 +8982,9 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) { mg_error(c, "ARP timeout"); } else if (s->ttype == MIP_TTYPE_SYN) { mg_error(c, "Connection timeout"); + } else if (s->ttype == MIP_TTYPE_FIN) { + s->ttype = MIP_TTYPE_CLOSED; + continue; } else { if (s->tmiss++ > 2) { mg_error(c, "keepalive"); @@ -8982,6 +8994,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) { mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0); } } + settmout(c, MIP_TTYPE_KEEPALIVE); } } @@ -9113,10 +9126,16 @@ static void close_conn(struct mg_connection *c) { mg_iobuf_free(&s->raw); // For TLS connections, release raw data if (c->is_udp == false && c->is_listening == false && c->is_connecting == false) { // For TCP conns, - struct mg_tcpip_if *ifp = + if (s->ttype != MIP_TTYPE_FIN && s->ttype != MIP_TTYPE_CLOSED) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN - tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, - mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + settmout(c, MIP_TTYPE_FIN); + } else if (s->ttype == MIP_TTYPE_CLOSED) { + mg_close_conn(c); + } + return; } mg_close_conn(c); } diff --git a/src/tcpip/tcpip.c b/src/tcpip/tcpip.c index a0078f87b76..cebd1ff7fb7 100644 --- a/src/tcpip/tcpip.c +++ b/src/tcpip/tcpip.c @@ -12,6 +12,7 @@ #define MIP_TCP_ACK_MS 150 // Timeout for ACKing #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 100 // Timeout for closing connection struct connstate { uint32_t seq, ack; // TCP seq/ack counters @@ -22,6 +23,8 @@ struct connstate { #define MIP_TTYPE_ACK 1 // Peer sent us data, we have to ack it soon #define MIP_TTYPE_ARP 2 // ARP resolve sent, waiting for response #define MIP_TTYPE_SYN 3 // SYN sent, waiting for response +#define MIP_TTYPE_FIN 4 // FIN sent, waiting until terminating the connection +#define MIP_TTYPE_CLOSED 5 // Connection is closed uint8_t tmiss; // Number of keep-alive misses struct mg_iobuf raw; // For TLS only. Incoming raw data }; @@ -161,6 +164,7 @@ static void settmout(struct mg_connection *c, uint8_t type) { unsigned n = type == MIP_TTYPE_ACK ? MIP_TCP_ACK_MS : type == MIP_TTYPE_ARP ? MIP_TCP_ARP_MS : type == MIP_TTYPE_SYN ? MIP_TCP_SYN_MS + : type == MIP_TTYPE_FIN ? MIP_TCP_FIN_MS : MIP_TCP_KEEPALIVE_MS; s->timer = ifp->now + n; s->ttype = type; @@ -584,8 +588,15 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { struct mg_iobuf *io = c->is_tls ? &s->raw : &c->recv; uint32_t seq = mg_ntohl(pkt->tcp->seq); s->raw.align = c->recv.align; + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); if (pkt->tcp->flags & TH_FIN) { s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack); + if (c->is_closing) + // We initiated FIN so when we receive FIN, we will have to ACK it + 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); c->is_closing = 1; } else if (pkt->pay.len == 0) { // TODO(cpq): handle this peer's ACK @@ -594,8 +605,6 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { if (s->ack == ack) { MG_VERBOSE(("ignoring duplicate pkt")); } else { - uint32_t rem_ip; - memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); MG_VERBOSE(("SEQ != ACK: %x %x %x", seq, s->ack, 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), "", @@ -863,6 +872,9 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) { mg_error(c, "ARP timeout"); } else if (s->ttype == MIP_TTYPE_SYN) { mg_error(c, "Connection timeout"); + } else if (s->ttype == MIP_TTYPE_FIN) { + s->ttype = MIP_TTYPE_CLOSED; + continue; } else { if (s->tmiss++ > 2) { mg_error(c, "keepalive"); @@ -872,6 +884,7 @@ static void mg_tcpip_poll(struct mg_tcpip_if *ifp, uint64_t uptime_ms) { mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0); } } + settmout(c, MIP_TTYPE_KEEPALIVE); } } @@ -1003,10 +1016,16 @@ static void close_conn(struct mg_connection *c) { mg_iobuf_free(&s->raw); // For TLS connections, release raw data if (c->is_udp == false && c->is_listening == false && c->is_connecting == false) { // For TCP conns, - struct mg_tcpip_if *ifp = + if (s->ttype != MIP_TTYPE_FIN && s->ttype != MIP_TTYPE_CLOSED) { + struct mg_tcpip_if *ifp = (struct mg_tcpip_if *) c->mgr->priv; // send TCP FIN - tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, - mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + tx_tcp(ifp, s->mac, rem_ip, TH_FIN | TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq), mg_htonl(s->ack), NULL, 0); + settmout(c, MIP_TTYPE_FIN); + } else if (s->ttype == MIP_TTYPE_CLOSED) { + mg_close_conn(c); + } + return; } mg_close_conn(c); } diff --git a/test/mip_tap_test.c b/test/mip_tap_test.c index 97333c4dc19..c96007375b7 100644 --- a/test/mip_tap_test.c +++ b/test/mip_tap_test.c @@ -103,6 +103,7 @@ char *fetch(struct mg_mgr *mgr, const char *url, const char *fn_data) { } if (mgr->conns != 0) { conn->is_closing = 1; + usleep(150000); mg_mgr_poll(mgr, 0); } mg_mgr_poll(mgr, 0); @@ -175,9 +176,9 @@ static void test_http_fetch(void) { #if MG_USING_DHCP == 1 #else - mif.ip = 0x0220a8c0; // 192.168.32.2 // Triggering a network failure - mif.mask = 0x00ffffff; // 255.255.255.0 - mif.gw = 0x0120a8c0; // 192.168.32.1 + mif.ip = mg_htonl(MG_U32(192, 168, 32, 2)); // Triggering a network failure + mif.mask = mg_htonl(MG_U32(255, 255, 255, 0)) + mif.gw = mg_htonl(MG_U32(192, 168, 0, 1)); #endif sscanf(mac, "%hhx:%hhx:%hhx:%hhx:%hhx:%hhx", &mif.mac[0], &mif.mac[1],