Open5

nest: WebRTC Datachannel上のプロトコルを考える会

okuokuokuoku

とりあえず以下のレギュレーションで考える。

  • 1メッセージ最大長は64KiBまで
  • 最大ストリーム数 64k 本 (16bit識別子)
  • ストリームID ゼロ番は制御チャンネルとして予約
  • 制御チャンネルはJSON、最大メッセージ長は 4GiB

現実的には1メッセージあたり 16KiB以下 に抑える必要があるので、データ量の制約はかなり厳しい。

https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Using_data_channels#understanding_message_size_limits

Messages smaller than 16 KiB can be sent without concern, as all major user agents handle them the same way. Beyond that, things get more complicated.

1メッセージ64KiBというのがなかなか微妙な制約に見えるが、まぁそういう物ということで。。実際の運用では16000バイトに区切ってヘッダを着けることにする。

okuokuokuoku

提供するサービス

prev:

https://zenn.dev/okuoku/scraps/e33e8eaddd558a

まぁEthernetパケットさえやりとりできれば後は何も要らないだろという過激な考え方もあるが。。

効率や実装の容易性といった都合で、高レベルなサービスをとり揃えることになる。

  1. HTTP Proxyサービス -- デバイス側のHTTPサーバーにアクセスする
  2. SOCKS5サービス -- デバイスを通してLANにアクセスする(TCP/UDP/DNS)
  3. ストレージサービス -- デバイスのストレージにアクセスする

ストレージサービス、SOCKS5サービスは後まわしにして、とりあえずHTTP Proxyサービスだけ先に用意する。

okuokuokuoku

基本的なフレームフォーマット

今回、WebRTC Datachannel上の1つの message を "フレーム" と呼ぶことにする。フレームは最大16KiBで、2バイトのチャンネル番号が付与される。

長さ 内容
2 タグ番号
N データ

open/close等のout-of-bound信号はフレーム内に定義されない。タグ 0 が制御用にアサインされていて、制御チャンネル上のメッセージとして表現される。

下位のタグはサービスの制御用に予約されている。ペイロードは 1660000 の間のタグを使用する(TCP/IPで言うところのEphemeral portに相当する)

okuokuokuoku

JSONメッセージフォーマット

制御チャンネル 0 と HTTPサービス 1 はJSONを使用した双方向通信となる。

長さ 内容
2 タグ番号
2 "長さ"存在フラグ: 0 = 先頭、1 = 続き
4 (先頭のみ)JSONメッセージの長さ、ゼロの場合は中断
N JSONメッセージ

フォーマット上、無を送信することはできない。メッセージ長がゼロの場合はエラーと見做してメッセージを棄却する。

okuokuokuoku

HTTP Proxyメッセージフォーマット

何気に最低限のメッセージを規定するのが難しいな。。

通常のHTTPリクエスト

(リクエスト)

  • m: HTTP Method(文字列)
  • p: ペイロードのタグ番号(数値)
  • h: リクエストヘッダ(object)

(レスポンス)

  • r: レスポンス番号(数値)
  • h: レスポンスヘッダ(object)
  • p: ペイロードのタグ番号(数値) (省略可)
  • i: リクエストに付与されていたペイロードのタグ番号

リクエストには必ずペイロードのタグ番号を付与しなければならない。レスポンスのペイロードがゼロ長であるときはペイロード自体を省略できる。

ペイロードの終端

ペイロードの終端を示すには、ゼロ長のフレームを送信する。

ペイロードのabort

ペイロードが送信中に失われるなど何らかの形でエラーにする必要がある場合にabortを行う。

  • err: "payload-abort"
  • p: ペイロードのタグ番号