mirror of
https://github.com/mofeng-git/One-KVM.git
synced 2026-10-28 00:10:50 +08:00
perf(video): 优化视频流水线并统一使用 vendored OpenSSL
使用固定采集、解码和编码线程及同步最新帧槽,减少同步异步跨界和无效 MJPEG 解码。 编码前预留消费者容量,以完整批次投递编码结果并隔离慢客户端,避免丢失 H.264 参考帧;保留 PTS 修正,不增加 IDR 节流。 复用 Annex-B 缓冲并增加低频发送分项统计,默认启用 vendored OpenSSL SRTP AES-CM 后端。 HTTP 客户端、HTTPS 服务端和本地 DTLS 证书验证迁移至 OpenSSL,移除 rustls TLS 引擎依赖,保留证书验证、媒体加密和原有协议协商。
This commit is contained in:
174
vendor/dtls/src/fragment_buffer/fragment_buffer_test.rs
vendored
Normal file
174
vendor/dtls/src/fragment_buffer/fragment_buffer_test.rs
vendored
Normal file
@@ -0,0 +1,174 @@
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_fragment_buffer() -> Result<()> {
|
||||
let tests = vec![
|
||||
(
|
||||
"Single Fragment",
|
||||
vec![vec![
|
||||
0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x00,
|
||||
]],
|
||||
vec![vec![
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff,
|
||||
0x00,
|
||||
]],
|
||||
0,
|
||||
),
|
||||
(
|
||||
"Single Fragment Epoch 3",
|
||||
vec![vec![
|
||||
0x16, 0xfe, 0xff, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x03,
|
||||
0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x00,
|
||||
]],
|
||||
vec![vec![
|
||||
0x03, 0x00, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff,
|
||||
0x00,
|
||||
]],
|
||||
3,
|
||||
),
|
||||
(
|
||||
"Multiple Fragments",
|
||||
vec![
|
||||
vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
|
||||
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
],
|
||||
vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
|
||||
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09,
|
||||
],
|
||||
vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
|
||||
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x0A,
|
||||
0x0B, 0x0C, 0x0D, 0x0E,
|
||||
],
|
||||
],
|
||||
vec![vec![
|
||||
0x0b, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
]],
|
||||
0,
|
||||
),
|
||||
(
|
||||
"Multiple Unordered Fragments",
|
||||
vec![
|
||||
vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
|
||||
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00,
|
||||
0x01, 0x02, 0x03, 0x04,
|
||||
],
|
||||
vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81,
|
||||
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x05, 0x0A,
|
||||
0x0B, 0x0C, 0x0D, 0x0E,
|
||||
],
|
||||
vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x81,
|
||||
0x0b, 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x00, 0x05, 0x00, 0x00, 0x05, 0x05,
|
||||
0x06, 0x07, 0x08, 0x09,
|
||||
],
|
||||
],
|
||||
vec![vec![
|
||||
0x0b, 0x00, 0x00, 0x0f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0f, 0x00, 0x01,
|
||||
0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
|
||||
]],
|
||||
0,
|
||||
),
|
||||
(
|
||||
"Multiple Handshakes in Single Fragment",
|
||||
vec![vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
0x30, /* record header */
|
||||
0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff,
|
||||
0x01, 0x01, /*handshake msg 1*/
|
||||
0x03, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff,
|
||||
0x01, 0x01, /*handshake msg 2*/
|
||||
0x03, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe, 0xff,
|
||||
0x01, 0x01, /*handshake msg 3*/
|
||||
]],
|
||||
vec![
|
||||
vec![
|
||||
0x03, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe,
|
||||
0xff, 0x01, 0x01,
|
||||
],
|
||||
vec![
|
||||
0x03, 0x00, 0x00, 0x04, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe,
|
||||
0xff, 0x01, 0x01,
|
||||
],
|
||||
vec![
|
||||
0x03, 0x00, 0x00, 0x04, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0xfe,
|
||||
0xff, 0x01, 0x01,
|
||||
],
|
||||
],
|
||||
0,
|
||||
),
|
||||
// Ensure zero length fragments don't cause an infinite recursive loop which in turn causes
|
||||
// a stack overflow.
|
||||
(
|
||||
"Zero length fragment",
|
||||
vec![vec![
|
||||
0x16, 0xfe, 0xfd, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d, 0x00,
|
||||
0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
]],
|
||||
vec![vec![
|
||||
0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||
]],
|
||||
0,
|
||||
),
|
||||
];
|
||||
|
||||
for (name, inputs, expects, expected_epoch) in tests {
|
||||
let mut fragment_buffer = FragmentBuffer::new();
|
||||
for frag in inputs {
|
||||
let status = fragment_buffer.push(&frag)?;
|
||||
assert!(
|
||||
status,
|
||||
"fragment_buffer didn't accept fragments for '{name}'"
|
||||
);
|
||||
}
|
||||
|
||||
for expected in expects {
|
||||
let (out, epoch) = fragment_buffer.pop()?;
|
||||
assert_eq!(
|
||||
out, expected,
|
||||
"fragment_buffer '{name}' push/pop: got {out:?}, want {expected:?}"
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
epoch, expected_epoch,
|
||||
"fragment_buffer returned wrong epoch: got {epoch}, want {expected_epoch}"
|
||||
);
|
||||
}
|
||||
|
||||
let result = fragment_buffer.pop();
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"fragment_buffer popped single buffer multiple times for '{name}'"
|
||||
);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_fragment_buffer_overflow() -> Result<()> {
|
||||
let mut fragment_buffer = FragmentBuffer::new();
|
||||
|
||||
fragment_buffer.push(&[
|
||||
0x16, 0xfe, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0F, 0x03, 0x00,
|
||||
0x00, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0xfe, 0xff, 0x00,
|
||||
])?;
|
||||
|
||||
let big_buffer = vec![0; 2_000_000];
|
||||
let result = fragment_buffer.push(&big_buffer);
|
||||
|
||||
assert!(
|
||||
result.is_err(),
|
||||
"Pushing a buffer of size 2MB should have caused FragmentBuffer::push to return an error"
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
160
vendor/dtls/src/fragment_buffer/mod.rs
vendored
Normal file
160
vendor/dtls/src/fragment_buffer/mod.rs
vendored
Normal file
@@ -0,0 +1,160 @@
|
||||
#[cfg(test)]
|
||||
mod fragment_buffer_test;
|
||||
|
||||
use std::collections::HashMap;
|
||||
use std::io::{BufWriter, Cursor};
|
||||
|
||||
use crate::content::*;
|
||||
use crate::error::*;
|
||||
use crate::handshake::handshake_header::*;
|
||||
use crate::record_layer::record_layer_header::*;
|
||||
|
||||
// 2 mb max buffer size
|
||||
const FRAGMENT_BUFFER_MAX_SIZE: usize = 2_000_000;
|
||||
|
||||
pub(crate) struct Fragment {
|
||||
record_layer_header: RecordLayerHeader,
|
||||
handshake_header: HandshakeHeader,
|
||||
data: Vec<u8>,
|
||||
}
|
||||
|
||||
pub(crate) struct FragmentBuffer {
|
||||
// map of MessageSequenceNumbers that hold slices of fragments
|
||||
cache: HashMap<u16, Vec<Fragment>>,
|
||||
|
||||
current_message_sequence_number: u16,
|
||||
}
|
||||
|
||||
impl FragmentBuffer {
|
||||
pub fn new() -> Self {
|
||||
FragmentBuffer {
|
||||
cache: HashMap::new(),
|
||||
current_message_sequence_number: 0,
|
||||
}
|
||||
}
|
||||
|
||||
// Attempts to push a DTLS packet to the FragmentBuffer
|
||||
// when it returns true it means the FragmentBuffer has inserted and the buffer shouldn't be handled
|
||||
// when an error returns it is fatal, and the DTLS connection should be stopped
|
||||
pub fn push(&mut self, mut buf: &[u8]) -> Result<bool> {
|
||||
let current_size = self.size();
|
||||
if current_size + buf.len() >= FRAGMENT_BUFFER_MAX_SIZE {
|
||||
return Err(Error::ErrFragmentBufferOverflow {
|
||||
new_size: current_size + buf.len(),
|
||||
max_size: FRAGMENT_BUFFER_MAX_SIZE,
|
||||
});
|
||||
}
|
||||
|
||||
let mut reader = Cursor::new(buf);
|
||||
let record_layer_header = RecordLayerHeader::unmarshal(&mut reader)?;
|
||||
|
||||
// Fragment isn't a handshake, we don't need to handle it
|
||||
if record_layer_header.content_type != ContentType::Handshake {
|
||||
return Ok(false);
|
||||
}
|
||||
|
||||
buf = &buf[RECORD_LAYER_HEADER_SIZE..];
|
||||
while !buf.is_empty() {
|
||||
let mut reader = Cursor::new(buf);
|
||||
let handshake_header = HandshakeHeader::unmarshal(&mut reader)?;
|
||||
|
||||
self.cache
|
||||
.entry(handshake_header.message_sequence)
|
||||
.or_default();
|
||||
|
||||
// end index should be the length of handshake header but if the handshake
|
||||
// was fragmented, we should keep them all
|
||||
let mut end = HANDSHAKE_HEADER_LENGTH + handshake_header.length as usize;
|
||||
if end > buf.len() {
|
||||
end = buf.len();
|
||||
}
|
||||
|
||||
// Discard all headers, when rebuilding the packet we will re-build
|
||||
let data = buf[HANDSHAKE_HEADER_LENGTH..end].to_vec();
|
||||
|
||||
if let Some(x) = self.cache.get_mut(&handshake_header.message_sequence) {
|
||||
x.push(Fragment {
|
||||
record_layer_header,
|
||||
handshake_header,
|
||||
data,
|
||||
});
|
||||
}
|
||||
buf = &buf[end..];
|
||||
}
|
||||
|
||||
Ok(true)
|
||||
}
|
||||
|
||||
pub fn pop(&mut self) -> Result<(Vec<u8>, u16)> {
|
||||
let seq_num = self.current_message_sequence_number;
|
||||
if !self.cache.contains_key(&seq_num) {
|
||||
return Err(Error::ErrEmptyFragment);
|
||||
}
|
||||
|
||||
let (content, epoch) = if let Some(frags) = self.cache.get_mut(&seq_num) {
|
||||
let mut raw_message = vec![];
|
||||
// Recursively collect up
|
||||
if !append_message(0, frags, &mut raw_message) {
|
||||
return Err(Error::ErrEmptyFragment);
|
||||
}
|
||||
|
||||
let mut first_header = frags[0].handshake_header;
|
||||
first_header.fragment_offset = 0;
|
||||
first_header.fragment_length = first_header.length;
|
||||
|
||||
let mut raw_header = vec![];
|
||||
{
|
||||
let mut writer = BufWriter::<&mut Vec<u8>>::new(raw_header.as_mut());
|
||||
if first_header.marshal(&mut writer).is_err() {
|
||||
return Err(Error::ErrEmptyFragment);
|
||||
}
|
||||
}
|
||||
|
||||
let message_epoch = frags[0].record_layer_header.epoch;
|
||||
|
||||
raw_header.extend_from_slice(&raw_message);
|
||||
|
||||
(raw_header, message_epoch)
|
||||
} else {
|
||||
return Err(Error::ErrEmptyFragment);
|
||||
};
|
||||
|
||||
self.cache.remove(&seq_num);
|
||||
self.current_message_sequence_number += 1;
|
||||
|
||||
Ok((content, epoch))
|
||||
}
|
||||
|
||||
fn size(&self) -> usize {
|
||||
self.cache
|
||||
.values()
|
||||
.map(|fragment| fragment.iter().map(|f| f.data.len()).sum::<usize>())
|
||||
.sum()
|
||||
}
|
||||
}
|
||||
|
||||
fn append_message(target_offset: u32, frags: &[Fragment], raw_message: &mut Vec<u8>) -> bool {
|
||||
for f in frags {
|
||||
if f.handshake_header.fragment_offset == target_offset {
|
||||
let fragment_end =
|
||||
f.handshake_header.fragment_offset + f.handshake_header.fragment_length;
|
||||
|
||||
// NB: Order here is important, the `f.handshake_header.fragment_length != 0`
|
||||
// MUST come before the recursive call.
|
||||
if fragment_end != f.handshake_header.length
|
||||
&& f.handshake_header.fragment_length != 0
|
||||
&& !append_message(fragment_end, frags, raw_message)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
let mut message = vec![];
|
||||
message.extend_from_slice(&f.data);
|
||||
message.extend_from_slice(raw_message);
|
||||
*raw_message = message;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
false
|
||||
}
|
||||
Reference in New Issue
Block a user