概要
RTCQuicTransport は、QUIC プロトコルを使用してリモートピアと任意のデータを交換できる新しいウェブ プラットフォーム API です。これはピアツーピアのユースケースを対象としているため、スタンドアロンの RTCIceTransport API とともに使用され、ICE を介してピアツーピア接続を確立します。データは確実に順序どおりに転送されます(順序付けされていない信頼できない配信の詳細については、後述のセクションをご覧ください)。汎用的な双方向データ転送であるため、ゲーム、ファイル転送、メディア転送、メッセージングなどに使用できます。
理由
強力な低レベルのデータ転送 API を使用すると、アプリケーション(リアルタイム通信など)でウェブ上で新しいことを実現できます。API を基盤として独自のソリューションを構築し、ピアツーピア接続でできることの限界を押し上げることができます。たとえば、カスタム ビットレートの割り当てノブのロックを解除できます。今後、エンコードされたメディアのサポートがさらに進むと、低レベルのコントロールで独自のビデオ通信アプリケーションを構築することも可能になるでしょう。WebRTC の NV の取り組みは、低レベルの API に移行することであり、早い段階でこれをテストすることは価値があります。
QUIC を使用する理由
リアルタイム通信には QUIC プロトコルが適しています。UDP 上に構築され、暗号化と輻輳制御が組み込まれており、ヘッドオブライン ブロッキングなしで多重化されます。RTCQuicTransport
は RTCDataChannel
API と非常によく似ていますが、トランスポート プロトコルとして SCTP ではなく QUIC を使用します。RTCQuicTransport
はスタンドアロン API であるため、リアルタイム メディア スタックを含む RTCPeerConnection
API のオーバーヘッドはありません。
方法
一般的な API の概要
この API には、RTCIceTransport
、RTCQuicTransport
、RTCQuicStream
の 3 つの主な抽象化があります。
RTCIceTransport
ICE は、インターネット経由でピアツーピア接続を確立するプロトコルであり、現在 WebRTC で使用されています。このオブジェクトは、ICE 接続を確立するためのスタンドアロン API を提供します。これは QUIC 接続のパケット トランスポートとして使用され、RTCQuicTransport
はコンストラクタでこれを受け取ります。
RTCQuicTransport
QUIC 接続を表します。これは、QUIC 接続を確立し、QUIC ストリームを作成するために使用されます。また、QUIC 接続レベルに関連する統計情報も公開します。
RTCQuicStream
リモート側との間でのデータの読み取りと書き込みに使用されます。ストリームは、データを確実に順序どおりに転送します。同じ RTCQuicTransport
から複数のストリームを作成できます。データがストリームに書き込まれると、リモート トランスポートで「onquicstream」イベントが発生します。ストリームを使用すると、同じ QUIC 接続で異なるデータを区別できます。一般的な例としては、個別のファイルを個別のストリームに送信する、異なるストリームに小さなデータ チャンクを送信する、異なるストリームに異なるタイプのメディアを送信するなどがあります。RTCQuicStream
は軽量で、QUIC 接続で多重化され、他の RTCQuicStream
へのヘッドオブライン ブロッキングを引き起こしません。
接続の設定
ピアツーピアの QUIC 接続を設定する例を次に示します。RTCPeerConnection
と同様に、RTCQuicTransport
API では、セキュリティ パラメータを含む接続のパラメータをネゴシエートするために、安全なシグナリング チャネルを使用する必要があります。RTCIceTransport
は、ICE パラメータ(ufrag とパスワード)と RTCIceCandidate
をネゴシエートします。
クライアントの視点:
const iceTransport = new RTCIceTransport();
const quicTransport = new RTCQuicTransport(iceTransport);
// Signal parameters, key and candidates.
signalingChannel.send({
iceParams: iceTransport.getLocalParameters(),
quicKey: quicTransport.getKey(),
});
iceTransport.onicecandidate = e => {
if (e.candidate) {
signalingChannel.send({candidate: e.candidate});
}
};
// When remote parameters are signaled, start connection.
signalingChannel.onMessage = async ({iceParams, candidate}) => {
if (iceParams) {
iceTransport.start(iceParams);
quicTransport.connect();
} else if (candidate) {
iceTransport.addRemoteCandidate(candidate);
}
};
サーバー側の視点:
const iceTransport = new RTCIceTransport();
const quicTransport = new RTCQuicTransport(iceTransport);
// Signal parameters, key and candidates.
signalingChannel.send({
iceParams: iceTransport.getLocalParameters(),
});
iceTransport.onicecandidate = e => {
if (e.candidate) {
signalingChannel.send({candidate: e.candidate});
}
};
// When remote parameters are signaled, start connection.
signalingChannel.onMessage = async ({iceParams, quicKey, candidate}) => {
if (iceParams && quicKey) {
iceTransport.start(iceParams);
quicTransport.listen(quicKey);
} else if (candidate) {
iceTransport.addRemoteCandidate(candidate);
}
};
データ転送
データ転送は、読み取りと書き込みに RTCQuicStream API を使用して実現できます。
RTCQuicStreamReadResult readInto(Uint8Array data);
void write(RTCQuicStreamWriteParameters data);
Promise<void> waitForWriteBufferedAmountBelow(unsigned long amount);
Promise<void> waitForReadable(unsigned long amount);
バッファリング
waitFor*
メソッドから返される Promise を使用すると、JavaScript がビジー状態のときにデータをバッファリングできます。受信側で読み取りバッファがいっぱいになると、送信側にバックプレッシャーが適用されます。送信側には、バックプレッシャーが適用されたときに満たされる書き込みバッファがあります。そのため、書き込み側にも waitForWriteBufferedAmountBelow
メソッドがあり、バッファ内の書き込みスペースを待機できます。データの書き込みと読み取りの詳細については、デベロッパー向けのドキュメントをご覧ください。
注文されていない/信頼できない配送
RTCQuicStream
は、データを確実かつ順序に従って送信することのみをサポートしていますが、信頼できない/順序付けされていない配信は他の手段で実現できます。順序なし配信では、データがストリーム間で順序付けられないため、小さなデータ チャンクを個別のストリームで送信できます。信頼できない配信の場合は、finish を true に設定して小さなデータ チャンクを送信し、タイムアウト後にストリームで reset()
を呼び出すことができます。タイムアウトは、データを破棄する前に必要な再送信回数に応じて設定する必要があります。
時期
オリジン トライアルは Chrome 73 バージョンで開始され、M75 バージョンまでご利用いただけます。その後、オリジン トライアルは終了します。フィードバックと関心に基づいて適切な変更を行い、API をリリースするか、この API の新しいオリジン トライアルを継続するか、API を廃止します。
場所
iOS を除くすべてのプラットフォームの Chrome ブラウザ。
他には?
フィードバック
送信元トライアルの主な目的の 1 つは、デベロッパーの皆様からフィードバックを得ることです。興味のある分野:
- この API でできること
- この API は、他のデータ転送 API(
WebSocket
や WebRTC のRTCDataChannel
)と比べてどのような点が優れていますか?また、どのような点が改善されていますか? - パフォーマンス
- API の人間工学
オリジン トライアルに登録する
- 送信元のトークンをリクエストします。
- ページにトークンを追加します。このトークンは、オリジンの任意のページで次の 2 つの方法で指定できます。
- 任意のページのヘッダーに
origin-trial
<meta>
タグを追加します。たとえば、次のように指定します。<meta http-equiv="origin-trial" content="TOKEN_GOES_HERE">
- サーバーを構成できる場合は、
Origin-Trial
HTTP ヘッダーを使用してページにトークンを指定することもできます。生成されたレスポンス ヘッダーは次のようになります。Origin-Trial: TOKEN_GOES_HERE
- 任意のページのヘッダーに
ウェブ仕様
ドラフト仕様は、オリジン トライアルの API よりも進んでおり、次のような点があります。
- WHATWG ストリームに近い単方向ストリーム
- 再送信の無効化
- (近日提供予定)データグラム
仕様全体とそれ以降(WHATWG ストリームのサポートを含む)の実装に興味がありますが、まずは皆様からのフィードバックをお待ちしております。
セキュリティ
QUIC handshake のセキュリティは、事前共有キーを使用して暗号化された P2P QUIC 接続を確立することで適用されます。この鍵は、機密性と完全性が保証されたセキュアなアウトオブバンド チャネルを介して通知する必要があります。鍵は JavaScript に公開されます。
進行中の攻撃
証明書フィンガープリントのシグナリングに完全性のみが必要となる DTLS-SRTP とは異なり、事前共有キーのシグナリングには完全性と機密性が必要です。PSK が侵害された場合(シグナリング チャネル内のサーバーによって侵害された場合など)、アクティブな攻撃者が QUIC handshake に対して中間者攻撃を仕掛ける可能性があります。
現在のステータス
ステップ | ステータス |
---|---|
1. 説明を作成する | 完了 |
**2a. RTCQuicTransport 仕様 ** | **進行中** |
**2b. RTCIceTransport 仕様 ** | **進行中** |
**3. フィードバックを収集してデザインを反復処理する** | **進行中** |
4. オリジン トライアル | Chrome 73 で開始されます。 |
5. リリース | 開始していません |
関連リンク
- その他のドキュメント
- 一般向けの説明
- バグのトラッキング
- 送信元のトライアル トークンをリクエストする
- オリジン トライアル トークンの使用方法
- RTCQuicTransport に関する問題のディスカッション
- RTCIceTransport に関する問題に関するディスカッション