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

Add connection tester failure pixels #881

Merged
merged 7 commits into from
Jul 6, 2024
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import Common
final class NetworkProtectionConnectionTester {
enum Result {
case connected
case reconnected
case reconnected(failureCount: Int)
case disconnected(failureCount: Int)
}

Expand Down Expand Up @@ -267,9 +267,8 @@ final class NetworkProtectionConnectionTester {
if failureCount == 0 {
resultHandler(.connected)
} else if failureCount > 0 {
resultHandler(.reconnected(failureCount: failureCount))
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We want to know how many failures there were before recovery, as we want to send different recovery pixels depending on it.

failureCount = 0

resultHandler(.reconnected)
}
}

Expand Down
40 changes: 39 additions & 1 deletion Sources/NetworkProtection/PacketTunnelProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {

public enum Event {
case userBecameActive
case connectionTesterStatusChange(_ status: ConnectionTesterStatus, server: String)
case reportConnectionAttempt(attempt: ConnectionAttempt)
case tunnelStartAttempt(_ step: TunnelStartAttemptStep)
case tunnelStopAttempt(_ step: TunnelStopAttemptStep)
Expand Down Expand Up @@ -64,6 +65,16 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {
case failure
}

public enum ConnectionTesterStatus {
case failed(duration: Duration)
case recovered(duration: Duration, failureCount: Int)

public enum Duration: String {
case immediate
case extended
}
}

// MARK: - Error Handling

public enum TunnelError: LocalizedError, CustomNSError, SilentErrorConvertible {
Expand Down Expand Up @@ -309,23 +320,50 @@ open class PacketTunnelProvider: NEPacketTunnelProvider {

// MARK: - Connection tester

private static let connectionTesterExtendedFailuresCount = 8
private var isConnectionTesterEnabled: Bool = true

@MainActor
private lazy var connectionTester: NetworkProtectionConnectionTester = {
NetworkProtectionConnectionTester(timerQueue: timerQueue, log: .networkProtectionConnectionTesterLog) { @MainActor [weak self] result in
guard let self else { return }

let serverName = lastSelectedServerInfo?.name ?? "Unknown"

switch result {
case .connected:
self.tunnelHealth.isHavingConnectivityIssues = false
self.updateBandwidthAnalyzerAndRekeyIfExpired()

case .reconnected:
case .reconnected(let failureCount):
providerEvents.fire(
.connectionTesterStatusChange(
.recovered(duration: .immediate, failureCount: failureCount),
server: serverName))

if failureCount >= Self.connectionTesterExtendedFailuresCount {
providerEvents.fire(
.connectionTesterStatusChange(
.recovered(duration: .extended, failureCount: failureCount),
server: serverName))
}

self.tunnelHealth.isHavingConnectivityIssues = false
self.updateBandwidthAnalyzerAndRekeyIfExpired()

case .disconnected(let failureCount):
if failureCount == 1 {
providerEvents.fire(
.connectionTesterStatusChange(
.failed(duration: .immediate),
server: serverName))
} else if failureCount == 8 {
providerEvents.fire(
.connectionTesterStatusChange(
.failed(duration: .extended),
server: serverName))
}

self.tunnelHealth.isHavingConnectivityIssues = true
self.bandwidthAnalyzer.reset()
}
Expand Down
1 change: 1 addition & 0 deletions Sources/PixelKit/PixelKit+Parameters.swift
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import Foundation
public extension PixelKit {

enum Parameters: Hashable {
public static let count = "count"
public static let duration = "duration"
public static let test = "test"
public static let appVersion = "appVersion"
Expand Down
Loading