cmvr-es/test/quic_gateway/README.md

301 lines
9.3 KiB
Markdown
Raw Normal View History

# CMVR QUIC test Gateway
`cmvr_quic_test_gateway` 是开发和验收工具,不是平台端生产 Gateway。它在本机
监听真实的 MsQuic/TLS/UDP 连接,用来验证 `cmvr_es` 的 QUIC edge v1 客户端。
测试链路:
```text
output/bin/cmvr_es
├── reliable QUIC stream ──> cmvr_quic_test_gateway
│ register / heartbeat / media metadata
└── QUIC DATAGRAM ─────────> bounded media reassembler
```
Gateway 使用生产代码中的:
- `EdgeControlEnvelope` protobuf
- `ControlFrameEncoder` / `ControlFrameDecoder`
- `DatagramPacketizer::decodeHeader`
- `CMQD` v1 常量和类型。
它不会实现 WebTransport、WebRTC、HTTP API、节点数据库或浏览器播放。
## 构建
2026-07-27 17:47:30 +08:00
该目录的 `CMakeLists.txt` 由项目测试目录加入。MsQuic 通过根目录
`request.txt` 提供。依赖为:
2026-07-27 17:47:30 +08:00
- `msquic`
- `cmvr_es::proto`
- `cmvr_es::quic_edge_service`
- `Threads::Threads`
示例:
```bash
cmake -S . -B build \
-DCMAKE_BUILD_TYPE=Release \
-DCMVR_ARCH=x86 \
-DBUILD_TESTING=ON
cmake --build build --target cmvr_quic_test_gateway -j2
```
默认只生成 build-tree 测试程序,不污染部署目录。如确实希望一同安装:
```bash
cmake -S . -B build \
-DCMVR_INSTALL_QUIC_TEST_GATEWAY=ON
cmake --build build --target cmvr_quic_test_gateway -j2
cmake --install build
```
安装位置是 `output/bin/cmvr_quic_test_gateway`,可复用
`output/lib/libmsquic.so` 和现有相对 RUNPATH。
## 生成本地测试证书
QUIC 即使使用“不校验证书”的 client 模式Server 仍必须提供 TLS 证书。
不要提交真实私钥。下面命令只在 build 目录生成 loopback 测试证书:
```bash
mkdir -p build/test/quic_gateway/certs
openssl req -x509 -newkey rsa:2048 -nodes \
-keyout build/test/quic_gateway/certs/server.key \
-out build/test/quic_gateway/certs/server.crt \
-days 7 \
-subj "/CN=127.0.0.1" \
-addext "subjectAltName=IP:127.0.0.1"
```
MsQuic/OpenSSL 当前要求这里的 PEM 私钥不带密码。
## 启动
固定端口适合人工联调。构建树中请使用 CMake 生成的启动包装器;它会补齐
仓库内 gRPC 等传递动态库的搜索路径:
```bash
build/test/quic_gateway/run_cmvr_quic_test_gateway \
--bind 127.0.0.1 \
--port 4433 \
--cert build/test/quic_gateway/certs/server.crt \
--key build/test/quic_gateway/certs/server.key \
--scenario normal \
--summary-file build/test/quic_gateway/summary.json
```
自动化测试应使用 `--port 0` 避免端口冲突。Gateway 会查询 Listener 实际端口,
在 stdout 和 `--ready-file` 写入一个 JSON 对象:
```bash
build/test/quic_gateway/run_cmvr_quic_test_gateway \
--bind 127.0.0.1 \
--port 0 \
--cert build/test/quic_gateway/certs/server.crt \
--key build/test/quic_gateway/certs/server.key \
--ready-file build/test/quic_gateway/ready.json \
--summary-file build/test/quic_gateway/summary.json \
--exit-after-heartbeats 3
```
Ready 文件示例:
```json
{"event":"ready","bind":"127.0.0.1:52319","port":52319,"alpn":"cmvr-quic-edge/1","scenario":"normal","datagram_enabled":true}
```
自动 runner 读取 `port`,将它写入临时 `quic_edge_task.pb.txt` 后再启动
`cmvr_es`。不要直接改唯一一份 `output/bin/config/`;普通安装默认会覆盖它。
只更新程序与运行库时,应在配置构建目录时设置
`-DCMVR_INSTALL_DEFAULT_RUNTIME_ASSETS=OFF`
## cmvr_es 本机配置
第一轮只测试注册、IP 上报和心跳,保持设备和 `tracks` 关闭:
```protobuf
quic_edge {
id: "quic_edge"
server_host: "127.0.0.1"
server_port: 4433
alpn: "cmvr-quic-edge/1"
node_id: "local-quic-test"
software_version: "test"
grpc_endpoint_host: "127.0.0.1"
grpc_endpoint_port: 50052
grpc_endpoint_tls: false
include_loopback_interfaces: true
heartbeat_interval_ms: 1000
control_response_timeout_ms: 1000
tls {
allow_insecure: true
}
reconnect {
initial_delay_ms: 100
maximum_delay_ms: 1000
multiplier: 2.0
jitter_percent: 0
connect_timeout_ms: 3000
}
maximum_datagram_bytes: 1200
maximum_control_frame_bytes: 1048576
maximum_frame_bytes: 524288
datagram_send_queue_depth: 512
media_poll_interval_ms: 2
}
```
2026-07-27 17:47:30 +08:00
在 TaskManager 中将 `quic_edge` entry 设为 `enable: true`。然后运行一份独立的
临时配置树:
```bash
output/bin/cmvr_es /tmp/cmvr-quic-e2e/config/cmvr_es.pb.txt
```
## 场景
`--scenario` 支持:
当前 CTest 自动回归仅运行 `normal` 场景;其余场景保留为手工故障注入和验收入口,
尚未纳入自动回归。
| 名称 | 行为 | 预期 Edge 行为 |
| --- | --- | --- |
| `normal` | 接受注册并精确 ACK 心跳 | 保持同一连接 |
| `reject-registration` | 返回 `accepted=false` | 退避后重新注册 |
| `drop-heartbeat-ack` | 接收但不回复心跳 | response timeout 后重连 |
| `wrong-ack-session` | ACK 使用错误 session ID | 判定协议错误并重连 |
| `fatal-protocol-error` | 注册成功后发送 fatal `ProtocolError` | 重连 |
| `nonfatal-protocol-error` | 注册成功后发送 nonfatal `ProtocolError` | 保持连接并继续心跳 |
| `datagram-disabled` | 不协商 QUIC DATAGRAM | 注册和心跳正常,媒体不发送 |
可以用以下条件让程序自动成功退出:
- `--exit-after-registrations N`
- `--exit-after-heartbeats N`
- `--run-for-ms N`
收到 `SIGINT``SIGTERM`Gateway 会停止 Listener、关闭活动连接、排空工作
队列并写 summary。
## 协议验证
每个连接独立维护:
- control framing buffer
- Edge 和 Gateway 各自的严格递增 `message_sequence`
- node、boot、registration session
- media session epoch
- track descriptor generation token
- DATAGRAM 重组缓存。
Gateway 要求:
1. `NodeRegisterRequest` 是第一条应用消息;
2. protocol version 为 1
3. 后续 envelope sequence 严格增加;
4. heartbeat 的 node、boot 和 session 与注册一致;
5. media session 先于 descriptor
6. DATAGRAM 的 epoch、track、kind 和 generation token 与可靠元数据一致。
`observed_source_ip` 从 MsQuic peer address 获取,不从 Edge 上报字段复制。
Heartbeat 中存在 `device_manager`Gateway 会记录 Manager 元数据以及设备
总数、启用数、禁用数、确认异常数和未知健康数;该字段是 v1 的兼容性追加项,
并在最终 summary 的 `heartbeat_devices` 数组中保留最近一次完整设备行。测试
Gateway 仍接受没有该字段的旧 Edge。当前 Edge 只发送已启用设备,因此正常情况
下禁用数为 0该统计仍用于兼容旧发送端和发现协议违规。
summary 还会保留每类媒体最近一次 descriptor以及已完成帧中的最大
`frame_sequence`、长度、flags、采集时间戳和 FNV-1a 64 位载荷哈希。这里的哈希
只用于测试中精确比对字节,不用于安全认证。真实 E2E 会先发送 discovery 帧并等
descriptor 到达,再发送 priming/validation 帧,从而避免 reliable stream 与
DATAGRAM 跨通道乱序造成偶发误判。
## DATAGRAM 安全边界
MsQuic callback 只复制收到的数据并进入有界队列;控制消息使用高优先级队列,
不会被媒体洪峰长期阻塞。后台线程完成 protobuf 处理和媒体重组。
重组 key 是:
```text
(session_epoch, track_id, frame_sequence)
```
接收器限制:
- 总缓存字节;
- 在途帧数;
- 单帧大小;
- 单帧最多 8192 个分片;
- 不完整帧超时;
- fragment index 冲突;
- byte range 重叠;
- 新 session epoch 清理旧分片。
相关 CLI
```text
--max-reassembly-bytes
--max-reassembly-frames
--max-frame-bytes
--max-work-queue-bytes
--reassembly-timeout-ms
```
## 输出与判定
stdout 每行都是一个 JSON 对象或 JSON-compatible 单行事件。最终 summary 包含:
- connection/register/heartbeat 计数;
- 注册和最近一次心跳上报的网卡数量、gRPC endpoint 与对端源 IP
- 最近一次 DeviceManager 名称/版本/描述,以及已上报设备总数、启用数、兼容性
禁用数、确认异常数、未知健康数和 `heartbeat_devices` 完整设备行;
- ACK、故障场景和协议错误计数
- media session/descriptor/DATAGRAM 计数;
- 完整帧(含视频/音频分项)、无效包、队列丢包;
- 超时、容量淘汰和 session 清理的不完整帧。
自动化脚本至少应检查:
```text
runtime_failed == false
registrations_accepted >= 1 # normal 场景
heartbeats_received >= 1
heartbeat_acks_sent >= 1
protocol_violations == 0
```
媒体场景还应检查:
```text
media_sessions_opened >= 1
track_descriptors_received >= 1
datagrams_received >= 1
frames_completed >= 1
```
## 无设备主机的限制
关闭全部设备时,实际 `output/bin/cmvr_es` 可以完整验证 TLS、ALPN、控制 stream、
注册、IP 上报、心跳和重连,但不会产生音视频。
要在无硬件环境验证媒体 DATAGRAM测试侧还需要 synthetic MediaSourceHub producer
或测试专用 fake camera/microphone。该 Gateway 已具备媒体接收和重组能力,但不会
伪造 Edge 发出的媒体。
## 安全说明
- 仅监听 loopback 是默认值;
- `allow_insecure` 仅限本机开发;
- 不要将测试 Gateway 暴露到不受信任网络;
- 不要复用或提交生产证书、生产私钥;
- 该工具没有生产级认证、授权、持久化和多租户隔离。