package bridge import ( "log" "time" "github.com/wormhole/wormhole/internal/protocol" ) func (b *Bridge) startWatchdog() { go func() { ticker := time.NewTicker(WatchdogInterval) defer ticker.Stop() for range ticker.C { b.runWatchdog() } }() } func (b *Bridge) runWatchdog() { now := time.Now() b.mu.RLock() sessions := make([]*AgentSession, 0, len(b.agents)) for _, agent := range b.agents { sessions = append(sessions, agent) } b.mu.RUnlock() for _, agent := range sessions { if agent.closed.Load() { continue } lastPing, ok := b.cache.AgentLastPing(agent.ClientID) if !ok { continue } since := now.Sub(lastPing) if since > HeartbeatTimeout { log.Printf("[bridge] client %d heartbeat timeout (%v), closing", agent.ClientID, since.Round(time.Second)) agent.Close() continue } if since > ServerProbeAfter { go b.probeAgent(agent) } } } func (b *Bridge) probeAgent(agent *AgentSession) { if agent.closed.Load() { return } stream, err := agent.smux.OpenStream() if err != nil { return } defer stream.Close() if err := protocol.WriteMessage(stream, protocol.MsgPing, nil); err != nil { return } msgType, _, err := protocol.ReadMessage(stream) if err != nil || msgType != protocol.MsgPong { return } b.cache.TouchAgent(agent.ClientID) }