fix
This commit is contained in:
@@ -5,6 +5,7 @@ import (
|
||||
"fmt"
|
||||
"os"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
// Protocol constants (mirror of the Java Protocol class; see PROTOCOL.md).
|
||||
@@ -30,13 +31,27 @@ const (
|
||||
MuxFin = 0x02
|
||||
MuxRst = 0x03
|
||||
MuxWnd = 0x04
|
||||
MuxPing = 0x05
|
||||
MuxPong = 0x06
|
||||
|
||||
// MuxCtlSid is the reserved stream id carrying connection-scoped mux frames
|
||||
// (PING/PONG). Real streams are numbered from 1.
|
||||
MuxCtlSid = 0
|
||||
|
||||
FrameError = 0x7F
|
||||
|
||||
// SaturationThreshold caps how many streams share one worker conn once the
|
||||
// pool has grown to maxConn. Below maxConn the pool grows first (§7.1), so a
|
||||
// single connection is never a shared point of failure for every player.
|
||||
SaturationThreshold = 8
|
||||
|
||||
// Session-establishment feature flags (trailing VarInt on the Rekey message).
|
||||
FlagStreamFC = 0x01
|
||||
// FlagWorkerHeartbeat enables mux-level PING/PONG on worker conns. Without
|
||||
// it a worker conn whose path is silently blackholed (NAT/conntrack drop,
|
||||
// firewall) is never detected: the read loop parks forever, the dead conn
|
||||
// stays in the pool, and no player can be served until the client restarts.
|
||||
FlagWorkerHeartbeat = 0x02
|
||||
|
||||
// Per-stream flow-control window bounds (bytes). The advertised window is the
|
||||
// receiver's promise of how much un-credited DATA it will buffer per stream.
|
||||
@@ -49,11 +64,49 @@ const (
|
||||
DataChunkSize = 32 * 1024
|
||||
)
|
||||
|
||||
// Timeouts. Every tunnel socket is covered by one of these: without them a
|
||||
// silently dropped path (no FIN/RST) leaves the client parked forever.
|
||||
const (
|
||||
// HandshakeTimeout bounds session establishment end to end — the TCP dial,
|
||||
// the Rekey write and the SessionReady read. A hub that accepts the socket
|
||||
// but never answers must not park the caller (and, for the pool, every other
|
||||
// player behind it) indefinitely.
|
||||
HandshakeTimeout = 15 * time.Second
|
||||
|
||||
// TCPKeepAlivePeriod asks the kernel to probe idle tunnel sockets, so a peer
|
||||
// that becomes unreachable is detected even when no frames are in flight.
|
||||
TCPKeepAlivePeriod = 30 * time.Second
|
||||
|
||||
// MissedHeartbeats is how many ping intervals may pass with no reply before
|
||||
// a session is declared dead and dropped.
|
||||
MissedHeartbeats = 3
|
||||
|
||||
// MinPingIntervalMs floors the configured ping interval so the derived
|
||||
// heartbeat timeout can never be short enough to cause spurious drops.
|
||||
// Applied in LoadConfig, i.e. to configs that come from disk.
|
||||
MinPingIntervalMs = 1000
|
||||
)
|
||||
|
||||
// heartbeatTimeout is how long a session may go without a reply before it is
|
||||
// considered dead, derived from the configured ping interval.
|
||||
func (c *Config) heartbeatTimeout() time.Duration {
|
||||
return c.pingInterval() * MissedHeartbeats
|
||||
}
|
||||
|
||||
// pingInterval is the configured heartbeat period.
|
||||
func (c *Config) pingInterval() time.Duration {
|
||||
return time.Duration(c.PingIntervalMs) * time.Millisecond
|
||||
}
|
||||
|
||||
// Mapping routes a registered pattern to a real destination.
|
||||
type Mapping struct {
|
||||
Pattern string `json:"pattern"`
|
||||
Destination string `json:"destination"`
|
||||
ProxyProtocol bool `json:"proxyProtocol"`
|
||||
// VelocitySecret, when non-empty, answers the destination's Velocity
|
||||
// modern-forwarding login query (velocity:player_info) with this secret,
|
||||
// forwarding the player's real IP, username and UUID (see velocity.go).
|
||||
VelocitySecret string `json:"velocitySecret"`
|
||||
}
|
||||
|
||||
// Config is the client configuration (PROTOCOL.md §9.2).
|
||||
@@ -91,6 +144,9 @@ func LoadConfig(path string) (*Config, error) {
|
||||
if c.PingIntervalMs <= 0 {
|
||||
c.PingIntervalMs = 20000
|
||||
}
|
||||
if c.PingIntervalMs < MinPingIntervalMs {
|
||||
c.PingIntervalMs = MinPingIntervalMs
|
||||
}
|
||||
if len(c.Mappings) == 0 {
|
||||
return nil, fmt.Errorf("at least one mapping is required")
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user