How to get local and subnet mask ip address in swift - ios

I need to get the local IP address and subnet mask using Swift code.
Please help me in this. I have some code working in Objective-C. How to get the equivalent code in Swift??
Below I have added Objective-C code:
+(NSDictionary *)getLocalIPAddress{
NSDictionary *dictIPDetails;
NSString *address = #"error";
NSString *netmask = #"error";
struct ifaddrs *interfaces = NULL;
struct ifaddrs *temp_addr = NULL;int success = 0;
// retrieve the current interfaces - returns 0 on success
success = getifaddrs(&interfaces);
if (success == 0)
{
temp_addr = interfaces;
while(temp_addr != NULL)
{
// check if interface is en0 which is the wifi connection on the iPhone
if(temp_addr->ifa_addr->sa_family == AF_INET)
{
if([#(temp_addr->ifa_name) isEqualToString:#"en0"])
{
address = #(inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_addr)->sin_addr));
netmask = #(inet_ntoa(((struct sockaddr_in *)temp_addr->ifa_netmask)->sin_addr));
dictIPDetails = #{LOCAL_IP_ADDR:address,SUBNET_MASK:netmask};
}
}
temp_addr = temp_addr->ifa_next;
}
}
freeifaddrs(interfaces);
return dictIPDetails;
}

I have modified the answer from here to include netmask along with ip.
With the code below you can do something like this:
let ip = getIFAddresses().last!.ip
let netmask = getIFAddresses().last!.netmask
Hope this helps.
struct NetInfo {
let ip: String
let netmask: String
}
// Get the local ip addresses used by this node
func getIFAddresses() -> [NetInfo] {
var addresses = [NetInfo]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
var net = ptr.memory.ifa_netmask.memory
var netmaskName = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
getnameinfo(&net, socklen_t(net.sa_len), &netmaskName, socklen_t(netmaskName.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0
if let netmask = String.fromCString(netmaskName) {
addresses.append(NetInfo(ip: address, netmask: netmask))
}
}
}
}
}
}
freeifaddrs(ifaddr)
}
return addresses
}
If you need more bells and whistles I have this version of NetInfo which will calculate your network and broadcast addresses as well.
struct NetInfo {
// IP Address
let ip: String
// Netmask Address
let netmask: String
// CIDR: Classless Inter-Domain Routing
var cidr: Int {
var cidr = 0
for number in binaryRepresentation(netmask) {
let numberOfOnes = number.componentsSeparatedByString("1").count - 1
cidr += numberOfOnes
}
return cidr
}
// Network Address
var network: String {
return bitwise(&, net1: ip, net2: netmask)
}
// Broadcast Address
var broadcast: String {
let inverted_netmask = bitwise(~, net1: netmask)
let broadcast = bitwise(|, net1: network, net2: inverted_netmask)
return broadcast
}
private func binaryRepresentation(s: String) -> [String] {
var result: [String] = []
for numbers in (split(s) {$0 == "."}) {
if let intNumber = numbers.toInt() {
if let binary = String(intNumber, radix: 2).toInt() {
result.append(NSString(format: "%08d", binary) as String)
}
}
}
return result
}
private func bitwise(op: (UInt8,UInt8) -> UInt8, net1: String, net2: String) -> String {
let net1numbers = toInts(net1)
let net2numbers = toInts(net2)
var result = ""
for i in 0..<net1numbers.count {
result += "\(op(net1numbers[i],net2numbers[i]))"
if i < (net1numbers.count-1) {
result += "."
}
}
return result
}
private func bitwise(op: UInt8 -> UInt8, net1: String) -> String {
let net1numbers = toInts(net1)
var result = ""
for i in 0..<net1numbers.count {
result += "\(op(net1numbers[i]))"
if i < (net1numbers.count-1) {
result += "."
}
}
return result
}
private func toInts(networkString: String) -> [UInt8] {
return (split(networkString){$0 == "."}).map{UInt8($0.toInt()!)}
}
}

changed the code so it works with swift 3:
struct NetInfo {
let ip: String
let netmask: String
}
// Get the local ip addresses used by this node
class func getIFAddresses() -> [NetInfo] {
var addresses = [NetInfo]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr;
while ptr != nil {
let flags = Int32((ptr?.pointee.ifa_flags)!)
var addr = ptr?.pointee.ifa_addr.pointee
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr?.sa_family == UInt8(AF_INET) || addr?.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
if (getnameinfo(&addr!, socklen_t((addr?.sa_len)!), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.init(validatingUTF8:hostname) {
var net = ptr?.pointee.ifa_netmask.pointee
var netmaskName = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(&net!, socklen_t((net?.sa_len)!), &netmaskName, socklen_t(netmaskName.count),
nil, socklen_t(0), NI_NUMERICHOST)// == 0
if let netmask = String.init(validatingUTF8:netmaskName) {
addresses.append(NetInfo(ip: address, netmask: netmask))
}
}
}
}
}
ptr = ptr?.pointee.ifa_next
}
freeifaddrs(ifaddr)
}
return addresses
}

Here's Mellson's extended NetInfo re-written for Swift 2 (Hope it save's someone else the time to work it out)
struct NetInfo {
// IP Address
let ip: String
// Netmask Address
let netmask: String
// CIDR: Classless Inter-Domain Routing
var cidr: Int {
var cidr = 0
for number in binaryRepresentation(netmask) {
let numberOfOnes = number.componentsSeparatedByString("1").count - 1
cidr += numberOfOnes
}
return cidr
}
// Network Address
var network: String {
return bitwise(&, net1: ip, net2: netmask)
}
// Broadcast Address
var broadcast: String {
let inverted_netmask = bitwise(~, net1: netmask)
let broadcast = bitwise(|, net1: network, net2: inverted_netmask)
return broadcast
}
private func binaryRepresentation(s: String) -> [String] {
var result: [String] = []
for numbers in (s.characters.split {$0 == "."}) {
if let intNumber = Int(String(numbers)) {
if let binary = Int(String(intNumber, radix: 2)) {
result.append(NSString(format: "%08d", binary) as String)
}
}
}
return result
}
private func bitwise(op: (UInt8,UInt8) -> UInt8, net1: String, net2: String) -> String {
let net1numbers = toInts(net1)
let net2numbers = toInts(net2)
var result = ""
for i in 0..<net1numbers.count {
result += "\(op(net1numbers[i],net2numbers[i]))"
if i < (net1numbers.count-1) {
result += "."
}
}
return result
}
private func bitwise(op: UInt8 -> UInt8, net1: String) -> String {
let net1numbers = toInts(net1)
var result = ""
for i in 0..<net1numbers.count {
result += "\(op(net1numbers[i]))"
if i < (net1numbers.count-1) {
result += "."
}
}
return result
}
private func toInts(networkString: String) -> [UInt8] {
return (networkString.characters.split {$0 == "."}).map{UInt8(String($0))!}
}
}

let theOutput = Pipe()
func shell(Path:String ,args: String...) -> Int32 {
let task = Process()
task.launchPath = Path
task.arguments = args
task.standardOutput = theOutput
task.standardError = theOutput
task.launch()
task.waitUntilExit()
return task.terminationStatus
}
shell(Path:"/usr/sbin/arp",args: "-a")
let theTaskData = theOutput.fileHandleForReading.readDataToEndOfFile()
let stringResult = String(data: theTaskData, encoding: .utf8)
print(stringResult!)

Related

Swift: How to convert IPv4 string address to integer and vice-versa

I need to convert IP address (e.g. "127.0.0.1") to integer value and vice-versa for my logger. I've found some samples for ObjC:
How to convert an IP address from NSString to unsigned int in Objective-C?
iOS convert IP Address to integer and backwards
How to do it in Swift and what the best way?
This is how I would approach the conversion. It might look a bit over engineering but all properties are useful in other contexts as well:
extension Numeric {
var data: Data {
var bytes = self
return Data(bytes: &bytes, count: MemoryLayout<Self>.size)
}
}
extension Data {
func numeric<T: Numeric>() -> T { withUnsafeBytes { $0.load(as: T.self) } }
}
extension LosslessStringConvertible {
var string: String { .init(self) }
}
The following implementations rely on Network Technology:
import Network
extension StringProtocol {
var ipV4Address: IPv4Address? { .init(string) }
}
extension Data {
var ipV4Address: IPv4Address? { .init(self) }
}
extension IPv4Address {
var uint32: UInt32 { rawValue.numeric() }
}
extension UInt32 {
var ipV4Address: IPv4Address? { data.ipV4Address }
}
Usage:
if let ipV4Address = "10.0.0.1".ipV4Address { // 10.0.0.1
let uint32 = ipV4Address.uint32 // 16777226
let loadedIPv4Address = uint32.ipV4Address! // 10.0.0.1
}
There two possible approaches to do it in Swift:
Using old school inet_aton and inet_ntoa
func ipv4_StringToInt(_ value: String) -> UInt32? {
var addr = in_addr()
return inet_aton(value.cString(using: .ascii), &addr) != 0
? UInt32(addr.s_addr)
: nil
}
func ipv4_IntToString(_ value: UInt32) -> String {
let addr = in_addr(s_addr: value)
return String(cString:inet_ntoa(addr))
}
Using IPv4Address from Network
func ipv4_StringToInt(_ value: String) -> UInt32? {
IPv4Address(value)?.rawValue.withUnsafeBytes {
$0.load(as: UInt32.self)
}
}
func ipv4_IntToString(_ value: UInt32) -> String {
let data = withUnsafeBytes(of: value) { Data($0) }
return IPv4Address(data)!.debugDescription
}
How to use:
if let addr = ipv4_StringToInt("127.0.0.1") { // addr = 0x100007F
let ip = ipv4_IntToString(addr)
print(ip) // Outputs: 127.0.0.1
}

Getting the Local IP Address from iPhone, Sometimes it doesn't work, why?

I want to get the local IP address of the iPhone, sometimes it works and show this address:
http://192.168.8.152/home.htm
But sometimes it does't work and show this address:
http://fd4c:d1a1:ee79:6400:f5dd:b93:12b7:2d42/home.htm
What's wrong? How to fix it?
Here is the Swift code:
func getIpAddress() -> String! {
var address: String?
var ifaddr: UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
if let name: String = String(cString: (interface?.ifa_name)!), name == "en0" {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(
interface?.ifa_addr,
socklen_t((interface?.ifa_addr.pointee.sa_len)!),
&hostname,
socklen_t(hostname.count),
nil,
socklen_t(0),
NI_NUMERICHOST
)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
}
return address as? String ?? ""
}
#IBOutlet weak var lblUrl: UILabel! {
didSet {
sAddr = getIpAddress()
var sLabel : String! = "http://"
sLabel += sAddr
sLabel += "/home.htm"
lblUrl.text = sLabel
}
}

How to get ipaddress when connected to mobile data swift3

I am getting ipaddress of the phone in this way.
func getIPAddress() -> String? {
var address : String?
var ifaddr : UnsafeMutablePointer<ifaddrs>? = nil
if getifaddrs(&ifaddr) == 0 {
var ptr = ifaddr
while ptr != nil {
defer { ptr = ptr?.pointee.ifa_next }
let interface = ptr?.pointee
let addrFamily = interface?.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
if let name:String = String(cString: (interface?.ifa_name)!), name == "en0" {
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface?.ifa_addr, socklen_t((interface?.ifa_addr.pointee.sa_len)!),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
}
return address
}
But this returns when connected to wifi only. How to get ipaddress when I connected to mobile data.
To get IPAddress of device on turning Wifi or Mobile data ON, use below method :
func getIPAddress() -> String? {
var address : String?
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs>?
guard getifaddrs(&ifaddr) == 0 else { return nil }
guard let firstAddr = ifaddr else { return nil }
// For each interface ...
for ifptr in sequence(first: firstAddr, next: { $0.pointee.ifa_next }) {
let interface = ifptr.pointee
// Check for IPv4 or IPv6 interface:
let addrFamily = interface.ifa_addr.pointee.sa_family
if addrFamily == UInt8(AF_INET) || addrFamily == UInt8(AF_INET6) {
// Check interface name:
let name = String(cString: interface.ifa_name)
if name == "en0" || name == "pdp_ip0" {
// Convert interface address to a human readable string:
var hostname = [CChar](repeating: 0, count: Int(NI_MAXHOST))
getnameinfo(interface.ifa_addr, socklen_t(interface.ifa_addr.pointee.sa_len),
&hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST)
address = String(cString: hostname)
}
}
}
freeifaddrs(ifaddr)
return address
}
Here if name == "en0" || name == "pdp_ip0" works for both Wifi and Mobile data.
Hope will be helping! :)

How to include ifaddrs.h

i have the following issue:
i wanna to get the ip address from my app iOS.
But I get error when trying to import from swift
CODE:
module.modulemap
module ifaddrs [system] [extern_c] {
header "/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS.sdk/usr/include/ifaddrs.h"
export *
}
module net [system] [extern_c] {
module types {
header "/usr/include/sys/types.h"
export *
}
module if_dl {
header "/usr/include/net/if_dl.h"
export *
}
}
Bridging-header
#include <ifaddrs.h>
#include <net/if_dl.h>
import and functions
import ifaddrs
func getIFAddresses() -> [String] {
var addresses = [String]()
// Get list of all interfaces on the local machine:
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
if getifaddrs(&ifaddr) == 0 {
// For each interface ...
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
// Check for running IPv4, IPv6 interfaces. Skip the loopback interface.
if (flags & (IFF_UP|IFF_RUNNING|IFF_LOOPBACK)) == (IFF_UP|IFF_RUNNING) {
if addr.sa_family == UInt8(AF_INET) || addr.sa_family == UInt8(AF_INET6) {
// Convert interface address to a human readable string:
var hostname = [CChar](count: Int(NI_MAXHOST), repeatedValue: 0)
if (getnameinfo(&addr, socklen_t(addr.sa_len), &hostname, socklen_t(hostname.count),
nil, socklen_t(0), NI_NUMERICHOST) == 0) {
if let address = String.fromCString(hostname) {
addresses.append(address)
}
}
}
}
}
freeifaddrs(ifaddr)
}
return addresses
}
func getDataUsage() -> [UInt32] {
var ifaddr : UnsafeMutablePointer<ifaddrs> = nil
var networkData: UnsafeMutablePointer<if_data>! = nil
var wifiDataSent:UInt32 = 0
var wifiDataReceived:UInt32 = 0
var wwanDataSent:UInt32 = 0
var wwanDataReceived:UInt32 = 0
if getifaddrs(&ifaddr) == 0 {
for (var ptr = ifaddr; ptr != nil; ptr = ptr.memory.ifa_next) {
let name = String.fromCString(ptr.memory.ifa_name)
let flags = Int32(ptr.memory.ifa_flags)
var addr = ptr.memory.ifa_addr.memory
if addr.sa_family == UInt8(AF_LINK) {
if name?.hasPrefix("en") == true {
networkData = unsafeBitCast(ptr.memory.ifa_data, UnsafeMutablePointer<if_data>.self)
wifiDataSent += networkData.memory.ifi_obytes
wifiDataReceived += networkData.memory.ifi_ibytes
}
if name?.hasPrefix("pdp_ip") == true {
networkData = unsafeBitCast(ptr.memory.ifa_data, UnsafeMutablePointer<if_data>.self)
wwanDataSent += networkData.memory.ifi_obytes
wwanDataReceived += networkData.memory.ifi_ibytes
}
}
}
freeifaddrs(ifaddr)
}
return [wifiDataSent, wifiDataReceived, wwanDataSent, wwanDataReceived]
}

Check internet connectivity throughout the app by adding observer

I do not want to check internet connectivity on every time the app is open instead want to show the no connection banner in status bar or in navigation bar just like the Facebook app does.
Here is my code:
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}
var flags = SCNetworkReachabilityFlags()
if !SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) {
return false
}
let isReachable = (flags.rawValue & UInt32(kSCNetworkFlagsReachable)) != 0
let needsConnection = (flags.rawValue & UInt32(kSCNetworkFlagsConnectionRequired)) != 0
return (isReachable && !needsConnection)
}
}
Apply a periodic check by using NSTimer
override func viewDidLoad() {
super.viewDidLoad()
//Swift 2.2 selector syntax
var timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: #selector(MyClass.update), userInfo: nil, repeats: true)
}
// must be internal or public.
func update()
{
if(!Reachability.isConnectedToNetwork()){
print("Internet connection not available.");
return
}
}
your Reachability Class
import Foundation
import SystemConfiguration
public class Reachability {
class func isConnectedToNetwork() -> Bool {
var zeroAddress = sockaddr_in(sin_len: 0, sin_family: 0, sin_port: 0, sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
let defaultRouteReachability = withUnsafePointer(&zeroAddress) {
SCNetworkReachabilityCreateWithAddress(kCFAllocatorDefault, UnsafePointer($0))
}
var flags: SCNetworkReachabilityFlags = SCNetworkReachabilityFlags(rawValue: 0)
if SCNetworkReachabilityGetFlags(defaultRouteReachability!, &flags) == false {
return false
}
let isReachable = flags == .Reachable
let needsConnection = flags == .ConnectionRequired
return isReachable && !needsConnection
}
}
Creating a notificationc object to help notif the app when a change in connectivity is encountered
var reach: Reachability!
do {
reach = try Reachability.reachabilityForInternetConnection()
self.reach!.reachableOnWWAN = false
NSNotificationCenter.defaultCenter().addObserver(self,
selector: "reachabilityChanged:",
name: ReachabilityChangedNotification,
object: nil)
try self.reach!.startNotifier()
} catch {
}
and the function based on which the app behaves
func reachabilityChanged(notification: NSNotification) {
if self.reach!.isReachableViaWiFi() || self.reach!.isReachableViaWWAN() {
print("Service available !!!")
} else {
print("No service available !!!")
}
}
And use this Reachability class
import Foundation
import SystemConfiguration
import Foundation
public enum ReachabilityError: ErrorType {
case FailedToCreateWithAddress(sockaddr_in)
case FailedToCreateWithHostname(String)
case UnableToSetCallback
case UnableToSetDispatchQueue
}
public let ReachabilityChangedNotification = "ReachabilityChangedNotification"
func callback(reachability:SCNetworkReachability, flags: SCNetworkReachabilityFlags, info: UnsafeMutablePointer<Void>) {
let reachability = Unmanaged<Reachability>.fromOpaque(COpaquePointer(info)).takeUnretainedValue()
dispatch_async(dispatch_get_main_queue()) {
reachability.reachabilityChanged(flags)
}
}
public class Reachability: NSObject {
public typealias NetworkReachable = (Reachability) -> ()
public typealias NetworkUnreachable = (Reachability) -> ()
public enum NetworkStatus: CustomStringConvertible {
case NotReachable, ReachableViaWiFi, ReachableViaWWAN
public var description: String {
switch self {
case .ReachableViaWWAN:
return "Cellular"
case .ReachableViaWiFi:
return "WiFi"
case .NotReachable:
return "No Connection"
}
}
}
// MARK: - *** Public properties ***
public var whenReachable: NetworkReachable?
public var whenUnreachable: NetworkUnreachable?
public var reachableOnWWAN: Bool
public var notificationCenter = NSNotificationCenter.defaultCenter()
public var currentReachabilityStatus: NetworkStatus {
if isReachable() {
if isReachableViaWiFi() {
return .ReachableViaWiFi
}
if isRunningOnDevice {
return .ReachableViaWWAN
}
}
return .NotReachable
}
public var currentReachabilityString: String {
return "\(currentReachabilityStatus)"
}
private var previousFlags: SCNetworkReachabilityFlags?
// MARK: - *** Initialisation methods ***
required public init(reachabilityRef: SCNetworkReachability) {
reachableOnWWAN = true
self.reachabilityRef = reachabilityRef
}
public convenience init(hostname: String) throws {
let nodename = (hostname as NSString).UTF8String
guard let ref = SCNetworkReachabilityCreateWithName(nil, nodename) else { throw ReachabilityError.FailedToCreateWithHostname(hostname) }
self.init(reachabilityRef: ref)
}
public class func reachabilityForInternetConnection() throws -> Reachability {
var zeroAddress = sockaddr_in()
zeroAddress.sin_len = UInt8(sizeofValue(zeroAddress))
zeroAddress.sin_family = sa_family_t(AF_INET)
guard let ref = withUnsafePointer(&zeroAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else { throw ReachabilityError.FailedToCreateWithAddress(zeroAddress) }
return Reachability(reachabilityRef: ref)
}
public class func reachabilityForLocalWiFi() throws -> Reachability {
var localWifiAddress: sockaddr_in = sockaddr_in(sin_len: __uint8_t(0), sin_family: sa_family_t(0), sin_port: in_port_t(0), sin_addr: in_addr(s_addr: 0), sin_zero: (0, 0, 0, 0, 0, 0, 0, 0))
localWifiAddress.sin_len = UInt8(sizeofValue(localWifiAddress))
localWifiAddress.sin_family = sa_family_t(AF_INET)
// IN_LINKLOCALNETNUM is defined in <netinet/in.h> as 169.254.0.0
let address: UInt32 = 0xA9FE0000
localWifiAddress.sin_addr.s_addr = in_addr_t(address.bigEndian)
guard let ref = withUnsafePointer(&localWifiAddress, {
SCNetworkReachabilityCreateWithAddress(nil, UnsafePointer($0))
}) else { throw ReachabilityError.FailedToCreateWithAddress(localWifiAddress) }
return Reachability(reachabilityRef: ref)
}
// MARK: - *** Notifier methods ***
public func startNotifier() throws {
guard !notifierRunning else { return }
var context = SCNetworkReachabilityContext(version: 0, info: nil, retain: nil, release: nil, copyDescription: nil)
context.info = UnsafeMutablePointer(Unmanaged.passUnretained(self).toOpaque())
if !SCNetworkReachabilitySetCallback(reachabilityRef!, callback, &context) {
stopNotifier()
throw ReachabilityError.UnableToSetCallback
}
if !SCNetworkReachabilitySetDispatchQueue(reachabilityRef!, reachabilitySerialQueue) {
stopNotifier()
throw ReachabilityError.UnableToSetDispatchQueue
}
// Perform an intial check
dispatch_async(reachabilitySerialQueue) { () -> Void in
let flags = self.reachabilityFlags
self.reachabilityChanged(flags)
}
notifierRunning = true
}
public func stopNotifier() {
defer { notifierRunning = false }
guard let reachabilityRef = reachabilityRef else { return }
SCNetworkReachabilitySetCallback(reachabilityRef, nil, nil)
SCNetworkReachabilitySetDispatchQueue(reachabilityRef, nil)
}
// MARK: - *** Connection test methods ***
public func isReachable() -> Bool {
let flags = reachabilityFlags
return isReachableWithFlags(flags)
}
public func isReachableViaWWAN() -> Bool {
let flags = reachabilityFlags
// Check we're not on the simulator, we're REACHABLE and check we're on WWAN
return isRunningOnDevice && isReachable(flags) && isOnWWAN(flags)
}
public func isReachableViaWiFi() -> Bool {
let flags = reachabilityFlags
// Check we're reachable
if !isReachable(flags) {
return false
}
// Must be on WiFi if reachable but not on an iOS device (i.e. simulator)
if !isRunningOnDevice {
return true
}
// Check we're NOT on WWAN
return !isOnWWAN(flags)
}
// MARK: - *** Private methods ***
private var isRunningOnDevice: Bool = {
#if (arch(i386) || arch(x86_64)) && os(iOS)
return false
#else
return true
#endif
}()
private var notifierRunning = false
private var reachabilityRef: SCNetworkReachability?
private let reachabilitySerialQueue = dispatch_queue_create("uk.co.ashleymills.reachability", DISPATCH_QUEUE_SERIAL)
private func reachabilityChanged(flags: SCNetworkReachabilityFlags) {
guard previousFlags != flags else { return }
if isReachableWithFlags(flags) {
if let block = whenReachable {
block(self)
}
} else {
if let block = whenUnreachable {
block(self)
}
}
notificationCenter.postNotificationName(ReachabilityChangedNotification, object:self)
previousFlags = flags
}
private func isReachableWithFlags(flags: SCNetworkReachabilityFlags) -> Bool {
if !isReachable(flags) {
return false
}
if isConnectionRequiredOrTransient(flags) {
return false
}
if isRunningOnDevice {
if isOnWWAN(flags) && !reachableOnWWAN {
// We don't want to connect when on 3G.
return false
}
}
return true
}
// WWAN may be available, but not active until a connection has been established.
// WiFi may require a connection for VPN on Demand.
private func isConnectionRequired() -> Bool {
return connectionRequired()
}
private func connectionRequired() -> Bool {
let flags = reachabilityFlags
return isConnectionRequired(flags)
}
// Dynamic, on demand connection?
private func isConnectionOnDemand() -> Bool {
let flags = reachabilityFlags
return isConnectionRequired(flags) && isConnectionOnTrafficOrDemand(flags)
}
// Is user intervention required?
private func isInterventionRequired() -> Bool {
let flags = reachabilityFlags
return isConnectionRequired(flags) && isInterventionRequired(flags)
}
private func isOnWWAN(flags: SCNetworkReachabilityFlags) -> Bool {
#if os(iOS)
return flags.contains(.IsWWAN)
#else
return false
#endif
}
private func isReachable(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.Reachable)
}
private func isConnectionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.ConnectionRequired)
}
private func isInterventionRequired(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.InterventionRequired)
}
private func isConnectionOnTraffic(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.ConnectionOnTraffic)
}
private func isConnectionOnDemand(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.ConnectionOnDemand)
}
func isConnectionOnTrafficOrDemand(flags: SCNetworkReachabilityFlags) -> Bool {
return !flags.intersect([.ConnectionOnTraffic, .ConnectionOnDemand]).isEmpty
}
private func isTransientConnection(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.TransientConnection)
}
private func isLocalAddress(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.IsLocalAddress)
}
private func isDirect(flags: SCNetworkReachabilityFlags) -> Bool {
return flags.contains(.IsDirect)
}
private func isConnectionRequiredOrTransient(flags: SCNetworkReachabilityFlags) -> Bool {
let testcase:SCNetworkReachabilityFlags = [.ConnectionRequired, .TransientConnection]
return flags.intersect(testcase) == testcase
}
private var reachabilityFlags: SCNetworkReachabilityFlags {
guard let reachabilityRef = reachabilityRef else { return SCNetworkReachabilityFlags() }
var flags = SCNetworkReachabilityFlags()
let gotFlags = withUnsafeMutablePointer(&flags) {
SCNetworkReachabilityGetFlags(reachabilityRef, UnsafeMutablePointer($0))
}
if gotFlags {
return flags
} else {
return SCNetworkReachabilityFlags()
}
}
override public var description: String {
var W: String
if isRunningOnDevice {
W = isOnWWAN(reachabilityFlags) ? "W" : "-"
} else {
W = "X"
}
let R = isReachable(reachabilityFlags) ? "R" : "-"
let c = isConnectionRequired(reachabilityFlags) ? "c" : "-"
let t = isTransientConnection(reachabilityFlags) ? "t" : "-"
let i = isInterventionRequired(reachabilityFlags) ? "i" : "-"
let C = isConnectionOnTraffic(reachabilityFlags) ? "C" : "-"
let D = isConnectionOnDemand(reachabilityFlags) ? "D" : "-"
let l = isLocalAddress(reachabilityFlags) ? "l" : "-"
let d = isDirect(reachabilityFlags) ? "d" : "-"
return "\(W)\(R) \(c)\(t)\(i)\(C)\(D)\(l)\(d)"
}
deinit {
stopNotifier()
reachabilityRef = nil
whenReachable = nil
whenUnreachable = nil
}
}
Reachability class used from : https://github.com/ashleymills/Reachability.swift/blob/master/Reachability/Reachability.swift

Resources