Bug fixes:
- packetConn.Read: fix slice bounds panic when dlen > len(b);
n was set to dlen (the wire size) but only len(b) bytes were
copied to b; callers doing b[:n] would panic. Clamp n via copy().
- lockWriter.Close: add mutex lock to prevent data race with Write;
Router.Close calls connector.Close (lockWriter.Close) while
handlePacket concurrently calls Writer.Write — both touch w.w.
- Router.DelConnector: delete empty host slices from the map after
removing the last connector, preventing unbounded map growth.
Documentation:
- Package-level doc with architecture diagram, data flow, component
hierarchy, thread-safety invariants, and connector weighting rules.
- Documented every exported type (Connector, Router, ConnectorPool,
ConnectorOptions, routerHandler, metadata, lockWriter, packetConn)
and all non-trivial methods with purpose, parameters, lifecycle,
and algorithmic details (e.g., GetConnector weighted selection).
- Annotated critical code paths with step-by-step comments
(handleAssociate stages, handlePacket routing algorithm,
handleEntrypoint packet format and forwarding logic).
- Explained observeStats retry pattern and metadata key conventions.
Verification: build, vet, 98 tests race-clean.
- api: add fillServiceStatus helper and call it from getServiceList/getService
so status field appears in service list and detail API responses
- observeStats: unify retry pattern across all 9 handlers (http, http2, masque,
relay, router, socks4, socks5, tungo, tunnel) — buffer events on failure,
continue to skip fresh collection, clear on success; fix event-loss bug
where interim events were dropped during retry cycles
- handler/router: check WriteTo/Write return errors in associate.go and
entrypoint.go; fix DelConnector and ConnectorPool.Del using RLock instead
of Lock (write under read lock); remove unused fields t and cancel
The readTimeout field (default 15s) was being applied via xnet.Pipe to both
directions of a bidirectional proxy connection. During asymmetric transfers
(e.g. HTTP file download), the direction reading from the tunnel sees no
data after the initial request is forwarded, causing SetReadDeadline to fire
after 15s and abort the entire transfer.
Fix: add a separate idleTimeout field (default 0=disabled) to the metadata
structs in both forward/local and forward/remote handlers, and switch
xnet.Pipe to use idleTimeout instead of readTimeout. The readTimeout field
now only applies to the initial protocol sniffing/handshake phase.
Also document readTimeout vs idleTimeout semantics across all 24 locations
in the x/ module where these timeouts appear:
- readTimeout: handshake sniffing deadline (handlers), upstream response
header timeout (http.Transport), or transport-level read deadline
- idleTimeout: idle read deadline per Pipe direction (0=disabled)
- ReadTimeout on Sniffer/SnifferBuilder: upstream response header/TLS
handshake read timeout during sniffing