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.
This commit is contained in:
d00f committed 2026-09-18 02:39:52 +02:00
1 parent 10dd330e3c
commit 072edb36a8
1 file changed
+19 -15
+19 -15
View File
@@ -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;