Advertisement
Guest User

Untitled

a guest
Dec 2nd, 2016
98
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.61 KB | None | 0 0
  1. //
  2. // Reachability.swift
  3. // TestReach
  4. //
  5. // Created by Pavel Hlavnicka on 02/12/2016.
  6. // Copyright © 2016 Pavel Hlavnicka. All rights reserved.
  7. //
  8.  
  9. import Foundation
  10. import SystemConfiguration
  11.  
  12. let ReachabilityDidChangeNotificationName = "ReachabilityDidChangeNotification"
  13.  
  14. enum ReachabilityStatus {
  15. case notReachable
  16. case reachableViaWiFi
  17. case reachableViaWWAN
  18. }
  19.  
  20. /* SIMPLER: no need to inherit from NSObject */
  21. //class Reachability: NSObject {
  22. class Reachability {
  23.  
  24. private var networkReachability: SCNetworkReachability?
  25.  
  26. init?(hostName: String) {
  27. networkReachability = SCNetworkReachabilityCreateWithName(kCFAllocatorDefault, (hostName as NSString).utf8String!)
  28. //SIMPLER: no superclass
  29. //super.init()
  30. if networkReachability == nil {
  31. return nil
  32. }
  33. }
  34.  
  35. init?(hostAddress: sockaddr_in) {
  36. /* SIMPLER: Swift has some buildins to solve this */
  37. /*
  38. var address = hostAddress
  39.  
  40. guard let defaultRouteReachability = withUnsafePointer(to: &address, {
  41. $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
  42. SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, $0)
  43. }
  44. }) else {
  45. return nil
  46. }
  47.  
  48. networkReachability = defaultRouteReachability
  49. */
  50.  
  51. var address = unsafeBitCast(hostAddress, to: sockaddr.self)
  52. networkReachability = SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, &address)
  53.  
  54. //SIMPLER: no superclass
  55. //super.init()
  56. if networkReachability == nil {
  57. return nil
  58. }
  59. }
  60.  
  61. deinit {
  62. stopNotifier()
  63. }
  64.  
  65. class func networkReachabilityForInternetConnection() -> Reachability? {
  66. var zeroAddress = sockaddr_in()
  67. zeroAddress.sin_len = UInt8(MemoryLayout.size(ofValue: zeroAddress))
  68. zeroAddress.sin_family = sa_family_t(AF_INET)
  69. return Reachability(hostAddress: zeroAddress)
  70. }
  71.  
  72. class func networkReachabilityForLocalWiFi() -> Reachability? {
  73. var localWifiAddress = sockaddr_in()
  74. localWifiAddress.sin_len = UInt8(MemoryLayout.size(ofValue: localWifiAddress))
  75. localWifiAddress.sin_family = sa_family_t(AF_INET)
  76. // IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0 (0xA9FE0000).
  77. localWifiAddress.sin_addr.s_addr = 0xA9FE0000
  78.  
  79. return Reachability(hostAddress: localWifiAddress)
  80. }
  81.  
  82. private var notifying: Bool = false
  83.  
  84. func startNotifier() -> Bool {
  85.  
  86. guard notifying == false else {
  87. return false
  88. }
  89.  
  90. var context = SCNetworkReachabilityContext()
  91.  
  92. //SIMPLER: I believe calling an initializer is redundant
  93. //context.info = UnsafeMutableRawPointer(Unmanaged.passUnretained(self).toOpaque())
  94. context.info = Unmanaged.passUnretained(self).toOpaque()
  95.  
  96.  
  97. //SIMPLER: I believe the below can be simplified as we are quite sure about the context.info type
  98. //though there are never enough paranoia checks ;)
  99. /*
  100. guard let reachability = networkReachability, SCNetworkReachabilitySetCallback(reachability, { (target: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) in
  101. if let currentInfo = info {
  102. let infoObject = Unmanaged<AnyObject>.fromOpaque(currentInfo).takeUnretainedValue()
  103. if infoObject is Reachability {
  104. let networkReachability = infoObject as! Reachability
  105. NotificationCenter.default.post(name: Notification.Name(rawValue: ReachabilityDidChangeNotificationName), object: networkReachability)
  106. }
  107. }
  108. }, &context) == true else { return false }
  109. */
  110.  
  111. guard let reachability = networkReachability, SCNetworkReachabilitySetCallback(reachability, { (target: SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutableRawPointer?) in
  112. if let currentInfo = info {
  113. let callbackSelf = Unmanaged<Reachability>.fromOpaque(currentInfo).takeUnretainedValue()
  114. NotificationCenter.default.post(name: Notification.Name(rawValue: ReachabilityDidChangeNotificationName), object: callbackSelf)
  115. }
  116. }, &context) else { return false }
  117.  
  118. //SIMPLER: == true checks are killing kittens ;)
  119. /*
  120. guard SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue) == true else { return false }
  121. */
  122. guard SCNetworkReachabilityScheduleWithRunLoop(reachability, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode.rawValue) else { return false }
  123.  
  124. notifying = true
  125. return notifying
  126. }
  127.  
  128. func stopNotifier() {
  129. if let reachability = networkReachability, notifying == true {
  130. SCNetworkReachabilityUnscheduleFromRunLoop(reachability, CFRunLoopGetCurrent(), CFRunLoopMode.defaultMode as! CFString)
  131. notifying = false
  132. }
  133. }
  134.  
  135. private var flags: SCNetworkReachabilityFlags {
  136.  
  137. var flags = SCNetworkReachabilityFlags(rawValue: 0)
  138.  
  139. //SIMPLER: again Swift makes bridging a bit easier
  140. /*
  141. if let reachability = networkReachability, withUnsafeMutablePointer(to: &flags, { SCNetworkReachabilityGetFlags(reachability, UnsafeMutablePointer($0)) }) == true {
  142. return flags
  143. }
  144. else {
  145. return []
  146. }
  147. */
  148.  
  149. if let reachability = networkReachability, SCNetworkReachabilityGetFlags(reachability, &flags) {
  150. return flags
  151. } else {
  152. return []
  153. }
  154. }
  155.  
  156. var currentReachabilityStatus: ReachabilityStatus {
  157.  
  158. if flags.contains(.reachable) == false {
  159. // The target host is not reachable.
  160. return .notReachable
  161. }
  162. else if flags.contains(.isWWAN) == true {
  163. // WWAN connections are OK if the calling application is using the CFNetwork APIs.
  164. return .reachableViaWWAN
  165. }
  166. else if flags.contains(.connectionRequired) == false {
  167. // If the target host is reachable and no connection is required then we'll assume that you're on Wi-Fi...
  168. return .reachableViaWiFi
  169. }
  170. else if (flags.contains(.connectionOnDemand) == true || flags.contains(.connectionOnTraffic) == true) && flags.contains(.interventionRequired) == false {
  171. // The connection is on-demand (or on-traffic) if the calling application is using the CFSocketStream or higher APIs and no [user] intervention is needed
  172. return .reachableViaWiFi
  173. }
  174. else {
  175. return .notReachable
  176. }
  177. }
  178.  
  179. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement