3.3. 【拡張仕様】 WebTransport トランスポート

本拡張仕様では、iSCPの下位層のトランスポートプロトコルとして draft-ietf-webtrans-overview で規定される WebTransport を使用した場合の仕様について規定します。

3.3.1. シーケンス

3.3.1.1. 接続開始

はじめに、クライアントはサーバーに対して、WebTransport のコネクションを確立します。

コネクションが確立するとただちに、クライアントは WebTransport の送信ストリームを1つ開く必要があります。 開いたストリームは、事前ネゴシエーションに使用します。

事前ネゴシエーションが完了すると、クライアントはネゴシエーションに使用したストリームを直ちに切断します。 その後、クライアントとサーバーは、再度別の WebTransport 送信ストリームを1つずつ開く必要があります。 再度開いたストリームは、主にリクエストメッセージの送信や、 QoS=RELIABLE,PARTIAL のメッセージ送信など、 信頼性のあるトランスポートとして使用します。

3.3.1.2. メッセージの送受信

リクエストメッセージは、接続開始時に開いたストリームを使用して送信しなければなりません。

WebSocket のストリームは、順序保証されたロスレスのバイトストリームであるため、 本拡張仕様にてメッセージ境界の特定方法を定義する必要があります。 メッセージ境界に関する仕様については、 メッセージ境界 を参照してください。

3.3.1.3. ストリームメッセージの送受信

上り方向のストリームメッセージのうち、メタデータの送信に関わる2メッセージと、 Upstream Chunk Ack の送信には、ネットワーク接続を開始したときに開いた WebTransport ストリームを使用しなければなりません。 また、 Upstream Open Request で、 QoS=RELIABLE,PARTIAL を指定した場合は、 Upstream Chunk もこのストリームを使用して送信しなければなりません。 QoS=UNRELIABLE を指定した場合は、 Upstream Chunk を DATAGRAM フレームを使用して送信しなければなりません。

下り方向のストリームメッセージのうち、メタデータの送信に関わる2メッセージと、 Downstream Chunk AckDownstream Chunk Ack Complete の送信には、 ネットワーク接続を開始したときに開いた WebTransport ストリームを使用しなければなりません。 また、 Downstream Open Request で、 QoS=RELIABLE,PARTIAL を指定した場合は、 Downstream Chunk もこのストリームを使用して送信しなければなりません。 QoS=UNRELIABLE を指定した場合は、 Downstream Chunk を DATAGRAM フレームを使用して送信しなければなりません。

WebTransport のストリームは、順序保証されたロスレスのバイトストリームであるため、 本拡張仕様にてメッセージ境界の特定方法を定義する必要があります。 メッセージ境界に関する仕様については、 メッセージ境界 を参照してください。

また、 DATAGRAM フレームにはフレームサイズの上限があり、 エンコーディング層にて生成した iSCP メッセージのバイナリ表現が、DATAGRAM フレームの最大フレームサイズを超える場合、 分割して送信しなければなりません。 メッセージ分割に関する仕様については、 メッセージ境界 を参照してください。

3.3.1.4. 接続終了

クライアントおよびサーバーは、接続を切断する際に Disconnect メッセージを送信します。 Disconnect メッセージを受信したクライアントおよびサーバーは、WebTransport のコネクションを切断します。 Disconnect メッセージを送信したクライアントおよびサーバーは、WebTransport のコネクションが切断されるのを待機します。 妥当な時間が経過してもコネクションが切断されない場合は、 WebTransport のコネクションを切断します。

3.3.2. メッセージ境界

WebTransport ストリームを伝送に使用する場合は、本規定にしたがって、ストリームをメッセージに分割する必要があります。

 0               1               2               3
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+---------------+---------------+---------------+---------------+
| Message Length                                                |
+---------------+---------------+---------------+---------------+
| Message Bytes                                                 |
+                                                               +
:                                                               :
+---------------+---------------+---------------+---------------+
| Message Length                                                |
+---------------+---------------+---------------+---------------+
| Message Bytes                                                 |
+                                                               +
:                                                               :
Message Length - メッセージ長

メッセージバイナリのバイト長です。 本フィールドは、ネットワークバイトオーダーを使用して格納されなければなりません。

本フィールドのバイト長が4バイトであるため、WebTransport ストリームを使用して送信できるメッセージバイナリの最大長は、 約4GB( 2^32-1 バイト)までとなります。

ノードにおいて、メッセージバイナリの長さが最大長を超えた場合、 アプリケーションにエラーを返すか、もしくはブローカーに Disconnect を送信して接続を切断することができます。 ブローカーにおいて、iSCP メッセージを表すバイト列の長さが最大長を超えた場合、 ノードに Disconnect を送信して接続を切断しなければなりません。 Disconnect を送信する場合、結果コードは TOO_LARGE_MESSAGE_SIZE を設定します。

Message Bytes - メッセージバイナリ

iSCP メッセージのバイナリ表現です。

3.3.3. メッセージ分割

DATAGRAM フレームにはフレームサイズの上限があり、 エンコーディング層にて生成した iSCP メッセージのバイナリ表現が、DATAGRAM フレームの最大メッセージサイズを超える場合があります。 DATAGRAM フレームを伝送に使用する場合は、本規定にしたがって、 iSCP メッセージを分割して、複数の DATAGRAM フレームに格納して伝送しなければなりません。

以降の説明では、 メッセージ境界 と同様、 iSCP メッセージのバイナリ表現をメッセージバイナリと呼びます。 メッセージバイナリのバイト長を message_length 、 DATAGRAM フレームが格納可能な最大ペイロード長を max_webtrans_payload 、 メッセージバイナリを分割したバイト列をセグメントと呼びます。

まず、DATAGRAM フレームへセグメントを格納する際のフォーマットを以下に示します。

 0               1               2               3
 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7 0 1 2 3 4 5 6 7
+---------------+---------------+---------------+---------------+
| Sequence Number                                               |
+---------------+---------------+---------------+---------------+
| Maximum Segment Index         | Segment Index                 |
+---------------+---------------+---------------+---------------+
| Segmented Message Bytes                                       |
+                                                               +
|                                                               |
+                                                               +
:                                                               :
Sequence Number - シーケンス番号

各メッセージバイナリごとに一意に割り振られる通し番号です。 0から開始して、新しいメッセージバイナリごとに1ずつインクリメントしなければなりません。 本フィールドは、ネットワークバイトオーダーで格納されます。

Maximum Segment Index - 最大セグメントインデックス

そのメッセージのセグメント化により生成されたセグメントに割り当てられた、最大のインデックス値を表します。 この値は、同一のメッセージバイナリから生成された複数のセグメントについて同一の値となります。 本フィールドは、ネットワークバイトオーダーで格納されます。

Segment Index - セグメントインデックス

セグメント化されたメッセージバイナリが、メッセージバイナリ全体の何番目のセグメントかを表すインデックスです。 本フィールドは、ネットワークバイトオーダーで格納されます。

Segmented Message Bytes - セグメント化されたメッセージバイナリ

メッセージバイナリのセグメント化により生成された、セグメントのバイト列です。

シーケンス番号やセグメントインデックスなどによって合計 8バイトが占められるため、 セグメント化されたメッセージバイナリの最大長は max_webtrans_payload - 8 バイトとなります。

DATAGRAM フレームを使用してデータを送信したいクライアントおよびサーバーは、 まず、メッセージバイナリを max_webtrans_payload - 8 バイトの長さになるようにセグメントへ分割します。 この結果、 floor[message_length / (max_webtrans_payload-8)] + 1 個のセグメントが生成されます。

次に、生成したセグメントを、 DATAGRAM フレームに格納します。 このとき、最大セグメントインデックスは、 floor[message_length / (max_webtrans_payload-8)] となります。 セグメントインデックスは、格納するセグメントが何番目かに基づいて、 0 から最大セグメントインデックスまでの値をとります。 セグメント化されたメッセージバイナリには、分割されたバイト列を割り当てます。

以上より、メッセージバイナリを分割送信できる最大長は、 (max_webtrans_payload-8) x 2^16 バイトです。 max_webtrans_payload を1200と仮定すると、約75MBまでとなります。

ノードにおいて、メッセージバイナリの長さが最大長を超えた場合、 アプリケーションにエラーを返すか、もしくはブローカーに Disconnect を送信して接続を切断することができます。 ブローカーにおいて、メッセージバイナリの長さが最大長を超えた場合、 ノードに Disconnect を送信して接続を切断しなければなりません。 Disconnect を送信する場合、結果コードは TOO_LARGE_MESSAGE_SIZE を設定します。

セグメントへ分割して伝送されたメッセージは、受信側でシーケンス番号、最大セグメントインデックス、セグメントインデックスを用いて再構成されます。 再構成のために、受信側はセグメントのバッファ機構を保有する必要がありますが、バッファ機構の実装方法は本仕様では規定しません。 分割されたセグメントの一部が伝送時に欠損した場合は、メッセージ全体が欠損したものとみなします。

3.3.4. エンコーディング

バイナリで表現されるエンコーディングを使用する場合は、生成されたバイナリをそのまま伝送します。 テキストで表現されるエンコーディングを使用する場合は、生成されたテキストをUTF-8にてエンコードして伝送しなければなりません。

3.3.5. 事前ネゴシエーション

本拡張仕様では、事前ネゴシエーションのためにクエリ文字列を使用します。

3.3.5.1. クエリ文字列で使用できる値

クエリ文字列には以下を使用する事ができます。

表 90 クエリ文字列で使用できる値

クエリ名

内容

enc

エンコーディング名。省略された場合は、サーバーが指定するデフォルト値が使用されます。(例: proto)

comp

圧縮のタイプ名。省略された場合は、圧縮を使用しません。(例: per-message, context-takeover)

clevel

圧縮レベル。省略された場合は、デフォルト値を使用します。(例: 1, 2, ... 9)

cwinbits

context-takeover 圧縮時のウィンドウサイズ。省略された場合は、デフォルト値を使用します。(例: 8, 9, ... 15)

以下に、クエリ文字列の例を示します。

表 91 クエリ文字列の例

?enc=proto&comp=per-message&clevel=6

?enc=proto&comp=context-takeover&clevel=6&cwinbits=15

?enc=proto

なお、同一のクエリ文字列は、複数送信してはいけません。 ブローカーが同一のクエリ文字列を複数を受け取った場合は、 400 Bad Request を返却します。

3.3.5.2. ブローカーからの応答

ノードが指定したクエリ文字列に、ブローカーが対応できない場合は 406 Not Acceptable を返却してコネクションを切断します。 問題なく受け入れが可能な場合は、そのまま後続の処理に移ります。