From 2849eebb287ca2c8f254b04846b6f42907709502 Mon Sep 17 00:00:00 2001 From: Riley Testut Date: Mon, 4 Oct 2021 15:57:23 -0700 Subject: [PATCH] [AltServer] Fixes potential crash due to race condition when device is disconnected Simultaneously updating WiredConnectionHandler.notificationConnections can cause a crash, so we enforce serial access to notificationConnections via DispatchQueue. --- .../Connections/WiredConnectionHandler.swift | 33 +++++++++++-------- 1 file changed, 20 insertions(+), 13 deletions(-) diff --git a/AltServer/Connections/WiredConnectionHandler.swift b/AltServer/Connections/WiredConnectionHandler.swift index 0aede491..c5f4c002 100644 --- a/AltServer/Connections/WiredConnectionHandler.swift +++ b/AltServer/Connections/WiredConnectionHandler.swift @@ -14,6 +14,7 @@ class WiredConnectionHandler: ConnectionHandler var disconnectionHandler: ((Connection) -> Void)? private var notificationConnections = [ALTDevice: NotificationConnection]() + private let queue = DispatchQueue(label: "WiredConnectionHandler", autoreleaseFrequency: .workItem, target: .global(qos: .utility)) func startListening() { @@ -32,29 +33,35 @@ private extension WiredConnectionHandler { func startNotificationConnection(to device: ALTDevice) { - ALTDeviceManager.shared.startNotificationConnection(to: device) { (connection, error) in - guard let connection = connection else { return } + self.queue.async { + ALTDeviceManager.shared.startNotificationConnection(to: device) { (connection, error) in + guard let connection = connection else { return } - let notifications: [CFNotificationName] = [.wiredServerConnectionAvailableRequest, .wiredServerConnectionStartRequest] - connection.startListening(forNotifications: notifications.map { String($0.rawValue) }) { (success, error) in - guard success else { return } + let notifications: [CFNotificationName] = [.wiredServerConnectionAvailableRequest, .wiredServerConnectionStartRequest] + connection.startListening(forNotifications: notifications.map { String($0.rawValue) }) { (success, error) in + guard success else { return } - connection.receivedNotificationHandler = { [weak self, weak connection] (notification) in - guard let self = self, let connection = connection else { return } - self.handle(notification, for: connection) + self.queue.async { + connection.receivedNotificationHandler = { [weak self, weak connection] (notification) in + guard let self = self, let connection = connection else { return } + self.handle(notification, for: connection) + } + + self.notificationConnections[device] = connection + } } - - self.notificationConnections[device] = connection } } } func stopNotificationConnection(to device: ALTDevice) { - guard let connection = self.notificationConnections[device] else { return } - connection.disconnect() + self.queue.async { + guard let connection = self.notificationConnections[device] else { return } + connection.disconnect() - self.notificationConnections[device] = nil + self.notificationConnections[device] = nil + } } func handle(_ notification: CFNotificationName, for connection: NotificationConnection)