diff options
| author | user <user@clank> | 2026-09-22 21:54:03 +0200 |
|---|---|---|
| committer | user <user@clank> | 2026-09-22 21:54:03 +0200 |
| commit | dcd1f1320c102f9cc4cff7eee387ec538304f7d1 (patch) | |
| tree | e0b48e345c8d34a5f110378e795b8690120ebd55 /usr/httpd.c | |
| parent | build: rebuild every object when include/*.inc changes (diff) | |
| download | gbos-dcd1f1320c102f9cc4cff7eee387ec538304f7d1.tar.gz gbos-dcd1f1320c102f9cc4cff7eee387ec538304f7d1.tar.xz gbos-dcd1f1320c102f9cc4cff7eee387ec538304f7d1.zip | |
net: one socket per client - four-tuple demux, spawning accept, bounded close
A server could only ever hold ONE connection, which makes an ircd pointless:
listen() turned the listener into the connection, and net_find_tcp demuxed on
local port alone, so two clients on 6667 were indistinguishable.
- net_find_tcp now matches an established socket on the full four-tuple
(local port + peer IP + peer port) and only falls back to a LISTENing
socket when none matches.
- A SYN at a listener no longer consumes it: tcp_spawn_conn clones a new
socket (local port + owning pid, so exit/kill still reclaims it) and the
listener keeps listening. accept() returns that socket; closing it leaves
the listener alone. A full table drops the SYN, and the client's retransmit
is taken once a slot frees.
- tcp_peer_is_current preserves BC: net_find_tcp scans with the socket index
there, and the compare needs BC for the rx buffer base. Without this the
scan died at the first mismatching socket, so a second client's handshake
ACK never reached its socket and it hung in SYNRCVD - tcpdump showed our
SYN+ACK going out and the client's NICK retransmitted five times into
silence.
- listen() only conflicts with another LISTENER on the port; connections
share it by design now.
- MAX_SOCKS 4 -> 6 (listener + 3 clients + 2 spare; 537 bytes of WRAM0 still
free), and SK_ACC marks a spawned connection as not yet accepted.
tcp_close's settle is also time-boxed to ~250 ms of real time. It counted
PUMPS (8 x 8000), which is ~30s of wall clock when the peer never answers -
invisible with well-behaved peers, but a daemon refusing a client that stayed
connected froze itself, and every other client with it, for half a minute.
httpd keeps its listener open across requests now, so the next client's SYN
is accepted immediately instead of being dropped between close and re-listen:
three parallel clients go 0.1/1.1/2.1s -> 0.4/1.0/0.1s.
Diffstat (limited to 'usr/httpd.c')
| -rw-r--r-- | usr/httpd.c | 31 |
1 files changed, 16 insertions, 15 deletions
diff --git a/usr/httpd.c b/usr/httpd.c index 335e824..e704e8c 100644 --- a/usr/httpd.c +++ b/usr/httpd.c @@ -33,7 +33,8 @@ #define REQSZ 120 /* the request line is all we parse */ #define PATHSZ 48 -static unsigned char sock; +static unsigned char lsock; /* the listener, held for our lifetime */ +static unsigned char sock; /* the client being served right now */ static unsigned char rbuf[BUFSZ]; static char obuf[OBUFSZ]; static unsigned char olen; @@ -256,22 +257,22 @@ void main(void) { puts(" (run it with & and kill it to stop)"); nl(); + lsock = net_socket(SOCK_TCP); + if (lsock == 0xFF) { + puts("httpd: no socket"); + nl(); + sexit(1); + } + if (net_listen(lsock, port) == 0xFF) { + puts("httpd: listen failed (port in use?)"); + nl(); + net_close(lsock); + sexit(1); + } for (;;) { - sock = net_socket(SOCK_TCP); - if (sock == 0xFF) { - puts("httpd: no socket"); - nl(); - sexit(1); - } - if (net_listen(sock, port) == 0xFF) { - puts("httpd: listen failed"); - nl(); - net_close(sock); - sexit(1); - } - while (net_accept(sock) != 0) /* one RX pump per call */ + while ((sock = net_accept(lsock)) == 0xFE) /* one RX pump per call */ msleep(20); handle(); - net_close(sock); /* FIN: this is what ends the body */ + net_close(sock); /* FIN: this is what ends the body; listener stays */ } } |
