HiveBrain v1.2.0
Get Started
← Back to all entries
patternswiftMinor

C Socket API Call with Swift

Submitted by: @import:stackexchange-codereview··
0
Viewed 0 times
swiftwithapicallsocket

Problem

I have a small function in Objective-C which uses the C Socket API to check if the device has an active internet connection:

#include 

- (BOOL)isNetworkAvailable {
    char *hostname;
    struct hostent *hostinfo;
    hostname = "youtube.com";
    hostinfo = gethostbyname(hostname);
    if (hostinfo == NULL) {
        return NO;
    } else {
        return YES;
    }
}


I have rewritten this function in Swift, using an UnsafeMutablePointer type for the hostent struct:

func isNetworkAvailable() -> Bool {
    var hostinfo: UnsafeMutablePointer
    let hostString: String = "youtube.com"
    var hostname = (hostString.cStringUsingEncoding(NSUTF8StringEncoding))!
    hostinfo = gethostbyname(hostname)
    if (hostinfo == nil) {
        hostinfo.destroy()
        return false
    } else {
        hostinfo.destroy()
        return true
    }
}


Is there a better way to check for network connectivity in Swift without using the C API? How can I improve this function, possibly removing the need to manually retain and release an UnsafeMutablePointer?

Solution

Wrong memory management

gethostbyname() returns a pointer to an internal structure. You don't
have initialized that memory and don't own it, therefore you must not
call destroy().

Things that can be improved

var hostinfo: UnsafeMutablePointer
// ...
hostinfo = gethostbyname(...)


can be combined to

let hostinfo = gethostbyname(...)


There is no need to declare the variable in advance, and the type
can be inferred automatically. Also you can define it as a constant
with let because it is not modified subsequently.

let hostString: String = "youtube.com"
var hostname = (hostString.cStringUsingEncoding(NSUTF8StringEncoding))!
let hostinfo = gethostbyname(hostname)


can be simplified to

let hostname = "youtube.com"
let hostinfo = gethostbyname(hostname)


because a Swift string is automatically converted to a C string when
passed to a C API taking a const char * parameter.

Finally, since the destroy() has been removed,

if (hostinfo == nil) {
    return false
} else {
    return true
}


can be simplified to

return hostinfo != nil


So your function is now

func isNetworkAvailable() -> Bool {
    let hostname = "youtube.com"
    let hostinfo = gethostbyname(hostname)
    return hostinfo != nil
}


BUT: This does not what you expect it to do!

gethostbyname() "only" resolves a host name to an IP address.
That does not necessarily involve any network communication, as
the local DNS resolver might have cached the information.

Better: Use the SCNetworkReachability framework.

From the documentation:


The SCNetworkReachability programming interface allows an application
to determine the status of a system's current network configuration
and the reachability of a target host. A remote host is considered
reachable when a data packet, sent by an application into the network
stack, can leave the local device. Reachability does not guarantee
that the data packet will actually be received by the host.

Other Resources:

  • Apple provides Objective-C sample code at https://developer.apple.com/library/ios/samplecode/Reachability/Introduction/Intro.html



  • A Swift wrapper can be found here: https://github.com/ashleymills/Reachability.swift



  • And perhaps you can use the code from https://stackoverflow.com/questions/25623272/working-with-c-structs-in-swift.

Code Snippets

var hostinfo: UnsafeMutablePointer<hostent>
// ...
hostinfo = gethostbyname(...)
let hostinfo = gethostbyname(...)
let hostString: String = "youtube.com"
var hostname = (hostString.cStringUsingEncoding(NSUTF8StringEncoding))!
let hostinfo = gethostbyname(hostname)
let hostname = "youtube.com"
let hostinfo = gethostbyname(hostname)
if (hostinfo == nil) {
    return false
} else {
    return true
}

Context

StackExchange Code Review Q#92579, answer score: 8

Revisions (0)

No revisions yet.