Files
firezone/swift/apple/FirezoneNetworkExtension/SessionEventLoop.swift
Mariusz Klochowicz ac6b3922be fix(apple): don't call setConfiguration when not connected (#10747)
Skip `setConfiguration()` IPC call when not in connected state; this was
observed as the root cause of the utun interface increments which we've
seen
recently.

Note: `utun` increments can still happen during other IPC calls when not
signed in,
notably during log export when signed out of Firezone. This is not a
major issue though,
as other IPC calls happen only as a result of user interaction between
network extension sleeps.
To fully get rid of the problem, we should address #10754.

To ensure we still are able to pass on configuration before sign in, we
are now
passing configuration directly in the startTunnel() options dictionary.

Fixes #10603
2025-10-28 23:51:50 +00:00

77 lines
1.9 KiB
Swift

import FirezoneKit
import Foundation
/// Commands that can be sent to the Session.
enum SessionCommand {
case disconnect
case setInternetResourceState(Bool)
case setDns([String])
case reset(String)
}
/// Runs the session event loop, owning the Session lifecycle.
///
/// When either task completes, both are cancelled and the function returns.
/// This ensures the Session's Drop is called on the Rust side.
func runSessionEventLoop(
session: Session,
commandReceiver: Receiver<SessionCommand>,
eventSender: Sender<Event>
) async {
// Multiplex between commands and events
await withTaskGroup(of: Void.self) { group in
group.addTask {
await forwardEvents(from: session, to: eventSender)
}
group.addTask {
await forwardCommands(from: commandReceiver, to: session)
}
// Wait for first task to complete, then cancel all
_ = await group.next()
group.cancelAll()
}
}
/// Forwards events from the session to the event sender.
private func forwardEvents(from session: Session, to eventSender: Sender<Event>) async {
while !Task.isCancelled {
guard let event = await session.nextEvent() else {
Log.log("Event stream ended")
break
}
eventSender.send(event)
}
}
/// Forwards commands from the command receiver to the session.
private func forwardCommands(from commandReceiver: Receiver<SessionCommand>, to session: Session)
async
{
for await command in commandReceiver.stream {
if Task.isCancelled {
Log.log("Command forwarding cancelled")
break
}
switch command {
case .disconnect:
session.disconnect()
case .setInternetResourceState(let active):
session.setInternetResourceState(active: active)
case .setDns(let servers):
session.setDns(dnsServers: servers)
case .reset(let reason):
session.reset(reason: reason)
}
}
Log.log("Command stream ended")
}