コンテンツにスキップ

ハンドシェイクと可観測性のつまみ

接続が運ぶ内容そのものは変えず、接続がそこへ至る過程と、あわせて記録される情報だけを変える 4 つのサーバーオプションです。 セッションチケットによる再開、RFC 9000 8.1.2 の Retry、 輻輳制御(ネットワークの混み具合に合わせて送信量を調整する仕組み)のアルゴリズム、 そして qlog / NSS key log の出力です。

コード

main.c
#define WIRED_MAIN
#include "wired.h"
static int on_request(
void* ctx,
const wired_h3reqdrive_req* req,
u64 offset,
wired_obuf* body_out,
const char** content_type,
int* more,
u64* total_size) {
(void)ctx;
(void)req;
(void)offset;
(void)more;
(void)total_size;
wired_log_str("request /\n");
*content_type = "text/plain";
wired_obuf_printf(body_out, "ok");
return 1;
}
int wired_main(int argc, char** argv) {
/* The same fixed demo identity as the HTTP/3 hello page. */
static wired_srvboot_demo_keys keys;
wired_srvboot_id id;
wired_srvboot_demo(&id, &keys, 0x50, "guide-h3");
/* Non-0 enables session-ticket resumption/0-RTT (RFC 8446 4.6.1): the
* SDK's per-process ticket seed; the sealing side and this id derive the
* same rotating ticket keys from it. */
id.ticket_key = wired_srvloop_ticket_key();
wired_srvrun_opt opt = {0};
opt.incoming_cpu = -1;
/* RFC 9000 8.1.2: answer every Initial with a stateless Retry first,
* only accepting one that carries a valid Retry token. */
opt.force_retry = 1;
wired_srvrun_obs obs = {
"demo.qlog", /* RFC 9002-shaped packet_sent/packet_received events */
"demo.keylog", /* SSLKEYLOGFILE, decrypts a capture in Wireshark */
0,
0,
1, /* CC_ALGO_CUBIC (see transport/recovery/congestion/cc/cc.h);
* 0 = NewReno, 2 = BBR */
};
u16 port = (u16)wired_cliargs_int(argc, argv, "--port", 4433);
wired_srvrun_handler h = {.cb = on_request};
return wired_server_run_opt(port, &id, h, obs, &opt) ? 0 : 1;
}

実行結果

Terminal window
$ ./ops-handshake-knobs --port 4433
request /
conn closed by peer (CONNECTION_CLOSE)
Terminal window
$ probe h3get 127.0.0.1:4433 /
GET / status=200 content-type=text/plain body="ok"
  • id.ticket_key = wired_srvloop_ticket_key() は、セッションチケットによる再開 (RFC 8446 4.6.1。往復を待たずにデータを送り始める 0-RTT の前提条件)を有効にします。 チケットキーは SDK がプロセスごとに持つシードから導出し、2 時間ごとに切り替えます。 新しいチケットは現在のキーで封印し、提示されたチケットは現在か 1 つ前のキーで復号します。 それより古いチケットは無視され、クライアントは通常のハンドシェイクを行います。
  • opt.force_retry = 1 を設定すると、有効な Retry トークンを持たない Initial (接続開始時の最初のパケット)には、 まずステートレスな Retry が返るようになります(RFC 9000 8.1.2)。 quic-interop-runner の retry テストケースにおけるサーバー側の動作です。 実際のクライアントはこれを自動で処理するので、往復が 1 回増えるだけで、ハンドシェイクは普通に完了します。
  • obs.cc_algo は、新しい接続の輻輳制御アルゴリズムを選びます (CC_ALGO_NEWRENO が 0、CC_ALGO_CUBIC が 1、CC_ALGO_BBR が 2。 transport/recovery/congestion/cc/cc.h を参照)。 ビルド側で上書きしない限り、0 は Cubic(srvrun.c の WIRED_CC_ALGO_DEFAULT)を意味します。 実行時に NewReno を明示的に指定しても値は同じ 0 で、 「未指定」と区別できないためです。 デフォルトを NewReno にしたいビルドは、代わりに -DWIRED_CC_ALGO_DEFAULT=0 を上書きします。
  • obs.qlog_path と obs.keylog_path は、qlog(RFC 9002 の形式に沿った packet_sent / packet_received イベント)と、 Wireshark などのツールがキャプチャの復号に使う NSS key log(SSLKEYLOGFILE 形式)を書き出します。 どちらもデフォルトは 0(無効)です。