0001    // NetworkReachabilityManager.swift
0002    //
0003    // Copyright (c) 2014–2016 Alamofire Software Foundation (http://alamofire.org/)
0004    //
0005    // Permission is hereby granted, free of charge, to any person obtaining a copy
0006    // of this software and associated documentation files (the "Software"), to deal
0007    // in the Software without restriction, including without limitation the rights
0008    // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
0009    // copies of the Software, and to permit persons to whom the Software is
0010    // furnished to do so, subject to the following conditions:
0011    //
0012    // The above copyright notice and this permission notice shall be included in
0013    // all copies or substantial portions of the Software.
0014    //
0015    // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
0016    // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
0017    // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
0018    // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
0019    // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
0020    // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
0021    // THE SOFTWARE.
0022    
0023    #if !os(watchOS)
0024    
0025    import Foundation
0026    import SystemConfiguration
0027    
0028    /**
0029        The `NetworkReachabilityManager` class listens for reachability changes of hosts and addresses for both WWAN and
0030        WiFi network interfaces.
0031    
0032        Reachability can be used to determine background information about why a network operation failed, or to retry
0033        network requests when a connection is established. It should not be used to prevent a user from initiating a network
0034        request, as it's possible that an initial request may be required to establish reachability.
0035    */
0036    public class NetworkReachabilityManager
NetworkReachabilityManager.swift:156
                let reachability = Unmanaged<NetworkReachabilityManager>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
NetworkReachabilityManager.swift:212
extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {}
NetworkReachabilityManager.swift:223
    lhs: NetworkReachabilityManager.NetworkReachabilityStatus,
NetworkReachabilityManager.swift:224
    rhs: NetworkReachabilityManager.NetworkReachabilityStatus)
{ 0037 /** 0038 Defines the various states of network reachability. 0039 0040 - Unknown: It is unknown whether the network is reachable. 0041 - NotReachable: The network is not reachable. 0042 - ReachableOnWWAN: The network is reachable over the WWAN connection. 0043 - ReachableOnWiFi: The network is reachable over the WiFi connection. 0044 */ 0045 public enum NetworkReachabilityStatus
NetworkReachabilityManager.swift:64
    public typealias Listener = NetworkReachabilityStatus -> Void
NetworkReachabilityManager.swift:78
    public var networkReachabilityStatus: NetworkReachabilityStatus {
NetworkReachabilityManager.swift:191
    func networkReachabilityStatusForFlags(flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus {
NetworkReachabilityManager.swift:194
        var networkStatus: NetworkReachabilityStatus = .NotReachable
NetworkReachabilityManager.swift:212
extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {}
NetworkReachabilityManager.swift:223
    lhs: NetworkReachabilityManager.NetworkReachabilityStatus,
NetworkReachabilityManager.swift:224
    rhs: NetworkReachabilityManager.NetworkReachabilityStatus)
{ 0046 case Unknown
NetworkReachabilityManager.swift:79
        guard let flags = self.flags else { return .Unknown }
NetworkReachabilityManager.swift:228
    case (.Unknown, .Unknown):
NetworkReachabilityManager.swift:228
    case (.Unknown, .Unknown):
0047 case NotReachable
NetworkReachabilityManager.swift:192
        guard flags.contains(.Reachable) else { return .NotReachable }
NetworkReachabilityManager.swift:194
        var networkStatus: NetworkReachabilityStatus = .NotReachable
NetworkReachabilityManager.swift:230
    case (.NotReachable, .NotReachable):
NetworkReachabilityManager.swift:230
    case (.NotReachable, .NotReachable):
0048 case Reachable
NetworkReachabilityManager.swift:72
    public var isReachableOnWWAN: Bool { return networkReachabilityStatus == .Reachable(.WWAN) }
NetworkReachabilityManager.swift:75
    public var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .Reachable(.EthernetOrWiFi) }
NetworkReachabilityManager.swift:196
        if !flags.contains(.ConnectionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) }
NetworkReachabilityManager.swift:199
            if !flags.contains(.InterventionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) }
NetworkReachabilityManager.swift:232
    case let (.Reachable(lhsConnectionType), .Reachable(rhsConnectionType)):
NetworkReachabilityManager.swift:232
    case let (.Reachable(lhsConnectionType), .Reachable(rhsConnectionType)):
(ConnectionType) 0049 } 0050 0051 /** 0052 Defines the various connection types detected by reachability flags. 0053 0054 - EthernetOrWiFi: The connection type is either over Ethernet or WiFi. 0055 - WWAN: The connection type is a WWAN connection. 0056 */ 0057 public enum ConnectionType
NetworkReachabilityManager.swift:48
        case Reachable(ConnectionType)
{ 0058 case EthernetOrWiFi
NetworkReachabilityManager.swift:75
    public var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .Reachable(.EthernetOrWiFi) }
NetworkReachabilityManager.swift:196
        if !flags.contains(.ConnectionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) }
NetworkReachabilityManager.swift:199
            if !flags.contains(.InterventionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) }
0059 case WWAN
NetworkReachabilityManager.swift:72
    public var isReachableOnWWAN: Bool { return networkReachabilityStatus == .Reachable(.WWAN) }
0060 } 0061 0062 /// A closure executed when the network reachability status changes. The closure takes a single argument: the 0063 /// network reachability status. 0064 public typealias Listener
NetworkReachabilityManager.swift:87
    public var listener: Listener?
= NetworkReachabilityStatus -> Void 0065 0066 // MARK: - Properties 0067 0068 /// Whether the network is currently reachable. 0069 public var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi } 0070 0071 /// Whether the network is currently reachable over the WWAN interface. 0072 public var isReachableOnWWAN
NetworkReachabilityManager.swift:69
    public var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi }
: Bool { return networkReachabilityStatus == .Reachable(.WWAN) } 0073 0074 /// Whether the network is currently reachable over Ethernet or WiFi interface. 0075 public var isReachableOnEthernetOrWiFi
NetworkReachabilityManager.swift:69
    public var isReachable: Bool { return isReachableOnWWAN || isReachableOnEthernetOrWiFi }
: Bool { return networkReachabilityStatus == .Reachable(.EthernetOrWiFi) } 0076 0077 /// The current network reachability status. 0078 public var networkReachabilityStatus
NetworkReachabilityManager.swift:72
    public var isReachableOnWWAN: Bool { return networkReachabilityStatus == .Reachable(.WWAN) }
NetworkReachabilityManager.swift:75
    public var isReachableOnEthernetOrWiFi: Bool { return networkReachabilityStatus == .Reachable(.EthernetOrWiFi) }
: NetworkReachabilityStatus { 0079 guard let flags = self.flags else { return .Unknown } 0080 return networkReachabilityStatusForFlags(flags) 0081 } 0082 0083 /// The dispatch queue to execute the `listener` closure on. 0084 public var listenerQueue
NetworkReachabilityManager.swift:162
        let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue)
NetworkReachabilityManager.swift:164
        dispatch_async(listenerQueue) {
: dispatch_queue_t = dispatch_get_main_queue() 0085 0086 /// A closure executed when the network reachability status changes. 0087 public var listener
NetworkReachabilityManager.swift:186
        listener?(networkReachabilityStatusForFlags(flags))
: Listener? 0088 0089 private var flags
NetworkReachabilityManager.swift:79
        guard let flags = self.flags else { return .Unknown }
NetworkReachabilityManager.swift:166
            self.notifyListener(self.flags ?? SCNetworkReachabilityFlags())
: SCNetworkReachabilityFlags? { 0090 var flags = SCNetworkReachabilityFlags() 0091 0092 if SCNetworkReachabilityGetFlags(reachability, &flags) { 0093 return flags 0094 } 0095 0096 return nil 0097 } 0098 0099 private let reachability
NetworkReachabilityManager.swift:92
        if SCNetworkReachabilityGetFlags(reachability, &flags) {
NetworkReachabilityManager.swift:134
        self.reachability = reachability
NetworkReachabilityManager.swift:154
            reachability,
NetworkReachabilityManager.swift:162
        let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue)
NetworkReachabilityManager.swift:176
        SCNetworkReachabilitySetCallback(reachability, nil, nil)
NetworkReachabilityManager.swift:177
        SCNetworkReachabilitySetDispatchQueue(reachability, nil)
: SCNetworkReachability 0100 private var previousFlags
NetworkReachabilityManager.swift:135
        self.previousFlags = SCNetworkReachabilityFlags()
NetworkReachabilityManager.swift:165
            self.previousFlags = SCNetworkReachabilityFlags()
NetworkReachabilityManager.swift:183
        guard previousFlags != flags else { return }
NetworkReachabilityManager.swift:184
        previousFlags = flags
: SCNetworkReachabilityFlags 0101 0102 // MARK: - Initialization 0103 0104 /** 0105 Creates a `NetworkReachabilityManager` instance with the specified host. 0106 0107 - parameter host: The host used to evaluate network reachability. 0108 0109 - returns: The new `NetworkReachabilityManager` instance. 0110 */ 0111 public convenience init?(host: String) { 0112 guard let reachability = SCNetworkReachabilityCreateWithName(nil, host) else { return nil } 0113 self.init(reachability: reachability) 0114 } 0115 0116 /** 0117 Creates a `NetworkReachabilityManager` instance with the default socket address (`sockaddr_in6`). 0118 0119 - returns: The new `NetworkReachabilityManager` instance. 0120 */ 0121 public convenience init?() { 0122 var address = sockaddr_in6() 0123 address.sin6_len = UInt8(sizeofValue(address)) 0124 address.sin6_family = sa_family_t(AF_INET6) 0125 0126 guard let reachability = withUnsafePointer(&address, { 0127 SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0)) 0128 }) else { return nil } 0129 0130 self.init(reachability: reachability) 0131 } 0132 0133 private init
NetworkReachabilityManager.swift:113
        self.init(reachability: reachability)
NetworkReachabilityManager.swift:130
        self.init(reachability: reachability)
(reachability: SCNetworkReachability) { 0134 self.reachability = reachability 0135 self.previousFlags = SCNetworkReachabilityFlags() 0136 } 0137 0138 deinit { 0139 stopListening() 0140 } 0141 0142 // MARK: - Listening 0143 0144 /** 0145 Starts listening for changes in network reachability status. 0146 0147 - returns: `true` if listening was started successfully, `false` otherwise. 0148 */ 0149 public func startListening() -> Bool { 0150 var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil) 0151 context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque()) 0152 0153 let callbackEnabled = SCNetworkReachabilitySetCallback( 0154 reachability, 0155 { (_, flags, info) in 0156 let reachability = Unmanaged<NetworkReachabilityManager>.fromOpaque(COpaquePointer(info)).takeUnretainedValue() 0157 reachability.notifyListener(flags) 0158 }, 0159 &context 0160 ) 0161 0162 let queueEnabled = SCNetworkReachabilitySetDispatchQueue(reachability, listenerQueue) 0163 0164 dispatch_async(listenerQueue) { 0165 self.previousFlags = SCNetworkReachabilityFlags() 0166 self.notifyListener(self.flags ?? SCNetworkReachabilityFlags()) 0167 } 0168 0169 return callbackEnabled && queueEnabled 0170 } 0171 0172 /** 0173 Stops listening for changes in network reachability status. 0174 */ 0175 public func stopListening
NetworkReachabilityManager.swift:139
        stopListening()
() { 0176 SCNetworkReachabilitySetCallback(reachability, nil, nil) 0177 SCNetworkReachabilitySetDispatchQueue(reachability, nil) 0178 } 0179 0180 // MARK: - Internal - Listener Notification 0181 0182 func notifyListener
NetworkReachabilityManager.swift:157
                reachability.notifyListener(flags)
NetworkReachabilityManager.swift:166
            self.notifyListener(self.flags ?? SCNetworkReachabilityFlags())
(flags: SCNetworkReachabilityFlags) { 0183 guard previousFlags != flags else { return } 0184 previousFlags = flags 0185 0186 listener?(networkReachabilityStatusForFlags(flags)) 0187 } 0188 0189 // MARK: - Internal - Network Reachability Status 0190 0191 func networkReachabilityStatusForFlags
NetworkReachabilityManager.swift:80
        return networkReachabilityStatusForFlags(flags)
NetworkReachabilityManager.swift:186
        listener?(networkReachabilityStatusForFlags(flags))
(flags: SCNetworkReachabilityFlags) -> NetworkReachabilityStatus { 0192 guard flags.contains(.Reachable) else { return .NotReachable } 0193 0194 var networkStatus: NetworkReachabilityStatus = .NotReachable 0195 0196 if !flags.contains(.ConnectionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) } 0197 0198 if flags.contains(.ConnectionOnDemand) || flags.contains(.ConnectionOnTraffic) { 0199 if !flags.contains(.InterventionRequired) { networkStatus = .Reachable(.EthernetOrWiFi) } 0200 } 0201 0202 #if os(iOS) 0203 if flags.contains(.IsWWAN) { networkStatus = .Reachable(.WWAN) } 0204 #endif 0205 0206 return networkStatus 0207 } 0208 } 0209 0210 // MARK: - 0211 0212 extension NetworkReachabilityManager.NetworkReachabilityStatus: Equatable {} 0213 0214 /** 0215 Returns whether the two network reachability status values are equal. 0216 0217 - parameter lhs: The left-hand side value to compare. 0218 - parameter rhs: The right-hand side value to compare. 0219 0220 - returns: `true` if the two values are equal, `false` otherwise. 0221 */ 0222 public func ==( 0223 lhs: NetworkReachabilityManager.NetworkReachabilityStatus, 0224 rhs: NetworkReachabilityManager.NetworkReachabilityStatus) 0225 -> Bool 0226 { 0227 switch (lhs, rhs) { 0228 case (.Unknown, .Unknown): 0229 return true 0230 case (.NotReachable, .NotReachable): 0231 return true 0232 case let (.Reachable(lhsConnectionType), .Reachable(rhsConnectionType)): 0233 return lhsConnectionType == rhsConnectionType 0234 default: 0235 return false 0236 } 0237 } 0238 0239 #endif 0240