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.

2015-10-30

Socket Programming in Swift: Part 1 - getaddrinfo

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

The first thing to mention when blogging about socket programming is that you really, really should read Beej's Guide to Network Programming it's free, so you don't have an excuse...

In fact, I created this series while working through this guide. Thus much of the code in this series is more or less the Swift version of the code in that book. That said, I will not discuss the general nature of socket programming. I could not do a better job that Beej did anyway. This series will focus on the Swift side of things and some Cocoa aspects.

Still I do want to give some perspective first. So here is the sequence of calls to be made to implement the server side of things:

1) getaddrinfo(): To retrieve the information needed to create a socket descriptor.
2) socket(): To create a socket descriptor
3) setsockopt(): To set the options on the socket
4) bind(): To connect the socket descriptor to a local port
5) freeaddrinfo(): To deallocate used resources
6) listen(): To listen for connection requests
7) -- do some cocoa magic
8) accept(): To accept connection requests
9) recv(): To read the data that is received from the client
10) close()

The client side of things will follow in a later series of posts.

In this post: getaddrinfo

This is the code for Swift 3 Xcode 8, copy & paste into Playground:

// Defs for playground purposes

let servicePortNumber = "3333"
let applicationInDebugMode = true

/// Returns the (host, service) tuple for a given sockaddr

func sockaddrDescription(addr: UnsafePointer<sockaddr>) -> (String?, String?) {
    
    var host : String?
    var service : String?
    
    var hostBuffer = [CChar](repeating: 0, count: Int(NI_MAXHOST))
    var serviceBuffer = [CChar](repeating: 0, count: Int(NI_MAXSERV))
    
    if getnameinfo(
        addr,
        socklen_t(addr.pointee.sa_len),
        &hostBuffer,
        socklen_t(hostBuffer.count),
        &serviceBuffer,
        socklen_t(serviceBuffer.count),
        NI_NUMERICHOST | NI_NUMERICSERV)
        
        == 0 {
        
        host = String(cString: hostBuffer)
        service = String(cString: serviceBuffer)
    }
    return (host, service)
    
}


// General purpose status variable, used to detect error returns from socket functions

var status: Int32 = 0


// ==================================================================
// Retrieve the information necessary to create the socket descriptor
// ==================================================================

// Protocol configuration, used to retrieve the data needed to create the socket descriptor

var hints = addrinfo(
    ai_flags: AI_PASSIVE,       // Assign the address of the local host to the socket structures
    ai_family: AF_UNSPEC,       // Either IPv4 or IPv6
    ai_socktype: SOCK_STREAM,   // TCP
    ai_protocol: 0,
    ai_addrlen: 0,
    ai_canonname: nil,
    ai_addr: nil,
    ai_next: nil)


// For the information needed to create a socket (result from the getaddrinfo)

var servinfo: UnsafeMutablePointer<addrinfo>? = nil


// Get the info we need to create our socket descriptor

status = getaddrinfo(
    nil,                        // Any interface
    servicePortNumber,          // The port on which will be listenend
    &hints,                     // Protocol configuration as per above
    &servinfo)                  // The created information


// Cop out if there is an error

if status != 0 {
    var strError: String
    if status == EAI_SYSTEM {
        strError = String(validatingUTF8: strerror(errno)) ?? "Unknown error code"
    } else {
        strError = String(validatingUTF8: gai_strerror(status)) ?? "Unknown error code"
    }
    print(strError)

else {

   // Print a list of the found IP addresses

   if applicationInDebugMode {
       var info = servinfo
       while info != nil {
           let (clientIp, service) = sockaddrDescription(addr: info!.pointee.ai_addr)
           let message = "HostIp: " + (clientIp ?? "?") + " at port: " + (service ?? "?")
           print(message)
           info = info!.pointee.ai_next
       }
   }   
}

There are a few noteworthy things:
a) I would like to keep the code agnostic with respect to IPv4 or IPv6, thus the use of AF_UNSPEC in the hints structure.
b) Notice that the definition of servinfo only defines a pointer, not the actual structure. It only allocates memory for the pointer, not the structure it points at.
c) The getaddrinfo call is given a pointer to servinfo i.e. a pointer to a pointer. getaddrinfo itself will allocate memory for the structure that servinfo will point at. However after the call to getaddrinfo we "own" the memory that was allocated. And thus must dispose of it later when we no longer need it. (See step 5) (Note: This has nothing to do with ARC, we really need to dispose of the memory ourself otherwise it will create a "memory leak")
d) The servicePortNumber is the port we want the server to listen on for connection requests. A HTTP server would normally listen on port 80.
e) The call to gai_strerror will produce a readable error message, still it is always useful to also have the original error code if we want to google for possible reasons.
f) The call to  uses our (free) SwifterLog error logging mechanism. See the link on the left hand side.
g) The addrinfo structure is recursive, hence when the global variable applicationInDebugMode indicates that the application is in debug mode, it will log a list of all addresses the server is using. These can be IPv4 and IPv6 addresses on multiple network interfaces (multiple ethernet connections, wifi connection, etc)

Socket Programming in Swift: part 2 - socket and setsockopt

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.

2015-10-18

ASCII definitions in Swift

The new String type in Swift is rather fancy. But from time to time I have to do some work on low level stuff that requires me to access a memory area as a sequence of ASCII characters.

So I created this ASCII table that defines all ASCII characters under several different names, and includes a few extra operations as plain functions and as an extension on the UInt8 (typealias ASCII).

import Foundation


typealias ASCII = UInt8


// Control Characters

let ASCII_NUL: ASCII = 0x00
let ASCII_SOH: ASCII = 0x01
let ASCII_STX: ASCII = 0x02
let ASCII_ETX: ASCII = 0x03
let ASCII_EOT: ASCII = 0x04
let ASCII_ENQ: ASCII = 0x05
let ASCII_ACK: ASCII = 0x06
let ASCII_BEL: ASCII = 0x07
let ASCII_BS:  ASCII = 0x08; let ASCII_BACKSPACE = ASCII_BS
let ASCII_TAB: ASCII = 0x09
let ASCII_LF:  ASCII = 0x0A; let ASCII_LINEFEED = ASCII_LF; let ASCII_NEWLINE = ASCII_LF
let ASCII_VT:  ASCII = 0x0B
let ASCII_FF:  ASCII = 0x0C; let ASCII_FORMFEED = ASCII_FF
let ASCII_CR:  ASCII = 0x0D; let ASCII_CARRIAGE_RETURN = ASCII_CR; let ASCII_RETURN = ASCII_CR
let ASCII_SO:  ASCII = 0x0E
let ASCII_SI:  ASCII = 0x0F

let ASCII_DLE: ASCII = 0x10
let ASCII_DC1: ASCII = 0x11
let ASCII_DC2: ASCII = 0x12
let ASCII_DC3: ASCII = 0x13
let ASCII_DC4: ASCII = 0x14
let ASCII_NAK: ASCII = 0x15
let ASCII_SYN: ASCII = 0x16
let ASCII_ETB: ASCII = 0x17
let ASCII_CAN: ASCII = 0x18
let ASCII_EM:  ASCII = 0x19
let ASCII_SUB: ASCII = 0x1A
let ASCII_ESC: ASCII = 0x1B
let ASCII_FS:  ASCII = 0x1C
let ASCII_GS:  ASCII = 0x1D
let ASCII_RS:  ASCII = 0x1E
let ASCII_US:  ASCII = 0x1F
    

// Printable characters

let ASCII_SPACE: ASCII                = 0x20; let ASCII_BLANK = ASCII_SPACE
let ASCII_EXCLAMATION_MARK: ASCII     = 0x21
let ASCII_DOUBLE_QUOTES: ASCII        = 0x22
let ASCII_NUMBER: ASCII               = 0x23; let ASCII_HASH = ASCII_NUMBER
let ASCII_DOLLAR: ASCII               = 0x24
let ASCII_PERCENT_SIGN: ASCII         = 0x25
let ASCII_AMPERSAND: ASCII            = 0x26
let ASCII_SINGLE_QUOTE: ASCII         = 0x27
let ASCII_ROUND_BRACKET_OPEN: ASCII   = 0x28; let ASCII_PARENTHESES_OPEN = ASCII_ROUND_BRACKET_OPEN; let ASCII_FUNCTION_BRACKET_OPEN = ASCII_ROUND_BRACKET_OPEN
let ASCII_ROUND_BRACKET_CLOSE: ASCII  = 0x29; let ASCII_PARENTHESES_CLOSE = ASCII_ROUND_BRACKET_CLOSE; let ASCII_FUNCTION_BRACKET_CLOSE = ASCII_ROUND_BRACKET_CLOSE
let ASCII_ASTERISK: ASCII             = 0x2A
let ASCII_PLUS: ASCII                 = 0x2B
let ASCII_COMMA: ASCII                = 0x2C
let ASCII_HYPHEN: ASCII               = 0x2D; let ASCII_MINUS = ASCII_HYPHEN; let ASCII_DASH = ASCII_HYPHEN
let ASCII_PERIOD: ASCII               = 0x2E; let ASCII_DOT = ASCII_PERIOD; let ASCII_POINT = ASCII_PERIOD
let ASCII_SLASH: ASCII                = 0x2F; let ASCII_SOLIDUS = ASCII_SLASH; let ASCII_FOREWARD_SLASH = ASCII_SLASH; let ASCII_SLASH_FOREWARD = ASCII_SLASH

let ASCII_0: ASCII                    = 0x30
let ASCII_1: ASCII                    = 0x31
let ASCII_2: ASCII                    = 0x32
let ASCII_3: ASCII                    = 0x33
let ASCII_4: ASCII                    = 0x34
let ASCII_5: ASCII                    = 0x35
let ASCII_6: ASCII                    = 0x36
let ASCII_7: ASCII                    = 0x37
let ASCII_8: ASCII                    = 0x38
let ASCII_9: ASCII                    = 0x39
let ASCII_COLON: ASCII                = 0x3A
let ASCII_SEMICOLON: ASCII            = 0x3B
let ASCII_LESS_THAN: ASCII            = 0x3C; let ASCII_LT = ASCII_LESS_THAN
let ASCII_EQUALS: ASCII               = 0x3D
let ASCII_GREATER_THAN: ASCII         = 0x3E; let ASCII_GT = ASCII_GREATER_THAN
let ASCII_QUESTION_MARK: ASCII        = 0x3F

let ASCII_AT_SYMBOL: ASCII            = 0x40
let ASCII_A: ASCII                    = 0x41
let ASCII_B: ASCII                    = 0x42
let ASCII_C: ASCII                    = 0x43
let ASCII_D: ASCII                    = 0x44
let ASCII_E: ASCII                    = 0x45
let ASCII_F: ASCII                    = 0x46
let ASCII_G: ASCII                    = 0x47
let ASCII_H: ASCII                    = 0x48
let ASCII_I: ASCII                    = 0x49
let ASCII_J: ASCII                    = 0x4A
let ASCII_K: ASCII                    = 0x4B
let ASCII_L: ASCII                    = 0x4C
let ASCII_M: ASCII                    = 0x4D
let ASCII_N: ASCII                    = 0x4E
let ASCII_O: ASCII                    = 0x4F

let ASCII_P: ASCII                    = 0x50
let ASCII_Q: ASCII                    = 0x51
let ASCII_R: ASCII                    = 0x52
let ASCII_S: ASCII                    = 0x53
let ASCII_T: ASCII                    = 0x54
let ASCII_U: ASCII                    = 0x55
let ASCII_V: ASCII                    = 0x56
let ASCII_W: ASCII                    = 0x57
let ASCII_X: ASCII                    = 0x58
let ASCII_Y: ASCII                    = 0x59
let ASCII_Z: ASCII                    = 0x5A
let ASCII_SQUARE_BRACKET_OPEN: ASCII  = 0x5B; let ASCII_BOX_BRACKET_OPEN = ASCII_SQUARE_BRACKET_OPEN; let ASCII_ARRAY_BRACKET_OPEN = ASCII_SQUARE_BRACKET_OPEN
let ASCII_BACKSLASH: ASCII            = 0x5C; let ASCII_REVERSE_SOLIDUS = ASCII_BACKSLASH; let ASCII_BACKWARD_SLASH = ASCII_BACKSLASH; let ASCII_SLASH_BACKWARD = ASCII_BACKSLASH
let ASCII_SQUARE_BRACKET_CLOSE: ASCII = 0x5D; let ASCII_BOX_BRACKET_CLOSE = ASCII_SQUARE_BRACKET_CLOSE; let ASCII_ARRAY_BRACKET_CLOSE = ASCII_SQUARE_BRACKET_CLOSE
let ASCII_CARET: ASCII                = 0x5E
let ASCII_UNDERSCORE: ASCII           = 0x5F

let ASCII_GRAVE_ACCENT: ASCII         = 0x60
let ASCII_a: ASCII                    = 0x61
let ASCII_b: ASCII                    = 0x62
let ASCII_c: ASCII                    = 0x63
let ASCII_d: ASCII                    = 0x64
let ASCII_e: ASCII                    = 0x65
let ASCII_f: ASCII                    = 0x66
let ASCII_g: ASCII                    = 0x67
let ASCII_h: ASCII                    = 0x68
let ASCII_i: ASCII                    = 0x69
let ASCII_j: ASCII                    = 0x6A
let ASCII_k: ASCII                    = 0x6B
let ASCII_l : ASCII                   = 0x6C
let ASCII_m: ASCII                    = 0x6D
let ASCII_n: ASCII                    = 0x6E
let ASCII_o: ASCII                    = 0x6F

let ASCII_p: ASCII                    = 0x70
let ASCII_q: ASCII                    = 0x71
let ASCII_r: ASCII                    = 0x72
let ASCII_s: ASCII                    = 0x73
let ASCII_t: ASCII                    = 0x74
let ASCII_u: ASCII                    = 0x75
let ASCII_v: ASCII                    = 0x76
let ASCII_w: ASCII                    = 0x77
let ASCII_x: ASCII                    = 0x78
let ASCII_y: ASCII                    = 0x79
let ASCII_z: ASCII                    = 0x7A
let ASCII_BRACE_OPEN: ASCII           = 0x7B; let ASCII_CURLY_BRACE_OPEN = ASCII_BRACE_OPEN
let ASCII_VERTICAL_BAR: ASCII         = 0x7C
let ASCII_BRACE_CLOSE: ASCII          = 0x7D; let ASCII_CURLY_BRACE_CLOSE = ASCII_BRACE_CLOSE
let ASCII_TILDE: ASCII                = 0x7E
let ASCII_DELETE: ASCII               = 0x7F
    
func isAsciiControl(c: ASCII) -> Bool {
    return c < ASCII_SPACE
}

func isAsciiPrintable(c: ASCII) -> Bool {
    return (c >= ASCII_SPACE && c < ASCII_DELETE)
}

func isAsciiNumber(c: ASCII) -> Bool {
    return (c >= ASCII_0 && c <= ASCII_9)
}

func isAsciiHexadecimalDigit(c: ASCII) -> Bool {
    
    if isAsciiNumber(c) { return true }
    if (c >= ASCII_a && c <= ASCII_f) { return true }
    if (c >= ASCII_A && c <= ASCII_F) { return true }
    return false
}

func isAsciiWhitespace(c: ASCII) -> Bool {
    if c == ASCII_SPACE { return true }
    if c == ASCII_TAB { return true }
    if c == ASCII_CR { return true }
    if c == ASCII_LF { return true }
    return false
}

extension ASCII {
    
    func isAsciiControl() -> Bool {
        return self < ASCII_SPACE
    }
    
    func isAsciiPrintable() -> Bool {
        return (self >= ASCII_SPACE && self < ASCII_DELETE)
    }
    
    func isAsciiNumber() -> Bool {
        return (self >= ASCII_0 && self <= ASCII_9)
    }
    
    func isAsciiHexadecimalDigit() -> Bool {
        if self.isAsciiNumber() { return true }
        if (self >= ASCII_a && self <= ASCII_f) { return true }
        if (self >= ASCII_A && self <= ASCII_F) { return true }
        return false
    }
    
    func isAsciiWhitespace() -> Bool {
        if self == ASCII_SPACE { return true }
        if self == ASCII_TAB { return true }
        if self == ASCII_CR { return true }
        if self == ASCII_LF { return true }
        return false
    }

}

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.