fix(handler/router): 3 bugs fixed + comprehensive data-flow documentation
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.
This commit is contained in:
@@ -8,6 +8,43 @@ import (
|
||||
"github.com/go-gost/relay"
|
||||
)
|
||||
|
||||
// handleEntrypoint runs the UDP entrypoint read loop.
|
||||
//
|
||||
// The entrypoint is the UDP socket that receives packets from peer
|
||||
// nodes in the mesh. When this node doesn't have a direct connector
|
||||
// for a destination, handlePacket forwards the IP packet via
|
||||
// epConn.WriteTo() to another node's entrypoint. This function is
|
||||
// the receiving side of that exchange.
|
||||
//
|
||||
// # Packet format
|
||||
//
|
||||
// Each UDP datagram contains a relay request header followed by the
|
||||
// raw IP packet:
|
||||
//
|
||||
// ┌──────────────────┬─────────────────┐
|
||||
// │ Relay Request │ Raw IP Packet │
|
||||
// │ (TunnelFeature + │ │
|
||||
// │ AddrFeature) │ │
|
||||
// └──────────────────┴─────────────────┘
|
||||
//
|
||||
// The relay request carries the tunnel ID (so we know which router)
|
||||
// and the gateway address (so we know which connector).
|
||||
//
|
||||
// # Forwarding
|
||||
//
|
||||
// When a packet arrives, the function:
|
||||
// 1. Reads the datagram from epConn.
|
||||
// 2. Parses the relay request prefix to extract the tunnel ID and gateway.
|
||||
// 3. Looks up the connector in the pool.
|
||||
// 4. Writes ONLY the raw IP packet (after the relay header) to the
|
||||
// connector's writer — the relay header consumed by req.ReadFrom
|
||||
// is stripped.
|
||||
//
|
||||
// # Error handling
|
||||
//
|
||||
// Non-CmdAssociate requests and parse errors are silently skipped
|
||||
// (the iteration continues). A read error from the underlying socket
|
||||
// terminates the loop — this typically means the socket was closed.
|
||||
func (h *routerHandler) handleEntrypoint(log logger.Logger) error {
|
||||
buf := bufpool.Get(h.md.bufferSize)
|
||||
defer bufpool.Put(buf)
|
||||
@@ -46,9 +83,11 @@ func (h *routerHandler) handleEntrypoint(log logger.Logger) error {
|
||||
|
||||
log.Tracef("redirect from %s to %s@%s", addr, gateway, routerID)
|
||||
|
||||
// nn is the number of bytes consumed by the relay header.
|
||||
// buf[nn:] is the raw IP packet payload.
|
||||
if c := h.pool.Get(routerID, gateway); c != nil {
|
||||
if w := c.Writer(); w != nil {
|
||||
if _, werr := w.Write(buf[nn:]); werr != nil {
|
||||
if _, werr := w.Write(buf[nn:n]); werr != nil {
|
||||
log.Error(werr)
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user