SwiftでQUICでDatagramする

# はじめに
iOS16/macOS13から[Network.framework](https://developer.apple.com/documentation/network)がQUICのDatagramに対応しました
6分24秒〜あたりで触れられています

https://developer.apple.com/videos/play/wwdc2022/10078/

試しに、[quic-go](https://github.com/quic-go/quic-go)とDatagramでechoしてみました
iOS16とmacOS13で動作することを確認しました

# 実装

リポジトリはこちら

https://github.com/fuziki/swift-quic-examples

## Client (Swift)
[NWProtocolQUIC.Options](https://developer.apple.com/documentation/network/nwprotocolquic/options)を作成して、isDatagramを有効にし、maxDatagramFrameSizeを設定します
今回はローカルでテストしたのでオレオレ証明書でも信頼します
[NWConnectionGroup](https://developer.apple.com/documentation/network/nwconnectiongroup)を作成して、各種handerを登録してstartします
NWConnectionと違い、NWConnectionGroupはメッセージを受け取る度に、[setReceiveHandler](https://developer.apple.com/documentation/network/nwconnectiongroup/3600706-setreceivehandler)を再帰的に設定する必要はないようです

```swift
let options = NWProtocolQUIC.Options(alpn: ["echo"])
options.direction = .bidirectional
options.isDatagram = true
options.maxDatagramFrameSize = 65535
let securityProtocolOptions: sec_protocol_options_t = options.securityProtocolOptions
sec_protocol_options_set_verify_block(securityProtocolOptions,
                                      { (_: sec_protocol_metadata_t,
                                         _: sec_trust_t,
                                         complete: @escaping sec_protocol_verify_complete_t) in
    complete(true) // オレオレ証明書でも信頼する
}, DispatchQueue.main)
let params = NWParameters(quic: options)
let desc = NWMultiplexGroup(to: .hostPort(host: "xxx.xxx.xxx.xxx", port: 4433))
let group = NWConnectionGroup(with: desc, using: params)

group.setReceiveHandler { (message: NWConnectionGroup.Message,
                           content: Data?,
                           isComplete: Bool) in
    print("receive message: \(message)")
    print("receive content: \(String(describing: content))")
    print("receive isComplete: \(isComplete)")
}

group.stateUpdateHandler = { (state: NWConnectionGroup.State) in
    print("state: \(state)")
}

group.start(queue: queue)
```

メッセージを送信する際には、[NWConnectionGroup.send(content: to:message:completion:)](https://developer.apple.com/documentation/network/nwconnectiongroup/3600705-send)を利用します

```swift
group.send(content: "Hello".data(using: .utf8)!) { (error: Error?) in
    print("send error: \(String(describing: error))")
}
```

## Server (Go)
quic.Connectionが作成されるのを待って、受け取ったデータをそのまま返します

```go
package main

import (
	"context"
	"crypto/tls"

	"github.com/alta/insecure"
	"github.com/quic-go/quic-go"
)

func main() {
	cert, _ := insecure.Cert()
	tlsConfig := &tls.Config{
		Certificates: []tls.Certificate{cert},
		NextProtos:   []string{"echo"},
	}
	quicConfig := &quic.Config{
		EnableDatagrams: true,
	}
	listener, _ := quic.ListenAddr(":4433", tlsConfig, quicConfig)
	for {
		conn, _ := listener.Accept(context.Background())
		go func(conn quic.Connection) {
			for {
				bytes, _ := conn.ReceiveMessage()
				conn.SendMessage(bytes)
			}
		}(conn)
	}
}
```

# 終わりに
Network.frameworkを利用することでシンプルに、iOS/macOSでもDatagramを利用できました
ただNetwork.frameworkもquic-goもドキュメントが若干少なく、QUICの予備知識が自分に無かったので、どちらが悪いのか、自分の実装が悪いのか分からず、困る場面もありました
↑結果的に、自分の実装が悪かったようですw
Appleが思いの外？QUICの実装に積極的な印象があるので、このままWebTransportまで実装してくれたら嬉しいななどと思っています

Network.frameworkのQUICのストリームについても書いてます！

https://qiita.com/fuziki/items/93d86457afc5d72185a8