SwiftでTCPサーバーを作ってみる


Swiftでは，Cの構造体でさえもExtensionでどんどん拡張できてしまうのは愉快痛快ですね．
C言語でのソケット関連のお約束をSwiftで拡張して使いやすくしてみようという試みです．

Cの，というかソケットAPIでは，

```c
struct sockaddr_in sin;
    memset(&sin, 0, sizeof(sin));
    sin.sin_len = sizeof(sin);
    sin.sin_family = AF_INET;
    sin.sin_port = htons(0);
    sin.sin_addr.s_addr= INADDR_ANY;
 
bind(sock, (struct sockaddr *)&sin, sizeof(sin))
...
```
という感じで`sockaddr_in`から`sockaddr`へキャストするのがお約束．swiftではこれをストレートに表現できないので，Extensionを使って直感的キャスト（コピー）できるようにしてみる．
swiftでは，Cの`sockaddr_in`, `sockaddr`構造体はそれぞれ次のようにコンバートされて定義されている．

```swift
struct sockaddr_in {
    var sin_len: __uint8_t
    var sin_family: sa_family_t
    var sin_port: in_port_t
    var sin_addr: in_addr
    var sin_zero: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
}

struct sockaddr {
    var sa_len: __uint8_t
    var sa_family: sa_family_t
    var sa_data: (Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8, Int8)
}
```
これらを眺めつつ，Extension使って`sockaddr_in`/`sockaddr`の初期化処理を追加．引数に`sockaddr_in`/`sockaddr`タイプ変数を与えて初期化，つまり相互変換できるようにする．

```swift
extension sockaddr {
    init(_ saddr_in: sockaddr_in) {　// cast(copy) from sockaddr_in
        self = saddr_in.copyAsSockAddr()
    }

    func copyAsSockAddrIn() -> sockaddr_in {
        let len = UInt8(sizeof(sockaddr_in))
        let family = self.sa_family
        let (hi, lo) = (self.sa_data.0, self.sa_data.1)
        let port = (hi.asUInt16 << 8) | lo.asUInt16       // what's asUInt16?
        let b = (UInt32(self.sa_data.2), UInt32(self.sa_data.3),
                 UInt32(self.sa_data.4), UInt32(self.sa_data.5))
        let sadr =  b.0 << 24 | b.1 << 16 | b.2 << 8 | b.3
        let addr = in_addr(s_addr: sadr)

        return sockaddr_in(sin_len: len, sin_family: family, sin_port: port,
                    sin_addr: addr, sin_zero: (0,0,0,0,0,0,0,0))
    }

    func unsafeCopyAsSockAddrIn() -> sockaddr_in {
        return unsafeBitCast(self, sockaddr_in.self)
    }
}
```
　　　（`unsafeBitCast`を使ってしまえば一発で可能みたいだけど，ここでは生々しくやっていきたい．）

`struct sockaddr_in`も同様な感じにExtensionして，

```swift
extension sockaddr_in {
    init(_ saddr: sockaddr) {
        self = saddr.copyAsSockAddrIn()
    }

    func copyAsSockAddr() -> sockaddr {
        let len = self.sin_len
        let family = self.sin_family
        let port = self.sin_port.bigEndian
        let (hi, lo) = ((port >> 8).asInt8, (port & 0x00ff).asInt8)
        let sadr: UInt32 = self.sin_addr.s_addr.bigEndian
        let b = (Int8( sadr >> 24        ),
                 Int8((sadr >> 16) & 0xff),
                 Int8((sadr >>  8) & 0xff),
                 Int8( sadr        & 0xff))
        let z: Int8 = 0
        let data = (hi, lo, b.0, b.1, b.2, b.3, z,z,z,z,z,z,z,z)
        return sockaddr(sa_len: len, sa_family: family, sa_data: data)
    }
}
```

ところで，`copyAsSockAddrIn`メソッド内の`hi, lo`(Int8タイプ)変数のところの`asInt8`とか`asUInt16`なんていうプロパティは整数タイプにありましたっけ？
これも次のようにExtensionしちゃってます．これ，符号なし16ビット整数を符号付8ビット整数に強引に変換するのに必要なんですね．`UInt16(Int8(-128))`なんてことをやるとコンパイラに怒られてしまうので．

```swift
extension Int8 {
    var asUInt16: UInt16 {
        return UInt16(Int16(self) & 0xff)
    }
}

extension UInt16 {
    var asInt8: Int8 {
        let v = self & 0xff
        return Int8(v >> 4) << 4 | Int8(v & 0xf)
    }
}
```
　
さて，以上で準備は終わり．
swiftでソケットAPIを呼んでみましょう．（長ったらしいのでエラー処理は省略．）

```swift
class EchoServer {
    ...
    func start(port: UInt16) {
        serverSocket = socket(AF_INET, SOCK_STREAM, 0)
   	    ...
        var addrIn = sockaddr_in(port: port)
        var len = socklen_t(addrIn.sin_len)
        var addr = sockaddr(addrIn)

        bind(serverSocket, &addr, len)
        listen(serverSocket, 4)

        let src = my_create_disp_src(serverSocket)
        dispatch_source_set_event_handler(src, acceptClient)
        dispatch_resume(src)
    }
```
　
ほとんどC言語のお約束と同様にいけますね．`listen`した後は，仕事をGCDに丸投げします．

ひとつ残念なのが，現状(XCode6 Beta5)では，swiftからGCDの`dispatch_source_create()`の直接呼び出しがうまく機能せず，正しく機能させるためにC言語のブリッジを使わざるを得ないことです．その関数が`my_create_disp_src()`でこんなふうに定義しています．

```c
dispatch_source_t my_create_disp_src(int sock) {
    return dispatch_source_create(DISPATCH_SOURCE_TYPE_READ,
                           sock, 0, dispatch_get_global_queue(0, 0));
}
```
　
次は，`dispatch_source_set_event_handler`に渡すハンドラ(`acceptClient`)の定義です.

```swift
    func acceptClient() {
        var addrIn = sockaddr_in()
        var addr = sockaddr(addrIn)
        var len = socklen_t(addrIn.sin_len)

        let sock = accept(serverSocket, &addr, &len)

        addrIn = sockaddr_in(addr) // copy back
        let ipStr = addrIn.addressString
        let port = addrIn.sin_port
        println("Accepted client(=\(ipStr):\(port))")

        var csrc = my_create_disp_src(sock)
        dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER)
        clientsAccepted[sock] = csrc
        dispatch_semaphore_signal(semaphore)

        dispatch_source_set_event_handler(csrc, readAndEchoBack(sock))
        dispatch_resume(csrc)
    }
```

`accept`もほとんどお約束通りいけますね．
あと，`inet_ntoa()`なんか使わず，`sockaddr_in`にExtensionして`addressString`プロパティを追加しました．`addressString`でIPアドレスの文字列表現を取れるようにしてます．なるべくピュアswiftで行きたいものでして．

お次は，接続してきたクライアントに対するイベント処理です．イベントハンドラ登録関数(`dispatch_source_set_event_handler`)に渡すハンドラ関数(クロージャ)はタイプが無引数無戻値な'`() -> ()`'でないとダメです．ですが，クライアントからのread／へのwriteや，切断時の後始末のためにクライアントのソケットが必要で，どうしても整数引数を渡さないといけません．
そこで関数の部分適用の出番です．
これがサラッと書ける言語はほんと楽でいいですねー．
つまり，"`(Int) -> () -> ()`"な関数を作ってしまえばいいのでした．
上記コードの`readAndEchoBack(sock)`に注目．これ関数コールしてますが戻り値は"`() -> ()`"です．
その実装は，

```swift
    func readAndEchoBack(sock: Int32) -> () -> () {
        let client = sock
        return {
            () -> () in dispatch_async(GlobalQueue) {
//                [unowned self] in    // <=== Linkage error in Xcode6 Beta5
                let bufSize = 64
                var buf = [UInt8](count: bufSize, repeatedValue: 0)
                let size = read(client, &buf, UInt(bufSize))

                if size > 0 {
                    write(client, &buf, UInt(size))
                } else if size == 0 {
                    dispatch_semaphore_wait(self.semaphore, DISPATCH_TIME_FOREVER)

                    var csrc = self.clientsAccepted.removeValueForKey(client)
                    if let src = csrc {
                        dispatch_source_cancel(src)
                        dispatch_release(src)
                        close(client)
                    }
                    
                    dispatch_semaphore_signal(self.semaphore)
                } else {/* size == -1 somethig wrong happned...*/}
            }
        }
    }

```
~~現状(XCode6 Beta5)，"`[unowned self]`"を付けると何故かリンク時にエラーになってしまいます．~~ (循環参照していないのでキャプチャリストは必要ありません．)

　　
以上で，swiftでもそこそこ簡単に生ソケットAPI使ってTCPサーバーを実装できることが分かりました．SwiftでC言語用APIをサラッと使えるのはとても便利ですね．
（一部残念ですが，swift環境はまだベータ版，というかむしろアルファ版ですからね．我慢しましょう．）

Gistにソースを置きました．
[Extensions.swift](https://gist.github.com/satoshiam/9b97daf97e8efe868d97)
[EchoServer.swift](https://gist.github.com/satoshiam/65f74106f5c69697314f)