initial commit

This commit is contained in:
DJMrTV 2025-01-19 13:02:15 +01:00
commit 0ed05f6116
15 changed files with 645 additions and 0 deletions

221
src/endianness.rs Normal file
View file

@ -0,0 +1,221 @@
use std::io;
use std::io::Read;
use std::marker::PhantomData;
use std::pin::Pin;
use bytemuck::Pod;
#[cfg(target_endian = "little")]
pub const IS_LITTLE_ENDIAN: bool = true;
#[cfg(target_endian = "big")]
pub const IS_LITTLE_ENDIAN: bool = false;
pub const IS_BIG_ENDIAN: bool = !IS_LITTLE_ENDIAN;
pub mod little_endian{
use std::io;
use std::io::Read;
#[inline]
pub fn read_u16(reader: &mut (impl Read + ?Sized)) -> io::Result<u16>{
let mut data = [0u8; 2];
reader.read_exact(&mut data)?;
Ok(((data[0] as u16) << 8) | (data[1] as u16))
}
#[inline]
pub fn read_u32(reader: &mut (impl Read + ?Sized)) -> io::Result<u32>{
let mut data = [0u8; 4];
reader.read_exact(&mut data)?;
Ok(
((data[0] as u32) << 24) |
((data[1] as u32) << 16) |
((data[2] as u32) << 8) |
(data[3] as u32)
)
}
}
pub struct StructMultiReadIter<'a, T: Pod + SwapEndian>{
reader: &'a mut dyn Read,
left_to_read: usize,
swap_endian: bool,
_phantom_data: PhantomData<&'static T>
}
impl<'a, T: Pod + SwapEndian> Iterator for StructMultiReadIter<'a, T>{
type Item = io::Result<T>;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
if self.left_to_read == 0{
None
} else {
Some(self.reader.read_struct(self.swap_endian))
}
}
}
impl<'a, T: Pod + SwapEndian> Drop for StructMultiReadIter<'a, T>{
#[inline]
fn drop(&mut self) {
// read all the structs we would be reading and discard them to make the result after using
// this always be the same
while let Some(_) = self.next() { }
}
}
pub trait ReadExtensions: Read{
#[inline]
fn read_le_u16(&mut self) -> io::Result<u16>{
little_endian::read_u16(self)
}
#[inline]
fn read_le_u32(&mut self) -> io::Result<u32>{
little_endian::read_u32(self)
}
#[inline]
fn read_le_struct<T: Pod + SwapEndian>(&mut self) -> io::Result<T>{
let mut data = T::zeroed();
let bytes = bytemuck::bytes_of_mut(&mut data);
self.read_exact(bytes)?;
if cfg!(not(target_endian = "little")){
data = data.swap_endian();
}
Ok(data)
}
#[inline]
fn read_struct<T: Pod + SwapEndian>(&mut self, swap_endian: bool) -> io::Result<T>{
let mut data = T::zeroed();
let bytes = bytemuck::bytes_of_mut(&mut data);
self.read_exact(bytes)?;
if swap_endian{
data = data.swap_endian();
}
Ok(data)
}
fn read_struct_multi<T: Pod + SwapEndian>(&mut self, swap_endian: bool, count: usize) -> io::Result<StructMultiReadIter<T>>;
}
impl<T: Read> ReadExtensions for T{
// i was forced to put this here because it requires info about self
#[inline]
fn read_struct_multi<U: Pod + SwapEndian>(&mut self, swap_endian: bool, count: usize) -> io::Result<StructMultiReadIter<'_, U>>{
Ok(StructMultiReadIter{
reader: self,
swap_endian,
left_to_read: count,
_phantom_data: Default::default()
})
}
}
pub trait SwapEndian: Clone + Copy{
fn swap_endian(self) -> Self;
}
impl SwapEndian for u8{
#[inline]
fn swap_endian(self) -> Self {
self
}
}
impl SwapEndian for u16{
#[inline]
fn swap_endian(self) -> Self {
self.swap_bytes()
}
}
impl SwapEndian for u32{
#[inline]
fn swap_endian(self) -> Self {
self.swap_bytes()
}
}
impl SwapEndian for u64{
#[inline]
fn swap_endian(self) -> Self {
self.swap_bytes()
}
}
impl SwapEndian for i8{
#[inline]
fn swap_endian(self) -> Self {
self
}
}
impl SwapEndian for i16{
#[inline]
fn swap_endian(self) -> Self {
self.swap_bytes()
}
}
impl SwapEndian for i32{
#[inline]
fn swap_endian(self) -> Self {
self.swap_bytes()
}
}
impl SwapEndian for i64{
#[inline]
fn swap_endian(self) -> Self {
self.swap_bytes()
}
}
impl<T: SwapEndian, U: SwapEndian> SwapEndian for (T, U){
#[inline]
fn swap_endian(self) -> Self {
(self.0.swap_endian(), self.1.swap_endian())
}
}
impl<T: SwapEndian, U: SwapEndian, V: SwapEndian> SwapEndian for (T, U, V){
#[inline]
fn swap_endian(self) -> Self {
(self.0.swap_endian(), self.1.swap_endian(), self.2.swap_endian())
}
}
impl<T: SwapEndian, U: SwapEndian, V: SwapEndian, W: SwapEndian> SwapEndian for (T, U, V, W){
#[inline]
fn swap_endian(self) -> Self {
(self.0.swap_endian(), self.1.swap_endian(), self.2.swap_endian(), self.3.swap_endian())
}
}
impl<T: SwapEndian, const size: usize> SwapEndian for [T; size]{
#[inline]
fn swap_endian(mut self) -> Self {
for elem in &mut self{
*elem = elem.swap_endian();
}
self
}
}

6
src/main.rs Normal file
View file

@ -0,0 +1,6 @@
mod endianness;
mod prudp;
fn main() {
println!("Hello, world!");
}

0
src/prudp/auth_module.rs Normal file
View file

3
src/prudp/endpoint.rs Normal file
View file

@ -0,0 +1,3 @@
pub struct Endpoint{
}

4
src/prudp/mod.rs Normal file
View file

@ -0,0 +1,4 @@
pub mod packet;
mod server;
mod endpoint;
mod auth_module;

228
src/prudp/packet.rs Normal file
View file

@ -0,0 +1,228 @@
use std::fmt::{Debug, Formatter};
use std::hint::unreachable_unchecked;
use std::io;
use std::io::{Cursor, ErrorKind, Read, Seek};
use bytemuck::{Pod, Zeroable};
use thiserror::Error;
use v_byte_macros::{EnumTryInto, SwapEndian};
use crate::endianness::{IS_BIG_ENDIAN, IS_LITTLE_ENDIAN, ReadExtensions};
#[derive(Error, Debug)]
pub enum Error{
#[error("{0}")]
IO(#[from] io::Error),
#[error("invalid magic {0:#06x}")]
InvalidMagic(u16),
#[error("invalid version {0}")]
InvalidVersion(u8),
#[error("invalid option id {0}")]
InvalidOptionId(u8),
#[error("option size {size} doesnt match expected option for given option id {id}")]
InvalidOptionSize{
id: u8,
size: u8
}
}
pub type Result<T> = std::result::Result<T, Error>;
#[repr(transparent)]
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian)]
pub struct TypesFlags(u16);
impl TypesFlags{
pub fn get_types(self) -> u8 {
(self.0 & 0x000F) as u8
}
pub fn get_flags(self) -> u16 {
(self.0 & 0xFFF0) >> 4
}
pub fn types(self, val: u8) -> Self {
Self((self.0 & 0xFFF0) | (val as u16 & 0x000F))
}
pub fn flags(self, val: u16) -> Self {
Self((self.0 & 0x000F) | ((val << 4) & 0xFFF0) )
}
}
impl Debug for TypesFlags{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let stream_type = self.get_types();
let port_number = self.get_flags();
write!(f, "TypesFlags{{ types: {}, flags: {} }}", stream_type, port_number)
}
}
#[repr(transparent)]
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian)]
pub struct VirtualPort(u8);
impl VirtualPort{
pub fn get_stream_type(self) -> u8 {
(self.0 & 0x0F) as u8
}
pub fn get_port_number(self) -> u8 {
(self.0 & 0xF0) >> 4
}
pub fn stream_type(self, val: u8) -> Self {
let masked_val = val & 0x0F;
assert_eq!(masked_val, val);
Self((self.0 & 0xF0) | masked_val)
}
pub fn port_number(self, val: u8) -> Self {
let masked_val = val & 0x0F;
assert_eq!(masked_val, val);
Self((self.0 & 0x0F) | (masked_val << 4))
}
}
impl Debug for VirtualPort{
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
let stream_type = self.get_stream_type();
let port_number = self.get_port_number();
write!(f, "VirtualPort{{ stream_type: {}, port_number: {} }}", stream_type, port_number)
}
}
#[repr(C, packed)]
#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian)]
pub struct PRUDPHeader{
magic: [u8; 2],
version: u8,
pub packet_specific_size: u8,
pub payload_size: u16,
pub source_port: VirtualPort,
pub destination_port: VirtualPort,
pub types_and_flags: TypesFlags,
pub session_id: u8,
pub substream_id: u8,
pub sequence_id: u16,
}
#[repr(u16)]
#[derive(EnumTryInto)]
enum PacketSpecificData{
E = 0x10
}
#[derive(Debug)]
pub struct PRUDPPacket{
pub header: PRUDPHeader
}
#[derive(Copy, Clone, Debug)]
// Invariant: can only contain 0, 1, 2, 3 or 4
struct OptionId(u8);
impl OptionId{
fn new(val: u8) -> Result<Self>{
// Invariant is upheld because we only create the object if it doesn't violate the invariant
match val {
0 | 1 | 2 | 3 | 4 => Ok(Self(val)),
_ => Err(Error::InvalidOptionId(val))
}
}
fn option_type_size(self) -> u8{
match self.0{
0 => 4,
1 => 16,
2 => 1,
3 => 2,
4 => 1,
// Getting here would mean that the invariant has been violated, thus this isnt my
// problem lmao
_ => unsafe { unreachable_unchecked() }
}
}
}
impl Into<u8> for OptionId{
fn into(self) -> u8 {
self.0
}
}
impl PRUDPPacket{
pub fn new(reader: &mut (impl Read + Seek)) -> Result<Self>{
let header: PRUDPHeader = reader.read_struct(IS_BIG_ENDIAN)?;
if header.magic[0] != 0xEA ||
header.magic[1] != 0xD0{
return Err(Error::InvalidMagic(u16::from_be_bytes(header.magic)));
}
if header.version != 1{
return Err(Error::InvalidVersion(header.version))
}
//discard it for now
let _: [u8; 16] = reader.read_struct(IS_BIG_ENDIAN)?;
assert_eq!(reader.stream_position().ok(), Some(14+16));
let mut packet_specific_buffer = vec![0u8; header.packet_specific_size as usize];
reader.read_exact(&mut packet_specific_buffer)?;
//no clue whats up with options but they are broken
/*let mut packet_specific_data_cursor = Cursor::new(&packet_specific_buffer);
loop {
let Ok(option_id): io::Result<u8> = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else {
break
};
let Ok(value_size): io::Result<u8> = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else {
break
};
if value_size == 0 {
// skip it if its 0 and dont check?
continue;
}
let option_id: OptionId = OptionId::new(option_id)?;
if option_id.option_type_size() != value_size{
return Err(Error::InvalidOptionSize {
size: value_size,
id: option_id.0
})
}
let mut option_data = vec![0u8,value_size];
if packet_specific_data_cursor.read_exact(&mut option_data).is_err(){
break;
}
}*/
let mut packet_payload = vec![0u8; header.payload_size as usize];
reader.read_exact(&mut packet_payload)?;
Ok(Self{
header
})
}
}
#[cfg(test)]
mod test{
use super::{PRUDPHeader};
#[test]
fn size_test(){
assert_eq!(size_of::<PRUDPHeader>(), 14);
}
}

42
src/prudp/server.rs Normal file
View file

@ -0,0 +1,42 @@
use std::marker::PhantomData;
use std::ops::{Deref, DerefMut};
use std::sync::{Arc, Mutex};
use crate::prudp::endpoint::Endpoint;
pub struct NexServer{
pub endpoints: Mutex<Vec<Endpoint>>,
_no_outside_construction: PhantomData<()>
}
impl NexServer{
fn server_thread_entry(){
}
pub fn new() -> Arc<Self>{
let own_impl = NexServer{
endpoints: Default::default(),
_no_outside_construction: Default::default()
};
let arc = Arc::new(own_impl);
}
}
#[cfg(test)]
mod test{
use std::ops::Deref;
use std::sync::Arc;
use crate::prudp::server::{NexServer};
#[test]
fn test(){
let server = NexServer::new();
let a = (server.deref()).clone();
}
}