# TURN 機能

Sora は TURN 機能を内蔵しています。そのため TURN サーバーを別途立てる必要はありません。

## 推奨設定

一番接続率が高くなる設定は以下の通りです。

- TURN-TCP を 443 番ポートで待ち受け
- TURN-TLS を 443 番ポートで待ち受け

上記設定をしたい場合は [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) をご確認ください。

## TURN はすべて同時に試される

TURN 利用時には TURN-UDP と TURN-TCP と TURN-TLS をすべて同時に試みて、
確立が早かった経路を利用する仕組みになっています。

## ブラウザの TURN 対応状況

Chrome、Firefox、Edge、Safari は TURN-UDP / TURN-TCP / TURN-TLS に対応しています。

## 注意

Firefox では TURN の urls を 5 個より多く送るとエラーがコンソールに表示されます。

## 設定

**Sora はデフォルトで TURN 機能が有効になっています**

```ini
## TURN 機能を有効にするかどうかを指定してください
# turn = false

## TURN 機能で利用するレルムを指定してください
# turn_realm = sora-turn.example.com

## TURN 機能で TURN URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください
# turn_fqdn = sora-turn.example.com

## TURN 機能で TURN-TCP を有効にするかどうかを指定してください
# turn_tcp = false

## TURN 機能で TURN-TCP を有効にした際に利用するポート番号を指定してください
# turn_tcp_listen_port = 3478

## TURN 機能で TURN-TCP URL 払い出し時のポート番号を指定してください
# turn_tcp_port = 3478

## TURN 機能で TURN-TLS URL 払い出し機能を有効にするかどうかを指定してください
## オプションでデフォルトは false です
# turn_tls = true

## TURN 機能で TURN-TLS URL 払い出し機能で利用する FQDN (最後の . なし)を指定してください
## turn_tls_fqdn は turn_fqdn の値を上書きします
# turn_tls_fqdn = sora-turn.example.com

## TURN 機能で TURN-TLS URL 払い出し機能を有効にした際に利用するポート番号を指定してください
# turn_tls_port = 5349
```

### 設定の優先順位

TURN が有効な場合 Sora が TURN 用の URL を生成する優先順位が存在します。

1. 認証時に外部サーバーから払い出される `ipv4_address` が採用されます- `sora.conf` で `ipv6` が `true` の場合は払い出された `ipv6_address` も採用されます
2. 外部サーバーから `ipv4_address` が払い出されなかった場合は `sora.conf` の `ipv4_address` が採用されます- `sora.conf` で `ipv6` が `true` の場合は `sora.conf` の `ipv6_address` も採用されます
3. TURN-TLS を有効にしている場合、外部サーバーから払い出される `turn_tls_fqdn` が払い出されなかった場合は `sora.conf` の `turn_tls_fqdn` が採用されます。さらに `turn_tls_fqdn` が指定されてない場合は `turn_fqdn` が採用されます。

#### 設定例 1

```ini
ipv4_address = 192.0.2.10

ipv6 = false

turn = true
turn_realm = sora-turn.example.com
turn_fqdn = sora-turn.example.com

turn_tcp = true
turn_tcp_listen_port = 3478
turn_tcp_port = 3478

turn_tls = true
turn_tls_fqdn = sora-turn.example.com
turn_tls_port = 5349
```

外部サーバーから払い出しは `turn_tls_fqdn` が `"sora-turn.example.com"` の場合、払い出される TURN の urls は 3 つです。
UDP のポートは動的に決まるためここでは 54321 としています。

- turn:sora-turn.example.com:54321?transport=udp
- turn:sora-turn.example.com:3478?transport=tcp
- turns:sora-turn.example.com:5349?transport=tcp

#### 設定例 2

- sora.conf- 全てデフォルト
  - 収集された IP アドレスは 192.0.2.10 と 192.0.2.20
- 外部サーバーから払い出し- なし
  - auth_webhook_url コメントアウト

この場合、払い出される TURN の urls は 4 つです。 UDP のポートは動的に決まるためここでは 54321 としています。

- turn:192.0.2.10:54321?transport=udp
- turn:192.0.2.10:3478?transport=tcp
- turn:192.0.2.20:54321?transport=udp
- turn:192.0.2.20:3478?transport=tcp

## 内蔵 TURN 機能のメリット

- Sora との通信経路を強制的に TURN 経由に固定することで、効率よく接続の確立が行えます- `"type": "candidate"` を待つ必要がなく、 Answer さえ受け取ってしまえば接続の確立まで進めます
- 接続ごとに TURN に使用する Username や Credential を意識する必要がなくなります
- TURN-TCP や TURN-TLS 機能を使用することで UDP が使用できない環境でも WebRTC を利用できるようになります

## Sora の TURN 機能

- TURN-UDP での TURN 機能- 動的なポートでの TURN-UDP にのみ対応しています
- TURN-TCP での TURN 機能
- TURN-TLS での TURN URL 払い出し機能- nginx の利用を前提とした機能です
- ワンタイムな Username や Credential、TURN の URL の自動払い出し- Sora がすべて自動で行ってくれます
  - Sora は TURN 機能に必要な Username や Credential をクライアントごとにワンタイムで生成します
- TURN-UDP / TURN-TCP の IPv6 対応- TURN で払い出す urls も IPv6 に対応します
  - TURN-TLS での IPv6 対応については nginx 依存となります
- TURN-TCP の Proxy Protocol 対応- nginx などを利用したリバースプロキシが前段にいて Proxy Protocol を利用する場合でも対応が可能です

## Sora の TURN-TCP 機能

- デフォルトでは有効になっていますので、無効にしたい場合は `sora.conf` にて `turn_tcp = false` を指定してください
- TURN-TCP で受信するポート番号を指定したい場合は `sora.conf` にて `turn_tcp_listen_port = 3478` のように指定してください
- TURN-TCP の設定で払い出すポート番号を指定したい場合は `sora.conf` にて `turn_tcp_port = 443` のように指定してください

## Sora の TURN-TLS URL 払い出し機能

Sora では TURN-TLS 機能は直接提供していません。 TLS の終端には nginx を利用します。
つまり nginx 側で TURN-TLS の TLS を終端して、 TURN-TCP として Sora に投げてもらいます。

> **重要**
>
> 必ず turn_tcp の設定を有効にしてください

デフォルトでは無効になっていますので、有効にしたい場合は `sora.conf` で `turn_tls = true` を指定してください。

TURN-TLS で使用するポート番号を指定したい場合は `sora.conf` で `turn_tls_port = 5349` のように指定してください。デフォルトでは 5349 をお勧めします。

さらに TURN-TLS では使用する場合はかならず証明書の FQDN を指定する必要があります。
sora-turn.example.com の証明書を使用する場合は `sora.conf` で `turn_tls_fqdn = sora-turn.example.com` のように指定してください。

詳細は [TURN-TLS、TURN-TCP、シグナリングで 443 番ポートを使用する](PRODUCTION.html#14258d) をご確認ください。

## Sora の TURN IPv6 対応

IPv6 のアドレスが使用できる場合、クライアントに送られる TURN UDP/TCP サーバー機能も IPv6 で提供します。

## TURN-TCP / TURN-TLS の検証

`sora.conf` に `turn_tcp_only = true` や `turn_tls_only = true` の設定を有効にすることで強制的に TURN-TCP や TURN-TLS を利用することが可能になります。

こちらは、あくまで検証のみで利用していただくことを想定している機能です。そのため有効にしている場合は `sora.log` に警告メッセージが出力されます。

## Sora TURN 機能の制限

Sora の TURN 機能には一部制限があります。

- TURN で使用される UDP のポート番号の固定ができない- TURN のポート番号は個々のクライアントに対して動的に生成されるため、固定できません。

この課題を解決したい場合は、 Sora の TURN 機能を無効にして、別途 TURN サーバーを立てる必要があります。
ただし、別途 TURN サーバーを立てることは推奨していません。

## 外部の TURN サーバーを使用する場合

> **警告**
>
> Sora の内蔵 TURN サーバーを無効にして外部の TURN サーバーを利用するのは非推奨です、もし利用したい場合はサポートまでご連絡ください

## TURN 機能を使う場合の注意点

> **重要**
>
> 弊社が提供している Sora の SDK を利用する場合は、 SDK 側で TURN 機能に対応しているため、対応は不要です

TURN 機能を使用する場合、 Sora はシグナリングの `"type": "offer"` 時に、
WebSocket 経由で送られてくる JSON 形式のメッセージの config: に、 TURN 接続に必要な情報を含めてクライアントに送信します。

この config を、 PeerConnection を new する際の引数に指定してください。

```javascript
// ws_url は Sora のシグナリング API の URL を指定する
ws = new WebSocket(ws_url);
// WebSocket 経由で送られてきたメッセージのコールバックを指定する
ws.onmessage = onMessage;

function onMessage(event) {
    var message = JSON.parse(event.data);
    if (message.type == 'offer') {
        // TURN 機能を有効に為た場合は offer メッセージの config に TURN で使用する情報が入っています
        var config = message.config;

        // 途中から省略しています
        RTCPeerConnection.generateCertificate({ name: "ECDSA", namedCurve: "P-256" })
            .then(function(certificate) {
                config.certificates = [certificate];
                // ここで RTCPeerConnection を生成する際の config に送られてきた config を指定してください
                peerConnection = new RTCPeerConnection(config);
```

この Sora から Offer として送られてくる config には、常に接続を TURN 経由で行う仕組みが入っています。

- urls に記載される URL の IP アドレスは sora.conf の ip_address に設定した値になります
- urls に記載される URL のポート番号は Sora が動的に生成したポートの値になります
- username と credential は Sora の TURN 機能が動的に生成したワンタイムな値が使用されます

```javascript
// offer メッセージの config のサンプルです
config = {
    "iceTransportPolicy": "relay",
    // urls は Sora が動的に生成したポートを使用した URL が入ります
    "iceServers": [{"urls": ["turn:sora-turn.example.com:3478?transport=udp",
                             "turn:sora-turn.example.com:3478?transport=tcp",
                             "turns:sora-turn.example.com:5349?transport=tcp"],
                    "username": "one-time-username",
                    "credential": "one-time-credential"}]
};
```

## シーケンス図

### TURN への接続は同時に試す

TURN-UDP のポートは動的に決まります。

seqdiag {
    default_fontsize = 15;
    edge_length = 300;

    activation = none;


    クライアント; nginx; Sora;

    クライアント -> nginx [label = 'シグナリング (443 番)'];

        nginx -> Sora [label = 'シグナリング (5000 番)'];
        nginx <- Sora [label = '"type": "offer"'];
    クライアント <- nginx [label = '"type": "offer"'];
    クライアント -> nginx [label = '"type": "answer"'];
        nginx ->> Sora [label = '"type": "answer"'];

    クライアント ->> Sora [label = "TURN-UDP Allocate-Request (52520 番)"];
    クライアント ->> nginx [label = 'TURN-TCP Allocate-Request (443 番)'];
        nginx -> Sora [label = 'TURN-TCP Allocate-Request (3478 番)'];
    クライアント ->> nginx [label = 'TURN-TLS Allocate-Request (443 番)'];
        nginx -> Sora [label = 'TURN-TCP Allocate-Request (3478 番)'];

    クライアント <- Sora [label = 'TURN-UDP Allocate-Success'];

    クライアント -> Sora [label = 'TURN-UDP Permission-Request'];
    クライアント <- Sora [label = 'TURN-UDP Permission-Success'];

    クライアント -> Sora [label = 'TURN-UDP Channel-Reuqest'];
    クライアント <- Sora [label = 'TURN-UDP Channel-Success'];

    クライアント ->> Sora [label = 'DTLS Client Hello over TURN (443 番)'];
}
