From 320da5e84c70a57acbfcd1e845dfa407ec703992 Mon Sep 17 00:00:00 2001 From: robert Date: Tue, 11 Jul 2023 05:11:38 -0400 Subject: [PATCH 1/2] implemented tcp retransmission --- mongoose.c | 14 ++++-- src/tcpip/tcpip.c | 14 ++++-- test/mip_test.c | 119 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 137 insertions(+), 10 deletions(-) diff --git a/mongoose.c b/mongoose.c index 16fa3f10..51656457 100644 --- a/mongoose.c +++ b/mongoose.c @@ -8064,9 +8064,11 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { if (s->ack == ack) { MG_VERBOSE(("ignoring duplicate pkt")); } else { - // TODO(cpq): peer sent us SEQ which we don't expect. Retransmit - // rather than close this connection - mg_error(c, "SEQ != ACK: %x %x %x", seq, s->ack, ack); + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + MG_DEBUG(("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), "", 0); } } else if (io->size - io->len < pkt->pay.len && !mg_iobuf_resize(io, io->len + pkt->pay.len)) { @@ -8083,10 +8085,12 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { MG_DEBUG(("%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 +#ifdef MIP_TEST // 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, c->rem.ip, TH_ACK, c->loc.port, + 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 diff --git a/src/tcpip/tcpip.c b/src/tcpip/tcpip.c index c415d3d5..db995e25 100644 --- a/src/tcpip/tcpip.c +++ b/src/tcpip/tcpip.c @@ -579,9 +579,11 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { if (s->ack == ack) { MG_VERBOSE(("ignoring duplicate pkt")); } else { - // TODO(cpq): peer sent us SEQ which we don't expect. Retransmit - // rather than close this connection - mg_error(c, "SEQ != ACK: %x %x %x", seq, s->ack, ack); + uint32_t rem_ip; + memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); + MG_DEBUG(("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), "", 0); } } else if (io->size - io->len < pkt->pay.len && !mg_iobuf_resize(io, io->len + pkt->pay.len)) { @@ -598,10 +600,12 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { MG_DEBUG(("%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 +#ifdef MIP_TEST // 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, c->rem.ip, TH_ACK, c->loc.port, + 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 diff --git a/test/mip_test.c b/test/mip_test.c index 29db4d8c..20199945 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -3,6 +3,8 @@ #define MG_ENABLE_TCPIP 1 #define MG_ENABLE_PACKED_FS 0 +#define MIP_TEST + #include "mongoose.c" #include "driver_mock.c" @@ -48,9 +50,126 @@ static void test_poll(void) { mg_mgr_free(&mgr); } +#define DRIVER_BUF_SIZE 1540 + +struct driver_data { + char buf[DRIVER_BUF_SIZE]; + size_t len; +}; + +static struct driver_data s_driver_data; + +static size_t if_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) { + struct driver_data *driver_data = (struct driver_data *) ifp->driver_data; + if (len > DRIVER_BUF_SIZE) len = DRIVER_BUF_SIZE; + memcpy(driver_data->buf, buf, len); + return len; +} + +static bool if_up(struct mg_tcpip_if *ifp) { + return ifp->driver_data ? true : false; +} + +static size_t if_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) { + struct driver_data *driver_data = (struct driver_data *) ifp->driver_data; + if (len > driver_data->len) len = driver_data->len; + memcpy(buf, driver_data->buf, len); + return len; +} + +static void create_tcp_pkt(struct eth *e, struct ip *ip, uint32_t seq, + uint32_t ack, uint8_t flags, size_t payload_len) { + struct tcp t; + memset(&t, 0, sizeof(struct tcp)); + t.flags = flags; + t.seq = mg_htonl(seq); + t.ack = mg_htonl(ack); + t.off = 5 << 4; + memcpy(s_driver_data.buf, e, sizeof(*e)); + memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); + memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(struct tcp)); + s_driver_data.len = + sizeof(*e) + sizeof(*ip) + sizeof(struct tcp) + payload_len; +} + +static void test_retransmit(void) { + struct mg_mgr mgr; + struct eth e; + struct ip ip; + struct tcp *t; + struct mg_tcpip_driver driver; + struct mg_tcpip_if mif; + struct mg_connection *c; + + mg_mgr_init(&mgr); + memset(&mif, 0, sizeof(mif)); + memset(&s_driver_data, 0, sizeof(struct driver_data)); + driver.init = NULL, driver.tx = if_tx, driver.up = if_up, driver.rx = if_rx; + mif.driver = &driver; + mif.driver_data = &s_driver_data; + mg_tcpip_init(&mgr, &mif); + c = mg_alloc_conn(&mgr); + LIST_ADD_HEAD(struct mg_connection, &mgr.conns, c); + c->is_listening = 1; + mg_mgr_poll(&mgr, 0); + + memset(&e, 0, sizeof(e)); + memcpy(e.dst, mif.mac, 6 * sizeof(uint8_t)); + e.type = mg_htons(0x800); + + memset(&ip, 0, sizeof(ip)); + ip.ver = 4 << 4, ip.proto = 6; + ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp)); + + // SYN + create_tcp_pkt(&e, &ip, 1000, 0, TH_SYN | TH_ACK, 0); + mg_mgr_poll(&mgr, 0); + + // SYN-ACK + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((t->flags == (TH_SYN | TH_ACK))); + ASSERT((t->ack == mg_htonl(1001))); + + // ACK + create_tcp_pkt(&e, &ip, 1001, 1, TH_ACK, 0); + mg_mgr_poll(&mgr, 0); + + // packet with seq_no = 1001 + ip.len = + mg_htons(sizeof(struct ip) + sizeof(struct tcp) + /* TCP Payload */ 1); + create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1); + mg_mgr_poll(&mgr, 0); + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((t->flags == TH_ACK)); + ASSERT((t->ack == mg_htonl(1002))); + + // packet with seq_no = 1003 + create_tcp_pkt(&e, &ip, 1003, 1, TH_PUSH | TH_ACK, 1); + mg_mgr_poll(&mgr, 0); + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((t->flags == TH_ACK)); + ASSERT((t->ack == mg_htonl(1002))); + + // retransmitting packet with seq_no = 1002 + create_tcp_pkt(&e, &ip, 1002, 1, TH_PUSH | TH_ACK, 1); + mg_mgr_poll(&mgr, 0); + t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + + sizeof(struct ip)); + ASSERT((t->flags == TH_ACK)); + ASSERT((t->ack == mg_htonl(1003))); + + s_driver_data.len = 0; + mg_mgr_free(&mgr); + mg_tcpip_free(&mif); +} + int main(void) { test_statechange(); test_poll(); + test_retransmit(); printf("SUCCESS. Total tests: %d\n", s_num_tests); return 0; } From ac40673a9e748847c0dd0a5eea07eb5d8d4383df Mon Sep 17 00:00:00 2001 From: "Sergio R. Caprile" Date: Tue, 11 Jul 2023 14:08:49 -0300 Subject: [PATCH 2/2] test for retransmitted segment --- mongoose.c | 2 +- src/tcpip/tcpip.c | 2 +- test/mip_test.c | 56 +++++++++++++++++++++++++++++++++++++++-------- 3 files changed, 49 insertions(+), 11 deletions(-) diff --git a/mongoose.c b/mongoose.c index 51656457..0c74ad75 100644 --- a/mongoose.c +++ b/mongoose.c @@ -8085,7 +8085,7 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { MG_DEBUG(("%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); -#ifdef MIP_TEST +#if 0 // Send ACK immediately uint32_t rem_ip; memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); diff --git a/src/tcpip/tcpip.c b/src/tcpip/tcpip.c index db995e25..a3f9cef6 100644 --- a/src/tcpip/tcpip.c +++ b/src/tcpip/tcpip.c @@ -600,7 +600,7 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { MG_DEBUG(("%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); -#ifdef MIP_TEST +#if 0 // Send ACK immediately uint32_t rem_ip; memcpy(&rem_ip, c->rem.ip, sizeof(uint32_t)); diff --git a/test/mip_test.c b/test/mip_test.c index 20199945..be44cf77 100644 --- a/test/mip_test.c +++ b/test/mip_test.c @@ -3,8 +3,6 @@ #define MG_ENABLE_TCPIP 1 #define MG_ENABLE_PACKED_FS 0 -#define MIP_TEST - #include "mongoose.c" #include "driver_mock.c" @@ -55,6 +53,7 @@ static void test_poll(void) { struct driver_data { char buf[DRIVER_BUF_SIZE]; size_t len; + bool tx_ready; // data can be read from tx }; static struct driver_data s_driver_data; @@ -62,7 +61,9 @@ static struct driver_data s_driver_data; static size_t if_tx(const void *buf, size_t len, struct mg_tcpip_if *ifp) { struct driver_data *driver_data = (struct driver_data *) ifp->driver_data; if (len > DRIVER_BUF_SIZE) len = DRIVER_BUF_SIZE; + driver_data->len = len; memcpy(driver_data->buf, buf, len); + driver_data->tx_ready = true; return len; } @@ -72,11 +73,19 @@ static bool if_up(struct mg_tcpip_if *ifp) { static size_t if_rx(void *buf, size_t len, struct mg_tcpip_if *ifp) { struct driver_data *driver_data = (struct driver_data *) ifp->driver_data; + if (!driver_data->len) return 0; if (len > driver_data->len) len = driver_data->len; memcpy(buf, driver_data->buf, len); + driver_data->len = 0; // cleaning up the buffer return len; } +static bool received_response(struct driver_data *driver) { + bool was_ready = driver->tx_ready; + driver->tx_ready = false; + return was_ready; +} + static void create_tcp_pkt(struct eth *e, struct ip *ip, uint32_t seq, uint32_t ack, uint8_t flags, size_t payload_len) { struct tcp t; @@ -88,8 +97,8 @@ static void create_tcp_pkt(struct eth *e, struct ip *ip, uint32_t seq, memcpy(s_driver_data.buf, e, sizeof(*e)); memcpy(s_driver_data.buf + sizeof(*e), ip, sizeof(*ip)); memcpy(s_driver_data.buf + sizeof(*e) + sizeof(*ip), &t, sizeof(struct tcp)); - s_driver_data.len = - sizeof(*e) + sizeof(*ip) + sizeof(struct tcp) + payload_len; + s_driver_data.len = sizeof(*e) + sizeof(*ip) + + sizeof(struct tcp) + payload_len; } static void test_retransmit(void) { @@ -97,6 +106,8 @@ static void test_retransmit(void) { struct eth e; struct ip ip; struct tcp *t; + uint64_t start, now; + bool response_recv = true; struct mg_tcpip_driver driver; struct mg_tcpip_if mif; struct mg_connection *c; @@ -108,15 +119,17 @@ static void test_retransmit(void) { mif.driver = &driver; mif.driver_data = &s_driver_data; mg_tcpip_init(&mgr, &mif); - c = mg_alloc_conn(&mgr); + c = mg_alloc_conn(&mgr); // create dummy connection LIST_ADD_HEAD(struct mg_connection, &mgr.conns, c); c->is_listening = 1; mg_mgr_poll(&mgr, 0); + // setting the Ethernet header memset(&e, 0, sizeof(e)); memcpy(e.dst, mif.mac, 6 * sizeof(uint8_t)); e.type = mg_htons(0x800); + // setting the IP header memset(&ip, 0, sizeof(ip)); ip.ver = 4 << 4, ip.proto = 6; ip.len = mg_htons(sizeof(ip) + sizeof(struct tcp)); @@ -126,6 +139,7 @@ static void test_retransmit(void) { mg_mgr_poll(&mgr, 0); // SYN-ACK + while(!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + sizeof(struct ip)); ASSERT((t->flags == (TH_SYN | TH_ACK))); @@ -140,26 +154,50 @@ static void test_retransmit(void) { mg_htons(sizeof(struct ip) + sizeof(struct tcp) + /* TCP Payload */ 1); create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1); mg_mgr_poll(&mgr, 0); + while(!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + sizeof(struct ip)); ASSERT((t->flags == TH_ACK)); - ASSERT((t->ack == mg_htonl(1002))); + ASSERT((t->ack == mg_htonl(1002))); // OK - // packet with seq_no = 1003 + // resend packet with seq_no = 1001 (e.g.: MIP ACK lost) + create_tcp_pkt(&e, &ip, 1001, 1, TH_PUSH | TH_ACK, 1); + mg_mgr_poll(&mgr, 0); + start = mg_millis(); + while(!received_response(&s_driver_data)) { + mg_mgr_poll(&mgr, 0); + now = mg_millis() - start; + // we wait enough time for a reply + if (now > 2 * MIP_TCP_ACK_MS) { + response_recv = false; + break; + } + } + ASSERT((!response_recv)); // replies should not be sent for duplicate packets + + // packet with seq_no = 1002 got lost/delayed, send seq_no = 1003 create_tcp_pkt(&e, &ip, 1003, 1, TH_PUSH | TH_ACK, 1); mg_mgr_poll(&mgr, 0); + start = mg_millis(); + while(!received_response(&s_driver_data)) { + mg_mgr_poll(&mgr, 0); + now = mg_millis() - start; + if (now > 2 * MIP_TCP_ACK_MS) + ASSERT(0); // response should have been received by now + } t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + sizeof(struct ip)); ASSERT((t->flags == TH_ACK)); - ASSERT((t->ack == mg_htonl(1002))); + ASSERT((t->ack == mg_htonl(1002))); // dup ACK // retransmitting packet with seq_no = 1002 create_tcp_pkt(&e, &ip, 1002, 1, TH_PUSH | TH_ACK, 1); mg_mgr_poll(&mgr, 0); + while(!received_response(&s_driver_data)) mg_mgr_poll(&mgr, 0); t = (struct tcp *) (s_driver_data.buf + sizeof(struct eth) + sizeof(struct ip)); ASSERT((t->flags == TH_ACK)); - ASSERT((t->ack == mg_htonl(1003))); + ASSERT((t->ack == mg_htonl(1003))); // OK s_driver_data.len = 0; mg_mgr_free(&mgr);