diff --git a/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift b/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift index 443ff5ddedd9..54cbb7353275 100644 --- a/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift +++ b/ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift @@ -101,65 +101,12 @@ public final class TunnelMonitor: TunnelMonitorProtocol { func evaluateConnection(now: Date, pingTimeout: Duration) -> ConnectionEvaluation { switch connectionState { case .connecting: - if now.timeIntervalSince(timeoutReference) >= pingTimeout { - return .pingTimeout - } - - guard let lastRequestDate = pingStats.lastRequestDate else { - return .sendInitialPing - } - - if now.timeIntervalSince(lastRequestDate) >= pingDelay { - return .sendNextPing - } - + return handleConnectingState(now: now, pingTimeout: pingTimeout) case .connected: - if now.timeIntervalSince(timeoutReference) >= pingTimeout, !isHeartbeatSuspended { - return .pingTimeout - } - - guard let lastRequestDate = pingStats.lastRequestDate else { - return .sendInitialPing - } - - let timeSinceLastPing = now.timeIntervalSince(lastRequestDate) - if let lastReplyDate = pingStats.lastReplyDate, - lastRequestDate.timeIntervalSince(lastReplyDate) >= heartbeatReplyTimeout, - timeSinceLastPing >= pingDelay, !isHeartbeatSuspended { - return .retryHeartbeatPing - } - - guard let lastSeenRx, let lastSeenTx else { return .ok } - - let rxTimeElapsed = now.timeIntervalSince(lastSeenRx) - let txTimeElapsed = now.timeIntervalSince(lastSeenTx) - - if timeSinceLastPing >= heartbeatPingInterval { - // Send heartbeat if traffic is flowing. - if rxTimeElapsed <= trafficFlowTimeout || txTimeElapsed <= trafficFlowTimeout { - return .sendHeartbeatPing - } - - if !isHeartbeatSuspended { - return .suspendHeartbeat - } - } - - if timeSinceLastPing >= pingDelay { - if txTimeElapsed >= trafficTimeout || rxTimeElapsed >= trafficTimeout { - return .trafficTimeout - } - - if lastSeenTx > lastSeenRx, rxTimeElapsed >= inboundTrafficTimeout { - return .inboundTrafficTimeout - } - } - + return handleConnectedState(now: now, pingTimeout: pingTimeout) default: - break + return .ok } - - return .ok } func getPingTimeout() -> Duration { @@ -206,6 +153,67 @@ public final class TunnelMonitor: TunnelMonitorProtocol { return pingTimestamp } + + private func handleConnectingState(now: Date, pingTimeout: Duration) -> ConnectionEvaluation { + if now.timeIntervalSince(timeoutReference) >= pingTimeout { + return .pingTimeout + } + + guard let lastRequestDate = pingStats.lastRequestDate else { + return .sendInitialPing + } + + if now.timeIntervalSince(lastRequestDate) >= pingDelay { + return .sendNextPing + } + + return .ok + } + + private func handleConnectedState(now: Date, pingTimeout: Duration) -> ConnectionEvaluation { + if now.timeIntervalSince(timeoutReference) >= pingTimeout, !isHeartbeatSuspended { + return .pingTimeout + } + + guard let lastRequestDate = pingStats.lastRequestDate else { + return .sendInitialPing + } + + let timeSinceLastPing = now.timeIntervalSince(lastRequestDate) + if let lastReplyDate = pingStats.lastReplyDate, + lastRequestDate.timeIntervalSince(lastReplyDate) >= heartbeatReplyTimeout, + timeSinceLastPing >= pingDelay, !isHeartbeatSuspended { + return .retryHeartbeatPing + } + + guard let lastSeenRx, let lastSeenTx else { return .ok } + + let rxTimeElapsed = now.timeIntervalSince(lastSeenRx) + let txTimeElapsed = now.timeIntervalSince(lastSeenTx) + + if timeSinceLastPing >= heartbeatPingInterval { + // Send heartbeat if traffic is flowing. + if rxTimeElapsed <= trafficFlowTimeout || txTimeElapsed <= trafficFlowTimeout { + return .sendHeartbeatPing + } + + if !isHeartbeatSuspended { + return .suspendHeartbeat + } + } + + if timeSinceLastPing >= pingDelay { + if txTimeElapsed >= trafficTimeout || rxTimeElapsed >= trafficTimeout { + return .trafficTimeout + } + + if lastSeenTx > lastSeenRx, rxTimeElapsed >= inboundTrafficTimeout { + return .inboundTrafficTimeout + } + } + + return .ok + } } /// Ping statistics.