mirror of https://github.com/oxen-io/session-ios
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
128 lines
4.0 KiB
Swift
128 lines
4.0 KiB
Swift
5 years ago
|
//
|
||
|
// 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 {
|
||
5 years ago
|
AssertIsOnMainThread()
|
||
|
ensureCheckTimer()
|
||
5 years ago
|
}
|
||
|
}
|
||
|
|
||
|
// 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
|
||
|
}
|
||
|
}
|
||
|
}
|