Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Get rid of swiftlint warnings and move files around #5770

Merged
merged 1 commit into from
Feb 6, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
Loading