| Commit message (Collapse) | Author | Age |
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
| |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| |
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.
|
|
|
Userland sources live in usr/ (fits the Unix theme better than 'c').
SDCC output .bin blobs land in build/usr/ with the other build artifacts
instead of littering the source dir; programs.asm INCBINs them from there.
Byte-identical ROM.
|