use std::io::{self, Seek};
use std::time::SystemTime;
use bytes::Bytes;
use complex::ComplexHandshakeServer;
use simple::SimpleHandshakeServer;
pub mod complex;
pub mod simple;
pub const RTMP_HANDSHAKE_SIZE: usize = 1536;
pub const TIME_VERSION_LENGTH: usize = 8;
pub const CHUNK_LENGTH: usize = (RTMP_HANDSHAKE_SIZE - TIME_VERSION_LENGTH) / 2;
nutype_enum::nutype_enum! {
pub enum RtmpVersion(u8) {
Version3 = 0x3,
}
}
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum ServerHandshakeState {
ReadC0C1,
ReadC2,
Finish,
}
pub enum HandshakeServer {
Simple(SimpleHandshakeServer),
Complex(ComplexHandshakeServer),
}
impl Default for HandshakeServer {
fn default() -> Self {
Self::Complex(ComplexHandshakeServer::default())
}
}
impl HandshakeServer {
pub fn is_finished(&self) -> bool {
match self {
HandshakeServer::Simple(handshaker) => handshaker.is_finished(),
HandshakeServer::Complex(handshaker) => handshaker.is_finished(),
}
}
pub fn handshake(&mut self, input: &mut io::Cursor<Bytes>, writer: &mut Vec<u8>) -> Result<(), crate::error::RtmpError> {
match self {
HandshakeServer::Complex(handshaker) => {
let position = input.position();
let result = handshaker.handshake(input, writer);
if result.is_err() {
let mut simple = SimpleHandshakeServer::default();
input.seek(io::SeekFrom::Start(position))?;
simple.handshake(input, writer)?;
*self = HandshakeServer::Simple(simple);
}
}
HandshakeServer::Simple(handshaker) => {
handshaker.handshake(input, writer)?;
}
}
Ok(())
}
}
pub fn current_time() -> u32 {
let duration = SystemTime::now().duration_since(SystemTime::UNIX_EPOCH);
match duration {
Ok(result) => result.as_nanos() as u32,
_ => 0,
}
}
#[cfg(test)]
#[cfg_attr(all(test, coverage_nightly), coverage(off))]
mod tests {
use std::io::{Read, Write};
use byteorder::{BigEndian, ReadBytesExt, WriteBytesExt};
use bytes::Bytes;
use crate::handshake::HandshakeServer;
use crate::handshake::complex::digest::DigestProcessor;
use crate::handshake::complex::{
RTMP_CLIENT_KEY_FIRST_HALF, RTMP_SERVER_KEY, RTMP_SERVER_KEY_FIRST_HALF, RTMP_SERVER_VERSION, SchemaVersion,
};
#[test]
fn test_simple_handshake() {
let mut handshake_server = HandshakeServer::default();
let mut c0c1 = Vec::with_capacity(1528 + 8);
c0c1.write_u8(3).unwrap(); c0c1.write_u32::<BigEndian>(123).unwrap(); c0c1.write_u32::<BigEndian>(0).unwrap();
for i in 0..1528 {
c0c1.write_u8((i % 256) as u8).unwrap();
}
let c0c1 = Bytes::from(c0c1);
let mut writer = Vec::new();
handshake_server
.handshake(&mut std::io::Cursor::new(c0c1.clone()), &mut writer)
.unwrap();
let mut reader = std::io::Cursor::new(writer);
assert_eq!(reader.read_u8().unwrap(), 3); let timestamp = reader.read_u32::<BigEndian>().unwrap(); assert_eq!(reader.read_u32::<BigEndian>().unwrap(), 0);
let mut server_random = vec![0; 1528];
reader.read_exact(&mut server_random).unwrap();
assert_eq!(reader.read_u32::<BigEndian>().unwrap(), 123); let timestamp2 = reader.read_u32::<BigEndian>().unwrap();
assert!(timestamp2 >= timestamp);
let mut read_client_random = vec![0; 1528];
reader.read_exact(&mut read_client_random).unwrap();
assert_eq!(&c0c1[9..], &read_client_random);
let mut c2 = Vec::with_capacity(1528 + 8);
c2.write_u32::<BigEndian>(timestamp).unwrap(); c2.write_u32::<BigEndian>(124).unwrap(); c2.write_all(&server_random).unwrap();
let mut writer = Vec::new();
handshake_server
.handshake(&mut std::io::Cursor::new(Bytes::from(c2)), &mut writer)
.unwrap();
assert!(handshake_server.is_finished());
}
#[test]
fn test_complex_handshake() {
let mut handshake_server = HandshakeServer::default();
let mut writer = Vec::with_capacity(3073);
writer.write_u8(3).unwrap();
let mut c0c1 = Vec::with_capacity(1528 + 8);
c0c1.write_u32::<BigEndian>(123).unwrap(); c0c1.write_u32::<BigEndian>(100).unwrap();
for i in 0..1528 {
c0c1.write_u8((i % 256) as u8).unwrap();
}
let data_digest = DigestProcessor::new(Bytes::from(c0c1), RTMP_CLIENT_KEY_FIRST_HALF);
let res = data_digest.generate_and_fill_digest(SchemaVersion::Schema1).unwrap();
res.write_to(&mut writer).unwrap();
let mut bytes = Vec::new();
handshake_server
.handshake(&mut std::io::Cursor::new(Bytes::from(writer)), &mut bytes)
.unwrap();
let s0 = &bytes[0..1];
let s1 = &bytes[1..1537];
let s2 = &bytes[1537..3073];
assert_eq!(s0[0], 3); assert_ne!((&s1[..4]).read_u32::<BigEndian>().unwrap(), 0); assert_eq!((&s1[4..8]).read_u32::<BigEndian>().unwrap(), RTMP_SERVER_VERSION);
let data_digest = DigestProcessor::new(Bytes::copy_from_slice(s1), RTMP_SERVER_KEY_FIRST_HALF);
let (digest, schema) = data_digest.read_digest().unwrap();
assert_eq!(schema, SchemaVersion::Schema1);
assert_ne!((&s2[..4]).read_u32::<BigEndian>().unwrap(), 0); assert_eq!((&s2[4..8]).read_u32::<BigEndian>().unwrap(), 123);
let key_digest = DigestProcessor::new(Bytes::new(), RTMP_SERVER_KEY);
let key = key_digest.make_digest(&res.digest, &[]).unwrap();
let data_digest = DigestProcessor::new(Bytes::new(), &key);
assert_eq!(data_digest.make_digest(&s2[..1504], &[]).unwrap(), s2[1504..]);
let key = key_digest.make_digest(&digest, &[]).unwrap();
let data_digest = DigestProcessor::new(Bytes::new(), &key);
let mut c2 = Vec::new();
for i in 0..1528 {
c2.write_u8((i % 256) as u8).unwrap();
}
let digest = data_digest.make_digest(&c2, &[]).unwrap();
let mut c2 = Vec::with_capacity(1528 + 8);
c2.write_u32::<BigEndian>(123).unwrap(); c2.write_u32::<BigEndian>(124).unwrap(); c2.write_all(&digest).unwrap();
let mut writer = Vec::new();
handshake_server
.handshake(&mut std::io::Cursor::new(Bytes::from(c2)), &mut writer)
.unwrap();
assert!(handshake_server.is_finished());
}
}