From fa37331780050771ba67d842765fbf1c2e675ee3 Mon Sep 17 00:00:00 2001 From: DJMrTV Date: Sun, 23 Mar 2025 10:54:01 +0100 Subject: [PATCH] feat: stuff happend --- macros/src/lib.rs | 321 +++++++------------------------ macros/src/protos.rs | 173 +++++++++++++++++ src/grpc/mod.rs | 4 + src/main.rs | 28 ++- src/rmc/protocols/auth.rs | 34 ++++ src/rmc/protocols/mod.rs | 92 +++------ src/rmc/response.rs | 74 +++++-- src/rmc/structures/buffer.rs | 2 + src/rmc/structures/list.rs | 3 + src/rmc/structures/mod.rs | 13 +- src/rmc/structures/primitives.rs | 108 +++++++++++ 11 files changed, 510 insertions(+), 342 deletions(-) create mode 100644 macros/src/protos.rs create mode 100644 src/rmc/protocols/auth.rs diff --git a/macros/src/lib.rs b/macros/src/lib.rs index 1da5d58..eb3d5da 100644 --- a/macros/src/lib.rs +++ b/macros/src/lib.rs @@ -1,10 +1,12 @@ +mod protos; + extern crate proc_macro; use proc_macro2::{Ident, Literal, Span, TokenTree}; use proc_macro::TokenStream; use std::iter::FromIterator; use std::mem; -use syn::{parse_macro_input, DeriveInput, Data, PathSegment, TraitItem, FieldsNamed, Fields, Visibility, Type, TypePath, Path, ImplItem, ImplItemConst, Expr, ExprLit, Lit, TypeParamBound, TraitBound, TraitBoundModifier, LitInt, Token, FnArg, Receiver, PatType, Pat, TypeInfer, TypeReference, TraitItemFn, Signature, Block, Stmt, Local, LocalInit, LitStr, PathArguments}; +use syn::{parse_macro_input, DeriveInput, Data, PathSegment, TraitItem, FieldsNamed, Fields, Visibility, Type, TypePath, Path, ImplItem, ImplItemConst, Expr, ExprLit, Lit, TypeParamBound, TraitBound, TraitBoundModifier, LitInt, Token, FnArg, Receiver, PatType, Pat, TypeInfer, TypeReference, TraitItemFn, Signature, Block, Stmt, Local, LocalInit, LitStr, PathArguments, ReturnType}; use quote::{quote, ToTokens, TokenStreamExt}; use syn::buffer::TokenBuffer; use syn::parse::{Parse, ParseBuffer, ParseStream}; @@ -12,6 +14,7 @@ use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::token::Comma; use syn::Visibility::Public; +use crate::protos::{ProtoMethodData, RmcProtocolData}; fn self_referece_type() -> Type { Type::Reference( @@ -90,9 +93,6 @@ fn single_ident_path(ident: Ident) -> Path{ } -/// Example of user-defined [derive mode macro][1] -/// -/// [1]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-mode-macros #[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))] pub fn rmc_serialize(input: TokenStream) -> TokenStream { let derive_input = parse_macro_input!(input as DeriveInput); @@ -245,6 +245,30 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream { tokens.into() } +/// Macro to automatically generate code to use a specific trait as an rmc protocol for calling to +/// remote objects or accepting incoming remote requests. +/// This is needed in order to be able to use this as part of an rmc server interface. +/// +/// The protocol id which is needed to be specified is specified as a parameter to this attribute. +/// +/// You will also need to assign each function inside the trait a method id by using the +/// [`macro@method_id`] attribute. +/// +/// You can also specify to have the protocol to be non-returning by adding a second parameter to +/// the attribute which is just `NoReturn` e.g. ` #[rmc_proto(1, NoReturn)]` +/// +/// Example +/// ``` +/// // this rmc protocol has protocol id 1 +/// use macros::rmc_proto; +/// +/// #[rmc_proto(1)] +/// trait ExampleProtocol{ +/// // this defines an rmc method with id 1 +/// #[rmc_method(1)] +/// async fn hello_world_method(&self, name: String) -> Result; +/// } +/// ``` #[proc_macro_attribute] pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{ @@ -259,263 +283,63 @@ pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{ i.to_string() == "NoReturn" })); - let param_err_return = match no_return_data{ - true => quote!{ - return; - }, - false => quote!{ - return Err(ErrorCode::Core_InvalidArgument); - } - }; - let mut input = parse_macro_input!(input as syn::ItemTrait); - let info_struct_ident = format!("Raw{}Info",input.ident.to_string()); - let info_struct_ident = Ident::new(&info_struct_ident, input.ident.span()); - - let raw_details_struct = syn::ItemStruct{ - vis: Public(Default::default()), - struct_token: Default::default(), - fields: Fields::Unit, - semi_token: Some(Default::default()), - ident: info_struct_ident.clone(), - attrs: vec![], - generics: Default::default() - }; - - let raw_details_impl_block = syn::ItemImpl{ - impl_token: Default::default(), - generics: Default::default(), - attrs: vec![], - brace_token: Default::default(), - defaultness: None, - trait_: None, - self_ty: Box::new(Type::Path(TypePath{ - qself: None, - path: Path{ - segments: { - let mut punc = Punctuated::new(); - punc.push(PathSegment::from(info_struct_ident)); - punc - }, - leading_colon: None, - } - })), - unsafety: None, - items: vec![ - ImplItem::Const( - ImplItemConst{ - defaultness: None, - semi_token: Default::default(), - attrs: vec![], - generics: Default::default(), - ident: Ident::new("PROTOCOL_ID", Span::call_site()), - vis: Public(Default::default()), - colon_token: Default::default(), - const_token: Default::default(), - eq_token: Default::default(), - expr: Expr::Lit(ExprLit{ - attrs: vec![], - lit: Lit::Int(proto_num), - }), - ty: Type::Path(TypePath{ - qself: None, - path: Path{ - segments: { - let mut punc = Punctuated::new(); - punc.push(PathSegment::from(Ident::new("u16", Span::call_site()))); - punc - }, - leading_colon: None, - } - }) - } - ) - ] - }; - - let mut raw_trait = input.clone(); - - raw_trait.ident = Ident::new(&format!("Raw{}",raw_trait.ident.to_string()), raw_trait.ident.span()); - raw_trait.colon_token = Some(Default::default()); - raw_trait.supertraits = { - let mut punct = Punctuated::new(); - punct.push(TypeParamBound::Trait(TraitBound{ - path: single_ident_path(input.ident.clone()), - lifetimes: None, - modifier: TraitBoundModifier::None, - paren_token: None - })); - punct - }; - - let mut functions: Vec<(LitInt, Ident)> = Vec::new(); - - let funcs = raw_trait.items.iter_mut().filter_map(|v| if let TraitItem::Fn(v) = v {Some(v)} else { None }); - - for func in funcs{ - - if matches!(func.default, Some(_)){ - return syn::Error::new(func.default.span(), "rmc methods may not have bodies").to_compile_error().into(); - } - - let Some(attr) = func.attrs.iter() - .find(|a| a.path().segments.last().is_some_and(|s| s.ident.to_string() == "method_id")) else { - let span = func.sig.asyncness.span().join(func.semi_token.unwrap().span()).unwrap_or(func.sig.span()); - return syn::Error::new(span, "every function inside of an rmc protocol must have a method id").to_compile_error().into(); - }; - - let Ok(func_id): Result = attr.parse_args() else { - return syn::Error::new(Span::call_site(), "todo: put a propper error message here").to_compile_error().into(); - }; - - - if !func.sig.inputs.first().is_some_and(|v| matches!(v, FnArg::Receiver(Receiver{ - colon_token: None, - mutability: None, - reference: Some(_), - .. - }))){ - return syn::Error::new(func.sig.inputs.span(), "every protocol function must have a ` & self ` as its first parameter.").to_compile_error().into(); - } - - let old_ident = func.sig.ident.clone(); - - func.sig.ident = Ident::new(&format!("raw_{}", func.sig.ident), func.sig.ident.span()); - - let mut new_params: Punctuated<_,_> = Punctuated::new(); - - new_params.push_value(FnArg::Receiver(Receiver{ - attrs: vec![], - mutability: None, - ty: Box::new(self_referece_type()), - colon_token: None, - self_token: Default::default(), - reference: Some((Default::default(), None)) - })); - - new_params.push_punct(Comma::default()); -/* - new_params.push_value(FnArg::Typed(PatType{ - attrs: vec![], - pat: Box::new(Pat::Verbatim(quote! { method_id })), - colon_token: Default::default(), - ty: Box::new(Type::Verbatim(quote!{u32})) - })); - - new_params.push_punct(Comma::default());*/ - - new_params.push_value(FnArg::Typed(PatType{ - attrs: vec![], - pat: Box::new(Pat::Verbatim(quote! {data})), - colon_token: Default::default(), - ty: Box::new(Type::Verbatim(quote!{::std::vec::Vec})) - })); - - mem::swap(&mut new_params, &mut func.sig.inputs); - let old_params = new_params; - - - let mut inner_raw_tokens = quote!{ - let mut cursor = ::std::io::Cursor::new(data); - }; - - let mut call_params = quote!{}; - - - for param in old_params.iter().skip(1).filter_map(|v| if let FnArg::Typed(t) = v { - Some(t) - } else { - None - }){ - let param_name = &*param.pat; - let ty = &*param.ty; - - inner_raw_tokens.append_all(quote!{ - let Ok(#param_name) = <#ty as crate::rmc::structures::RmcSerialize>::deserialize(&mut cursor) else { - #param_err_return + // gigantic ass struct initializer (to summarize this gets all of the data) + let raw_data = RmcProtocolData{ + has_returns: !no_return_data, + name: input.ident.clone(), + id: proto_num, + methods: input + .items + .iter() + .filter_map(|v| match v{ TraitItem::Fn(v) => Some(v), _ => None }) + .map(|func|{ + let Some(attr) = func.attrs.iter() + .find(|a| a.path().segments.last().is_some_and(|s| s.ident.to_string() == "method_id")) else { + panic!( "every function inside of an rmc protocol must have a method id"); }; - }); - call_params.append_all(quote!{#param_name ,}) - } + let Ok(id): Result = attr.parse_args() else { + panic!("todo: put a propper error message here"); + }; - inner_raw_tokens.append_all(quote!{ - let retval = self.#old_ident(#call_params).await; - }); + let funcs = func + .sig + .inputs + .iter() + .skip(1) + .map(|f| { + let FnArg::Typed(t) = f else { + panic!("what"); + }; + let Pat::Ident(i) = &*t.pat else { + panic!("unable to handle non identifier patterns as parameter bindings"); + }; - if !no_return_data{ - //let + (i.ident.clone(), t.ty.as_ref().clone()) + }).collect(); - //inner_raw_tokens.append_all() - } - - - let braced = quote! { - { - #inner_raw_tokens - } - }; - - let braced = braced.into(); - - func.default = Some( - parse_macro_input!(braced as Block) - ); - - functions.push((func_id, func.sig.ident.clone())); - } - - let mut inner_match = quote!{}; - - for toks in functions.iter().map(|(lit, ident)|{ - quote! { - #lit => self.#ident(data).await, - } - }){ - inner_match.append_all(toks); - } - - if no_return_data{ - inner_match.append_all(quote!{ - _ => return - }) - } else { - // - inner_match.append_all(quote!{ - _ => return - }) - } - - raw_trait.items.push( - TraitItem::Verbatim( - quote!{ - async fn rmc_call_proto(&self, method_id: u32, data: Vec){ - match method_id{ - #inner_match - } + ProtoMethodData{ + id, + name: func.sig.ident.clone(), + parameters: funcs } - } - ) - ); + }).collect() - - - let regular_trait_name = &input.ident; - let raw_trait_name = &raw_trait.ident; + }; quote!{ #input - #raw_details_struct - #raw_details_impl_block - #raw_trait - - impl #raw_trait_name for T{} + #raw_data }.into() - } - +/// Used to specify the method id of methods when making rmc protocols. +/// See [`macro@rmc_proto`] for further details. +/// +/// Note: This attribute doesn't do anything by itself and just returns the thing it was attached to +/// unchanged. #[proc_macro_attribute] pub fn method_id(_attr: TokenStream, input: TokenStream) -> TokenStream{ // this attribute doesnt do anything by itself, see `rmc_proto` @@ -523,6 +347,7 @@ pub fn method_id(_attr: TokenStream, input: TokenStream) -> TokenStream{ } + #[proc_macro_attribute] pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{ let mut type_data = parse_macro_input!(input as DeriveInput); @@ -542,8 +367,8 @@ pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{ } impl crate::rmc::protocols::RmcCallable for #struct_name{ - async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec){ - ::rmc_call(self, protocol_id, method_id, rest).await; + async fn rmc_call(&self, remote_response_connection: &crate::prudp::socket::SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ + ::rmc_call(self, remote_response_connection, protocol_id, method_id, call_id, rest).await; } } }; diff --git a/macros/src/protos.rs b/macros/src/protos.rs new file mode 100644 index 0000000..cc0e5cd --- /dev/null +++ b/macros/src/protos.rs @@ -0,0 +1,173 @@ +use proc_macro2::{Ident, Span, TokenStream, TokenTree}; +use quote::{quote, ToTokens}; +use syn::{LitInt, Token, Type}; +use syn::token::{Brace, Paren, Semi}; + +pub struct ProtoMethodData{ + pub id: LitInt, + pub name: Ident, + pub parameters: Vec<(Ident, Type)> +} + + +/// This is a representation of the code generated by `rmc_proto` it serves to split the logic of +/// acquiring data from the actual generation to tidy up the process into first getting then +/// generating. +/// +/// Use the [`ToTokens`] trait to generate the actual code. +pub struct RmcProtocolData{ + pub has_returns: bool, + pub id: LitInt, + pub name: Ident, + pub methods: Vec +} + +impl ToTokens for RmcProtocolData{ + fn to_tokens(&self, tokens: &mut TokenStream) { + let Self{ + has_returns, + name, + id, + methods + } = self; + + // this gives us the name which the identifier of the corresponding Raw trait + let raw_name = Ident::new(&format!("Raw{}", name), name.span()); + + + // boilerplate tokens which all raw traits need + quote!{ + #[doc(hidden)] + pub trait #raw_name: #name + }.to_tokens(tokens); + + // generate the body of the raw protocol trait + Brace::default().surround(tokens, |tokens|{ + //generate each raw method + for method in methods{ + let ProtoMethodData { + name, + parameters, + .. + } = method; + + let raw_name = Ident::new(&format!("raw_{}", name), name.span()); + quote!{ + async fn #raw_name + }.to_tokens(tokens); + + Paren::default().surround(tokens, |tokens|{ + quote!{ &self, data: ::std::vec::Vec }.to_tokens(tokens); + }); + + quote!{ + -> ::core::result::Result, ErrorCode> + }.to_tokens(tokens); + + Brace::default().surround(tokens, |tokens|{ + quote! { let mut cursor = ::std::io::Cursor::new(data); }.to_tokens(tokens); + + for (param_name, param_type) in parameters{ + quote!{ + let Ok(#param_name) = + <#param_type as crate::rmc::structures::RmcSerialize>::deserialize( + &mut cursor + ) else { + return Err(ErrorCode::Core_InvalidArgument); + }; + }.to_tokens(tokens) + } + + quote!{ + let retval = self.#name + }.to_tokens(tokens); + + Paren::default().surround(tokens, |tokens|{ + for (paren_name, _) in parameters{ + quote!{#paren_name,}.to_tokens(tokens); + } + }); + + quote!{ + .await; + }.to_tokens(tokens); + + if *has_returns{ + quote!{ + let retval = retval?; + let mut vec = Vec::new(); + crate::rmc::structures::RmcSerialize::serialize(&retval, &mut vec).ok(); + Ok(vec) + }.to_tokens(tokens); + } + }) + } + + quote!{ + async fn rmc_call_proto( + &self, + remote_response_connection: &crate::prudp::socket::SendingConnection, + method_id: u32, + call_id: u32, + data: Vec, + ) + }.to_tokens(tokens); + + Brace::default().surround(tokens, |tokens|{ + quote! { + let ret = match method_id + }.to_tokens(tokens); + + Brace::default().surround(tokens, |tokens|{ + for method in methods{ + let ProtoMethodData{ + id, + name, + .. + } = method; + + let raw_name = Ident::new(&format!("raw_{}", name), name.span()); + + quote!{ + #id => self.#raw_name(data).await, + }.to_tokens(tokens); + } + quote!{ + _ => Err(crate::rmc::response::ErrorCode::Core_NotImplemented) + }.to_tokens(tokens); + }); + + Semi::default().to_tokens(tokens); + + if *has_returns{ + quote!{ + crate::rmc::response::send_result( + remote_response_connection, + ret, + #id, + method_id, + call_id, + ).await + }.to_tokens(tokens); + } + }); + }); + + quote!{ + impl RawAuth for T{} + }.to_tokens(tokens); + + let raw_info_name = Ident::new(&format!("Raw{}Info", name), Span::call_site()); + + + quote!{ + #[doc(hidden)] + pub struct #raw_info_name; + + impl #raw_info_name { + pub const PROTOCOL_ID: u16 = #id; + } + }.to_tokens(tokens); + } +} + diff --git a/src/grpc/mod.rs b/src/grpc/mod.rs index d1a4342..2ca742e 100644 --- a/src/grpc/mod.rs +++ b/src/grpc/mod.rs @@ -1,3 +1,7 @@ +//! Legacy grpc communication server for being able to use this with pretendos infrastructure +//! before account rs is finished. +//! +//! This WILL be deprecated as soon as account rs is in a stable state. use tonic::{Request, Status}; type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result, Status> + Send)>; diff --git a/src/main.rs b/src/main.rs index bb44bc5..cb2d033 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,24 +1,24 @@ #![allow(dead_code)] +#![warn(missing_docs)] + +//! # Splatoon RNEX server +//! +//! This server still includes the code for rnex itself as this is the first rnex server and thus +//! also the first and only current usage of rnex, expect this and rnex to be split into seperate +//! repos soon. use std::{env, fs}; -use std::collections::BTreeMap; use std::fs::File; use std::net::{Ipv4Addr, SocketAddrV4}; -use std::sync::Arc; use chrono::{Local, SecondsFormat}; use log::info; use once_cell::sync::Lazy; -use rc4::{KeyInit, Rc4, StreamCipher}; -use rc4::consts::U5; use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger}; -use tokio::sync::RwLock; -use tokio::task::JoinHandle; use crate::nex::account::Account; -use crate::prudp::socket::{EncryptionPair, Unsecure}; +use crate::prudp::socket::Unsecure; use crate::prudp::packet::{VirtualPort}; use crate::prudp::router::Router; use crate::prudp::sockaddr::PRUDPSockAddr; -use crate::prudp::station_url::Type::PRUDP; mod endianness; mod prudp; @@ -234,6 +234,18 @@ async fn start_secure_server() -> SecureServer{ socket, } }*/ +/* +define_rmc_proto!( + proto AuthClientProtocol{ + Auth + } +);*/ + + +//#[rmc_struct(AuthClientProtocol)] +struct AuthClient{ + +} async fn start_servers(){ diff --git a/src/rmc/protocols/auth.rs b/src/rmc/protocols/auth.rs new file mode 100644 index 0000000..5aa84f3 --- /dev/null +++ b/src/rmc/protocols/auth.rs @@ -0,0 +1,34 @@ +use crate::rmc::response::ErrorCode; +use crate::rmc::structures::any::Any; +use crate::rmc::structures::connection_data::ConnectionData; +use crate::rmc::structures::qresult::QResult; +use macros::{method_id, rmc_proto}; + + +/// This is the representation for `Ticket Granting`(for details see the +/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) +#[rmc_proto(10)] +pub trait Auth { + #[method_id(1)] + async fn login(&self, name: String) -> Result<(), ErrorCode>; + + #[method_id(2)] + async fn login_ex( + &self, + name: String, + extra_data: Any, + ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode>; + + #[method_id(3)] + async fn request_ticket( + &self, + source_pid: u32, + destination_pid: u32, + ) -> Result<(QResult, Vec), ErrorCode>; + + #[method_id(4)] + async fn get_pid(&self, username: String) -> Result; + + #[method_id(5)] + async fn get_name(&self, pid: u32) -> Result; +} diff --git a/src/rmc/protocols/mod.rs b/src/rmc/protocols/mod.rs index 2603f8c..74c020c 100644 --- a/src/rmc/protocols/mod.rs +++ b/src/rmc/protocols/mod.rs @@ -1,3 +1,7 @@ +#![allow(async_fn_in_trait)] + +pub mod auth; + use macros::method_id; use std::collections::HashMap; use std::ops::Add; @@ -10,16 +14,18 @@ use paste::paste; use tokio::sync::{Mutex, Notify}; use tokio::time::{sleep_until, Instant}; use crate::prudp::socket::{ExternalConnection, SendingConnection}; +use crate::rmc::response::ErrorCode; use crate::rmc::structures::connection_data::ConnectionData; +use crate::rmc::structures::Error; use crate::rmc::structures::matchmake::AutoMatchmakeParam; pub struct RmcConnection(pub SendingConnection, pub RmcResponseReceiver); -pub struct RmcResponseReceiver(Notify, Mutex>>); +pub struct RmcResponseReceiver(Notify, Mutex>>); impl RmcResponseReceiver{ // returns none if timed out - pub async fn get_response_data(&self, proto: u16, method: u32) -> Option>{ + pub async fn get_response_data(&self, call_id: u32) -> Option>{ let mut end_wait_time = Instant::now(); end_wait_time += Duration::from_secs(5); @@ -29,13 +35,15 @@ impl RmcResponseReceiver{ loop { let mut locked = self.1.lock().await; - if let Some(v) = locked.remove(&(proto, method)){ + if let Some(v) = locked.remove(&call_id){ return Some(v); } + drop(locked); + + let notif_fut = self.0.notified(); - drop(locked); tokio::select! { _ = &mut sleep_fut => { @@ -49,6 +57,10 @@ impl RmcResponseReceiver{ } } +pub trait HasRmcConnection{ + fn get_response_receiver(&self) -> &RmcConnection; +} + pub trait RemoteObject{ fn new(conn: RmcConnection) -> Self; } @@ -57,84 +69,36 @@ impl RemoteObject for (){ fn new(_: RmcConnection) -> Self {} } + + pub trait RmcCallable{ //type Remote: RemoteObject; //fn new_callable(remote: Self::Remote); - async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec); + async fn rmc_call(&self, responder: &SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec); } - +#[macro_export] macro_rules! define_rmc_proto { (proto $name:ident{ $($protocol:path),* }) => { - paste!{ + paste::paste!{ trait []: std::any::Any $( + [] + $protocol)* { - async fn rmc_call(&self, protocol_id: u16, method_id: u32, rest: Vec){ + async fn rmc_call(&self, remote_response_connection: &crate::prudp::socket::SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec){ match protocol_id{ $( - []::PROTOCOL_ID => ]>::rmc_call_proto(self, method_id, rest).await, + []::PROTOCOL_ID => ]>::rmc_call_proto(self, remote_response_connection, method_id, call_id, rest).await, )* v => log::error!("invalid protocol called on rmc object {}", v) } } } + + struct [](crate::rmc::protocols::RmcConnection); + + } }; -} - -trait RawNotif{ - async fn rmc_call_proto(&self, method_id: u32, rest: Vec){ - - } -} -trait Notif{ - -} - -struct RawNotifInfo; -impl RawNotifInfo{ - const PROTOCOL_ID: u16 = 10; -} - -pub trait ImplementRemoteCalls{} - -#[rmc_proto(1, NoReturn)] -pub trait Another{ - #[method_id(1)] - async fn test(&self, thing: AutoMatchmakeParam); -} - -define_rmc_proto!{ - proto TestProto{ - Notif, - Another - } -} - - - -#[rmc_struct(TestProto)] -struct TestProtoImplementor{ - -} - - - -impl Notif for TestProtoImplementor{ - -} - -impl RawNotif for TestProtoImplementor{ - -} - -impl Another for TestProtoImplementor{ - async fn test(&self, thing: AutoMatchmakeParam) { - - } -} - -impl ImplementRemoteCalls for TestProtoImplementor{} \ No newline at end of file +} \ No newline at end of file diff --git a/src/rmc/response.rs b/src/rmc/response.rs index bbbfb13..ece1486 100644 --- a/src/rmc/response.rs +++ b/src/rmc/response.rs @@ -6,41 +6,42 @@ use crate::prudp::packet::{PRUDPPacket}; use crate::prudp::packet::flags::{NEED_ACK, RELIABLE}; use crate::prudp::packet::PacketOption::FragmentId; use crate::prudp::packet::types::DATA; -use crate::prudp::socket::ExternalConnection; +use crate::prudp::socket::{ExternalConnection, SendingConnection}; use crate::rmc::structures::qresult::ERROR_MASK; +use crate::rmc::structures::RmcSerialize; use crate::web::DirectionalData::{Incoming, Outgoing}; use crate::web::WEB_DATA; pub enum RMCResponseResult { - Success{ + Success { call_id: u32, method_id: u32, data: Vec, }, - Error{ + Error { error_code: ErrorCode, call_id: u32, - } + }, } pub struct RMCResponse { pub protocol_id: u8, - pub response_result: RMCResponseResult + pub response_result: RMCResponseResult, } impl RMCResponse { - pub fn to_data(self) -> Vec{ + pub fn to_data(self) -> Vec { generate_response(self.protocol_id, self.response_result).expect("failed to generate response") } } -pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result>{ - let size = 1 + 1 + match &response{ +pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result> { + let size = 1 + 1 + match &response { RMCResponseResult::Success { data, .. } => 4 + 4 + data.len(), - RMCResponseResult::Error{..} => 4 + 4, + RMCResponseResult::Error { .. } => 4 + 4, }; let mut data_out = Vec::with_capacity(size + 4); @@ -50,7 +51,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re data_out.write_all(bytes_of(&u32_size))?; data_out.push(protocol_id); - match response{ + match response { RMCResponseResult::Success { call_id, method_id, @@ -61,7 +62,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re let ored_method_id = method_id | 0x8000; data_out.write_all(bytes_of(&ored_method_id))?; data_out.write_all(&data)?; - }, + } RMCResponseResult::Error { call_id, error_code @@ -78,10 +79,44 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re Ok(data_out) } -pub async fn send_response(original_packet: &PRUDPPacket, connection: &mut ExternalConnection, rmcresponse: RMCResponse){ + +pub async fn send_result( + connection: &SendingConnection, + result: Result, ErrorCode>, + protocol_id: u8, + method_id: u32, + call_id: u32, +) { + let response_result = match result { + Ok(v) => RMCResponseResult::Success { + call_id, + method_id, + data: { + let mut vec = Vec::new(); + v.serialize(&mut vec).expect("serialization error"); + vec + } + }, + Err(e) => + RMCResponseResult::Error { + call_id, + error_code: e.into() + } + }; + + let response = RMCResponse{ + response_result, + protocol_id + }; + + send_response(connection, response).await +} + +pub async fn send_response(connection: &SendingConnection, rmcresponse: RMCResponse) { connection.send(rmcresponse.to_data()).await; } + //taken from kinnays error list directly #[allow(nonstandard_style)] #[repr(u32)] @@ -356,25 +391,25 @@ pub enum ErrorCode { Custom_Unknown = 0x00740001, Ess_Unknown = 0x00750001, Ess_GameSessionError = 0x00750002, - Ess_GameSessionMaintenance = 0x00750003 + Ess_GameSessionMaintenance = 0x00750003, } -impl Into for ErrorCode { +impl Into for ErrorCode { fn into(self) -> u32 { - unsafe{ transmute(self) } + unsafe { transmute(self) } } } #[cfg(test)] -mod test{ +mod test { use hmac::digest::consts::U5; use hmac::digest::KeyInit; use rc4::{Rc4, StreamCipher}; use crate::rmc::response::ErrorCode; #[test] - fn test(){ - let mut data_orig = [0,1,2,3,4,5,6,7,8,9,69,4,20]; + fn test() { + let mut data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20]; let mut data = data_orig; let mut rc4: Rc4 = @@ -390,11 +425,10 @@ mod test{ rc4.apply_keystream(&mut data); assert_eq!(data_orig, data); - } #[test] - fn test_enum_equivilance(){ + fn test_enum_equivilance() { let val: u32 = ErrorCode::Core_Unknown.into(); assert_eq!(val, 0x00010001) } diff --git a/src/rmc/structures/buffer.rs b/src/rmc/structures/buffer.rs index aea5a45..5370cf5 100644 --- a/src/rmc/structures/buffer.rs +++ b/src/rmc/structures/buffer.rs @@ -1,6 +1,8 @@ use std::io::{Read, Write}; use crate::rmc::structures::RmcSerialize; + + impl<'a> RmcSerialize for &'a [u8]{ fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { let u32_size = self.len() as u32; diff --git a/src/rmc/structures/list.rs b/src/rmc/structures/list.rs index 7f6c97c..6f6b456 100644 --- a/src/rmc/structures/list.rs +++ b/src/rmc/structures/list.rs @@ -4,6 +4,9 @@ use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; + +// this is also for implementing `Buffer` this is tecnically not the same as its handled internaly +// probably but as it has the same mapping it doesn't matter and simplifies things impl RmcSerialize for Vec{ fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { let u32_len = self.len() as u32; diff --git a/src/rmc/structures/mod.rs b/src/rmc/structures/mod.rs index 667af6e..a9f9ab6 100644 --- a/src/rmc/structures/mod.rs +++ b/src/rmc/structures/mod.rs @@ -17,7 +17,7 @@ pub enum Error{ VersionMismatch(u8), } -pub(crate) type Result = std::result::Result; +pub type Result = std::result::Result; pub mod string; pub mod any; @@ -30,9 +30,18 @@ pub mod qbuffer; pub mod primitives; pub mod matchmake; pub mod variant; -mod ranking; +pub mod ranking; pub trait RmcSerialize: Sized{ fn serialize(&self, writer: &mut dyn Write) -> Result<()>; fn deserialize(reader: &mut dyn Read) -> Result; +} + +impl RmcSerialize for (){ + fn serialize(&self, writer: &mut dyn Write) -> Result<()> { + Ok(()) + } + fn deserialize(reader: &mut dyn Read) -> Result { + Ok(()) + } } \ No newline at end of file diff --git a/src/rmc/structures/primitives.rs b/src/rmc/structures/primitives.rs index bd08da8..e8855f0 100644 --- a/src/rmc/structures/primitives.rs +++ b/src/rmc/structures/primitives.rs @@ -91,4 +91,112 @@ impl RmcSerialize for (T, U){ Ok((first, second)) } +} + +impl RmcSerialize for (T, U, V){ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + self.2.serialize(writer)?; + Ok(()) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + let third = V::deserialize(reader)?; + + Ok((first, second, third)) + } +} + +impl RmcSerialize for (T, U, V, W){ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + self.2.serialize(writer)?; + self.3.serialize(writer)?; + Ok(()) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + let third = V::deserialize(reader)?; + let fourth = W::deserialize(reader)?; + + Ok((first, second, third, fourth)) + } +} + +impl RmcSerialize for (T, U, V, W, X){ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + self.2.serialize(writer)?; + self.3.serialize(writer)?; + self.4.serialize(writer)?; + + Ok(()) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + let third = V::deserialize(reader)?; + let fourth = W::deserialize(reader)?; + let fifth = X::deserialize(reader)?; + + Ok((first, second, third, fourth, fifth)) + } +} + +impl RmcSerialize for (T, U, V, W, X, Y){ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + self.2.serialize(writer)?; + self.3.serialize(writer)?; + self.4.serialize(writer)?; + self.5.serialize(writer)?; + + Ok(()) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + let third = V::deserialize(reader)?; + let fourth = W::deserialize(reader)?; + let fifth = X::deserialize(reader)?; + let sixth = Y::deserialize(reader)?; + + Ok((first, second, third, fourth, fifth, sixth)) + } +} + +impl RmcSerialize for (T, U, V, W, X, Y, Z){ + fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { + self.0.serialize(writer)?; + self.1.serialize(writer)?; + self.2.serialize(writer)?; + self.3.serialize(writer)?; + self.4.serialize(writer)?; + self.5.serialize(writer)?; + self.6.serialize(writer)?; + + Ok(()) + } + + fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result { + let first = T::deserialize(reader)?; + let second = U::deserialize(reader)?; + let third = V::deserialize(reader)?; + let fourth = W::deserialize(reader)?; + let fifth = X::deserialize(reader)?; + let sixth = Y::deserialize(reader)?; + let seventh = Z::deserialize(reader)?; + + Ok((first, second, third, fourth, fifth, sixth, seventh)) + } } \ No newline at end of file