Skip to content

Commit

Permalink
Get rid of swiftlint warnings and move files around
Browse files Browse the repository at this point in the history
  • Loading branch information
buggmagnet committed Feb 6, 2024
1 parent f42dcb3 commit 7eecc67
Show file tree
Hide file tree
Showing 5 changed files with 224 additions and 200 deletions.
8 changes: 8 additions & 0 deletions ios/MullvadVPN.xcodeproj/project.pbxproj
Original file line number Diff line number Diff line change
Expand Up @@ -616,6 +616,8 @@
A935594C2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift in Sources */ = {isa = PBXBuildFile; fileRef = A935594B2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift */; };
A94D691A2ABAD66700413DD4 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 58FE25E22AA72AE9003D1918 /* WireGuardKitTypes */; };
A94D691B2ABAD66700413DD4 /* WireGuardKitTypes in Frameworks */ = {isa = PBXBuildFile; productRef = 58FE25E72AA7399D003D1918 /* WireGuardKitTypes */; };
A95EEE362B722CD600A8A39B /* TunnelMonitorState.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95EEE352B722CD600A8A39B /* TunnelMonitorState.swift */; };
A95EEE382B722DFC00A8A39B /* PingStats.swift in Sources */ = {isa = PBXBuildFile; fileRef = A95EEE372B722DFC00A8A39B /* PingStats.swift */; };
A970C89D2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift in Sources */ = {isa = PBXBuildFile; fileRef = A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */; };
A97D25AE2B0BB18100946B2D /* ProtocolObfuscator.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */; };
A97D25B02B0BB5C400946B2D /* ProtocolObfuscationStub.swift in Sources */ = {isa = PBXBuildFile; fileRef = A97D25AF2B0BB5C400946B2D /* ProtocolObfuscationStub.swift */; };
Expand Down Expand Up @@ -1779,6 +1781,8 @@
A935594B2B4C2DA900D5D524 /* APIAvailabilityTestRequest.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = APIAvailabilityTestRequest.swift; sourceTree = "<group>"; };
A935594D2B4E919F00D5D524 /* Api.xcconfig */ = {isa = PBXFileReference; lastKnownFileType = text.xcconfig; path = Api.xcconfig; sourceTree = "<group>"; };
A9467E7E2A29DEFE000DC21F /* RelayCacheTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = RelayCacheTests.swift; sourceTree = "<group>"; };
A95EEE352B722CD600A8A39B /* TunnelMonitorState.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TunnelMonitorState.swift; sourceTree = "<group>"; };
A95EEE372B722DFC00A8A39B /* PingStats.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = PingStats.swift; sourceTree = "<group>"; };
A970C89C2B29E38C000A7684 /* Socks5UsernamePasswordCommand.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Socks5UsernamePasswordCommand.swift; sourceTree = "<group>"; };
A97D25AD2B0BB18100946B2D /* ProtocolObfuscator.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscator.swift; sourceTree = "<group>"; };
A97D25AF2B0BB5C400946B2D /* ProtocolObfuscationStub.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ProtocolObfuscationStub.swift; sourceTree = "<group>"; };
Expand Down Expand Up @@ -3116,9 +3120,11 @@
isa = PBXGroup;
children = (
58225D252A84E8A10083D7F1 /* DefaultPathObserverProtocol.swift */,
A95EEE372B722DFC00A8A39B /* PingStats.swift */,
582403162A821FD700163DE8 /* TunnelDeviceInfoProtocol.swift */,
58FC040927B3EE03001C21F0 /* TunnelMonitor.swift */,
58C7A42C2A85067A0060C66F /* TunnelMonitorProtocol.swift */,
A95EEE352B722CD600A8A39B /* TunnelMonitorState.swift */,
7A6B4F582AB8412E00123853 /* TunnelMonitorTimings.swift */,
58A3BDAF28A1821A00C8C2C6 /* WgStats.swift */,
);
Expand Down Expand Up @@ -4658,6 +4664,7 @@
58C7A4592A863FB90060C66F /* WgStats.swift in Sources */,
7AD0AA1F2AD6C8B900119E10 /* URLRequestProxyProtocol.swift in Sources */,
7A6B4F592AB8412E00123853 /* TunnelMonitorTimings.swift in Sources */,
A95EEE362B722CD600A8A39B /* TunnelMonitorState.swift in Sources */,
58FE25DB2AA72A8F003D1918 /* StartOptions.swift in Sources */,
A97D25AE2B0BB18100946B2D /* ProtocolObfuscator.swift in Sources */,
583832212AC3174700EA2071 /* PacketTunnelActor+NetworkReachability.swift in Sources */,
Expand All @@ -4670,6 +4677,7 @@
5838322B2AC3EF9600EA2071 /* CommandChannel.swift in Sources */,
586C145A2AC4735F00245C01 /* PacketTunnelActor+Public.swift in Sources */,
58342C042AAB61FB003BA12D /* State+Extensions.swift in Sources */,
A95EEE382B722DFC00A8A39B /* PingStats.swift in Sources */,
583832272AC3193600EA2071 /* PacketTunnelActor+SleepCycle.swift in Sources */,
58FE25DC2AA72A8F003D1918 /* AnyTask.swift in Sources */,
58FE25D92AA72A8F003D1918 /* AutoCancellingTask.swift in Sources */,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -138,8 +138,7 @@ class RedeemVoucherViewController: UIViewController, UINavigationControllerDeleg

contentView.state = .logout

Task {
[weak self] in
Task { [weak self] in
guard let self else { return }
await interactor.logout()
contentView.state = .initial
Expand Down
21 changes: 21 additions & 0 deletions ios/PacketTunnelCore/TunnelMonitor/PingStats.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
//
// PingStats.swift
// PacketTunnelCore
//
// Created by Marco Nikic on 2024-02-06.
// Copyright © 2024 Mullvad VPN AB. All rights reserved.
//

import Foundation

/// Ping statistics.
struct PingStats {
/// Dictionary holding sequence and corresponding date when echo request took place.
var requests = [UInt16: Date]()

/// Timestamp when last echo request was sent.
var lastRequestDate: Date?

/// Timestamp when last echo reply was received.
var lastReplyDate: Date?
}
200 changes: 2 additions & 198 deletions ios/PacketTunnelCore/TunnelMonitor/TunnelMonitor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,188 +14,6 @@ import NetworkExtension

/// Tunnel monitor.
public final class TunnelMonitor: TunnelMonitorProtocol {
/// Connection state.
private enum ConnectionState {
/// Initialized and doing nothing.
case stopped

/// Preparing to start.
/// Intermediate state before receiving the first path update.
case pendingStart

/// Establishing connection.
case connecting

/// Connection is established.
case connected

/// Delegate is recovering connection.
/// Delegate has to call `start(probeAddress:)` to complete recovery and resume monitoring.
case recovering

/// Waiting for network connectivity.
case waitingConnectivity
}

/// Tunnel monitor state.
private struct State {
/// Current connection state.
var connectionState: ConnectionState = .stopped

/// Network counters.
var netStats = WgStats()

/// Ping stats.
var pingStats = PingStats()

/// Reference date used to determine if timeout has occurred.
var timeoutReference = Date()

/// Last seen change in rx counter.
var lastSeenRx: Date?

/// Last seen change in tx counter.
var lastSeenTx: Date?

/// Whether periodic heartbeat is suspended.
var isHeartbeatSuspended = false

/// Retry attempt.
var retryAttempt: UInt32 = 0

// Timings and timeouts.
let timings: TunnelMonitorTimings

func evaluateConnection(now: Date, pingTimeout: Duration) -> ConnectionEvaluation {
switch connectionState {
case .connecting:
return handleConnectingState(now: now, pingTimeout: pingTimeout)
case .connected:
return handleConnectedState(now: now, pingTimeout: pingTimeout)
default:
return .ok
}
}

func getPingTimeout() -> Duration {
switch connectionState {
case .connecting:
let multiplier = timings.establishTimeoutMultiplier.saturatingPow(retryAttempt)
let nextTimeout = timings.initialEstablishTimeout * Double(multiplier)

if nextTimeout.isFinite, nextTimeout < timings.maxEstablishTimeout {
return nextTimeout
} else {
return timings.maxEstablishTimeout
}

case .pendingStart, .connected, .waitingConnectivity, .stopped, .recovering:
return timings.pingTimeout
}
}

mutating func updateNetStats(newStats: WgStats, now: Date) {
if newStats.bytesReceived > netStats.bytesReceived {
lastSeenRx = now
}

if newStats.bytesSent > netStats.bytesSent {
lastSeenTx = now
}

netStats = newStats
}

mutating func updatePingStats(sendResult: PingerSendResult, now: Date) {
pingStats.requests.updateValue(now, forKey: sendResult.sequenceNumber)
pingStats.lastRequestDate = now
}

mutating func setPingReplyReceived(_ sequenceNumber: UInt16, now: Date) -> Date? {
guard let pingTimestamp = pingStats.requests.removeValue(forKey: sequenceNumber) else {
return nil
}

pingStats.lastReplyDate = now
timeoutReference = now

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) >= timings.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) >= timings.heartbeatReplyTimeout,
timeSinceLastPing >= timings.pingDelay, !isHeartbeatSuspended {
return .retryHeartbeatPing
}

guard let lastSeenRx, let lastSeenTx else { return .ok }

let rxTimeElapsed = now.timeIntervalSince(lastSeenRx)
let txTimeElapsed = now.timeIntervalSince(lastSeenTx)

if timeSinceLastPing >= timings.heartbeatPingInterval {
// Send heartbeat if traffic is flowing.
if rxTimeElapsed <= timings.trafficFlowTimeout || txTimeElapsed <= timings.trafficFlowTimeout {
return .sendHeartbeatPing
}

if !isHeartbeatSuspended {
return .suspendHeartbeat
}
}

if timeSinceLastPing >= timings.pingDelay {
if txTimeElapsed >= timings.trafficTimeout || rxTimeElapsed >= timings.trafficTimeout {
return .trafficTimeout
}

if lastSeenTx > lastSeenRx, rxTimeElapsed >= timings.inboundTrafficTimeout {
return .inboundTrafficTimeout
}
}

return .ok
}
}

/// Ping statistics.
private struct PingStats {
/// Dictionary holding sequence and corresponding date when echo request took place.
var requests = [UInt16: Date]()

/// Timestamp when last echo request was sent.
var lastRequestDate: Date?

/// Timestamp when last echo reply was received.
var lastReplyDate: Date?
}

private let tunnelDeviceInfo: TunnelDeviceInfoProtocol

private let nslock = NSLock()
Expand All @@ -207,7 +25,7 @@ public final class TunnelMonitor: TunnelMonitorProtocol {
private var isObservingDefaultPath = false
private var timer: DispatchSourceTimer?

private var state: State
private var state: TunnelMonitorState
private var probeAddress: IPv4Address?

private let logger = Logger(label: "TunnelMonitor")
Expand Down Expand Up @@ -236,7 +54,7 @@ public final class TunnelMonitor: TunnelMonitorProtocol {
self.tunnelDeviceInfo = tunnelDeviceInfo

self.timings = timings
state = State(timings: timings)
state = TunnelMonitorState(timings: timings)

self.pinger = pinger
self.pinger.onReply = { [weak self] reply in
Expand Down Expand Up @@ -547,18 +365,6 @@ public final class TunnelMonitor: TunnelMonitorProtocol {
}
}

private enum ConnectionEvaluation {
case ok
case sendInitialPing
case sendNextPing
case sendHeartbeatPing
case retryHeartbeatPing
case suspendHeartbeat
case inboundTrafficTimeout
case trafficTimeout
case pingTimeout
}

private func getStats() -> WgStats? {
do {
return try tunnelDeviceInfo.getStats()
Expand All @@ -568,6 +374,4 @@ public final class TunnelMonitor: TunnelMonitorProtocol {
return nil
}
}

// swiftlint:disable:next file_length
}
Loading

0 comments on commit 7eecc67

Please sign in to comment.