Getting started with BlueSocket and SPM

I recently had a need for regular TCP sockets in Swift on macOS, and unfortunately my go-to iOS socket library, SwiftSocket, is iOS only. A quick peruse of cocoapods.org showed a significant lack of other options.

I then found BlueSocket by IBM (?!), which appeared to do roughly what I was after. Unfortunately, BlueSocket doesn’t use Cocoapods but instead Apples own Swift Package Manager, which has a significant lack of documentation and like Swift itself, changes week-to-week.

Fundamentally this is very straight-forward, but worth documenting here because it doesn’t appear to be elsewhere. This was done on:

  • Xcode 8.1
  • Swift 3.0.1

First, we create a new Xcode project called BasicBlueSocket targeting a Command Line Tool for macOS in swift.

screenie001

Now we need Swift Package Manager to come on board and get our dependency: BlueSocket.

Close Xcode and create the following file, named Package.swift in the root directory of our project folder:

import PackageDescription
let package = Package(
    name: "BasicBlueSocket",
    targets: [],
    dependencies: [
        .Package(url: "https://github.com/IBM-Swift/BlueSocket.git",
                 majorVersion: 0),
    ]
)

Now, open a Terminal and browse to the root of your project directory, where this file is located, and run: swift package generate-xcodeproj.

You should see SPM grab the required code from github and re-jiggle your folder structure:

screenie002.jpg

If you now open BasicBlueSocket.xcodeproj, you’ll be able to go ahead and import Socket – the code library for easy sockets is now available.

We can test that we have BlueSocket up and running with the following code:

import Foundation
import Socket
print("I want a socket")
var socket: Socket
let webRequest = "GET / HTTP/1.1\r\nHOST: 127.0.0.1\r\n\r\n"
var responseData = ""
var data: Data = Data()
do {
    socket = try Socket.create()
    try socket.connect(to: "127.0.0.1", port: 9999)
    try socket.write(from: webRequest)
    let result = try socket.read(into: &data)
    let response = String(data: data, encoding: String.Encoding.utf8)
    print(response ?? "No Response Data")
} catch {
    print("ruh-roh")
}

If you then run python -m SimpleHTTPServer 9999 in a Terminal and run the project, you should see a web request arrive in the python terminal, and the response show up in Xcode. Voila! easy sockets thanks to BlueSocket and SPM.

swift overflow detection

The swift programming language takes a few steps forward for security in a number of areas over it’s predecessor Objective-C, which itself is a lot less of a footgun by design than C/C++.

One feature it has is by-default wrapping prevention for it’s Int values. The following code in Swift will cause an exception – you’ll break in a debugger or simply terminate the entire app if you’re running on iOS:

var i:Int8 = 100
i = i + 30

How does this work under the covers? The following screenshots from hopper show us a disassembly of the compiled binaries, in x64 and ARM.

swift_x64_2

In the above x64 disassembly, the constant 0x14 (20) is added to the low 8 bits of RAX (AL). The SETO instruction then sets the R8 register (R8B) conditionally if the previous ADD has caused an overflow. This value is then tested using TEST, and finally causes a conditional Jump to 0x100001532 if TEST showed R8 having been set (IE, there was an overflow).

The resulting jump if there has been an overflow is simply to UD2 – UnDefined instruction; raise an invalid opcode exception.

swift_overflow_arm

ARM follows a fairly similar path, with B.VS conditionally jumping based on overflow being set, branching out to a BRK; trigger a debug breakpoint.

Interestingly, both ARM and x64 in particular places use a full 64-bit register which is still capable of catching an overflow condition when the Swift data type is Int8 (IE triggers exception when incremented beyond 127) This likely is necessary to be synthesized on ARM due to a lack of access to lower 16 and 8 bits.