feat(common): 协议 v2——版本号 + 帧头 seq/keyframe + 长度下界校验
为接入安卓主控做准备,先把三端共享契约改到能承载多客户端。改动集中在 common/src/lib.rs,三端适配在同一提交内完成以保证可编译。 协议版本(PROTO_VERSION=2) - ControlMsg::Auth/AuthOk 增加 proto_version 字段;认证顺序改为「先版本后验证码」: 版本不一致时字段布局可能不同,验证码的解析结果不可信 - 任一端版本不符即 AuthFail 并明确报错,把「连上了但行为诡异」变成「连不上且提示升级」 视频帧头(VideoFrameHeader) - 新增 seq: u64(每次实际发送递增,含静止桌面重发)与 keyframe: bool - keyframe 由新增的 common::h264_contains_idr() 从实际 Annex-B 码流判定, 不依赖编码器 API 推断——NVENC 与 openh264 规则不同,实际输出才是唯一可信来源 - 该字段是 MediaCodec 判断解码器重置时机的必要条件,避免客户端自己写 NAL 扫描 不可信输入防护 - read_video_frame 补齐长度下界:total 必须 >= 4,hlen 必须落在 [1, total-4] - 旧实现只校验上界,构造 total<4 的帧会让接收端在 buf[0..4] 处 panic(进程级DoS) - 测试从 0 增至 11 个,覆盖序列化往返与 6 类越界/损坏输入 顺带修复(与上述契约直接相关) - 新增 common::split_video_frame():静止桌面重发时复用载荷但重建帧头, 否则 seq/ts_ms 会停在上次发送时刻,破坏 seq 单调递增契约 - agent-core 与 agent 两端的静止重发路径均改用该函数 验证:cargo test -p common → 20 passed(9 signaling + 11 新增)
This commit is contained in:
1 parent
703eb64fc0
commit
9e50bc6237
6 files changed
+560
-55
No files matched your search
+32
-6
@@ -69,16 +69,42 @@ async fn main() -> Result<()> {
|
||||
// 流 1:认证 + 视频下行
|
||||
let (mut send, mut recv) = conn.accept_bi().await?;
|
||||
|
||||
// 认证
|
||||
// 认证:先校验版本,再校验验证码。
|
||||
// 顺序刻意如此——版本不一致时字段布局可能不同,验证码的解析结果不可信。
|
||||
let first = read_control(&mut recv).await?;
|
||||
let code_ok = matches!(&first, ControlMsg::Auth { code: c } if *c == code);
|
||||
if !code_ok {
|
||||
write_control(&mut send, &ControlMsg::AuthFail("bad code".into())).await?;
|
||||
let auth_err: Option<String> = match &first {
|
||||
ControlMsg::Auth {
|
||||
code: c,
|
||||
proto_version,
|
||||
} => {
|
||||
if *proto_version != common::PROTO_VERSION {
|
||||
Some(format!(
|
||||
"protocol version mismatch: client={proto_version}, server={}",
|
||||
common::PROTO_VERSION
|
||||
))
|
||||
} else if *c != code {
|
||||
Some("bad code".into())
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
other => Some(format!("expected Auth, got {other:?}")),
|
||||
};
|
||||
if let Some(msg) = auth_err {
|
||||
write_control(&mut send, &ControlMsg::AuthFail(msg.clone())).await?;
|
||||
send.finish()?;
|
||||
anyhow::bail!("auth failed");
|
||||
anyhow::bail!(msg);
|
||||
}
|
||||
let (w, h) = capture::desktop_size()?;
|
||||
write_control(&mut send, &ControlMsg::AuthOk { width: w, height: h }).await?;
|
||||
write_control(
|
||||
&mut send,
|
||||
&ControlMsg::AuthOk {
|
||||
width: w,
|
||||
height: h,
|
||||
proto_version: common::PROTO_VERSION,
|
||||
},
|
||||
)
|
||||
.await?;
|
||||
println!("[agent] auth ok, desktop {w}x{h}");
|
||||
|
||||
// 流 2:键鼠输入 + 控制上行(与视频分离,避免被视频积压阻塞)
|
||||
|
||||
Reference in new issue
Block a user