parent
7f34c0123b
commit
b67f45e497
|
|
@ -54,12 +54,12 @@ const (
|
||||||
defaultRecvBuf = 256 * 1024
|
defaultRecvBuf = 256 * 1024
|
||||||
defaultSendBuf = 256 * 1024
|
defaultSendBuf = 256 * 1024
|
||||||
wsPoolSize = 4
|
wsPoolSize = 4
|
||||||
wsPoolMaxAge = 90.0 // seconds — reduced from 120 to catch stale faster
|
wsPoolMaxAge = 60.0 // seconds — reduced from 90 to 60 for VPNs
|
||||||
wsBridgeIdle = 120.0 // seconds — max idle time before bridge considers WS dead
|
wsBridgeIdle = 120.0 // seconds — max idle time before bridge considers WS dead
|
||||||
|
|
||||||
dcFailCooldown = 30.0 // seconds
|
dcFailCooldown = 30.0 // seconds
|
||||||
wsFailTimeout = 2.0 // seconds
|
wsFailTimeout = 2.0 // seconds
|
||||||
poolMaintainInterval = 30 // seconds — how often pool evicts stale and refills
|
poolMaintainInterval = 15 // seconds — frequent to send pings/keep-alives
|
||||||
)
|
)
|
||||||
|
|
||||||
var (
|
var (
|
||||||
|
|
@ -169,6 +169,7 @@ var ipToDC = map[string]dcInfo{
|
||||||
// DC2
|
// DC2
|
||||||
"149.154.167.41": {2, false}, "149.154.167.50": {2, false},
|
"149.154.167.41": {2, false}, "149.154.167.50": {2, false},
|
||||||
"149.154.167.51": {2, false}, "149.154.167.220": {2, false},
|
"149.154.167.51": {2, false}, "149.154.167.220": {2, false},
|
||||||
|
"149.154.167.35": {2, false}, "149.154.167.36": {2, false},
|
||||||
"95.161.76.100": {2, false},
|
"95.161.76.100": {2, false},
|
||||||
"149.154.167.151": {2, true}, "149.154.167.222": {2, true},
|
"149.154.167.151": {2, true}, "149.154.167.222": {2, true},
|
||||||
"149.154.167.223": {2, true}, "149.154.162.123": {2, true},
|
"149.154.167.223": {2, true}, "149.154.162.123": {2, true},
|
||||||
|
|
@ -242,7 +243,7 @@ func (s *Stats) Summary() string {
|
||||||
ph := s.poolHits.Load()
|
ph := s.poolHits.Load()
|
||||||
pm := s.poolMisses.Load()
|
pm := s.poolMisses.Load()
|
||||||
return fmt.Sprintf(
|
return fmt.Sprintf(
|
||||||
"total=%d ws=%d tcp_fb=%d http_skip=%d pass=%d err=%d pool=%d/%d up=%s down=%s",
|
"total=%d ws=%d tcp_fb=%d http_skip=%d pass=%d err=%d pool_hits=%d/%d up=%s down=%s",
|
||||||
s.connectionsTotal.Load(),
|
s.connectionsTotal.Load(),
|
||||||
s.connectionsWs.Load(),
|
s.connectionsWs.Load(),
|
||||||
s.connectionsTcpFallback.Load(),
|
s.connectionsTcpFallback.Load(),
|
||||||
|
|
@ -554,6 +555,17 @@ func (ws *RawWebSocket) Close() {
|
||||||
_ = ws.conn.Close()
|
_ = ws.conn.Close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ws *RawWebSocket) SendPing() error {
|
||||||
|
if ws.closed.Load() {
|
||||||
|
return fmt.Errorf("WebSocket closed")
|
||||||
|
}
|
||||||
|
frame := buildFrame(opPing, []byte{}, true)
|
||||||
|
ws.mu.Lock()
|
||||||
|
defer ws.mu.Unlock()
|
||||||
|
_, err := ws.conn.Write(frame)
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
func buildFrame(opcode int, data []byte, mask bool) []byte {
|
func buildFrame(opcode int, data []byte, mask bool) []byte {
|
||||||
length := len(data)
|
length := len(data)
|
||||||
fb := byte(0x80 | opcode)
|
fb := byte(0x80 | opcode)
|
||||||
|
|
@ -992,6 +1004,12 @@ func (p *WsPool) Maintain(ctx context.Context, dcOptMap map[int]string) {
|
||||||
if age > wsPoolMaxAge || e.ws.closed.Load() {
|
if age > wsPoolMaxAge || e.ws.closed.Load() {
|
||||||
go e.ws.Close()
|
go e.ws.Close()
|
||||||
} else {
|
} else {
|
||||||
|
// Send ping to keep VPN NAT session alive, and actively close if network is dead
|
||||||
|
go func(ws *RawWebSocket) {
|
||||||
|
if err := ws.SendPing(); err != nil {
|
||||||
|
ws.Close()
|
||||||
|
}
|
||||||
|
}(e.ws)
|
||||||
fresh = append(fresh, e)
|
fresh = append(fresh, e)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1016,6 +1034,16 @@ func (p *WsPool) Maintain(ctx context.Context, dcOptMap map[int]string) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (p *WsPool) IdleCount() int {
|
||||||
|
p.mu.Lock()
|
||||||
|
defer p.mu.Unlock()
|
||||||
|
count := 0
|
||||||
|
for _, bucket := range p.idle {
|
||||||
|
count += len(bucket)
|
||||||
|
}
|
||||||
|
return count
|
||||||
|
}
|
||||||
|
|
||||||
var wsPool = newWsPool()
|
var wsPool = newWsPool()
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
|
|
@ -1426,7 +1454,7 @@ func handleClient(ctx context.Context, conn net.Conn) {
|
||||||
dcOptMu.RUnlock()
|
dcOptMu.RUnlock()
|
||||||
|
|
||||||
if !dcOk || !dcConfigured {
|
if !dcOk || !dcConfigured {
|
||||||
logWarn.Printf("[%s] unknown DC%d for %s:%d -> TCP passthrough", label, dc, dst, port)
|
logDebug.Printf("[%s] unknown DC%d for %s:%d -> TCP passthrough", label, dc, dst, port)
|
||||||
tcpFallback(ctx, conn, dst, port, init, label, dc, isMedia)
|
tcpFallback(ctx, conn, dst, port, init, label, dc, isMedia)
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
@ -1565,7 +1593,7 @@ func handleClient(ctx context.Context, conn net.Conn) {
|
||||||
|
|
||||||
// Send init packet
|
// Send init packet
|
||||||
if err := ws.Send(init); err != nil {
|
if err := ws.Send(init); err != nil {
|
||||||
logWarn.Printf("[%s] failed to send init via WS: %v", label, err)
|
logDebug.Printf("[%s] reconnecting via TCP fallback (WS broken by NAT): %v", label, err)
|
||||||
ws.Close()
|
ws.Close()
|
||||||
tcpFallback(ctx, conn, dst, port, init, label, dc, isMedia)
|
tcpFallback(ctx, conn, dst, port, init, label, dc, isMedia)
|
||||||
return
|
return
|
||||||
|
|
@ -1651,7 +1679,8 @@ func runProxy(ctx context.Context, host string, port int, dcOptMap map[int]strin
|
||||||
if len(blParts) > 0 {
|
if len(blParts) > 0 {
|
||||||
bl = strings.Join(blParts, ", ")
|
bl = strings.Join(blParts, ", ")
|
||||||
}
|
}
|
||||||
logInfo.Printf("stats: %s | ws_bl: %s", stats.Summary(), bl)
|
idleCount := wsPool.IdleCount()
|
||||||
|
logInfo.Printf("stats: %s idle_conns=%d | ws_bl: %s", stats.Summary(), idleCount, bl)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
@ -1951,4 +1980,4 @@ func main() {
|
||||||
|
|
||||||
// Ensure mrand is used to avoid import errors
|
// Ensure mrand is used to avoid import errors
|
||||||
var _ = mrand.Int
|
var _ = mrand.Int
|
||||||
var _ = big.NewInt
|
var _ = big.NewInt
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue