コンテンツにスキップ

ロングヘッダーの往復

ロングヘッダーは、QUIC が接続を確立するまでのパケットに使うヘッダー形式です。 どのロングヘッダーも、同じ不変のフィールド(タイプ、バージョン、2 つのコネクション ID)から始まります。 このページでは Initial(接続の最初に送るパケット種別)のヘッダーをエンコードし、それをデコードし直します。

コード

main.c
#define WIRED_MAIN
#include "wired.h"
int wired_main(int argc, char** argv) {
(void)argc;
(void)argv;
/* An Initial, version 1, with the connection IDs of RFC 9001 Appendix A. */
wired_header in = {.long_type = WIRED_LP_INITIAL, .version = 1};
in.dcid_len = 8;
in.scid_len = 8;
memcpy(in.dcid, "\x83\x94\xc8\xf0\x3e\x51\x57\x08", 8);
memcpy(in.scid, "\xf0\x67\xa5\x50\x2a\x42\x62\xb5", 8);
u8 wire[64];
usz n = wired_header_build_long(wire, sizeof wire, &in);
wired_header out = {0};
if (n == 0 || wired_header_parse(wire, n, &out) != n) return 1;
static const char* types[] = {"Initial", "0-RTT", "Handshake", "Retry"};
wired_dprintf(2, "built %llu bytes: ", (u64)n);
wired_dump_hex(2, wired_span_of(wire, n));
wired_dprintf(
2, "\nform=%s type=%s version=0x%08x\ndcid=",
out.form == WIRED_FORM_LONG ? "long" : "short", types[out.long_type],
out.version);
wired_dump_hex(2, wired_span_of(out.dcid, out.dcid_len));
wired_dprintf(2, "\nscid=");
wired_dump_hex(2, wired_span_of(out.scid, out.scid_len));
wired_dprintf(2, "\n");
return 0;
}

実行結果

Terminal window
$ ./quic-header
built 23 bytes: c000000001088394c8f03e51570808f067a5502a4262b5
form=long type=Initial version=0x00000001
dcid=8394c8f03e515708
scid=f067a5502a4262b5
  • wired_header はヘッダーのフィールドを保持します。 long_type には WIRED_LP_INITIAL、WIRED_LP_0RTT、WIRED_LP_HANDSHAKE、WIRED_LP_RETRY のいずれかを入れます。
  • wired_header_build_long(buf, cap, &h) は先頭バイト、バージョン、長さ付きの DCID と SCID(宛先と送信元のコネクション ID)を書き込み、書いたバイト数を返します。 バッファーに収まらないときは 0 を返します。
  • wired_header_parse(buf, n, &h) はそれらを読み戻し、消費したバイト数を返します。 入力が途中で切れているか不正なときは 0 を返します。
  • wired_dprintf は数値と文字列 (%llu, %08x, %s) を stderr に書き出します。 バイト列を 16 進で出す変換指定は printf に無いので、wired_dump_hex を使います。