aboutsummaryrefslogtreecommitdiffstats
path: root/usr
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-22 17:12:41 +0200
committeruser <user@clank>2026-09-22 17:12:41 +0200
commite23fb93141be593cfd45c2bf8669f71e5aac9bbd (patch)
treea7f16c8670b8e0a7d52a50b6087ee1ae59aff0a9 /usr
parentkernel: per-process sleep - two sleepers used to deadlock each other (diff)
downloadgbos-e23fb93141be593cfd45c2bf8669f71e5aac9bbd.tar.gz
gbos-e23fb93141be593cfd45c2bf8669f71e5aac9bbd.tar.xz
gbos-e23fb93141be593cfd45c2bf8669f71e5aac9bbd.zip
net: passive open (listen/accept) + own sockets + close promptly
The stack could only ever dial out. Two new ops give it an ear: - listen(sock, port): sockets demux on LOCAL PORT alone, so the listener IS the connection - the SYN fills in the peer and the socket becomes the connection. One at a time, re-armed by listening again after close, which is all a 4-socket table can honestly promise. A second client's SYN is dropped in silence; its retransmit is taken once we are free (~1s), so three parallel clients complete in 0.1/1.1/2.1s. - accept(sock): one RX pump per call, never blocks (like recv_nb), so a server keeps its own main loop and stays killable. - TCP_LISTEN/TCP_SYNRCVD in tcp_in: answer a SYN with SYN+ACK, become established on the handshake's ACK, and process any data that ACK carries. tcp_peer_is_current tells a peer's retransmitted SYN from a newcomer's. Without it, "any SYN in SYNRCVD is a retransmission" let a second client *hijack* a connection mid-request: the first client got its SYN+ACK, sent its GET twice, and was never answered (found in a tcpdump of two parallel curls). listen() also refuses a port another socket already holds - two sockets on one port silently black-hole the second listener, since demux takes the first match. Sockets now record the pid that opened them (SK_OWNER) and exit *and* kill release them: with 4 slots, a few killed irc/nc/httpd runs used to leave the box unable to open a socket at all until reboot. tcp_close stops settling the moment the peer's FIN/ACK arrives instead of burning its whole pump budget. It otherwise sits in FINWAIT for about a second, and a server that closes and re-listens drops the next client's SYN in that window: every request after the first paid a SYN retransmit. 1.1s -> 0.1s per request.
Diffstat (limited to 'usr')
-rw-r--r--usr/sock.h16
1 files changed, 16 insertions, 0 deletions
diff --git a/usr/sock.h b/usr/sock.h
index 876e85c..efe7547 100644
--- a/usr/sock.h
+++ b/usr/sock.h
@@ -48,6 +48,22 @@ static unsigned char net_recv_nb(unsigned char s, void *buf, unsigned char max)
_nr.op = 8; _nr.sock = s; _nr.buf = (unsigned char *)buf; _nr.len = max;
return sys_net(&_nr);
}
+/* passive open: take connections on a local port (TCP). The listener and the
+ connection are the same socket, so serve one, close, then listen again. */
+static unsigned char net_listen(unsigned char s, unsigned int port) {
+ _nr.op = 9;
+ _nr.sock = s;
+ _nr.port_hi = (unsigned char)(port >> 8);
+ _nr.port_lo = (unsigned char)port;
+ return sys_net(&_nr);
+}
+/* -> 0 once a peer has connected, 0xFE if none yet. Never blocks: one RX pump
+ per call, so loop it with yield()/msleep() and poll the keyboard too. */
+static unsigned char net_accept(unsigned char s) {
+ _nr.op = 10;
+ _nr.sock = s;
+ return sys_net(&_nr);
+}
/* set the local (source) port - needed so UDP replies demux back to us */
static unsigned char net_bind(unsigned char s, unsigned int port) {
_nr.op = 5; _nr.sock = s;