Do you need help on a specific subject? Use the contact form (Request a blog entry) on the right hand side.

2015-10-31

Socket Programming in Swift: part 2 - socket and setsockopt

Updated on 2016-08-08 for Swift 3 Xcode 8 beta 3 & use in playground.

In the previous post the information needed to create a socket descriptor was generated. The following code follows on the code of the previous post and can be pasted after it in Playground.

In this post the socket descriptor is created and the options for the socket are set:

// ============================
// Create the socket descriptor
// ============================

let socketDescriptor = socket(
    servinfo!.pointee.ai_family,      // Use the servinfo created earlier, this makes it IPv4/IPv6 independant
    servinfo!.pointee.ai_socktype,    // Use the servinfo created earlier, this makes it IPv4/IPv6 independant
    servinfo!.pointee.ai_protocol)    // Use the servinfo created earlier, this makes it IPv4/IPv6 independant

print("Socket value: \(socketDescriptor)")


// Cop out if there is an error

if socketDescriptor == -1 {
    let strError = String(utf8String: strerror(errno)) ?? "Unknown error code"
    let message = "Socket creation error \(errno) (\(strError))"
    freeaddrinfo(servinfo)
    print(message)
    return
}


// ========================================================================
// Set the socket options (specifically: prevent the "socket in use" error)
// ========================================================================

var optval: Int = 1; // Use 1 to enable the option, 0 to disable

status = setsockopt(
    socketDescriptor,               // The socket descriptor of the socket on which the option will be set
    SOL_SOCKET,                     // Type of socket options
    SO_REUSEADDR,                   // The socket option id
    &optval,                        // The socket option value
    socklen_t(sizeof(Int.self)))    // The size of the socket option value

if status == -1 {
    let strError = String(utf8String: strerror(errno)) ?? "Unknown error code"
    let message = "Setsockopt error \(errno) (\(strError))"
    freeaddrinfo(servinfo)
    close(socketDescriptor)         // Ignore possible errors
    print(message)
    return
}


This code is pretty straightforward: using the socket call a socket descriptor is created. It takes the information from the servinfo that was created in the previous post. Doing it this way makes it agnostic with respect to IPv4 or IPv6. Possible errors are handled in the same way as before. Except that we now use the strerror call to retrieve the string that describes the error. And of course we have to deallocate the addrinfo structure(s) that were allocated in getaddrinfo. (See previous post)


The next call to setsockopt is not necessary per se, but I like to prevent the infamous "socket in use" error. This error can occur if you start your app, force-quit it and start it again. The first run took control of the socket and since the app did not terminate correctly the OS still thinks that the socket is in use. A second start of the application will thus result in the "socket in use" error.

Using the setsockopt call we can override the standard behaviour and specify that even when the socket is in use, we still want to gain access to it.

The error handling for the setsockopt is as before, but a new twist has been added: since the application at this point has claimed the socket, it must also free the socket when it is no longer needed. Hence the call to close.

Part 3: bind and listen

Check out my Port Spy app in the App Store. A utility that helps you debug your socket based application and includes its own source code. So you can see first hand how to implement socket based io in Swift. And you will be helping this blog!
Happy coding...

Did this help?, then please help out a small independent.
If you decide that you want to make a small donation, you can do so by clicking this
link: a cup of coffee ($2) or use the popup on the right hand side for different amounts.
Payments will be processed by PayPal, receiver will be sales at balancingrock dot nl
Bitcoins will be gladly accepted at: 1GacSREBxPy1yskLMc9de2nofNv2SNdwqH

We don't get the world we wish for... we get the world we pay for.

No comments:

Post a Comment