Skip to content

v0.3.5

Choose a tag to compare

@doronz88 doronz88 released this 12 Aug 23:51
· 11 commits to main since this release

Second stability round from the 2026-08 audit: every remaining P1 finding is fixed. All changes verified per-commit on Python 3.9 with the full test suite (4157 tests) and smoke-tested end-to-end against a physical iOS device over the pymobiledevice3 userspace tunnel (zero stranded tasks, latency unchanged).

Highlights

  • connect() failures always surface. A soft ICMP unreachable during the handshake used to wake the blocked connect() with an error value it never mapped — the caller returned as if connected to a session still mid-handshake. Per the stack's RFC 5927 hint-not-proof stance, the soft error is now recorded without waking the caller (a spoofed ICMP can't kill a pending connect) and is reported — as OSError(EHOSTUNREACH/ENETUNREACH) — if the R2 budget gives up, exactly Linux's sk_err_soft behavior. The R2 give-up also now releases a connect() parked through a crossed-SYN simultaneous open (SYN_RCVD), which previously hung forever.
  • Listener teardown resets its backlog. Closing/aborting a listening socket now aborts every established-but-unaccepted child (RST to the peer, socket deregistered, port released — Linux inet_csk_listen_stop parity) and wakes a blocked accept() with EBADF/ECONNABORTED instead of stranding it forever.
  • close() works on a session-less TCP socket. A bound-but-never-connected socket previously could not be closed at all (assert raised) and leaked its port permanently.
  • Datapath loops survive their first bug. One exception in a subsystem iteration (e.g. NUD maintenance), a periodic-housekeeping pass, or a frame's TX assembly used to kill the loop silently — neighbor resolution frozen, temp-address sweeps stopped, or egress wedged behind a poison frame — while the stack looked alive. All three now log through the stdlib logger and keep running.
  • recvmsg(MSG_ERRQUEUE) can no longer crash after an ICMP error burst: the bounded error queue's semaphore now stays in sync with the deque instead of accumulating phantom permits that ended in IndexError.