v2
This commit is contained in:
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
0 15 31
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 1 | msg_type(7) |max ttl(4) |curr ttl(4)| C | G | R | reserve(13) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| seq(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| src ID(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| dest ID(32) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| payload(n) |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
*/
|
||||
#![allow(dead_code)]
|
||||
use crate::protocol::transmission::TransmissionBytes;
|
||||
use bytes::{Bytes, BytesMut};
|
||||
use std::io;
|
||||
use zerocopy::byteorder::{NetworkEndian, U32};
|
||||
use zerocopy::{FromBytes, Immutable, IntoBytes, KnownLayout, Ref, Unaligned};
|
||||
|
||||
#[derive(Debug, FromBytes, IntoBytes, Unaligned, KnownLayout, Immutable)]
|
||||
#[repr(C)]
|
||||
pub struct NetHeader {
|
||||
/// Byte 0: bit7 = 1, bit0..6 = msg_type
|
||||
pub type_byte: u8,
|
||||
/// Byte 1: high 4 = max ttl, low 4 = curr ttl
|
||||
pub ttl_byte: u8,
|
||||
/// Byte 2: C(0x80) | G(0x40) | reserve
|
||||
pub flags_byte: u8,
|
||||
/// Byte 3: reserve
|
||||
pub _reserved: u8,
|
||||
|
||||
pub seq: U32<NetworkEndian>,
|
||||
pub src_id: U32<NetworkEndian>,
|
||||
pub dest_id: U32<NetworkEndian>,
|
||||
}
|
||||
const COMPRESSED: u8 = 0x80;
|
||||
const GATEWAY: u8 = 0x40;
|
||||
const FEC: u8 = 0x20;
|
||||
impl NetHeader {
|
||||
#[inline]
|
||||
pub fn msg_type(&self) -> u8 {
|
||||
self.type_byte & 0x7F
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_msg_type(&mut self, msg_type: u8) {
|
||||
self.type_byte = (msg_type & 0x7F) | 0x80;
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn max_ttl(&self) -> u8 {
|
||||
self.ttl_byte >> 4
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn curr_ttl(&self) -> u8 {
|
||||
self.ttl_byte & 0x0F
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn set_ttl(&mut self, max: u8, curr: u8) {
|
||||
self.ttl_byte = (max << 4) | (curr & 0x0F);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn decr_ttl(&mut self) {
|
||||
let curr = self.curr_ttl();
|
||||
if curr == 0 {
|
||||
return;
|
||||
}
|
||||
self.ttl_byte = (self.ttl_byte & 0xF0) | (curr - 1);
|
||||
}
|
||||
|
||||
fn set_flag(&mut self, mask: u8, val: bool) {
|
||||
if val {
|
||||
self.flags_byte |= mask;
|
||||
} else {
|
||||
self.flags_byte &= !mask;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Eq, PartialEq, Debug)]
|
||||
pub enum MsgType {
|
||||
Turn = 1,
|
||||
Broadcast = 2,
|
||||
ExcludeBroadcast = 3,
|
||||
TargetBroadcast = 4,
|
||||
|
||||
Ping = 5,
|
||||
Pong = 6,
|
||||
PingTurn = 7,
|
||||
PongTurn = 8,
|
||||
|
||||
PunchStart1 = 9,
|
||||
PunchStart2 = 10,
|
||||
PunchReq = 11,
|
||||
PunchRes = 12,
|
||||
|
||||
PushClientIps = 13,
|
||||
|
||||
RpcReq = 14,
|
||||
RpcRes = 15,
|
||||
|
||||
Quic = 17,
|
||||
}
|
||||
impl From<MsgType> for u8 {
|
||||
fn from(val: MsgType) -> Self {
|
||||
val as u8
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<u8> for MsgType {
|
||||
type Error = io::Error;
|
||||
|
||||
fn try_from(value: u8) -> Result<Self, Self::Error> {
|
||||
let val = match value {
|
||||
1 => MsgType::Turn,
|
||||
2 => MsgType::Broadcast,
|
||||
3 => MsgType::ExcludeBroadcast,
|
||||
4 => MsgType::TargetBroadcast,
|
||||
|
||||
5 => MsgType::Ping,
|
||||
6 => MsgType::Pong,
|
||||
7 => MsgType::PingTurn,
|
||||
8 => MsgType::PongTurn,
|
||||
|
||||
9 => MsgType::PunchStart1,
|
||||
10 => MsgType::PunchStart2,
|
||||
11 => MsgType::PunchReq,
|
||||
12 => MsgType::PunchRes,
|
||||
|
||||
13 => MsgType::PushClientIps,
|
||||
|
||||
14 => MsgType::RpcReq,
|
||||
15 => MsgType::RpcRes,
|
||||
|
||||
17 => MsgType::Quic,
|
||||
_ => {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
format!("invalid msg type:{value}"),
|
||||
));
|
||||
}
|
||||
};
|
||||
Ok(val)
|
||||
}
|
||||
}
|
||||
|
||||
pub const HEAD_LENGTH: usize = std::mem::size_of::<NetHeader>();
|
||||
|
||||
pub struct NetPacket<B> {
|
||||
buffer: B,
|
||||
}
|
||||
impl<B: AsRef<[u8]>> NetPacket<B> {
|
||||
pub fn new(buffer: B) -> io::Result<NetPacket<B>> {
|
||||
if buffer.as_ref().len() < HEAD_LENGTH {
|
||||
return Err(io::ErrorKind::InvalidInput.into());
|
||||
}
|
||||
Ok(NetPacket { buffer })
|
||||
}
|
||||
fn header(&self) -> Ref<&[u8], NetHeader> {
|
||||
// Safe: NetHeader is Unaligned and length is validated in new()
|
||||
let (header, _) = Ref::<&[u8], NetHeader>::from_prefix(self.buffer.as_ref()).unwrap();
|
||||
header
|
||||
}
|
||||
pub fn buffer(&self) -> &[u8] {
|
||||
self.buffer.as_ref()
|
||||
}
|
||||
pub fn into_buffer(self) -> B {
|
||||
self.buffer
|
||||
}
|
||||
pub fn source_buf(&self) -> &B {
|
||||
&self.buffer
|
||||
}
|
||||
pub fn msg_type(&self) -> io::Result<MsgType> {
|
||||
self.header().msg_type().try_into()
|
||||
}
|
||||
pub fn max_ttl(&self) -> u8 {
|
||||
self.header().max_ttl()
|
||||
}
|
||||
pub fn ttl(&self) -> u8 {
|
||||
self.header().curr_ttl()
|
||||
}
|
||||
|
||||
pub fn seq(&self) -> u32 {
|
||||
self.header().seq.get()
|
||||
}
|
||||
|
||||
pub fn src_id(&self) -> u32 {
|
||||
self.header().src_id.get()
|
||||
}
|
||||
|
||||
pub fn dest_id(&self) -> u32 {
|
||||
self.header().dest_id.get()
|
||||
}
|
||||
pub fn is_compressed(&self) -> bool {
|
||||
(self.header().flags_byte & COMPRESSED) != 0
|
||||
}
|
||||
pub fn is_gateway(&self) -> bool {
|
||||
(self.header().flags_byte & GATEWAY) != 0
|
||||
}
|
||||
pub fn is_fec(&self) -> bool {
|
||||
(self.header().flags_byte & FEC) != 0
|
||||
}
|
||||
pub fn head(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[..HEAD_LENGTH]
|
||||
}
|
||||
pub fn payload(&self) -> &[u8] {
|
||||
&self.buffer.as_ref()[HEAD_LENGTH..]
|
||||
}
|
||||
}
|
||||
|
||||
impl<B: AsRef<[u8]> + AsMut<[u8]>> NetPacket<B> {
|
||||
fn header_mut(&mut self) -> Ref<&mut [u8], NetHeader> {
|
||||
// Safe: NetHeader is Unaligned and length is validated in new()
|
||||
let (header, _) = Ref::<&mut [u8], NetHeader>::from_prefix(self.buffer.as_mut()).unwrap();
|
||||
header
|
||||
}
|
||||
|
||||
pub fn set_msg_type(&mut self, msg_type: MsgType) {
|
||||
self.header_mut().set_msg_type(msg_type.into());
|
||||
}
|
||||
|
||||
pub fn decr_ttl(&mut self){
|
||||
self.header_mut().decr_ttl()
|
||||
}
|
||||
|
||||
pub fn set_ttl(&mut self, ttl: u8) {
|
||||
self.header_mut().set_ttl(ttl, ttl);
|
||||
}
|
||||
|
||||
pub fn set_seq(&mut self, seq: u32) {
|
||||
self.header_mut().seq.set(seq);
|
||||
}
|
||||
|
||||
pub fn set_src_id(&mut self, id: u32) {
|
||||
self.header_mut().src_id.set(id);
|
||||
}
|
||||
|
||||
pub fn set_dest_id(&mut self, id: u32) {
|
||||
self.header_mut().dest_id.set(id);
|
||||
}
|
||||
|
||||
pub fn set_compressed_flag(&mut self, compressed: bool) {
|
||||
self.header_mut().set_flag(COMPRESSED, compressed);
|
||||
}
|
||||
pub fn set_gateway_flag(&mut self, gateway: bool) {
|
||||
self.header_mut().set_flag(GATEWAY, gateway);
|
||||
}
|
||||
pub fn set_fec_flag(&mut self, fec: bool) {
|
||||
self.header_mut().set_flag(FEC, fec);
|
||||
}
|
||||
|
||||
pub fn set_payload(&mut self, data: &[u8]) -> io::Result<()> {
|
||||
let buf = self.buffer.as_mut();
|
||||
if buf.len() < HEAD_LENGTH + data.len() {
|
||||
return Err(io::Error::new(
|
||||
io::ErrorKind::InvalidInput,
|
||||
"Invalid message length",
|
||||
));
|
||||
}
|
||||
buf[HEAD_LENGTH..HEAD_LENGTH + data.len()].copy_from_slice(data);
|
||||
Ok(())
|
||||
}
|
||||
pub fn head_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[..HEAD_LENGTH]
|
||||
}
|
||||
pub fn payload_mut(&mut self) -> &mut [u8] {
|
||||
&mut self.buffer.as_mut()[HEAD_LENGTH..]
|
||||
}
|
||||
pub fn source_buf_mut(&mut self) -> &mut B {
|
||||
&mut self.buffer
|
||||
}
|
||||
}
|
||||
|
||||
impl Clone for NetPacket<Bytes> {
|
||||
fn clone(&self) -> Self {
|
||||
NetPacket {
|
||||
buffer: self.buffer.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetPacket<BytesMut> {
|
||||
pub fn into_bytes(self) -> NetPacket<Bytes> {
|
||||
NetPacket {
|
||||
buffer: self.buffer.freeze(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl NetPacket<TransmissionBytes> {
|
||||
pub fn into_bytes(self) -> NetPacket<Bytes> {
|
||||
NetPacket {
|
||||
buffer: self.buffer.into_bytes().freeze(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user