From 072edb36a8309995a8a8be98b71fe147eb6cd79c Mon Sep 17 00:00:00 2001 From: d00f <8052722+DrDoof@users.noreply.github.com> Date: Fri, 18 Sep 2026 02:39:52 +0200 Subject: [PATCH] httpd: account for the bytes actually sent uip_mss() is the limit on the next segment, not a record of the last one: uIP recomputes it from the window the peer advertises in every incoming segment, before the application is called. The ACK path subtracted it from slen and added it to o_idx, and the retransmit path handed it to uip_send(), so whenever the window moved between a segment going out and its ACK coming back, the file being served lost or repeated the difference. A window shrinking from 1460 to 600 between the two repeats 860 bytes under fresh sequence numbers, which a browser writes into the file; a window opening the same way skips 860. Remember the length in tx_send() and use it in both places. The retransmit path then repeats exactly the segment uIP still counts as outstanding, which is what uip_connr->len makes it put on the wire. --- httpd/httpd.c | 34 +++++++++++++++++++--------------- 1 file changed, 19 insertions(+), 15 deletions(-) diff --git a/httpd/httpd.c b/httpd/httpd.c index aba33e40..1d5fadf8 100644 --- a/httpd/httpd.c +++ b/httpd/httpd.c @@ -37,6 +37,7 @@ __xdata uint8_t outbuf[TCP_OUTBUF_SIZE]; __xdata uint8_t entry; __xdata uint16_t slen; __xdata uint16_t o_idx; +__xdata uint16_t sent_len; __xdata uint16_t len_left; __xdata uint16_t cont_len; __xdata uint32_t cont_addr; @@ -826,6 +827,13 @@ void handle_post(void) } +static void tx_send(uint16_t len) +{ + sent_len = len; + uip_send(outbuf + o_idx, len); +} + + void httpd_appcall(void) { __xdata struct httpd_state * __xdata s = &(uip_conn->appstate); @@ -861,9 +869,9 @@ void httpd_appcall(void) } } else if (uip_acked() && s->tstate == TSTATE_TX) { dbg_string("ACK\n"); - if (slen > uip_mss()) { - slen -= uip_mss(); - o_idx += uip_mss(); + if (slen > sent_len) { + slen -= sent_len; + o_idx += sent_len; } else { slen = 0; } @@ -872,11 +880,11 @@ void httpd_appcall(void) if (slen > uip_mss()) { dbg_string("Sending A: "); dbg_short(slen); dbg_char('\n'); - uip_send(outbuf + o_idx, uip_mss()); + tx_send(uip_mss()); s->tstate = TSTATE_TX; } else if (slen > 0) { dbg_string("Sending B: "); dbg_short(slen); dbg_char('\n'); - uip_send(outbuf + o_idx, slen); + tx_send(slen); s->tstate = TSTATE_TX; } else if (cont_len) { dbg_string("CONT cont_len: "); dbg_short(cont_len); @@ -887,7 +895,7 @@ void httpd_appcall(void) flash_region.len = slen; flash_read_bulk(outbuf); o_idx = 0; - uip_send(outbuf + o_idx, slen); + tx_send(slen); cont_len -= slen; cont_addr += slen; s->tstate = TSTATE_TX; @@ -1045,24 +1053,20 @@ do_send: o_idx = 0; if (slen > uip_mss()) { dbg_string("Sending a: "); dbg_short(slen); dbg_char('\n'); - uip_send(outbuf + o_idx, uip_mss()); + tx_send(uip_mss()); dbg_string("Sending a done\n"); } else { dbg_string("Sending b: "); dbg_short(slen); dbg_char('\n'); - uip_send(outbuf + o_idx, slen); + tx_send(slen); dbg_string("Sending b done\n"); } s->tstate = TSTATE_TX; } else if (uip_rexmit()) { // Connection established, need to rexmit? dbg_string("RETRANSMIT requested\n"); - if (slen > uip_mss()) { - dbg_string("Sending C: "); dbg_short(slen); dbg_char('\n'); - uip_send(outbuf + o_idx, uip_mss()); + if (sent_len) { + dbg_string("Sending C: "); dbg_short(sent_len); dbg_char('\n'); + tx_send(sent_len); dbg_string("Sending C done\n"); - } else if (slen > 0) { - dbg_string("Sending D: "); dbg_short(slen); dbg_char('\n'); - uip_send(outbuf + o_idx, slen); - dbg_string("Sending D done\n"); } s->tstate = TSTATE_TX; uip_len = 0;