Initial commit

This commit is contained in:
2026-06-30 15:14:37 +08:00
commit 15dab96872
311 changed files with 95639 additions and 0 deletions
+754
View File
@@ -0,0 +1,754 @@
package connect
import (
"context"
"fmt"
"net"
"sync"
"time"
"go.uber.org/zap"
)
// Layer 传输层类型(9 层策略)
type Layer int
const (
// LayerDirectUDP Direct-UDP 直连(WireGuard over UDP- 最高效
LayerDirectUDP Layer = iota
// LayerFakeTCP Direct-FakeTCPUDP 封装 TCP 头部,欺骗防火墙)
LayerFakeTCP
// LayerRealTCP Direct-RealTCPP2P TCP 直连)
LayerRealTCP
// LayerTURNUDP TURN-UDP 中继(标准 RFC 5766
LayerTURNUDP
// LayerTURNQUIC TURN-QUIC 中继(私有扩展,RFC 9000
LayerTURNQUIC
// LayerTURNTCP TURN-TCP 中继(TCP 中继)
LayerTURNTCP
// LayerTURNTLS TURN-TLS 中继(TLS 加密,RFC 8656
LayerTURNTLS
// LayerWebRTC WebRTC DataChannelDTLS 加密)
LayerWebRTC
// LayerWS WS/WSS 兜底(仅 80/443 端口,终极兜底)
LayerWS
// LayerCount 传输层总数
LayerCount
)
// String 实现 Stringer 接口
func (l Layer) String() string {
switch l {
case LayerDirectUDP:
return "Direct-UDP"
case LayerFakeTCP:
return "Direct-FakeTCP"
case LayerRealTCP:
return "Direct-RealTCP"
case LayerTURNUDP:
return "TURN-UDP"
case LayerTURNQUIC:
return "TURN-QUIC"
case LayerTURNTCP:
return "TURN-TCP"
case LayerTURNTLS:
return "TURN-TLS"
case LayerWebRTC:
return "WebRTC"
case LayerWS:
return "WS/WSS"
default:
return "Unknown"
}
}
// DefaultLayerOrder 默认优先级顺序(从最优到兜底)
// 根据 MeshRay_项目文档 v2.0.1 第 132-153 行定义
var DefaultLayerOrder = []Layer{
LayerDirectUDP, // 1. Direct-UDP - 公网/锥型 NAT,首选链路
LayerFakeTCP, // 2. Direct-FakeTCP - 校园网、酒店 Wi-Fi、UDP 被 QoS 限速
LayerRealTCP, // 3. Direct-RealTCP - 完全禁用 UDP,仅允许 TCP 出站
LayerTURNUDP, // 4. TURN-UDP 中继 - 无 P2P 直连,但 UDP 可通
LayerTURNQUIC, // 5. TURN-QUIC 中继 - UDP 可通但弱网(4G/5G、高丢包)【私有扩展】
LayerTURNTCP, // 6. TURN-TCP 中继 - UDP 封禁,仅放行 TCP
LayerTURNTLS, // 7. TURN-TLS 中继 - 企业防火墙 DPI,仅放行 HTTPS
LayerWebRTC, // 8. WebRTC 终极兜底 - 最严格隔离内网、代理环境
LayerWS, // 9. WS/WSS 兜底 - 仅放行 80/443 端口,且封锁 TURN
}
// TransportFactory 传输工厂接口 - 每种传输方式必须实现
type TransportFactory interface {
// Layer 返回传输层类型
Layer() Layer
// Dial 建立连接到对端
// 返回标准的 net.Conn 接口
Dial(ctx context.Context, config *DialConfig) (net.Conn, error)
// Name 返回传输方式名称(用于日志)
Name() string
}
// DialConfig 拨号配置
type DialConfig struct {
// PeerID 对端标识
PeerID string
// PeerPublicKey 对端公钥
PeerPublicKey string
// STUNServers STUN 服务器列表(用于 P2P)
STUNServers []string
// TURNServers TURN 服务器列表
TURNServers []string
// WSServers WebSocket 服务器列表
WSServers []string
// SignalingServers WebRTC 第三方信令服务器列表
SignalingServers []string
// ICESServers ICE 服务器列表(STUN+TURN 的组合)
ICESServers []string
// Timeout 连接超时
Timeout time.Duration
// Logger 日志记录器
Logger *zap.Logger
}
// StrategyScheduler 9 层策略调度器(主动调度层)
// 职责:
// 1. 按优先级选择链路(P2P → Mesh中继 → TURN-UDP → ... → WS/WSS
// 2. 根据网络环境自动切换(500ms 超时 / 10s 丢包率 > 10%
// 3. 切换后探测恢复并自动切回高性能链路(30s)
type StrategyScheduler struct {
layerFactories map[Layer]TransportFactory // 各层的工厂
layerOrder []Layer // 优先级顺序
logger *zap.Logger
// 每个 Peer 的降级控制器
fallbackControllers map[string]*FallbackController // peerID -> controller
fallbackMu sync.RWMutex
// 当前活跃连接
activeConnections map[string]activeConn // peerID -> 连接信息
connMu sync.RWMutex
// 统计
stats *SchedulerStats
// 连接变更回调(通知上层 ConnManager
OnConnectionUpdate func(peerID string, conn net.Conn, err error)
}
// activeConn 活跃连接信息
type activeConn struct {
conn net.Conn
layer Layer
peerID string
established time.Time
config *DialConfig
}
// SchedulerStats 调度器统计
type SchedulerStats struct {
mu sync.RWMutex
totalDials int64
successDials int64
fallbackCount int64
recoveryCount int64
layerDialCount map[Layer]int64
layerFailCount map[Layer]int64
}
// NewStrategyScheduler 创建策略调度器
func NewStrategyScheduler(logger *zap.Logger) *StrategyScheduler {
return &StrategyScheduler{
layerFactories: make(map[Layer]TransportFactory),
layerOrder: DefaultLayerOrder,
logger: logger,
fallbackControllers: make(map[string]*FallbackController),
activeConnections: make(map[string]activeConn),
stats: &SchedulerStats{
layerDialCount: make(map[Layer]int64),
layerFailCount: make(map[Layer]int64),
},
}
}
// RegisterFactory 注册传输工厂
func (s *StrategyScheduler) RegisterFactory(factory TransportFactory) {
layer := factory.Layer()
s.layerFactories[layer] = factory
s.logger.Debug("注册传输工厂",
zap.String("layer", layer.String()),
zap.String("name", factory.Name()))
}
// SetLayerOrder 设置优先级顺序
func (s *StrategyScheduler) SetLayerOrder(order []Layer) {
if len(order) == 0 {
s.logger.Warn("空的层级顺序,使用默认顺序")
return
}
s.layerOrder = order
s.logger.Info("更新传输层优先级顺序", zap.Any("order", order))
}
// Dial 按优先级顺序尝试建立连接
// 这是核心方法,实现了 9 层策略调度
func (s *StrategyScheduler) Dial(config *DialConfig) (net.Conn, error) {
ctx := context.Background()
if config.Timeout > 0 {
var cancel context.CancelFunc
ctx, cancel = context.WithTimeout(ctx, config.Timeout)
defer cancel()
}
s.logger.Info("开始 8 层策略调度连接",
zap.String("peer_id", config.PeerID),
zap.Int("total_layers", len(s.layerOrder)))
// 统计
s.stats.mu.Lock()
s.stats.totalDials++
s.stats.mu.Unlock()
var lastErr error
for i, layer := range s.layerOrder {
factory, ok := s.layerFactories[layer]
if !ok {
s.logger.Debug("该传输层未注册,跳过",
zap.String("layer", layer.String()))
continue
}
s.logger.Debug("尝试第 N 层传输",
zap.Int("index", i),
zap.String("layer", layer.String()),
zap.String("name", factory.Name()))
// 统计该层拨号次数
s.stats.mu.Lock()
s.stats.layerDialCount[layer]++
s.stats.mu.Unlock()
startTime := time.Now()
conn, err := factory.Dial(ctx, config)
duration := time.Since(startTime)
if err == nil {
// 成功!
s.stats.mu.Lock()
s.stats.successDials++
s.stats.mu.Unlock()
// 记录活跃连接
s.connMu.Lock()
s.activeConnections[config.PeerID] = activeConn{
conn: conn,
layer: layer,
peerID: config.PeerID,
established: time.Now(),
config: config,
}
s.connMu.Unlock()
// 创建或更新降级控制器
s.ensureFallbackController(config.PeerID, layer)
s.logger.Info("连接建立成功",
zap.String("layer", layer.String()),
zap.String("name", factory.Name()),
zap.String("peer_id", config.PeerID),
zap.String("remote_addr", conn.RemoteAddr().String()),
zap.Duration("duration", duration))
// 包装连接,用于监控
return newMonitoredConn(conn, config.PeerID, layer, s), nil
}
// 失败,统计
s.stats.mu.Lock()
s.stats.layerFailCount[layer]++
s.stats.mu.Unlock()
// 记录失败并继续尝试下一层
lastErr = err
s.logger.Warn("该传输层连接失败,尝试下一层",
zap.String("layer", layer.String()),
zap.Duration("duration", duration),
zap.Error(err))
}
// 所有层都失败
return nil, fmt.Errorf("所有传输层均失败,最后错误:%w", lastErr)
}
// reconnectToLayer 触发重连到指定层级
func (s *StrategyScheduler) reconnectToLayer(peerID string, toLayer Layer) {
s.connMu.RLock()
ac, exists := s.activeConnections[peerID]
s.connMu.RUnlock()
if !exists || ac.config == nil {
s.logger.Warn("重连失败:找不到活跃连接配置", zap.String("peer_id", peerID))
return
}
factory, ok := s.layerFactories[toLayer]
if !ok {
s.logger.Error("重连失败:找不到目标层级工厂", zap.String("layer", toLayer.String()))
return
}
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
conn, err := factory.Dial(ctx, ac.config)
if err != nil {
s.logger.Error("降级重连失败", zap.Error(err))
if s.OnConnectionUpdate != nil {
s.OnConnectionUpdate(peerID, nil, err)
}
return
}
wrappedConn := newMonitoredConn(conn, peerID, toLayer, s)
s.connMu.Lock()
if oldAc, exists := s.activeConnections[peerID]; exists {
oldAc.conn.Close()
}
s.activeConnections[peerID] = activeConn{
conn: wrappedConn,
layer: toLayer,
peerID: peerID,
established: time.Now(),
config: ac.config,
}
s.connMu.Unlock()
if s.OnConnectionUpdate != nil {
s.OnConnectionUpdate(peerID, wrappedConn, nil)
}
}
// ensureFallbackController 确保对端有降级控制器
func (s *StrategyScheduler) ensureFallbackController(peerID string, initialLayer Layer) {
s.fallbackMu.Lock()
defer s.fallbackMu.Unlock()
if _, exists := s.fallbackControllers[peerID]; !exists {
controller := NewFallbackController(
initialLayer,
func(from, to Layer) {
// 降级回调
s.stats.mu.Lock()
s.stats.fallbackCount++
s.stats.mu.Unlock()
s.logger.Warn("链路降级",
zap.String("peer_id", peerID),
zap.String("from_layer", from.String()),
zap.String("to_layer", to.String()))
// 触发重连到新层级
go s.reconnectToLayer(peerID, to)
},
func(to Layer) {
// 恢复回调
s.stats.mu.Lock()
s.stats.recoveryCount++
s.stats.mu.Unlock()
s.logger.Info("链路恢复",
zap.String("peer_id", peerID),
zap.String("to_layer", to.String()))
// 回调处理已经在 probeHighLayers 中完成并传递了新连接
},
s.logger,
s, // pass scheduler to access activeConnections
)
s.fallbackControllers[peerID] = controller
}
}
// RecordLatency 记录延迟(供 MonitoredConn 调用)
func (s *StrategyScheduler) RecordLatency(peerID string, success bool, duration time.Duration) {
s.fallbackMu.RLock()
controller, exists := s.fallbackControllers[peerID]
s.fallbackMu.RUnlock()
if exists {
controller.CheckAndFallback(success, duration)
}
}
// GetActiveLayer 获取当前活跃的传输层(用于监控)
func (s *StrategyScheduler) GetActiveLayer() Layer {
// 返回第一个活跃连接的层级
s.connMu.RLock()
defer s.connMu.RUnlock()
for _, ac := range s.activeConnections {
return ac.layer
}
return LayerDirectUDP // 默认值
}
// GetAllActiveLayers 获取所有 Peer 的活跃层级(用于全局监控)
func (s *StrategyScheduler) GetAllActiveLayers() map[string]Layer {
s.connMu.RLock()
defer s.connMu.RUnlock()
result := make(map[string]Layer)
for peerID, ac := range s.activeConnections {
result[peerID] = ac.layer
}
return result
}
// GetPeerLayer 获取指定 Peer 的当前层级
func (s *StrategyScheduler) GetPeerLayer(peerID string) Layer {
s.connMu.RLock()
defer s.connMu.RUnlock()
if ac, exists := s.activeConnections[peerID]; exists {
return ac.layer
}
return LayerDirectUDP // 默认值
}
// GetStats 获取统计信息
func (s *StrategyScheduler) GetStats() map[string]interface{} {
s.stats.mu.RLock()
defer s.stats.mu.RUnlock()
layerStats := make(map[string]int64)
for layer, count := range s.stats.layerDialCount {
layerStats[layer.String()+"_dial"] = count
}
for layer, count := range s.stats.layerFailCount {
layerStats[layer.String()+"_fail"] = count
}
return map[string]interface{}{
"total_dials": s.stats.totalDials,
"success_dials": s.stats.successDials,
"fallback_count": s.stats.fallbackCount,
"recovery_count": s.stats.recoveryCount,
"layer_stats": layerStats,
}
}
// ClosePeer 关闭指定 Peer 的连接和控制器
func (s *StrategyScheduler) ClosePeer(peerID string) {
// 关闭连接
s.connMu.Lock()
if ac, exists := s.activeConnections[peerID]; exists {
ac.conn.Close()
delete(s.activeConnections, peerID)
}
s.connMu.Unlock()
// 移除降级控制器
s.fallbackMu.Lock()
if controller, exists := s.fallbackControllers[peerID]; exists {
// 停止恢复探测器
if controller.recoveryTimer != nil {
controller.recoveryTimer.Stop()
}
delete(s.fallbackControllers, peerID)
}
s.fallbackMu.Unlock()
s.logger.Debug("已关闭 Peer 连接和控制器",
zap.String("peer_id", peerID))
}
// MonitoredConn 带监控的连接包装器
type MonitoredConn struct {
net.Conn
peerID string
layer Layer
scheduler *StrategyScheduler
}
// newMonitoredConn 创建带监控的连接
func newMonitoredConn(conn net.Conn, peerID string, layer Layer, scheduler *StrategyScheduler) *MonitoredConn {
return &MonitoredConn{
Conn: conn,
peerID: peerID,
layer: layer,
scheduler: scheduler,
}
}
// Read 重写 Read 方法,记录延迟
func (c *MonitoredConn) Read(b []byte) (n int, err error) {
start := time.Now()
n, err = c.Conn.Read(b)
duration := time.Since(start)
// 记录成功/失败
c.scheduler.RecordLatency(c.peerID, err == nil, duration)
return n, err
}
// Write 重写 Write 方法,记录延迟
func (c *MonitoredConn) Write(b []byte) (n int, err error) {
start := time.Now()
n, err = c.Conn.Write(b)
duration := time.Since(start)
// 记录成功/失败
c.scheduler.RecordLatency(c.peerID, err == nil, duration)
return n, err
}
// FallbackController 降级控制器
type FallbackController struct {
currentLayer Layer // 当前使用的层
windowStart time.Time // 滑动窗口起始时间
packetCount int // 总包数
lostPacketCount int // 丢包数
mu chan struct{} // 互斥锁(用 channel 实现)
triggerFallback func(Layer, Layer) // 降级触发回调
triggerRecovery func(Layer) // 恢复触发回调
logger *zap.Logger
recoveryTimer *time.Timer // 恢复探测定时器
scheduler *StrategyScheduler
}
const (
// TimeoutThreshold 单次超时阈值
TimeoutThreshold = 500 * time.Millisecond
// PacketLossThreshold 丢包率阈值
PacketLossThreshold = 0.10 // 10%
// RecoveryInterval 恢复探测间隔
RecoveryInterval = 30 * time.Second
// SlidingWindowDuration 滑动窗口时长
SlidingWindowDuration = 10 * time.Second
)
// NewFallbackController 创建降级控制器
func NewFallbackController(
initialLayer Layer,
onFallback func(Layer, Layer),
onRecovery func(Layer),
logger *zap.Logger,
scheduler *StrategyScheduler,
) *FallbackController {
fc := &FallbackController{
currentLayer: initialLayer,
mu: make(chan struct{}, 1),
triggerFallback: onFallback,
triggerRecovery: onRecovery,
logger: logger,
scheduler: scheduler,
}
// 启动恢复探测
fc.startRecoveryProbe()
return fc
}
// CheckAndFallback 检查是否需要降级
// 在每次连接操作后调用
func (fc *FallbackController) CheckAndFallback(success bool, duration time.Duration) {
select {
case fc.mu <- struct{}{}:
defer func() { <-fc.mu }()
default:
// 锁被占用,说明正在处理,直接返回
return
}
// 重置滑动窗口
if time.Since(fc.windowStart) > SlidingWindowDuration {
fc.windowStart = time.Now()
fc.packetCount = 0
fc.lostPacketCount = 0
}
// 统计
fc.packetCount++
if !success || duration > TimeoutThreshold {
fc.lostPacketCount++
}
// 检查是否达到阈值
if fc.packetCount >= 10 {
lossRate := float64(fc.lostPacketCount) / float64(fc.packetCount)
if lossRate > PacketLossThreshold {
fc.triggerFallbackLocked()
}
}
}
// triggerFallbackLocked 执行降级(已持有锁)
func (fc *FallbackController) triggerFallbackLocked() {
currentIndex := int(fc.currentLayer)
if currentIndex >= int(LayerCount)-1 {
// 已经是最低优先级,无法降级
fc.logger.Warn("已是最底层级,无法降级",
zap.String("current_layer", fc.currentLayer.String()))
return
}
nextLayer := Layer(currentIndex + 1)
// 在更新 currentLayer 之前保存旧值用于回调
oldLayer := fc.currentLayer
fc.logger.Warn("触发降级",
zap.String("from_layer", oldLayer.String()),
zap.String("to_layer", nextLayer.String()))
fc.currentLayer = nextLayer
fc.resetWindow()
if fc.triggerFallback != nil {
fc.triggerFallback(oldLayer, nextLayer)
}
// 重置恢复定时器
fc.startRecoveryProbe()
}
// startRecoveryProbe 启动恢复探测
func (fc *FallbackController) startRecoveryProbe() {
if fc.recoveryTimer != nil {
fc.recoveryTimer.Stop()
}
fc.recoveryTimer = time.AfterFunc(RecoveryInterval, func() {
fc.probeHigherLayers()
})
}
// probeHigherLayers 探测更高层级
func (fc *FallbackController) probeHigherLayers() {
select {
case fc.mu <- struct{}{}:
defer func() { <-fc.mu }()
default:
return
}
currentIndex := int(fc.currentLayer)
if currentIndex == 0 {
// 已经是最高优先级,无需探测
return
}
// 尝试上一层
higherLayer := Layer(currentIndex - 1)
fc.logger.Info("探测更高层级",
zap.String("current_layer", fc.currentLayer.String()),
zap.String("probe_layer", higherLayer.String()))
// 获取 PeerID 及 Config
fc.scheduler.connMu.RLock()
var peerID string
var config *DialConfig
for pid, ac := range fc.scheduler.activeConnections {
if ac.layer == fc.currentLayer {
peerID = pid
config = ac.config
break
}
}
fc.scheduler.connMu.RUnlock()
if config == nil {
fc.logger.Warn("探测更高层级失败:找不到有效 DialConfig")
return
}
factory, ok := fc.scheduler.layerFactories[higherLayer]
if !ok {
fc.logger.Debug("更高层级未注册工厂,跳过探测")
return
}
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
defer cancel()
conn, err := factory.Dial(ctx, config)
if err == nil {
fc.logger.Info("更高层级探测成功,准备切换")
wrappedConn := newMonitoredConn(conn, peerID, higherLayer, fc.scheduler)
fc.scheduler.connMu.Lock()
if ac, exists := fc.scheduler.activeConnections[peerID]; exists {
ac.conn.Close() // Close old
ac.conn = wrappedConn
ac.layer = higherLayer
fc.scheduler.activeConnections[peerID] = ac
}
fc.scheduler.connMu.Unlock()
if fc.scheduler.OnConnectionUpdate != nil {
fc.scheduler.OnConnectionUpdate(peerID, wrappedConn, nil)
}
// 触发恢复回调
fc.triggerRecoveryLocked(higherLayer)
} else {
fc.logger.Debug("更高层级探测失败", zap.Error(err))
}
}
// triggerRecoveryLocked 执行恢复(已持有锁)
func (fc *FallbackController) triggerRecoveryLocked(higherLayer Layer) {
fc.logger.Info("触发恢复",
zap.String("from_layer", fc.currentLayer.String()),
zap.String("to_layer", higherLayer.String()))
fc.currentLayer = higherLayer
fc.resetWindow()
if fc.triggerRecovery != nil {
fc.triggerRecovery(higherLayer)
}
}
// resetWindow 重置滑动窗口
func (fc *FallbackController) resetWindow() {
fc.windowStart = time.Now()
fc.packetCount = 0
fc.lostPacketCount = 0
}
// GetCurrentLayer 获取当前层级
func (fc *FallbackController) GetCurrentLayer() Layer {
select {
case fc.mu <- struct{}{}:
defer func() { <-fc.mu }()
default:
return fc.currentLayer
}
return fc.currentLayer
}