From 7234e36d1d531af0a71090afeaf94a96b21d5926 Mon Sep 17 00:00:00 2001 From: vE5li Date: Thu, 2 May 2024 22:11:55 +0200 Subject: [PATCH] Move korangar_packets handler to separate module --- korangar/src/main.rs | 3 +- korangar_networking/src/lib.rs | 1 + ragnarok_packets/src/handler.rs | 244 ++++++++++++++++++++++++++++++++ ragnarok_packets/src/lib.rs | 220 +--------------------------- 4 files changed, 250 insertions(+), 218 deletions(-) create mode 100644 ragnarok_packets/src/handler.rs diff --git a/korangar/src/main.rs b/korangar/src/main.rs index e0ce334d..7e7d98cb 100644 --- a/korangar/src/main.rs +++ b/korangar/src/main.rs @@ -100,7 +100,8 @@ mod packet_recorder { use korangar_debug::profiling::RingBuffer; use korangar_interface::elements::WeakElementCell; - use ragnarok_packets::{IncomingPacket, OutgoingPacket, PacketCallback, PacketHeader, UnknownPacket}; + use ragnarok_packets::handler::{PacketCallback, UnknownPacket}; + use ragnarok_packets::{IncomingPacket, OutgoingPacket, PacketHeader}; use crate::interface::application::InterfaceSettings; use crate::interface::elements::PacketEntry; diff --git a/korangar_networking/src/lib.rs b/korangar_networking/src/lib.rs index c5c24491..a06c7147 100644 --- a/korangar_networking/src/lib.rs +++ b/korangar_networking/src/lib.rs @@ -14,6 +14,7 @@ use event::{ NoNetworkEvents, }; use ragnarok_bytes::{ByteStream, FromBytes}; +use ragnarok_packets::handler::{DuplicateHandlerError, HandlerResult, NoPacketCallback, PacketCallback, PacketHandler}; use ragnarok_packets::*; use server::{ServerConnectCommand, ServerConnection}; use tokio::io::{AsyncReadExt, AsyncWriteExt}; diff --git a/ragnarok_packets/src/handler.rs b/ragnarok_packets/src/handler.rs new file mode 100644 index 00000000..9e4b6667 --- /dev/null +++ b/ragnarok_packets/src/handler.rs @@ -0,0 +1,244 @@ +use std::collections::HashMap; + +use derive_new::new; +use ragnarok_bytes::{ByteStream, ConversionError, ConversionResult, FromBytes}; + +use crate::{IncomingPacket, OutgoingPacket, PacketHeader}; + +/// Helper struct for working with unknown incoming packets. +#[derive(Clone, new)] +pub struct UnknownPacket { + pub bytes: Vec, +} + +impl IncomingPacket for UnknownPacket { + const HEADER: PacketHeader = PacketHeader(0); + const IS_PING: bool = false; + + fn payload_from_bytes(byte_stream: &mut ByteStream) -> ConversionResult { + let _ = byte_stream; + unimplemented!() + } + + #[cfg(feature = "packet-to-prototype-element")] + fn to_prototype_element( + &self, + ) -> Box + Send> { + Box::new(self.clone()) + } +} + +#[cfg(feature = "interface")] +impl korangar_interface::elements::PrototypeElement for UnknownPacket { + fn to_element(&self, display: String) -> korangar_interface::elements::ElementCell { + use korangar_interface::elements::{ElementWrap, Expandable}; + + let mut byte_stream = ByteStream::<()>::without_metadata(&self.bytes); + + let elements = match self.bytes.len() >= 2 { + true => { + let signature = PacketHeader::from_bytes(&mut byte_stream).unwrap(); + let header = format!("0x{:0>4x}", signature.0); + let data = &self.bytes[byte_stream.get_offset()..]; + + vec![header.to_element("header".to_owned()), data.to_element("data".to_owned())] + } + false => { + vec![self.bytes.to_element("data".to_owned())] + } + }; + + Expandable::new(display, elements, false).wrap() + } +} + +/// Possible results of [`PacketHandler::process_one`]. +pub enum HandlerResult { + /// Packet was successfully processed and produced some output. + Ok(Output), + /// No packet handler was registered for the incoming packet. + UnhandledPacket, + /// Packet was most likely cut-off. + PacketCutOff, + /// An error occurred inside the packet handler. + InternalError(Box), +} + +/// Error when trying to register two separate handlers for the same packet. +#[derive(Debug, Clone)] +pub struct DuplicateHandlerError { + /// Header of the packet. + pub packet_header: PacketHeader, +} + +/// Trait for monitoring the incoming and outgoing packets. +pub trait PacketCallback: Clone + Send + 'static { + /// Called by the [`PacketHandler`] when a packet is received. + fn incoming_packet(&self, packet: &Packet) + where + Packet: IncomingPacket; + + /// Called by the [`NetworkingSystem`](super::NetworkingSystem) when a + /// packet is sent. + fn outgoing_packet(&self, packet: &Packet) + where + Packet: OutgoingPacket; + + /// Called by the [`PacketHandler`] when a packet arrives that doesn't have + /// a handler registered. + fn unknown_packet(&self, packet: &UnknownPacket); + + /// Called by the [`PacketHandler`] when a packet handler returned an error. + fn failed_packet(&self, header: PacketHeader, error: Box); +} + +#[derive(Debug, Default, Clone)] +pub struct NoPacketCallback; + +impl PacketCallback for NoPacketCallback { + fn incoming_packet(&self, _packet: &Packet) + where + Packet: IncomingPacket, + { + } + + fn outgoing_packet(&self, _packet: &Packet) + where + Packet: OutgoingPacket, + { + } + + fn unknown_packet(&self, _packet: &UnknownPacket) {} + + fn failed_packet(&self, _header: PacketHeader, _error: Box) {} +} + +pub type HandlerFunction = Box) -> ConversionResult>; + +/// A struct to help with reading packets from from a [`ByteStream`] and +/// converting them to some common event type. +/// +/// It allows passing a packet callback to monitor incoming packets. +pub struct PacketHandler +where + Meta: 'static, +{ + handlers: HashMap>, + packet_callback: Callback, +} + +impl Default for PacketHandler +where + Meta: 'static, + Callback: Default, +{ + fn default() -> Self { + Self { + handlers: Default::default(), + packet_callback: Default::default(), + } + } +} + +impl PacketHandler +where + Meta: Default + 'static, + Output: Default, + Callback: PacketCallback, +{ + /// Create a new packet handler with a callback. + pub fn with_callback(packet_callback: Callback) -> Self { + Self { + handlers: Default::default(), + packet_callback, + } + } + + /// Register a new packet handler. + pub fn register(&mut self, handler: impl Fn(Packet) -> Return + 'static) -> Result<(), DuplicateHandlerError> + where + Packet: IncomingPacket, + Return: Into, + { + let packet_callback = self.packet_callback.clone(); + let old_handler = self.handlers.insert( + Packet::HEADER, + Box::new(move |byte_stream| { + let packet = Packet::payload_from_bytes(byte_stream)?; + + packet_callback.incoming_packet(&packet); + + Ok(handler(packet).into()) + }), + ); + + match old_handler.is_some() { + true => Err(DuplicateHandlerError { + packet_header: Packet::HEADER, + }), + false => Ok(()), + } + } + + /// Register a noop packet handler. + pub fn register_noop(&mut self) -> Result<(), DuplicateHandlerError> + where + Packet: IncomingPacket, + { + let packet_callback = self.packet_callback.clone(); + let old_handler = self.handlers.insert( + Packet::HEADER, + Box::new(move |byte_stream| { + let packet = Packet::payload_from_bytes(byte_stream)?; + + packet_callback.incoming_packet(&packet); + + Ok(Output::default()) + }), + ); + + match old_handler.is_some() { + true => Err(DuplicateHandlerError { + packet_header: Packet::HEADER, + }), + false => Ok(()), + } + } + + /// Take a single packet from the byte stream. + pub fn process_one(&mut self, byte_stream: &mut ByteStream) -> HandlerResult { + let save_point = byte_stream.create_save_point(); + + let Ok(header) = PacketHeader::from_bytes(byte_stream) else { + // Packet is cut-off at the header. + byte_stream.restore_save_point(save_point); + return HandlerResult::PacketCutOff; + }; + + let Some(handler) = self.handlers.get(&header) else { + byte_stream.restore_save_point(save_point); + + self.packet_callback.unknown_packet(&UnknownPacket { + bytes: byte_stream.remaining_bytes(), + }); + + return HandlerResult::UnhandledPacket; + }; + + match handler(byte_stream) { + Ok(output) => HandlerResult::Ok(output), + // Cut-off packet (probably). + Err(error) if error.is_byte_stream_too_short() => { + byte_stream.restore_save_point(save_point); + HandlerResult::PacketCutOff + } + Err(error) => { + byte_stream.restore_save_point(save_point); + + self.packet_callback.failed_packet(header, error.clone()); + + HandlerResult::InternalError(error) + } + } + } +} diff --git a/ragnarok_packets/src/lib.rs b/ragnarok_packets/src/lib.rs index 3e270d34..17fb19f8 100644 --- a/ragnarok_packets/src/lib.rs +++ b/ragnarok_packets/src/lib.rs @@ -1,4 +1,5 @@ -use std::collections::HashMap; +pub mod handler; + use std::net::Ipv4Addr; use derive_new::new; @@ -13,6 +14,7 @@ use ragnarok_procedural::{CharacterServer, IncomingPacket, LoginServer, MapServe // To make proc macros work in korangar_interface. extern crate self as ragnarok_packets; +/// The header of a Ragnarok Online packet. It is always two bytes long. #[derive(Debug, Clone, Copy, PartialEq, Eq, ByteConvertable, PartialOrd, Ord, Hash)] pub struct PacketHeader(pub u16); @@ -2654,219 +2656,3 @@ pub struct ChangeMapCellPacket { #[length_hint(16)] pub map_name: String, } - -/// Helper struct for working with unknown incoming packets. -#[derive(Clone, new)] -pub struct UnknownPacket { - pub bytes: Vec, -} - -impl IncomingPacket for UnknownPacket { - const HEADER: PacketHeader = PacketHeader(0); - const IS_PING: bool = false; - - fn payload_from_bytes(byte_stream: &mut ByteStream) -> ConversionResult { - let _ = byte_stream; - unimplemented!() - } - - #[cfg(feature = "packet-to-prototype-element")] - fn to_prototype_element( - &self, - ) -> Box + Send> { - Box::new(self.clone()) - } -} - -#[cfg(feature = "interface")] -impl korangar_interface::elements::PrototypeElement for UnknownPacket { - fn to_element(&self, display: String) -> korangar_interface::elements::ElementCell { - use korangar_interface::elements::{ElementWrap, Expandable}; - - let mut byte_stream = ByteStream::<()>::without_metadata(&self.bytes); - - let elements = match self.bytes.len() >= 2 { - true => { - let signature = PacketHeader::from_bytes(&mut byte_stream).unwrap(); - let header = format!("0x{:0>4x}", signature.0); - let data = &self.bytes[byte_stream.get_offset()..]; - - vec![header.to_element("header".to_owned()), data.to_element("data".to_owned())] - } - false => { - vec![self.bytes.to_element("data".to_owned())] - } - }; - - Expandable::new(display, elements, false).wrap() - } -} - -pub enum HandlerResult { - Ok(Output), - UnhandledPacket, - PacketCutOff, - InternalError(Box), -} - -#[derive(Debug, Clone)] -pub struct DuplicateHandlerError { - pub packet_header: PacketHeader, -} - -pub trait PacketCallback: Clone + Send + 'static { - fn incoming_packet(&self, packet: &Packet) - where - Packet: IncomingPacket; - - fn outgoing_packet(&self, packet: &Packet) - where - Packet: OutgoingPacket; - - fn unknown_packet(&self, packet: &UnknownPacket); - - fn failed_packet(&self, header: PacketHeader, error: Box); -} - -#[derive(Debug, Default, Clone)] -pub struct NoPacketCallback; - -impl PacketCallback for NoPacketCallback { - fn incoming_packet(&self, _packet: &Packet) - where - Packet: IncomingPacket, - { - } - - fn outgoing_packet(&self, _packet: &Packet) - where - Packet: OutgoingPacket, - { - } - - fn unknown_packet(&self, _packet: &UnknownPacket) {} - - fn failed_packet(&self, _header: PacketHeader, _error: Box) {} -} - -pub type HandlerFunction = Box) -> ConversionResult>; - -pub struct PacketHandler -where - Meta: 'static, -{ - handlers: HashMap>, - packet_callback: Callback, -} - -impl Default for PacketHandler -where - Meta: 'static, - Callback: Default, -{ - fn default() -> Self { - Self { - handlers: Default::default(), - packet_callback: Default::default(), - } - } -} - -impl PacketHandler -where - Meta: Default + 'static, - Output: Default, - Callback: PacketCallback, -{ - pub fn with_callback(packet_callback: Callback) -> Self { - Self { - handlers: Default::default(), - packet_callback, - } - } - - pub fn register(&mut self, handler: impl Fn(Packet) -> Return + 'static) -> Result<(), DuplicateHandlerError> - where - Packet: IncomingPacket, - Return: Into, - { - let packet_callback = self.packet_callback.clone(); - let old_handler = self.handlers.insert( - Packet::HEADER, - Box::new(move |byte_stream| { - let packet = Packet::payload_from_bytes(byte_stream)?; - - packet_callback.incoming_packet(&packet); - - Ok(handler(packet).into()) - }), - ); - - match old_handler.is_some() { - true => Err(DuplicateHandlerError { - packet_header: Packet::HEADER, - }), - false => Ok(()), - } - } - - pub fn register_noop(&mut self) -> Result<(), DuplicateHandlerError> - where - Packet: IncomingPacket, - { - let packet_callback = self.packet_callback.clone(); - let old_handler = self.handlers.insert( - Packet::HEADER, - Box::new(move |byte_stream| { - let packet = Packet::payload_from_bytes(byte_stream)?; - - packet_callback.incoming_packet(&packet); - - Ok(Output::default()) - }), - ); - - match old_handler.is_some() { - true => Err(DuplicateHandlerError { - packet_header: Packet::HEADER, - }), - false => Ok(()), - } - } - - pub fn process_one(&mut self, byte_stream: &mut ByteStream) -> HandlerResult { - let save_point = byte_stream.create_save_point(); - - let Ok(header) = PacketHeader::from_bytes(byte_stream) else { - // Packet is cut-off at the header. - byte_stream.restore_save_point(save_point); - return HandlerResult::PacketCutOff; - }; - - let Some(handler) = self.handlers.get(&header) else { - byte_stream.restore_save_point(save_point); - - self.packet_callback.unknown_packet(&UnknownPacket { - bytes: byte_stream.remaining_bytes(), - }); - - return HandlerResult::UnhandledPacket; - }; - - match handler(byte_stream) { - Ok(output) => HandlerResult::Ok(output), - // Cut-off packet (probably). - Err(error) if error.is_byte_stream_too_short() => { - byte_stream.restore_save_point(save_point); - HandlerResult::PacketCutOff - } - Err(error) => { - byte_stream.restore_save_point(save_point); - - self.packet_callback.failed_packet(header, error.clone()); - - HandlerResult::InternalError(error) - } - } - } -}