diff --git a/crates/proto/src/error.rs b/crates/proto/src/error.rs index e3490534..c32cb232 100644 --- a/crates/proto/src/error.rs +++ b/crates/proto/src/error.rs @@ -71,6 +71,8 @@ pub enum TransportLayerError { IOError(#[from] Arc), #[error("Raknet UDP Error: {0}")] RaknetUDPError(#[from] RaknetError), + #[error("UDP Error: {0}")] + UDPError(#[from] UdpError), } #[derive(Error, Debug, Clone)] @@ -84,3 +86,11 @@ pub enum RaknetError { #[error("Format Error: {0}")] FormatError(String), } + +#[derive(Error, Debug, Clone)] +pub enum UdpError { + #[error("Error while Receive: {0}")] + RecvError(#[from] RecvError), + #[error("Format Error: {0}")] + FormatError(String), +} diff --git a/crates/proto/src/listener.rs b/crates/proto/src/listener.rs index 50ba13fb..64f6e22a 100644 --- a/crates/proto/src/listener.rs +++ b/crates/proto/src/listener.rs @@ -7,10 +7,10 @@ use rand::RngCore; use crate::connection::Connection; use crate::error::{ListenerError, RaknetError, TransportLayerError}; use crate::info::{MINECRAFT_EDITION_MOTD, MINECRAFT_VERSION, PROTOCOL_VERSION}; -use crate::transport_layer::TransportLaterListener; +use crate::transport_layer::TransportLayerListener; pub struct Listener { - listener: TransportLaterListener, + listener: TransportLayerListener, name: String, sub_name: String, player_count_max: u32, @@ -61,7 +61,7 @@ impl Listener { }; Ok(Self { - listener: TransportLaterListener::RaknetUDP(rak_listener), + listener: TransportLayerListener::RaknetUDP(rak_listener), name, sub_name, player_count_max, diff --git a/crates/proto/src/transport_layer/connection.rs b/crates/proto/src/transport_layer/connection.rs index 2f5a648d..7e173e3d 100644 --- a/crates/proto/src/transport_layer/connection.rs +++ b/crates/proto/src/transport_layer/connection.rs @@ -3,7 +3,7 @@ use std::sync::Arc; use bedrockrs_core::int::LE; -use crate::error::{RaknetError, TransportLayerError}; +use crate::error::{RaknetError, TransportLayerError, UdpError}; use crate::info::RAKNET_GAME_PACKET_ID; /// @@ -12,8 +12,8 @@ pub enum TransportLayerConnection { // TODO RaknetTCP(...), NetherNet(/* TODO */), // TODO Quic(s2n_quic::connection::Connection), - // TODO Tcp(net::TcpStream), - // TODO Udp(net::UdpSocket) + // Tcp(std::net::TcpStream), + Udp(tokio::net::UdpSocket) //MCBE over UDP :sobb:?? } impl TransportLayerConnection { @@ -34,6 +34,22 @@ impl TransportLayerConnection { .await .map_err(|e| TransportLayerError::RaknetUDPError(RaknetError::SendError(e))) } + TransportLayerConnection::Udp(conn) => { + //BIO + let mut final_stream = vec![]; + + LE::::write(&LE::new(RAKNET_GAME_PACKET_ID), &mut final_stream) + .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?; + + final_stream + .write_all(stream.get_ref()) + .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?; + + conn.send(final_stream.as_slice()) + .await + .map(|_| ()) + .map_err(|e| TransportLayerError::IOError(Arc::new(e))) //udp send error is std::io::Error + } _ => { todo!() } @@ -70,6 +86,39 @@ impl TransportLayerConnection { .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?) } + TransportLayerConnection::Udp(conn) => { + // TODO: Configure the socket for non-blocking (NIO) mode to improve efficiency and responsiveness. + // Non-blocking I/O allows the program to perform other tasks while waiting for I/O operations to complete, + // thereby avoiding potential bottlenecks and enhancing overall performance in high-concurrency scenarios. + let mut recv_buffer: Vec = vec![0; 4096]; + let _amt = conn + .recv(&mut recv_buffer) + .await + .map(|_| ()) + .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?; + + let mut recv_buffer = Cursor::new(recv_buffer.as_slice()); + + match LE::::read(&mut recv_buffer) + .map_err(|e| TransportLayerError::IOError(Arc::new(e)))? + .into_inner() + { + RAKNET_GAME_PACKET_ID => {} + other => { + return Err(TransportLayerError::UDPError( + UdpError::FormatError(format!( + "Expected RakNet Game Packet ID ({:?}), got: {:?}", + RAKNET_GAME_PACKET_ID, other + )), + )); + } + }; + + Ok(stream + .write_all(recv_buffer.into_inner()) + .map_err(|e| TransportLayerError::IOError(Arc::new(e)))?) + } + _ => { todo!() } @@ -81,6 +130,9 @@ impl TransportLayerConnection { TransportLayerConnection::RaknetUDP(conn) => { conn.close().await; } + TransportLayerConnection::Udp(socket) => { + std::mem::drop(socket); //for closing the socket explicitly(...do we need it?) + } _ => { todo!() } diff --git a/crates/proto/src/transport_layer/listener.rs b/crates/proto/src/transport_layer/listener.rs index 500283b3..5af18a67 100644 --- a/crates/proto/src/transport_layer/listener.rs +++ b/crates/proto/src/transport_layer/listener.rs @@ -1,15 +1,15 @@ use crate::error::{RaknetError, TransportLayerError}; use crate::transport_layer::TransportLayerConnection; -pub enum TransportLaterListener { +pub enum TransportLayerListener { RaknetUDP(rak_rs::Listener), NetherNet(/* TODO */), } -impl TransportLaterListener { +impl TransportLayerListener { pub async fn start(&mut self) -> Result<(), TransportLayerError> { match self { - TransportLaterListener::RaknetUDP(listener) => match listener.start().await { + TransportLayerListener::RaknetUDP(listener) => match listener.start().await { Ok(_) => Ok(()), Err(e) => Err(TransportLayerError::RaknetUDPError( RaknetError::ServerError(e), @@ -23,7 +23,7 @@ impl TransportLaterListener { pub async fn accept(&mut self) -> Result { match self { - TransportLaterListener::RaknetUDP(listener) => match listener.accept().await { + TransportLayerListener::RaknetUDP(listener) => match listener.accept().await { Ok(conn) => Ok(TransportLayerConnection::RaknetUDP(conn)), Err(e) => Err(TransportLayerError::RaknetUDPError( RaknetError::ServerError(e),