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-FakeTCP(UDP 封装 TCP 头部,欺骗防火墙) LayerFakeTCP // LayerRealTCP Direct-RealTCP(P2P 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 DataChannel(DTLS 加密) 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 }