mirror of
https://github.com/oxen-io/session-ios.git
synced 2023-12-13 21:30:14 +01:00
127 lines
4 KiB
Swift
127 lines
4 KiB
Swift
//
|
|
// Copyright (c) 2018 Open Whisper Systems. All rights reserved.
|
|
//
|
|
|
|
import Foundation
|
|
import os
|
|
|
|
@objc
|
|
public class OutageDetection: NSObject {
|
|
@objc(sharedManager)
|
|
public static let shared = OutageDetection()
|
|
|
|
@objc public static let outageStateDidChange = Notification.Name("OutageStateDidChange")
|
|
|
|
// These properties should only be accessed on the main thread.
|
|
@objc
|
|
public var hasOutage = false {
|
|
didSet {
|
|
AssertIsOnMainThread()
|
|
|
|
if hasOutage != oldValue {
|
|
Logger.info("hasOutage: \(hasOutage).")
|
|
|
|
NotificationCenter.default.postNotificationNameAsync(OutageDetection.outageStateDidChange, object: nil)
|
|
}
|
|
}
|
|
}
|
|
private var shouldCheckForOutage = false {
|
|
didSet {
|
|
AssertIsOnMainThread()
|
|
ensureCheckTimer()
|
|
}
|
|
}
|
|
|
|
// We only show the outage warning when we're certain there's an outage.
|
|
// DNS lookup failures, etc. are not considered an outage.
|
|
private func checkForOutageSync() -> Bool {
|
|
let host = CFHostCreateWithName(nil, "uptime.signal.org" as CFString).takeRetainedValue()
|
|
CFHostStartInfoResolution(host, .addresses, nil)
|
|
var success: DarwinBoolean = false
|
|
guard let addresses = CFHostGetAddressing(host, &success)?.takeUnretainedValue() as NSArray? else {
|
|
Logger.error("CFHostGetAddressing failed: no addresses.")
|
|
return false
|
|
}
|
|
guard success.boolValue else {
|
|
Logger.error("CFHostGetAddressing failed.")
|
|
return false
|
|
}
|
|
var isOutageDetected = false
|
|
for case let address as NSData in addresses {
|
|
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
|
|
if getnameinfo(address.bytes.assumingMemoryBound(to: sockaddr.self), socklen_t(address.length),
|
|
&hostname, socklen_t(hostname.count), nil, 0, NI_NUMERICHOST) == 0 {
|
|
let addressString = String(cString: hostname)
|
|
let kHealthyAddress = "127.0.0.1"
|
|
let kOutageAddress = "127.0.0.2"
|
|
if addressString == kHealthyAddress {
|
|
// Do nothing.
|
|
} else if addressString == kOutageAddress {
|
|
isOutageDetected = true
|
|
} else {
|
|
owsFailDebug("unexpected address: \(addressString)")
|
|
}
|
|
}
|
|
}
|
|
return isOutageDetected
|
|
}
|
|
|
|
private func checkForOutageAsync() {
|
|
Logger.info("")
|
|
|
|
DispatchQueue.global().async {
|
|
let isOutageDetected = self.checkForOutageSync()
|
|
DispatchQueue.main.async {
|
|
self.hasOutage = isOutageDetected
|
|
}
|
|
}
|
|
}
|
|
|
|
private var checkTimer: Timer?
|
|
private func ensureCheckTimer() {
|
|
// Only monitor for outages in the main app.
|
|
guard CurrentAppContext().isMainApp else {
|
|
return
|
|
}
|
|
|
|
if shouldCheckForOutage {
|
|
if checkTimer != nil {
|
|
// Already has timer.
|
|
return
|
|
}
|
|
|
|
// The TTL of the DNS record is 60 seconds.
|
|
checkTimer = WeakTimer.scheduledTimer(timeInterval: 60, target: self, userInfo: nil, repeats: true) { [weak self] _ in
|
|
AssertIsOnMainThread()
|
|
|
|
guard CurrentAppContext().isMainAppAndActive else {
|
|
return
|
|
}
|
|
|
|
guard let strongSelf = self else {
|
|
return
|
|
}
|
|
|
|
strongSelf.checkForOutageAsync()
|
|
}
|
|
} else {
|
|
checkTimer?.invalidate()
|
|
checkTimer = nil
|
|
}
|
|
}
|
|
|
|
@objc
|
|
public func reportConnectionSuccess() {
|
|
DispatchMainThreadSafe {
|
|
self.shouldCheckForOutage = false
|
|
self.hasOutage = false
|
|
}
|
|
}
|
|
|
|
@objc
|
|
public func reportConnectionFailure() {
|
|
DispatchMainThreadSafe {
|
|
self.shouldCheckForOutage = true
|
|
}
|
|
}
|
|
}
|