use crate::types::{Mid, Pid, Prio, Promises, Sid}; use std::{collections::VecDeque, convert::TryFrom}; // const FRAME_RESERVED_1: u8 = 0; const FRAME_HANDSHAKE: u8 = 1; const FRAME_INIT: u8 = 2; const FRAME_SHUTDOWN: u8 = 3; const FRAME_OPEN_STREAM: u8 = 4; const FRAME_CLOSE_STREAM: u8 = 5; const FRAME_DATA_HEADER: u8 = 6; const FRAME_DATA: u8 = 7; const FRAME_RAW: u8 = 8; //const FRAME_RESERVED_2: u8 = 10; //const FRAME_RESERVED_3: u8 = 13; /// Used for Communication between Channel <----(TCP/UDP)----> Channel #[derive(Debug, PartialEq, Clone)] pub /* should be crate only */ enum InitFrame { Handshake { magic_number: [u8; 7], version: [u32; 3], }, Init { pid: Pid, secret: u128, }, /* WARNING: Sending RAW is only used for debug purposes in case someone write a new API * against veloren Server! */ Raw(Vec), } /// Used for Communication between Channel <----(TCP/UDP)----> Channel #[derive(Debug, PartialEq, Clone)] pub enum Frame { Shutdown, /* Shutdown this channel gracefully, if all channels are shutdown (gracefully), * Participant is deleted */ OpenStream { sid: Sid, prio: Prio, promises: Promises, }, CloseStream { sid: Sid, }, DataHeader { mid: Mid, sid: Sid, length: u64, }, Data { mid: Mid, start: u64, data: Vec, }, } impl InitFrame { // Size WITHOUT the 1rst indicating byte pub(crate) const HANDSHAKE_CNS: usize = 19; pub(crate) const INIT_CNS: usize = 32; /// const part of the RAW frame, actual size is variable pub(crate) const RAW_CNS: usize = 2; //provide an appropriate buffer size. > 1500 pub(crate) fn to_bytes(self, bytes: &mut [u8]) -> usize { match self { InitFrame::Handshake { magic_number, version, } => { let x = FRAME_HANDSHAKE.to_be_bytes(); bytes[0] = x[0]; bytes[1..8].copy_from_slice(&magic_number); bytes[8..12].copy_from_slice(&version[0].to_le_bytes()); bytes[12..16].copy_from_slice(&version[1].to_le_bytes()); bytes[16..Self::HANDSHAKE_CNS + 1].copy_from_slice(&version[2].to_le_bytes()); Self::HANDSHAKE_CNS + 1 }, InitFrame::Init { pid, secret } => { bytes[0] = FRAME_INIT.to_be_bytes()[0]; bytes[1..17].copy_from_slice(&pid.to_le_bytes()); bytes[17..Self::INIT_CNS + 1].copy_from_slice(&secret.to_le_bytes()); Self::INIT_CNS + 1 }, InitFrame::Raw(data) => { bytes[0] = FRAME_RAW.to_be_bytes()[0]; bytes[1..3].copy_from_slice(&(data.len() as u16).to_le_bytes()); bytes[Self::RAW_CNS + 1..(data.len() + Self::RAW_CNS + 1)] .clone_from_slice(&data[..]); Self::RAW_CNS + 1 + data.len() }, } } pub(crate) fn to_frame(bytes: Vec) -> Option { let frame_no = match bytes.get(0) { Some(&f) => f, None => return None, }; let frame = match frame_no { FRAME_HANDSHAKE => { if bytes.len() < Self::HANDSHAKE_CNS + 1 { return None; } InitFrame::gen_handshake( *<&[u8; Self::HANDSHAKE_CNS]>::try_from(&bytes[1..Self::HANDSHAKE_CNS + 1]) .unwrap(), ) }, FRAME_INIT => { if bytes.len() < Self::INIT_CNS + 1 { return None; } InitFrame::gen_init( *<&[u8; Self::INIT_CNS]>::try_from(&bytes[1..Self::INIT_CNS + 1]).unwrap(), ) }, FRAME_RAW => { if bytes.len() < Self::RAW_CNS + 1 { return None; } let length = InitFrame::gen_raw( *<&[u8; Self::RAW_CNS]>::try_from(&bytes[1..Self::RAW_CNS + 1]).unwrap(), ); let mut data = vec![0; length as usize]; let slice = &bytes[Self::RAW_CNS + 1..]; if slice.len() != length as usize { return None; } data.copy_from_slice(&bytes[Self::RAW_CNS + 1..]); InitFrame::Raw(data) }, _ => InitFrame::Raw(bytes), }; Some(frame) } fn gen_handshake(buf: [u8; Self::HANDSHAKE_CNS]) -> Self { let magic_number = *<&[u8; 7]>::try_from(&buf[0..7]).unwrap(); InitFrame::Handshake { magic_number, version: [ u32::from_le_bytes(*<&[u8; 4]>::try_from(&buf[7..11]).unwrap()), u32::from_le_bytes(*<&[u8; 4]>::try_from(&buf[11..15]).unwrap()), u32::from_le_bytes(*<&[u8; 4]>::try_from(&buf[15..Self::HANDSHAKE_CNS]).unwrap()), ], } } fn gen_init(buf: [u8; Self::INIT_CNS]) -> Self { InitFrame::Init { pid: Pid::from_le_bytes(*<&[u8; 16]>::try_from(&buf[0..16]).unwrap()), secret: u128::from_le_bytes(*<&[u8; 16]>::try_from(&buf[16..Self::INIT_CNS]).unwrap()), } } fn gen_raw(buf: [u8; Self::RAW_CNS]) -> u16 { u16::from_le_bytes(*<&[u8; 2]>::try_from(&buf[0..Self::RAW_CNS]).unwrap()) } } impl Frame { pub(crate) const CLOSE_STREAM_CNS: usize = 8; /// const part of the DATA frame, actual size is variable pub(crate) const DATA_CNS: usize = 18; pub(crate) const DATA_HEADER_CNS: usize = 24; #[cfg(feature = "metrics")] pub const FRAMES_LEN: u8 = 5; pub(crate) const OPEN_STREAM_CNS: usize = 10; // Size WITHOUT the 1rst indicating byte pub(crate) const SHUTDOWN_CNS: usize = 0; #[cfg(feature = "metrics")] pub const fn int_to_string(i: u8) -> &'static str { match i { 0 => "Shutdown", 1 => "OpenStream", 2 => "CloseStream", 3 => "DataHeader", 4 => "Data", _ => "", } } #[cfg(feature = "metrics")] pub fn get_int(&self) -> u8 { match self { Frame::Shutdown => 0, Frame::OpenStream { .. } => 1, Frame::CloseStream { .. } => 2, Frame::DataHeader { .. } => 3, Frame::Data { .. } => 4, } } #[cfg(feature = "metrics")] pub fn get_string(&self) -> &str { Self::int_to_string(self.get_int()) } //provide an appropriate buffer size. > 1500 pub fn to_bytes(self, bytes: &mut [u8]) -> (/* buf */ usize, /* actual data */ u64) { match self { Frame::Shutdown => { bytes[Self::SHUTDOWN_CNS] = FRAME_SHUTDOWN.to_be_bytes()[0]; (Self::SHUTDOWN_CNS + 1, 0) }, Frame::OpenStream { sid, prio, promises, } => { bytes[0] = FRAME_OPEN_STREAM.to_be_bytes()[0]; bytes[1..9].copy_from_slice(&sid.to_le_bytes()); bytes[9] = prio.to_le_bytes()[0]; bytes[Self::OPEN_STREAM_CNS] = promises.to_le_bytes()[0]; (Self::OPEN_STREAM_CNS + 1, 0) }, Frame::CloseStream { sid } => { bytes[0] = FRAME_CLOSE_STREAM.to_be_bytes()[0]; bytes[1..Self::CLOSE_STREAM_CNS + 1].copy_from_slice(&sid.to_le_bytes()); (Self::CLOSE_STREAM_CNS + 1, 0) }, Frame::DataHeader { mid, sid, length } => { bytes[0] = FRAME_DATA_HEADER.to_be_bytes()[0]; bytes[1..9].copy_from_slice(&mid.to_le_bytes()); bytes[9..17].copy_from_slice(&sid.to_le_bytes()); bytes[17..Self::DATA_HEADER_CNS + 1].copy_from_slice(&length.to_le_bytes()); (Self::DATA_HEADER_CNS + 1, 0) }, Frame::Data { mid, start, data } => { bytes[0] = FRAME_DATA.to_be_bytes()[0]; bytes[1..9].copy_from_slice(&mid.to_le_bytes()); bytes[9..17].copy_from_slice(&start.to_le_bytes()); bytes[17..Self::DATA_CNS + 1].copy_from_slice(&(data.len() as u16).to_le_bytes()); bytes[Self::DATA_CNS + 1..(data.len() + Self::DATA_CNS + 1)] .clone_from_slice(&data[..]); (Self::DATA_CNS + 1 + data.len(), data.len() as u64) }, } } pub(crate) fn to_frame(bytes: &mut VecDeque) -> Option { let frame_no = match bytes.get(0) { Some(&f) => f, None => return None, }; let size = match frame_no { FRAME_SHUTDOWN => Self::SHUTDOWN_CNS, FRAME_OPEN_STREAM => Self::OPEN_STREAM_CNS, FRAME_CLOSE_STREAM => Self::CLOSE_STREAM_CNS, FRAME_DATA_HEADER => Self::DATA_HEADER_CNS, FRAME_DATA => { u16::from_le_bytes([bytes[16 + 1], bytes[17 + 1]]) as usize + Self::DATA_CNS }, _ => return None, }; if bytes.len() < size + 1 { return None; } let frame = match frame_no { FRAME_SHUTDOWN => { let _ = bytes.drain(..size + 1); Frame::Shutdown }, FRAME_OPEN_STREAM => { let bytes = bytes.drain(..size + 1).skip(1).collect::>(); Frame::gen_open_stream(<[u8; 10]>::try_from(bytes).unwrap()) }, FRAME_CLOSE_STREAM => { let bytes = bytes.drain(..size + 1).skip(1).collect::>(); Frame::gen_close_stream(<[u8; 8]>::try_from(bytes).unwrap()) }, FRAME_DATA_HEADER => { let bytes = bytes.drain(..size + 1).skip(1).collect::>(); Frame::gen_data_header(<[u8; 24]>::try_from(bytes).unwrap()) }, FRAME_DATA => { let info = bytes .drain(..Self::DATA_CNS + 1) .skip(1) .collect::>(); let (mid, start, length) = Frame::gen_data(<[u8; 18]>::try_from(info).unwrap()); debug_assert_eq!(length as usize, size - Self::DATA_CNS); let data = bytes.drain(..length as usize).collect::>(); Frame::Data { mid, start, data } }, _ => unreachable!("Frame::to_frame should be handled before!"), }; Some(frame) } fn gen_open_stream(buf: [u8; Self::OPEN_STREAM_CNS]) -> Self { Frame::OpenStream { sid: Sid::from_le_bytes(*<&[u8; 8]>::try_from(&buf[0..8]).unwrap()), prio: buf[8], promises: Promises::from_bits_truncate(buf[Self::OPEN_STREAM_CNS - 1]), } } fn gen_close_stream(buf: [u8; Self::CLOSE_STREAM_CNS]) -> Self { Frame::CloseStream { sid: Sid::from_le_bytes( *<&[u8; 8]>::try_from(&buf[0..Self::CLOSE_STREAM_CNS]).unwrap(), ), } } fn gen_data_header(buf: [u8; Self::DATA_HEADER_CNS]) -> Self { Frame::DataHeader { mid: Mid::from_le_bytes(*<&[u8; 8]>::try_from(&buf[0..8]).unwrap()), sid: Sid::from_le_bytes(*<&[u8; 8]>::try_from(&buf[8..16]).unwrap()), length: u64::from_le_bytes( *<&[u8; 8]>::try_from(&buf[16..Self::DATA_HEADER_CNS]).unwrap(), ), } } fn gen_data(buf: [u8; Self::DATA_CNS]) -> (Mid, u64, u16) { let mid = Mid::from_le_bytes(*<&[u8; 8]>::try_from(&buf[0..8]).unwrap()); let start = u64::from_le_bytes(*<&[u8; 8]>::try_from(&buf[8..16]).unwrap()); let length = u16::from_le_bytes(*<&[u8; 2]>::try_from(&buf[16..Self::DATA_CNS]).unwrap()); (mid, start, length) } } #[cfg(test)] mod tests { use super::*; use crate::types::{VELOREN_MAGIC_NUMBER, VELOREN_NETWORK_VERSION}; fn get_initframes() -> Vec { vec![ InitFrame::Handshake { magic_number: VELOREN_MAGIC_NUMBER, version: VELOREN_NETWORK_VERSION, }, InitFrame::Init { pid: Pid::fake(0), secret: 0u128, }, InitFrame::Raw(vec![1, 2, 3]), ] } fn get_frames() -> Vec { vec![ Frame::OpenStream { sid: Sid::new(1337), prio: 14, promises: Promises::GUARANTEED_DELIVERY, }, Frame::DataHeader { sid: Sid::new(1337), mid: 0, length: 36, }, Frame::Data { mid: 0, start: 0, data: vec![77u8; 20], }, Frame::Data { mid: 0, start: 20, data: vec![42u8; 16], }, Frame::CloseStream { sid: Sid::new(1337), }, Frame::Shutdown, ] } #[test] fn initframe_individual() { let dupl = |frame: InitFrame| { let mut buffer = vec![0u8; 1500]; let size = InitFrame::to_bytes(frame.clone(), &mut buffer); buffer.truncate(size); InitFrame::to_frame(buffer) }; for frame in get_initframes() { println!("initframe: {:?}", &frame); assert_eq!(Some(frame.clone()), dupl(frame)); } } #[test] fn initframe_multiple() { let mut buffer = vec![0u8; 3000]; let mut frames = get_initframes(); let mut last = 0; // to string let sizes = frames .iter() .map(|f| { let s = InitFrame::to_bytes(f.clone(), &mut buffer[last..]); last += s; s }) .collect::>(); // from string let mut last = 0; let mut framesd = sizes .iter() .map(|&s| { let f = InitFrame::to_frame(buffer[last..last + s].to_vec()); last += s; f }) .collect::>(); // compare for (f, fd) in frames.drain(..).zip(framesd.drain(..)) { println!("initframe: {:?}", &f); assert_eq!(Some(f), fd); } } #[test] fn frame_individual() { let dupl = |frame: Frame| { let mut buffer = vec![0u8; 1500]; let (size, _) = Frame::to_bytes(frame.clone(), &mut buffer); let mut deque = buffer[..size].iter().map(|b| *b).collect(); Frame::to_frame(&mut deque) }; for frame in get_frames() { println!("frame: {:?}", &frame); assert_eq!(Some(frame.clone()), dupl(frame)); } } #[test] fn frame_multiple() { let mut buffer = vec![0u8; 3000]; let mut frames = get_frames(); let mut last = 0; // to string let sizes = frames .iter() .map(|f| { let s = Frame::to_bytes(f.clone(), &mut buffer[last..]).0; last += s; s }) .collect::>(); assert_eq!(sizes[0], 1 + Frame::OPEN_STREAM_CNS); assert_eq!(sizes[1], 1 + Frame::DATA_HEADER_CNS); assert_eq!(sizes[2], 1 + Frame::DATA_CNS + 20); assert_eq!(sizes[3], 1 + Frame::DATA_CNS + 16); assert_eq!(sizes[4], 1 + Frame::CLOSE_STREAM_CNS); assert_eq!(sizes[5], 1 + Frame::SHUTDOWN_CNS); let mut buffer = buffer.drain(..).collect::>(); // from string let mut framesd = sizes .iter() .map(|&_| Frame::to_frame(&mut buffer)) .collect::>(); // compare for (f, fd) in frames.drain(..).zip(framesd.drain(..)) { println!("frame: {:?}", &f); assert_eq!(Some(f), fd); } } #[test] fn frame_exact_size() { let mut buffer = vec![0u8; Frame::CLOSE_STREAM_CNS+1/*first byte*/]; let frame1 = Frame::CloseStream { sid: Sid::new(1337), }; let _ = Frame::to_bytes(frame1.clone(), &mut buffer); let mut deque = buffer.iter().map(|b| *b).collect(); let frame2 = Frame::to_frame(&mut deque); assert_eq!(Some(frame1), frame2); } #[test] #[should_panic] fn initframe_too_short_buffer() { let mut buffer = vec![0u8; 10]; let frame1 = InitFrame::Handshake { magic_number: VELOREN_MAGIC_NUMBER, version: VELOREN_NETWORK_VERSION, }; let _ = InitFrame::to_bytes(frame1.clone(), &mut buffer); } #[test] fn initframe_too_less_data() { let mut buffer = vec![0u8; 20]; let frame1 = InitFrame::Handshake { magic_number: VELOREN_MAGIC_NUMBER, version: VELOREN_NETWORK_VERSION, }; let _ = InitFrame::to_bytes(frame1.clone(), &mut buffer); buffer.truncate(6); // simulate partial retrieve let frame1d = InitFrame::to_frame(buffer[..6].to_vec()); assert_eq!(frame1d, None); } #[test] fn initframe_rubish() { let buffer = b"dtrgwcser".to_vec(); assert_eq!( InitFrame::to_frame(buffer), Some(InitFrame::Raw(b"dtrgwcser".to_vec())) ); } #[test] fn initframe_attack_too_much_length() { let mut buffer = vec![0u8; 50]; let frame1 = InitFrame::Raw(b"foobar".to_vec()); let _ = InitFrame::to_bytes(frame1.clone(), &mut buffer); buffer[2] = 255; let framed = InitFrame::to_frame(buffer); assert_eq!(framed, None); } #[test] fn initframe_attack_too_low_length() { let mut buffer = vec![0u8; 50]; let frame1 = InitFrame::Raw(b"foobar".to_vec()); let _ = InitFrame::to_bytes(frame1.clone(), &mut buffer); buffer[2] = 3; let framed = InitFrame::to_frame(buffer); assert_eq!(framed, None); } #[test] #[should_panic] fn frame_too_short_buffer() { let mut buffer = vec![0u8; 10]; let frame1 = Frame::OpenStream { sid: Sid::new(88), promises: Promises::ENCRYPTED, prio: 88, }; let _ = Frame::to_bytes(frame1.clone(), &mut buffer); } #[test] fn frame_too_less_data() { let mut buffer = vec![0u8; 20]; let frame1 = Frame::OpenStream { sid: Sid::new(88), promises: Promises::ENCRYPTED, prio: 88, }; let _ = Frame::to_bytes(frame1.clone(), &mut buffer); buffer.truncate(6); // simulate partial retrieve let mut buffer = buffer.drain(..6).collect::>(); let frame1d = Frame::to_frame(&mut buffer); assert_eq!(frame1d, None); } #[test] fn frame_rubish() { let mut buffer = b"dtrgwcser".iter().map(|u| *u).collect::>(); assert_eq!(Frame::to_frame(&mut buffer), None); } #[test] fn frame_attack_too_much_length() { let mut buffer = vec![0u8; 50]; let frame1 = Frame::Data { mid: 7u64, start: 1u64, data: b"foobar".to_vec(), }; let _ = Frame::to_bytes(frame1.clone(), &mut buffer); buffer[17] = 255; let mut buffer = buffer.drain(..).collect::>(); let framed = Frame::to_frame(&mut buffer); assert_eq!(framed, None); } #[test] fn frame_attack_too_low_length() { let mut buffer = vec![0u8; 50]; let frame1 = Frame::Data { mid: 7u64, start: 1u64, data: b"foobar".to_vec(), }; let _ = Frame::to_bytes(frame1.clone(), &mut buffer); buffer[17] = 3; let mut buffer = buffer.drain(..).collect::>(); let framed = Frame::to_frame(&mut buffer); assert_eq!( framed, Some(Frame::Data { mid: 7u64, start: 1u64, data: b"foo".to_vec(), }) ); //next = Invalid => Empty let framed = Frame::to_frame(&mut buffer); assert_eq!(framed, None); } #[test] fn frame_int2str() { assert_eq!(Frame::int_to_string(0), "Shutdown"); assert_eq!(Frame::int_to_string(1), "OpenStream"); assert_eq!(Frame::int_to_string(2), "CloseStream"); assert_eq!(Frame::int_to_string(3), "DataHeader"); assert_eq!(Frame::int_to_string(4), "Data"); } }