From 06ab83dca65ed4318127d96f7062a413b757131a Mon Sep 17 00:00:00 2001 From: cpq Date: Thu, 8 Sep 2022 08:50:42 +0100 Subject: [PATCH] Implement keep-alive, 45 sec interval. Correct ACK piggyback --- examples/device-dashboard/packed_fs.c | 173 +++++++++++---------- examples/device-dashboard/web_root/main.js | 6 +- mip/mip.c | 14 +- mongoose.c | 14 +- 4 files changed, 118 insertions(+), 89 deletions(-) diff --git a/examples/device-dashboard/packed_fs.c b/examples/device-dashboard/packed_fs.c index 7c38e365..ac0b61e8 100644 --- a/examples/device-dashboard/packed_fs.c +++ b/examples/device-dashboard/packed_fs.c @@ -1133,85 +1133,102 @@ static const unsigned char v2[] = { 32, 109, 97, 120, 45, 97, 103, 101, 61, 51, 54, 48, // max-age=360 48, 96, 59, 10, 32, 32, 32, 32, 115, 101, 116, 85, // 0`;. setU 115, 101, 114, 40, 117, 46, 117, 115, 101, 114, 41, 59, // ser(u.user); - 10, 32, 32, 32, 32, 119, 97, 116, 99, 104, 40, 41, // . watch() - 59, 10, 32, 32, 32, 32, 114, 101, 116, 117, 114, 110, // ;. return + 10, 32, 32, 32, 32, 105, 102, 32, 40, 108, 111, 99, // . if (loc + 97, 116, 105, 111, 110, 46, 115, 101, 97, 114, 99, 104, // ation.search + 46, 115, 117, 98, 115, 116, 114, 105, 110, 103, 40, 49, // .substring(1 + 41, 32, 61, 61, 32, 39, 110, 111, 119, 115, 39, 41, // ) == 'nows') + 32, 123, 10, 32, 32, 32, 32, 32, 32, 47, 47, 32, // {. // + 73, 102, 32, 113, 117, 101, 114, 121, 32, 115, 116, 114, // If query str + 105, 110, 103, 32, 105, 115, 32, 63, 110, 111, 119, 115, // ing is ?nows + 44, 32, 116, 104, 101, 110, 32, 100, 111, 32, 110, 111, // , then do no + 116, 32, 99, 111, 110, 110, 101, 99, 116, 32, 116, 111, // t connect to + 32, 119, 101, 98, 115, 111, 99, 107, 101, 116, 46, 32, // websocket. + 70, 111, 114, 32, 100, 101, 98, 117, 103, 46, 10, 32, // For debug.. + 32, 32, 32, 125, 32, 101, 108, 115, 101, 32, 123, 10, // } else {. + 32, 32, 32, 32, 32, 32, 119, 97, 116, 99, 104, 40, // watch( + 41, 59, 32, 47, 47, 32, 67, 111, 110, 110, 101, 99, // ); // Connec + 116, 32, 116, 111, 32, 119, 101, 98, 115, 111, 99, 107, // t to websock + 101, 116, 44, 32, 114, 101, 99, 101, 105, 118, 101, 32, // et, receive + 99, 111, 110, 115, 116, 97, 110, 116, 32, 103, 114, 97, // constant gra + 112, 104, 32, 117, 112, 100, 97, 116, 101, 115, 10, 32, // ph updates. + 32, 32, 32, 125, 10, 32, 32, 32, 32, 114, 101, 116, // }. ret + 117, 114, 110, 32, 103, 101, 116, 99, 111, 110, 102, 105, // urn getconfi + 103, 40, 41, 59, 10, 32, 32, 125, 59, 10, 10, 32, // g();. };.. + 32, 99, 111, 110, 115, 116, 32, 108, 111, 103, 111, 117, // const logou + 116, 32, 61, 32, 101, 118, 32, 61, 62, 32, 123, 10, // t = ev => {. + 32, 32, 32, 32, 100, 111, 99, 117, 109, 101, 110, 116, // document + 46, 99, 111, 111, 107, 105, 101, 32, 61, 32, 96, 97, // .cookie = `a + 99, 99, 101, 115, 115, 95, 116, 111, 107, 101, 110, 61, // ccess_token= + 59, 32, 83, 101, 99, 117, 114, 101, 44, 32, 72, 116, // ; Secure, Ht + 116, 112, 79, 110, 108, 121, 59, 32, 83, 97, 109, 101, // tpOnly; Same + 83, 105, 116, 101, 61, 76, 97, 120, 59, 32, 112, 97, // Site=Lax; pa + 116, 104, 61, 47, 59, 32, 109, 97, 120, 45, 97, 103, // th=/; max-ag + 101, 61, 48, 96, 59, 10, 32, 32, 32, 32, 115, 101, // e=0`;. se + 116, 85, 115, 101, 114, 40, 39, 39, 41, 59, 10, 32, // tUser('');. + 32, 125, 59, 10, 10, 32, 32, 117, 115, 101, 69, 102, // };.. useEf + 102, 101, 99, 116, 40, 40, 41, 32, 61, 62, 32, 123, // fect(() => { + 10, 32, 32, 32, 32, 47, 47, 32, 67, 97, 108, 108, // . // Call + 101, 100, 32, 111, 110, 99, 101, 32, 97, 116, 32, 105, // ed once at i + 110, 105, 116, 32, 116, 105, 109, 101, 10, 32, 32, 32, // nit time. + 32, 80, 117, 98, 83, 117, 98, 46, 115, 117, 98, 115, // PubSub.subs + 99, 114, 105, 98, 101, 40, 109, 115, 103, 32, 61, 62, // cribe(msg => + 32, 109, 115, 103, 46, 110, 97, 109, 101, 32, 61, 61, // msg.name == + 32, 39, 99, 111, 110, 102, 105, 103, 39, 32, 38, 38, // 'config' && 32, 103, 101, 116, 99, 111, 110, 102, 105, 103, 40, 41, // getconfig() - 59, 10, 32, 32, 125, 59, 10, 10, 32, 32, 99, 111, // ;. };.. co - 110, 115, 116, 32, 108, 111, 103, 111, 117, 116, 32, 61, // nst logout = - 32, 101, 118, 32, 61, 62, 32, 123, 10, 32, 32, 32, // ev => {. - 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, 99, 111, // document.co - 111, 107, 105, 101, 32, 61, 32, 96, 97, 99, 99, 101, // okie = `acce - 115, 115, 95, 116, 111, 107, 101, 110, 61, 59, 32, 83, // ss_token=; S - 101, 99, 117, 114, 101, 44, 32, 72, 116, 116, 112, 79, // ecure, HttpO - 110, 108, 121, 59, 32, 83, 97, 109, 101, 83, 105, 116, // nly; SameSit - 101, 61, 76, 97, 120, 59, 32, 112, 97, 116, 104, 61, // e=Lax; path= - 47, 59, 32, 109, 97, 120, 45, 97, 103, 101, 61, 48, // /; max-age=0 - 96, 59, 10, 32, 32, 32, 32, 115, 101, 116, 85, 115, // `;. setUs - 101, 114, 40, 39, 39, 41, 59, 10, 32, 32, 125, 59, // er('');. }; - 10, 10, 32, 32, 117, 115, 101, 69, 102, 102, 101, 99, // .. useEffec - 116, 40, 40, 41, 32, 61, 62, 32, 123, 10, 32, 32, // t(() => {. - 32, 32, 47, 47, 32, 67, 97, 108, 108, 101, 100, 32, // // Called - 111, 110, 99, 101, 32, 97, 116, 32, 105, 110, 105, 116, // once at init - 32, 116, 105, 109, 101, 10, 32, 32, 32, 32, 80, 117, // time. Pu - 98, 83, 117, 98, 46, 115, 117, 98, 115, 99, 114, 105, // bSub.subscri - 98, 101, 40, 109, 115, 103, 32, 61, 62, 32, 109, 115, // be(msg => ms - 103, 46, 110, 97, 109, 101, 32, 61, 61, 32, 39, 99, // g.name == 'c - 111, 110, 102, 105, 103, 39, 32, 38, 38, 32, 103, 101, // onfig' && ge - 116, 99, 111, 110, 102, 105, 103, 40, 41, 41, 59, 10, // tconfig());. - 32, 32, 32, 32, 102, 101, 116, 99, 104, 40, 39, 47, // fetch('/ - 97, 112, 105, 47, 108, 111, 103, 105, 110, 39, 44, 32, // api/login', - 123, 104, 101, 97, 100, 101, 114, 115, 58, 32, 123, 65, // {headers: {A - 117, 116, 104, 111, 114, 105, 122, 97, 116, 105, 111, 110, // uthorization - 58, 32, 39, 39, 125, 125, 41, 10, 32, 32, 32, 32, // : ''}}). - 32, 32, 32, 32, 46, 116, 104, 101, 110, 40, 114, 32, // .then(r - 61, 62, 32, 114, 46, 106, 115, 111, 110, 40, 41, 41, // => r.json()) - 10, 32, 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, // . .th - 101, 110, 40, 114, 32, 61, 62, 32, 108, 111, 103, 105, // en(r => logi - 110, 40, 114, 41, 41, 10, 32, 32, 32, 32, 32, 32, // n(r)). - 32, 32, 46, 99, 97, 116, 99, 104, 40, 101, 114, 114, // .catch(err - 32, 61, 62, 32, 115, 101, 116, 85, 115, 101, 114, 40, // => setUser( - 39, 39, 41, 41, 59, 10, 32, 32, 125, 44, 32, 91, // ''));. }, [ - 93, 41, 59, 10, 10, 32, 32, 105, 102, 32, 40, 33, // ]);.. if (! - 117, 115, 101, 114, 41, 32, 114, 101, 116, 117, 114, 110, // user) return - 32, 104, 116, 109, 108, 96, 60, 36, 123, 76, 111, 103, // html`<${Log - 105, 110, 125, 32, 108, 111, 103, 105, 110, 61, 36, 123, // in} login=${ - 108, 111, 103, 105, 110, 125, 32, 47, 62, 96, 59, 10, // login} />`;. - 10, 32, 32, 114, 101, 116, 117, 114, 110, 32, 104, 116, // . return ht - 109, 108, 96, 10, 60, 36, 123, 78, 97, 118, 125, 32, // ml`.<${Nav} - 117, 115, 101, 114, 61, 36, 123, 117, 115, 101, 114, 125, // user=${user} - 32, 108, 111, 103, 111, 117, 116, 61, 36, 123, 108, 111, // logout=${lo - 103, 111, 117, 116, 125, 32, 47, 62, 10, 60, 100, 105, // gout} />.. < - 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, 114, // div class="r - 111, 119, 34, 62, 10, 32, 32, 32, 32, 60, 100, 105, // ow">. <${H - 101, 114, 111, 125, 32, 47, 62, 60, 47, 100, 105, 118, // ero} />.
<${Char - 116, 125, 32, 47, 62, 60, 47, 100, 105, 118, 62, 10, // t} />
. - 32, 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, //
. ${ - 117, 115, 101, 114, 32, 61, 61, 32, 39, 97, 100, 109, // user == 'adm - 105, 110, 39, 32, 38, 38, 32, 104, 40, 67, 111, 110, // in' && h(Con - 102, 105, 103, 117, 114, 97, 116, 105, 111, 110, 44, 32, // figuration, - 123, 99, 111, 110, 102, 105, 103, 125, 41, 125, 10, 32, // {config})}. - 32, 32, 32, 60, 47, 100, 105, 118, 62, 10, 32, 32, //
. + 41, 59, 10, 32, 32, 32, 32, 102, 101, 116, 99, 104, // );. fetch + 40, 39, 47, 97, 112, 105, 47, 108, 111, 103, 105, 110, // ('/api/login + 39, 44, 32, 123, 104, 101, 97, 100, 101, 114, 115, 58, // ', {headers: + 32, 123, 65, 117, 116, 104, 111, 114, 105, 122, 97, 116, // {Authorizat + 105, 111, 110, 58, 32, 39, 39, 125, 125, 41, 10, 32, // ion: ''}}). + 32, 32, 32, 32, 32, 32, 32, 46, 116, 104, 101, 110, // .then + 40, 114, 32, 61, 62, 32, 114, 46, 106, 115, 111, 110, // (r => r.json + 40, 41, 41, 10, 32, 32, 32, 32, 32, 32, 32, 32, // ()). + 46, 116, 104, 101, 110, 40, 114, 32, 61, 62, 32, 108, // .then(r => l + 111, 103, 105, 110, 40, 114, 41, 41, 10, 32, 32, 32, // ogin(r)). + 32, 32, 32, 32, 32, 46, 99, 97, 116, 99, 104, 40, // .catch( + 101, 114, 114, 32, 61, 62, 32, 115, 101, 116, 85, 115, // err => setUs + 101, 114, 40, 39, 39, 41, 41, 59, 10, 32, 32, 125, // er(''));. } + 44, 32, 91, 93, 41, 59, 10, 10, 32, 32, 105, 102, // , []);.. if + 32, 40, 33, 117, 115, 101, 114, 41, 32, 114, 101, 116, // (!user) ret + 117, 114, 110, 32, 104, 116, 109, 108, 96, 60, 36, 123, // urn html`<${ + 76, 111, 103, 105, 110, 125, 32, 108, 111, 103, 105, 110, // Login} login + 61, 36, 123, 108, 111, 103, 105, 110, 125, 32, 47, 62, // =${login} /> + 96, 59, 10, 10, 32, 32, 114, 101, 116, 117, 114, 110, // `;.. return + 32, 104, 116, 109, 108, 96, 10, 60, 36, 123, 78, 97, // html`.<${Na + 118, 125, 32, 117, 115, 101, 114, 61, 36, 123, 117, 115, // v} user=${us + 101, 114, 125, 32, 108, 111, 103, 111, 117, 116, 61, 36, // er} logout=$ + 123, 108, 111, 103, 111, 117, 116, 125, 32, 47, 62, 10, // {logout} />. + 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, //
. 32, 32, 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, //
<${Messages - 125, 32, 99, 111, 110, 102, 105, 103, 61, 36, 123, 99, // } config=${c - 111, 110, 102, 105, 103, 125, 32, 47, 62, 60, 47, 100, // onfig} />.
- 10, 60, 47, 100, 105, 118, 62, 96, 59, 10, 125, 59, // .
`;.}; - 10, 10, 119, 105, 110, 100, 111, 119, 46, 111, 110, 108, // ..window.onl - 111, 97, 100, 32, 61, 32, 40, 41, 32, 61, 62, 32, // oad = () => - 114, 101, 110, 100, 101, 114, 40, 104, 40, 65, 112, 112, // render(h(App - 41, 44, 32, 100, 111, 99, 117, 109, 101, 110, 116, 46, // ), document. - 98, 111, 100, 121, 41, 59, 10, 0 // body);. + 61, 34, 114, 111, 119, 34, 62, 10, 32, 32, 32, 32, // ="row">. + 60, 100, 105, 118, 32, 99, 108, 97, 115, 115, 61, 34, //
< + 36, 123, 72, 101, 114, 111, 125, 32, 47, 62, 60, 47, // ${Hero} />. <${C + 104, 97, 114, 116, 125, 32, 47, 62, 60, 47, 100, 105, // hart} />.
. + 32, 36, 123, 117, 115, 101, 114, 32, 61, 61, 32, 39, // ${user == ' + 97, 100, 109, 105, 110, 39, 32, 38, 38, 32, 104, 40, // admin' && h( + 67, 111, 110, 102, 105, 103, 117, 114, 97, 116, 105, 111, // Configuratio + 110, 44, 32, 123, 99, 111, 110, 102, 105, 103, 125, 41, // n, {config}) + 125, 10, 32, 32, 32, 32, 60, 47, 100, 105, 118, 62, // }.
+ 10, 32, 32, 32, 32, 60, 100, 105, 118, 32, 99, 108, // .
<${Messa + 103, 101, 115, 125, 32, 99, 111, 110, 102, 105, 103, 61, // ges} config= + 36, 123, 99, 111, 110, 102, 105, 103, 125, 32, 47, 62, // ${config} /> + 60, 47, 100, 105, 118, 62, 10, 32, 32, 60, 47, 100, //
. .
`; + 10, 125, 59, 10, 10, 119, 105, 110, 100, 111, 119, 46, // .};..window. + 111, 110, 108, 111, 97, 100, 32, 61, 32, 40, 41, 32, // onload = () + 61, 62, 32, 114, 101, 110, 100, 101, 114, 40, 104, 40, // => render(h( + 65, 112, 112, 41, 44, 32, 100, 111, 99, 117, 109, 101, // App), docume + 110, 116, 46, 98, 111, 100, 121, 41, 59, 10, 0 // nt.body);. }; static const unsigned char v3[] = { 118, 97, 114, 32, 101, 44, 110, 44, 95, 44, 116, 44, // var e,n,_,t, @@ -2802,7 +2819,7 @@ static const struct packed_file { time_t mtime; } packed_files[] = { {"/web_root/index.html", v1, sizeof(v1), 1659483223}, - {"/web_root/main.js", v2, sizeof(v2), 1661520054}, + {"/web_root/main.js", v2, sizeof(v2), 1662621376}, {"/web_root/preact.min.js", v3, sizeof(v3), 1659483223}, {"/web_root/style.css", v4, sizeof(v4), 1659483223}, {"/web_root/user.png", v5, sizeof(v5), 1659483223}, diff --git a/examples/device-dashboard/web_root/main.js b/examples/device-dashboard/web_root/main.js index 2ecfb2d0..b0968b3e 100644 --- a/examples/device-dashboard/web_root/main.js +++ b/examples/device-dashboard/web_root/main.js @@ -341,7 +341,11 @@ const App = function(props) { const login = function(u) { document.cookie = `access_token=${u.token}; Secure, HttpOnly; SameSite=Lax; path=/; max-age=3600`; setUser(u.user); - watch(); + if (location.search.substring(1) == 'nows') { + // If query string is ?nows, then do not connect to websocket. For debug. + } else { + watch(); // Connect to websocket, receive constant graph updates + } return getconfig(); }; diff --git a/mip/mip.c b/mip/mip.c index 16e2356a..1b591076 100644 --- a/mip/mip.c +++ b/mip/mip.c @@ -16,7 +16,7 @@ #define MIP_ARP_ENTRIES 5 // Number of ARP cache entries. Maximum 21 #endif #define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size -#define MIP_TCP_KEEPALIVE_MS 5000 // TCP keep-alive period, ms +#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms #define MIP_TCP_ACK_MS 150 // Timeout for ACKing struct connstate { @@ -546,6 +546,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn, } static void read_conn(struct mg_connection *c, struct pkt *pkt) { + struct mip_if *ifp = (struct mip_if *) c->mgr->priv; struct connstate *s = (struct connstate *) (c + 1); if (pkt->tcp->flags & TH_FIN) { s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack); @@ -562,6 +563,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { c->recv.len += pkt->pay.len; struct mg_str evd = mg_str_n((char *) pkt->pay.buf, pkt->pay.len); mg_call(c, MG_EV_READ, &evd); + s->timer = ifp->now + MIP_TCP_ACK_MS; // Don't send an ACK immediately + s->ttype = 0; // Set ACK timeout instead } } @@ -590,8 +593,6 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) { mg_hexdump(pkt->pay.buf, pkt->pay.len); #endif read_conn(c, pkt); - s->timer = ifp->now + MIP_TCP_ACK_MS; // Set ACK timeout - s->ttype = 0; } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); } else if (pkt->tcp->flags & TH_SYN) { @@ -725,11 +726,13 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) { struct connstate *s = (struct connstate *) (c + 1); if (uptime_ms > s->timer) { if (s->ttype == 0) { - MG_INFO(("%lu sending ack", c->id)); + MG_DEBUG(("%lu sending ack", c->id)); tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); } else { - MG_INFO(("%lu sending keepalive", c->id)); + MG_DEBUG(("%lu sending keepalive", c->id)); + tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0); } s->timer = uptime_ms + MIP_TCP_KEEPALIVE_MS; s->ttype = 1; @@ -821,6 +824,7 @@ static void write_conn(struct mg_connection *c) { s->seq += (uint32_t) n; mg_call(c, MG_EV_WRITE, &n); } + s->ttype = 1, s->timer = ifp->now + MIP_TCP_KEEPALIVE_MS; // Clear ACK timer } static void fin_conn(struct mg_connection *c) { diff --git a/mongoose.c b/mongoose.c index 9a307cfe..916f0925 100644 --- a/mongoose.c +++ b/mongoose.c @@ -6304,7 +6304,7 @@ struct mip_driver mip_driver_w5500 = { #define MIP_ARP_ENTRIES 5 // Number of ARP cache entries. Maximum 21 #endif #define MIP_ARP_CS (2 + 12 * MIP_ARP_ENTRIES) // ARP cache size -#define MIP_TCP_KEEPALIVE_MS 5000 // TCP keep-alive period, ms +#define MIP_TCP_KEEPALIVE_MS 45000 // TCP keep-alive period, ms #define MIP_TCP_ACK_MS 150 // Timeout for ACKing struct connstate { @@ -6834,6 +6834,7 @@ static struct mg_connection *accept_conn(struct mg_connection *lsn, } static void read_conn(struct mg_connection *c, struct pkt *pkt) { + struct mip_if *ifp = (struct mip_if *) c->mgr->priv; struct connstate *s = (struct connstate *) (c + 1); if (pkt->tcp->flags & TH_FIN) { s->ack = mg_htonl(pkt->tcp->seq) + 1, s->seq = mg_htonl(pkt->tcp->ack); @@ -6850,6 +6851,8 @@ static void read_conn(struct mg_connection *c, struct pkt *pkt) { c->recv.len += pkt->pay.len; struct mg_str evd = mg_str_n((char *) pkt->pay.buf, pkt->pay.len); mg_call(c, MG_EV_READ, &evd); + s->timer = ifp->now + MIP_TCP_ACK_MS; // Don't send an ACK immediately + s->ttype = 0; // Set ACK timeout instead } } @@ -6878,8 +6881,6 @@ static void rx_tcp(struct mip_if *ifp, struct pkt *pkt) { mg_hexdump(pkt->pay.buf, pkt->pay.len); #endif read_conn(c, pkt); - s->timer = ifp->now + MIP_TCP_ACK_MS; // Set ACK timeout - s->ttype = 0; } else if ((c = getpeer(ifp->mgr, pkt, true)) == NULL) { tx_tcp_pkt(ifp, pkt, TH_RST | TH_ACK, pkt->tcp->ack, NULL, 0); } else if (pkt->tcp->flags & TH_SYN) { @@ -7013,11 +7014,13 @@ static void mip_poll(struct mip_if *ifp, uint64_t uptime_ms) { struct connstate *s = (struct connstate *) (c + 1); if (uptime_ms > s->timer) { if (s->ttype == 0) { - MG_INFO(("%lu sending ack", c->id)); + MG_DEBUG(("%lu sending ack", c->id)); tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, mg_htonl(s->seq), mg_htonl(s->ack), "", 0); } else { - MG_INFO(("%lu sending keepalive", c->id)); + MG_DEBUG(("%lu sending keepalive", c->id)); + tx_tcp(ifp, c->rem.ip, TH_ACK, c->loc.port, c->rem.port, + mg_htonl(s->seq - 1), mg_htonl(s->ack), "", 0); } s->timer = uptime_ms + MIP_TCP_KEEPALIVE_MS; s->ttype = 1; @@ -7109,6 +7112,7 @@ static void write_conn(struct mg_connection *c) { s->seq += (uint32_t) n; mg_call(c, MG_EV_WRITE, &n); } + s->ttype = 1, s->timer = ifp->now + MIP_TCP_KEEPALIVE_MS; // Clear ACK timer } static void fin_conn(struct mg_connection *c) {