XX-net/XX-Net · warning
Except %s flush_send_s BlockingIOError %r
Error message
Except %s flush_send_s BlockingIOError %r
What it means
Logged when flush_send_s() raises BlockingIOError while writing split-SNI buffered data to the non-blocking socket s2 during the pipe loop. The send buffer is full so the OS would block; the write side of s2 is closed and the loop continues.
Source
Thrown at code/default/smart_router/local/pipe_socks.py:262
s2.port == 443 and \
d[0] == '\x16' and \
g.gfwlist.in_block_list(s2.host):
p1 = d.find(s2.host)
if p1 > 1:
if b"google" in s2.host:
p2 = d.find(b"google") + 3
else:
p2 = p1 + len(s2.host) - 6
d1 = d[:p2]
d2 = d[p2:]
try:
flush_send_s(s2, d1)
s2.sent_data += len(d1)
s2.sent_times += 1
except BlockingIOError as e:
xlog.warn("Except %s flush_send_s BlockingIOError %r", s2, e)
self.close(s2, "w")
continue
except Exception as e:
xlog.warn("send split SNI:%s fail:%r", s2.host, e)
self.close(s2, "w")
continue
s2.add_dat(d2)
d = b""
xlog.debug("pipe send split SNI:%s", s2.host)
if s2.buf_size == 0:
try:
sent = s2.send(d)
s2.sent_data += sent
s2.sent_times += 1
# xlog.debug("direct send %d to %s from:%s total:%d", sent, s2, s1, len(d))
except BlockingIOError as e:View on GitHub (pinned to cfa5bc17b6)
Solutions
- Tune/raise SO_SNDBUF on s2 or reduce the amount of buffered data before flushing
- Enable/verify the buffering path so partial sends queue instead of closing the write side
- Check remote peer health and network throughput; close dead connections earlier
- Retry flush later instead of closing the write side on transient EAGAIN
Example fix
// before
except BlockingIOError as e:
xlog.warn("Except %s flush_send_s BlockingIOError %r", s2, e)
self.close(s2, "w")
// after
except BlockingIOError as e:
xlog.warn("Except %s flush_send_s BlockingIOError %r", s2, e)
s2.set_blocking_wakeup() # defer flush to next epoll/select cycle Defensive patterns
Strategy: retry
Validate before calling
if s2.buffered_size > HIGH_WATER: defer_flush() # wait for writability
Try / catch
Catch BlockingIOError separately from socket.error and treat as 'retry later', not fatal.
Prevention
- Monitor per-socket buffered bytes and apply backpressure
- Use select/epoll writability before flushing large buffers
When it happens
Trigger: Non-blocking socket s2 whose send buffer is full (slow remote peer / fast local writer) when pipe() tries to flush buffered data after SNI splitting.
Common situations: Slow upstream server or throttled link while large buffered data is flushed; mismatched socket timeouts; peer stalled.
Related errors
AI-assisted analysis of XX-net/XX-Net@cfa5bc17b6 (2026-08-27).
Data as JSON: /api/errors/2a434f29362d62e4.
Report an issue: GitHub.