diff --git a/rnex-core/Cargo.toml b/rnex-core/Cargo.toml index 34034d9..69a4f9f 100644 --- a/rnex-core/Cargo.toml +++ b/rnex-core/Cargo.toml @@ -14,7 +14,7 @@ simplelog = "0.12.2" chrono = "0.4.39" log = "0.4.25" rand = "0.8.5" - +cfg-if = "1.0.4" hmac = "0.12.1" md-5 = "^0.10.6" tokio = { version = "1.43.0", features = ["macros", "rt-multi-thread", "net", "sync", "fs"] } diff --git a/rnex-core/src/executables/backend_server_insecure.rs b/rnex-core/src/executables/backend_server_insecure.rs index 5c4db20..efb08db 100644 --- a/rnex-core/src/executables/backend_server_insecure.rs +++ b/rnex-core/src/executables/backend_server_insecure.rs @@ -1,6 +1,8 @@ +use cfg_if::cfg_if; use once_cell::sync::Lazy; use rnex_core::common::setup; use rnex_core::executables::common::{SECURE_SERVER_ACCOUNT, new_simple_backend}; +use rnex_core::executables::regular_backend; use rnex_core::nex::auth_handler::AuthHandler; use rnex_core::reggie::EdgeNodeHolderConnectOption::DontRegister; use rnex_core::reggie::RemoteEdgeNodeHolder; @@ -23,25 +25,11 @@ pub static FORWARD_EDGE_NODE_HOLDER: Lazy = Lazy::new(|| { async fn main() { setup(); - let conn = TcpStream::connect(&*FORWARD_EDGE_NODE_HOLDER) - .await - .unwrap(); + cfg_if! { + if #[cfg(features = "friends")]{ - let conn: SplittableBufferConnection = conn.into(); - - conn.send(DontRegister.to_data().unwrap()).await; - - let conn = new_rmc_gateway_connection(conn, |r| { - Arc::new(OnlyRemote::::new(r)) - }); - - new_simple_backend(move |_, _| { - let controller = conn.clone(); - Arc::new(AuthHandler { - destination_server_acct: &SECURE_SERVER_ACCOUNT, - build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0", - control_server: controller, - }) - }) - .await; + } else { + regular_backend::start_regular_backend().await + } + } } diff --git a/rnex-core/src/executables/backend_server_secure.rs b/rnex-core/src/executables/backend_server_secure.rs index 598b039..51d9647 100644 --- a/rnex-core/src/executables/backend_server_secure.rs +++ b/rnex-core/src/executables/backend_server_secure.rs @@ -1,5 +1,7 @@ +use cfg_if::cfg_if; use rnex_core::common::setup; use rnex_core::executables::common::new_simple_backend; +use rnex_core::executables::friends_backend::start_friends_backend; use rnex_core::nex::matchmake::MatchmakeManager; use rnex_core::nex::remote_console::RemoteConsole; use rnex_core::nex::user::User; @@ -11,27 +13,11 @@ use std::sync::atomic::AtomicU32; async fn main() { setup(); - let mmm = Arc::new(MatchmakeManager { - //gid_counter: AtomicU32::new(1), - sessions: Default::default(), - users: Default::default(), - rv_cid_counter: AtomicU32::new(1), - }); - - let weak_mmm = Arc::downgrade(&mmm); - - MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; - - new_simple_backend(move |c, r| { - let mmm = mmm.clone(); - Arc::new_cyclic(move |this| User { - this: this.clone(), - ip: c.prudpsock_addr, - pid: c.pid, - remote: RemoteConsole::new(r), - matchmake_manager: mmm, - station_url: Default::default(), - }) - }) - .await; + cfg_if! { + if #[cfg(feature = "friends")]{ + start_friends_backend().await; + } else { + regular_backend::start_regular_backend().await + } + } } diff --git a/rnex-core/src/executables/friends_backend.rs b/rnex-core/src/executables/friends_backend.rs new file mode 100644 index 0000000..2626fbe --- /dev/null +++ b/rnex-core/src/executables/friends_backend.rs @@ -0,0 +1,22 @@ +use std::sync::{Arc, atomic::AtomicU32}; + +use crate::{ + executables::common::new_simple_backend, + nex::friends_handler::{FriendsManager, FriendsUser}, +}; + +pub async fn start_friends_backend() { + let fm = Arc::new(FriendsManager { + cid_counter: AtomicU32::new(1), + }); + + new_simple_backend(move |c, r| { + let fm = fm.clone(); + Arc::new_cyclic(move |this| FriendsUser { + fm, + addr: c.prudpsock_addr, + pid: c.pid, + }) + }) + .await; +} diff --git a/rnex-core/src/executables/mod.rs b/rnex-core/src/executables/mod.rs index ffac467..cc9b83d 100644 --- a/rnex-core/src/executables/mod.rs +++ b/rnex-core/src/executables/mod.rs @@ -1 +1,3 @@ -pub mod common; \ No newline at end of file +pub mod common; +pub mod friends_backend; +pub mod regular_backend; diff --git a/rnex-core/src/executables/regular_backend.rs b/rnex-core/src/executables/regular_backend.rs new file mode 100644 index 0000000..65cb2ca --- /dev/null +++ b/rnex-core/src/executables/regular_backend.rs @@ -0,0 +1,33 @@ +use std::sync::{Arc, atomic::AtomicU32}; + +use crate::{ + executables::common::new_simple_backend, + nex::{matchmake::MatchmakeManager, remote_console::RemoteConsole, user::User}, + rmc::protocols::RmcPureRemoteObject, +}; + +pub async fn start_regular_backend() { + let mmm = Arc::new(MatchmakeManager { + //gid_counter: AtomicU32::new(1), + sessions: Default::default(), + users: Default::default(), + rv_cid_counter: AtomicU32::new(1), + }); + + let weak_mmm = Arc::downgrade(&mmm); + + MatchmakeManager::initialize_garbage_collect_thread(weak_mmm).await; + + new_simple_backend(move |c, r| { + let mmm = mmm.clone(); + Arc::new_cyclic(move |this| User { + this: this.clone(), + ip: c.prudpsock_addr, + pid: c.pid, + remote: RemoteConsole::new(r), + matchmake_manager: mmm, + station_url: Default::default(), + }) + }) + .await; +} diff --git a/rnex-core/src/kerberos/mod.rs b/rnex-core/src/kerberos/mod.rs index a5963d8..88700a6 100644 --- a/rnex-core/src/kerberos/mod.rs +++ b/rnex-core/src/kerberos/mod.rs @@ -1,5 +1,5 @@ -use crate::rmc::structures::RmcSerialize; use bytemuck::{Pod, Zeroable, bytes_of}; +use cfg_if::cfg_if; use chrono::{Datelike, NaiveDate, NaiveDateTime, NaiveTime, Timelike, Utc}; use hmac::Hmac; use hmac::Mac; @@ -8,7 +8,20 @@ use rc4::KeyInit; use rc4::cipher::StreamCipherCoreWrapper; use rc4::consts::U16; use rc4::{Rc4, Rc4Core, StreamCipher}; +use rnex_core::rmc::structures::RmcSerialize; use std::io::{Read, Write}; +use typenum::Unsigned; + +use rnex_core::rmc::structures::Result; + +cfg_if! { + if #[cfg(feature = "friends")]{ + pub type SESSION_KEY_LENGTH_TY = U16; + } else { + pub type SESSION_KEY_LENGTH_TY = U32; + } +} +pub const SESSION_KEY_LENGTH: usize = SESSION_KEY_LENGTH_TY::USIZE; type Md5Hmac = Hmac; @@ -99,11 +112,11 @@ impl KerberosDateTime { } impl RmcSerialize for KerberosDateTime { - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { Ok(self.0.serialize(writer)?) } - fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> Result { Ok(Self(u64::deserialize(reader)?)) } } @@ -113,7 +126,7 @@ impl RmcSerialize for KerberosDateTime { pub struct TicketInternalData { pub issued_time: KerberosDateTime, pub pid: u32, - pub session_key: [u8; 32], + pub session_key: [u8; SESSION_KEY_LENGTH], } impl TicketInternalData { @@ -148,7 +161,7 @@ impl TicketInternalData { #[derive(Pod, Zeroable, Copy, Clone)] #[repr(C, packed)] pub struct Ticket { - pub session_key: [u8; 32], + pub session_key: [u8; SESSION_KEY_LENGTH], pub pid: u32, } diff --git a/rnex-core/src/nex/auth_handler.rs b/rnex-core/src/nex/auth_handler.rs index 21f67dc..0ab6910 100644 --- a/rnex-core/src/nex/auth_handler.rs +++ b/rnex-core/src/nex/auth_handler.rs @@ -1,6 +1,7 @@ use crate::grpc::account; use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement}; use crate::{define_rmc_proto, kerberos}; +use cfg_if::cfg_if; use log::{info, warn}; use macros::rmc_struct; use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key}; @@ -11,6 +12,7 @@ use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::response::ErrorCode::Core_Unknown; use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::connection_data::ConnectionData; +use rnex_core::rmc::structures::connection_data::ConnectionDataOld; use rnex_core::rmc::structures::qresult::QResult; use std::hash::{DefaultHasher, Hasher}; use std::net::SocketAddrV4; @@ -49,7 +51,13 @@ pub fn generate_ticket( encrypted_session_ticket } -async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> { +async fn get_login_data_by_pid(pid: u32) -> Option<(u32, Box<[u8]>)> { + if pid == GUEST_ACCOUNT.pid { + let source_login_data = GUEST_ACCOUNT.get_login_data(); + + return Some((source_login_data.0, source_login_data.1.into())); + } + let Ok(mut client) = account::Client::new().await else { return None; }; @@ -58,7 +66,7 @@ async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> { return None; }; - Some((pid, passwd)) + Some((pid, passwd.into())) } fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String { @@ -118,6 +126,42 @@ impl Auth for AuthHandler { async fn login( &self, name: String, + ) -> Result<(QResult, u32, Vec, ConnectionDataOld, String), ErrorCode> { + let (pid, ticket) = self.generate_ticket_from_name(&name).await?; + + let result = QResult::success(Core_Unknown); + + let mut hasher = DefaultHasher::new(); + + hasher.write(name.as_bytes()); + + let Ok(addr) = self.control_server.get_url(hasher.finish()).await else { + warn!("no secure proxies"); + return Err(ErrorCode::Core_Exception); + }; + + let connection_data = ConnectionDataOld { + station_url: station_url_from_sock_addr(addr), + special_station_url: "".to_string(), + special_protocols: Vec::new(), + }; + + let ret = ( + result, + pid, + ticket.into(), + connection_data, + self.build_name.to_string(), + ); + + info!("data: {:?}", ret); + Ok(ret) + } + + async fn login_ex( + &self, + name: String, + _extra_data: Any, ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { let (pid, ticket) = self.generate_ticket_from_name(&name).await?; @@ -152,14 +196,6 @@ impl Auth for AuthHandler { Ok(ret) } - async fn login_ex( - &self, - name: String, - _extra_data: Any, - ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode> { - self.login(name).await - } - async fn request_ticket( &self, source_pid: u32, diff --git a/rnex-core/src/nex/common.rs b/rnex-core/src/nex/common.rs new file mode 100644 index 0000000..d2fa40f --- /dev/null +++ b/rnex-core/src/nex/common.rs @@ -0,0 +1,93 @@ +use rnex_core::prudp::station_url::StationUrl; +use rnex_core::prudp::station_url::UrlOptions::{ + Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID, +}; +use rnex_core::prudp::station_url::nat_types::PUBLIC; +use rnex_core::rmc::response::ErrorCode::Core_Exception; + +use rnex_core::prudp::socket_addr::PRUDPSockAddr; +use rnex_core::rmc::response::ErrorCode; + +pub async fn get_station_urls( + station_urls: &[StationUrl], + addr: PRUDPSockAddr, + pid: u32, + cid: u32, +) -> Result, ErrorCode> { + let mut public_station: Option = None; + let mut private_station: Option = None; + + for station in station_urls { + let is_public = station.options.iter().any(|v| { + if let NatType(v) = v { + if *v & PUBLIC != 0 { + return true; + } + } + false + }); + + let Some(nat_filtering) = station.options.iter().find_map(|v| match v { + NatFiltering(v) => Some(v), + _ => None, + }) else { + return Err(Core_Exception); + }; + + let Some(nat_mapping) = station.options.iter().find_map(|v| match v { + NatMapping(v) => Some(v), + _ => None, + }) else { + return Err(Core_Exception); + }; + + if !is_public || (*nat_filtering == 0 && *nat_mapping == 0) { + private_station = Some(station.clone()); + } + + if is_public { + public_station = Some(station.clone()); + } + } + + let Some(mut private_station) = private_station else { + return Err(Core_Exception); + }; + + let mut public_station = if let Some(public_station) = public_station { + public_station + } else { + let mut public_station = private_station.clone(); + + public_station.options.retain(|v| match v { + Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false, + _ => true, + }); + + public_station + .options + .push(Address(*addr.regular_socket_addr.ip())); + public_station + .options + .push(Port(addr.regular_socket_addr.port())); + public_station.options.push(NatFiltering(0)); + public_station.options.push(NatMapping(0)); + public_station.options.push(NatType(3)); + + public_station + }; + + let both = [&mut public_station, &mut private_station]; + + for station in both { + station.options.retain(|v| match v { + PrincipalID(_) | RVConnectionID(_) => false, + _ => true, + }); + + station.options.push(PrincipalID(pid)); + station.options.push(RVConnectionID(cid)); + } + + Ok(vec![public_station]) +} diff --git a/rnex-core/src/nex/friends_handler.rs b/rnex-core/src/nex/friends_handler.rs new file mode 100644 index 0000000..a2d42ca --- /dev/null +++ b/rnex-core/src/nex/friends_handler.rs @@ -0,0 +1,160 @@ +use std::sync::{Arc, atomic::AtomicU32}; +use std::time::Duration; + +use log::info; +use macros::rmc_struct; +use rnex_core::rmc::protocols::friends::{Friends, RawFriends, RawFriendsInfo, RemoteFriends}; +use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; +use rnex_core::{ + define_rmc_proto, + kerberos::KerberosDateTime, + nex::common::get_station_urls, + prudp::{socket_addr::PRUDPSockAddr, station_url::StationUrl}, + rmc::{ + protocols::friends::{ + BlacklistedPrincipal, Comment, FriendInfo, FriendRequest, NNAInfo, NintendoPresenceV2, + PersistentNotification, PrincipalPreference, + }, + response::ErrorCode, + structures::{any::Any, qresult::QResult}, + }, +}; +use std::sync::atomic::Ordering::Relaxed; +use tokio::time::sleep; + +use rnex_core::rmc::protocols::friends::{GameKey, MiiV2, PrincipalBasicInfo}; + +define_rmc_proto!( + proto FriendsUser{ + Secure, + Friends + } +); +#[rmc_struct(FriendsUser)] +pub struct FriendsUser { + pub fm: Arc, + pub addr: PRUDPSockAddr, + pub pid: u32, +} + +pub struct FriendsManager { + pub cid_counter: AtomicU32, +} + +impl FriendsManager { + pub fn next_cid(&self) -> u32 { + self.cid_counter.fetch_add(1, Relaxed) + } +} + +impl Friends for FriendsUser { + async fn update_and_get_all_information( + &self, + info: NNAInfo, + presence: NintendoPresenceV2, + date_time: KerberosDateTime, + ) -> Result< + ( + PrincipalPreference, + Comment, + Vec, + Vec, + Vec, + Vec, + bool, + Vec, + bool, + ), + ErrorCode, + > { + Ok(( + PrincipalPreference { + block_friend_request: false, + show_online: false, + show_playing_title: false, + }, + Comment { + last_changed: KerberosDateTime::now(), + message: "".to_string(), + unk: 0, + }, + vec![FriendInfo { + became_friends: KerberosDateTime::now(), + comment: Comment { + last_changed: KerberosDateTime::now(), + message: "I'm just a dummy account :3".to_string(), + unk: 0, + }, + last_online: KerberosDateTime::now(), + nna_info: NNAInfo { + principal_basic_info: PrincipalBasicInfo { + pid: 101, + nnid: "dummyaccount".to_string(), + mii: MiiV2{ + date_time: KerberosDateTime::now(), + name: "Dummy Account".to_string(), + mii_data: hex::decode("030000402bd7c32986a771f2dc6b35e31da15e37ff7c0000391e6f006f006d0069000000000000000000000000004040001065033568641e2013661a611821640f0000290052485000000000000000000000000000000000000000000000e838").unwrap(), + unk: 0, + unk2: 0, + }, + unk: 0 + }, + unk: 0, + unk2: 0 + }, + presence: NintendoPresenceV2{ + changed_flags: 0, + message: "".to_string(), + app_data: vec![], + game_key: GameKey{ + tid: 0x00050002101ce400, + version: 0x0 + }, + game_server_id: 0, + is_online: true, + gid: 0, + pid: 101, + unk: 0, + unk2: 0, + unk3: 0, + unk4: 0, + unk5: 0, + unk6: 0, + unk7: 0 + }, + unk: 0 + }], + vec![], + vec![], + vec![], + false, + vec![], + false, + )) + } +} + +impl Secure for FriendsUser { + async fn register( + &self, + station_urls: Vec, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + let cid = self.fm.next_cid(); + Ok(( + QResult::success(ErrorCode::Core_Unknown), + cid, + get_station_urls(&station_urls, self.addr, self.pid, cid).await?[0].clone(), + )) + } + async fn register_ex( + &self, + station_urls: Vec, + data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + info!("register"); + self.register(station_urls).await + } + async fn replace_url(&self, target: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> { + Err(ErrorCode::Core_NotImplemented) + } +} diff --git a/rnex-core/src/nex/mod.rs b/rnex-core/src/nex/mod.rs index 76791bc..0f52c13 100644 --- a/rnex-core/src/nex/mod.rs +++ b/rnex-core/src/nex/mod.rs @@ -1,5 +1,7 @@ pub mod account; pub mod auth_handler; -pub mod user; +pub mod common; +pub mod friends_handler; +pub mod matchmake; pub mod remote_console; -pub mod matchmake; \ No newline at end of file +pub mod user; diff --git a/rnex-core/src/nex/user.rs b/rnex-core/src/nex/user.rs index 221c90a..1666d56 100644 --- a/rnex-core/src/nex/user.rs +++ b/rnex-core/src/nex/user.rs @@ -1,4 +1,5 @@ use crate::define_rmc_proto; +use crate::nex::common::get_station_urls; use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager}; use crate::nex::remote_console::RemoteConsole; use crate::rmc::protocols::matchmake::{ @@ -21,6 +22,7 @@ use rnex_core::rmc::protocols::matchmake_extension::{ use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking}; use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure}; use rnex_core::rmc::response::ErrorCode; +use rnex_core::rmc::structures::any::Any; use rnex_core::rmc::structures::matchmake::{ AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession, }; @@ -71,97 +73,27 @@ impl Secure for User { users.insert(cid, self.this.clone()); drop(users); - let mut public_station: Option = None; - let mut private_station: Option = None; + let stations = get_station_urls(&station_urls, self.ip, self.pid, cid).await?; - for station in station_urls { - let is_public = station.options.iter().any(|v| { - if let NatType(v) = v { - if *v & PUBLIC != 0 { - return true; - } - } - false - }); - - let Some(nat_filtering) = station.options.iter().find_map(|v| match v { - NatFiltering(v) => Some(v), - _ => None, - }) else { - return Err(Core_Exception); - }; - - let Some(nat_mapping) = station.options.iter().find_map(|v| match v { - NatMapping(v) => Some(v), - _ => None, - }) else { - return Err(Core_Exception); - }; - - if !is_public || (*nat_filtering == 0 && *nat_mapping == 0) { - private_station = Some(station.clone()); - } - - if is_public { - public_station = Some(station); - } - } - - let Some(mut private_station) = private_station else { - return Err(Core_Exception); - }; - - let mut public_station = if let Some(public_station) = public_station { - public_station - } else { - let mut public_station = private_station.clone(); - - public_station.options.retain(|v| match v { - Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false, - _ => true, - }); - - public_station - .options - .push(Address(*self.ip.regular_socket_addr.ip())); - public_station - .options - .push(Port(self.ip.regular_socket_addr.port())); - public_station.options.push(NatFiltering(0)); - public_station.options.push(NatMapping(0)); - public_station.options.push(NatType(3)); - - public_station - }; - - let both = [&mut public_station, &mut private_station]; - - for station in both { - station.options.retain(|v| match v { - PrincipalID(_) | RVConnectionID(_) => false, - _ => true, - }); - - station.options.push(PrincipalID(self.pid)); - station.options.push(RVConnectionID(cid)); - } + let first = stations.first().unwrap().clone(); let mut lock = self.station_url.write().await; - *lock = vec![ - public_station.clone(), - // private_station.clone() - ]; + *lock = stations; drop(lock); let result = QResult::success(ErrorCode::Core_Unknown); - let out = public_station.to_string(); + Ok((result, cid, first)) + } - println!("out: {}", out); - - Ok((result, cid, public_station)) + async fn register_ex( + &self, + station_urls: Vec, + _data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode> { + self.register(station_urls).await } async fn replace_url(&self, target_url: StationUrl, dest: StationUrl) -> Result<(), ErrorCode> { diff --git a/rnex-core/src/prudp/mod.rs b/rnex-core/src/prudp/mod.rs index fdc991a..501463a 100644 --- a/rnex-core/src/prudp/mod.rs +++ b/rnex-core/src/prudp/mod.rs @@ -1,5 +1,6 @@ pub mod encryption; pub mod socket_addr; pub mod station_url; +pub mod ticket; pub mod types_flags; pub mod virtual_port; diff --git a/rnex-core/src/prudp/socket_addr.rs b/rnex-core/src/prudp/socket_addr.rs index f5eb179..4ffac83 100644 --- a/rnex-core/src/prudp/socket_addr.rs +++ b/rnex-core/src/prudp/socket_addr.rs @@ -1,26 +1,24 @@ +use hmac::Hmac; +use macros::RmcSerialize; +use md5::digest::Mac; +use rnex_core::prudp::virtual_port::VirtualPort; use std::io::Write; use std::net::SocketAddrV4; -use hmac::{Hmac}; -use md5::digest::Mac; -use macros::RmcSerialize; -use rnex_core::prudp::virtual_port::VirtualPort; type Md5Hmac = Hmac; #[derive(Eq, PartialEq, Hash, Debug, Copy, Clone, Ord, PartialOrd, RmcSerialize)] #[rmc_struct(0)] -pub struct PRUDPSockAddr{ +pub struct PRUDPSockAddr { pub regular_socket_addr: SocketAddrV4, - pub virtual_port: VirtualPort + pub virtual_port: VirtualPort, } - - -impl PRUDPSockAddr{ - pub fn new(regular_socket_addr: SocketAddrV4, virtual_port: VirtualPort) -> Self{ - Self{ +impl PRUDPSockAddr { + pub fn new(regular_socket_addr: SocketAddrV4, virtual_port: VirtualPort) -> Self { + Self { regular_socket_addr, - virtual_port + virtual_port, } } @@ -30,8 +28,11 @@ impl PRUDPSockAddr{ let data = self.regular_socket_addr.ip().octets().to_vec(); //data.extend_from_slice(&self.regular_socket_addr.port().to_be_bytes()); - hmac.write_all(&data).expect("figuring this out was complete ass"); - let result: [u8; 16] = hmac.finalize().into_bytes()[0..16].try_into().expect("fuck"); + hmac.write_all(&data) + .expect("figuring this out was complete ass"); + let result: [u8; 16] = hmac.finalize().into_bytes()[0..16] + .try_into() + .expect("fuck"); result } -} \ No newline at end of file +} diff --git a/rnex-core/src/prudp/ticket.rs b/rnex-core/src/prudp/ticket.rs new file mode 100644 index 0000000..9fd094d --- /dev/null +++ b/rnex-core/src/prudp/ticket.rs @@ -0,0 +1,81 @@ +use std::io::Cursor; + +use log::{error, info}; +use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher, cipher::StreamCipherCoreWrapper}; +use typenum::{U16, U32}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; + +use crate::{ + kerberos::{SESSION_KEY_LENGTH, SESSION_KEY_LENGTH_TY, TicketInternalData, derive_key}, + nex::account::Account, + rmc::structures::RmcSerialize, +}; + +pub fn read_secure_connection_data( + data: &[u8], + act: &Account, +) -> Option<([u8; SESSION_KEY_LENGTH], u32, u32)> { + let mut cursor = Cursor::new(data); + + let mut ticket_data: Vec = Vec::deserialize(&mut cursor).ok()?; + let mut request_data: Vec = Vec::deserialize(&mut cursor).ok()?; + info!( + "done + request data" + ); + + let ticket_data_size = ticket_data.len(); + + let ticket_data = &mut ticket_data[0..ticket_data_size - 0x10]; + + let server_key = derive_key(act.pid, &act.kerbros_password[..]); + + let mut rc4: StreamCipherCoreWrapper> = + Rc4::new_from_slice(&server_key).expect("unable to init rc4 keystream"); + + rc4.apply_keystream(ticket_data); + + let ticket_data: &TicketInternalData = match bytemuck::try_from_bytes(ticket_data) { + Ok(v) => v, + Err(e) => { + error!("unable to read internal ticket data: {}", e); + return None; + } + }; + + // todo: add ticket expiration + + let TicketInternalData { + session_key, + pid: ticket_source_pid, + issued_time, + } = *ticket_data; + + // todo: add checking if tickets are signed with a valid md5-hmac + let request_data_length = request_data.len(); + let request_data = &mut request_data[0..request_data_length - 0x10]; + + let mut rc4: StreamCipherCoreWrapper> = + Rc4::new_from_slice(&session_key).expect("unable to init rc4 keystream"); + + rc4.apply_keystream(request_data); + + let mut reqest_data_cursor = Cursor::new(request_data); + + let pid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; + + if pid != ticket_source_pid { + let ticket_created_on = issued_time.to_regular_time(); + + error!( + "someone tried to spoof their pid, ticket was created on: {}", + ticket_created_on.to_rfc2822() + ); + return None; + } + + let _cid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; + let response_check: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?; + + Some((session_key, pid, response_check)) +} diff --git a/rnex-core/src/rmc/protocols/auth.rs b/rnex-core/src/rmc/protocols/auth.rs index 774f1f9..594d9dd 100644 --- a/rnex-core/src/rmc/protocols/auth.rs +++ b/rnex-core/src/rmc/protocols/auth.rs @@ -1,4 +1,4 @@ -use crate::rmc::structures::connection_data::ConnectionData; +use crate::rmc::structures::connection_data::{ConnectionData, ConnectionDataOld}; use macros::{method_id, rmc_proto}; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::any::Any; @@ -14,7 +14,7 @@ pub trait Auth { async fn login( &self, name: String, - ) -> Result<(QResult, u32, Vec, ConnectionData, String), ErrorCode>; + ) -> Result<(QResult, u32, Vec, ConnectionDataOld, String), ErrorCode>; /// representation of the `LoginEx` method(for details see the /// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol)) diff --git a/rnex-core/src/rmc/protocols/friends.rs b/rnex-core/src/rmc/protocols/friends.rs new file mode 100644 index 0000000..775016e --- /dev/null +++ b/rnex-core/src/rmc/protocols/friends.rs @@ -0,0 +1,146 @@ +use macros::{RmcSerialize, method_id, rmc_proto}; + +use rnex_core::{kerberos::KerberosDateTime, rmc::response::ErrorCode}; + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct MiiV2 { + pub name: String, + pub unk: u8, + pub unk2: u8, + pub mii_data: Vec, + pub date_time: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct PrincipalBasicInfo { + pub pid: u32, + pub nnid: String, + pub mii: MiiV2, + pub unk: u8, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NNAInfo { + pub principal_basic_info: PrincipalBasicInfo, + pub unk: u8, + pub unk2: u8, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct GameKey { + pub tid: u64, + pub version: u16, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct NintendoPresenceV2 { + pub changed_flags: u32, + pub is_online: bool, + pub game_key: GameKey, + pub unk: u8, + pub message: String, + pub unk2: u32, + pub unk3: u8, + pub game_server_id: u32, + pub unk4: u32, + pub pid: u32, + pub gid: u32, + pub app_data: Vec, + pub unk5: u8, + pub unk6: u8, + pub unk7: u8, +} +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct PrincipalPreference { + pub show_online: bool, + pub show_playing_title: bool, + pub block_friend_request: bool, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct Comment { + pub unk: u8, + pub message: String, + pub last_changed: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct FriendInfo { + pub nna_info: NNAInfo, + pub presence: NintendoPresenceV2, + pub comment: Comment, + pub became_friends: KerberosDateTime, + pub last_online: KerberosDateTime, + pub unk: u64, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct FriendRequestMessage { + pub friend_request_id: u64, + pub is_recieved: u8, + pub unk: u8, + pub message: String, + pub unk2: u8, + pub unk3: String, + pub game_key: GameKey, + pub unk4: KerberosDateTime, + pub expires_on: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct FriendRequest { + pub basic_info: PrincipalBasicInfo, + pub request_message: FriendRequestMessage, + pub sent_on: KerberosDateTime, +} + +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct BlacklistedPrincipal { + pub basic_info: PrincipalBasicInfo, + pub game_key: GameKey, + pub since: KerberosDateTime, +} +#[derive(RmcSerialize)] +#[rmc_struct(0)] +pub struct PersistentNotification { + pub unk1: u64, + pub unk2: u32, + pub unk3: u32, + pub unk4: u32, + pub unk5: String, +} + +#[rmc_proto(102)] +pub trait Friends { + #[method_id(1)] + async fn update_and_get_all_information( + &self, + info: NNAInfo, + presence: NintendoPresenceV2, + date_time: KerberosDateTime, + ) -> Result< + ( + PrincipalPreference, + Comment, + Vec, + Vec, + Vec, + Vec, + bool, + Vec, + bool, + ), + ErrorCode, + >; +} diff --git a/rnex-core/src/rmc/protocols/mod.rs b/rnex-core/src/rmc/protocols/mod.rs index fb0f055..6896cf3 100644 --- a/rnex-core/src/rmc/protocols/mod.rs +++ b/rnex-core/src/rmc/protocols/mod.rs @@ -1,6 +1,7 @@ #![allow(async_fn_in_trait)] pub mod auth; +pub mod friends; pub mod matchmake; pub mod matchmake_ext; pub mod matchmake_extension; @@ -294,8 +295,8 @@ async fn handle_incoming( } = message; info!( - "RMC REQUEST: Proto: {}; Method: {};", - protocol_id, method_id + "RMC REQUEST: Proto: {}; Method: {}; cid: {}", + protocol_id, method_id, call_id ); remote diff --git a/rnex-core/src/rmc/protocols/secure.rs b/rnex-core/src/rmc/protocols/secure.rs index 50afb5b..3df23c6 100644 --- a/rnex-core/src/rmc/protocols/secure.rs +++ b/rnex-core/src/rmc/protocols/secure.rs @@ -3,10 +3,21 @@ use rnex_core::prudp::station_url::StationUrl; use rnex_core::rmc::response::ErrorCode; use rnex_core::rmc::structures::qresult::QResult; +use crate::rmc::structures::any::Any; + #[rmc_proto(11)] pub trait Secure { #[method_id(1)] - async fn register(&self, station_urls: Vec) -> Result<(QResult, u32, StationUrl), ErrorCode>; + async fn register( + &self, + station_urls: Vec, + ) -> Result<(QResult, u32, StationUrl), ErrorCode>; + #[method_id(4)] + async fn register_ex( + &self, + station_urls: Vec, + data: Any, + ) -> Result<(QResult, u32, StationUrl), ErrorCode>; #[method_id(7)] async fn replace_url(&self, target: StationUrl, dest: StationUrl) -> Result<(), ErrorCode>; } diff --git a/rnex-core/src/rmc/structures/any.rs b/rnex-core/src/rmc/structures/any.rs index b60ca8a..c4dc2ce 100644 --- a/rnex-core/src/rmc/structures/any.rs +++ b/rnex-core/src/rmc/structures/any.rs @@ -1,14 +1,14 @@ +use rnex_core::rmc::structures::{Result, RmcSerialize}; use std::io::{Read, Write}; use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -use super::{Result, RmcSerialize}; #[derive(Debug, Default)] -pub struct Any{ +pub struct Any { pub name: String, - pub data: Vec + pub data: Vec, } -impl RmcSerialize for Any{ +impl RmcSerialize for Any { fn serialize(&self, writer: &mut impl Write) -> Result<()> { self.name.serialize(writer)?; @@ -32,11 +32,6 @@ impl RmcSerialize for Any{ reader.read_exact(&mut data)?; - Ok( - Any{ - name, - data - } - ) + Ok(Any { name, data }) } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/buffer.rs b/rnex-core/src/rmc/structures/buffer.rs index 085f053..c147133 100644 --- a/rnex-core/src/rmc/structures/buffer.rs +++ b/rnex-core/src/rmc/structures/buffer.rs @@ -1,10 +1,9 @@ -use std::io::{Read, Write}; +use crate::rmc::structures::Result; use crate::rmc::structures::RmcSerialize; +use std::io::{Read, Write}; - - -impl<'a> RmcSerialize for &'a [u8]{ - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { +impl<'a> RmcSerialize for &'a [u8] { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { let u32_size = self.len() as u32; writer.write(bytemuck::bytes_of(&u32_size))?; writer.write(self)?; @@ -13,25 +12,25 @@ impl<'a> RmcSerialize for &'a [u8]{ } /// DO NOT USE (also maybe split off the serialize and deserialize functions at some point) - fn deserialize(_reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(_reader: &mut impl Read) -> Result { panic!("cannot deserialize to a u8 slice reference (use this ONLY for writing)") } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { Ok(4 + self.len() as u32) } } -impl RmcSerialize for Box<[u8]>{ - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { +impl RmcSerialize for Box<[u8]> { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { (&self[..]).serialize(writer) } - fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { + fn deserialize(reader: &mut impl Read) -> Result { Vec::deserialize(reader).map(|v| v.into_boxed_slice()) } - fn serialize_write_size(&self) -> crate::rmc::structures::Result { + fn serialize_write_size(&self) -> Result { (&self[..]).serialize_write_size() } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/connection_data.rs b/rnex-core/src/rmc/structures/connection_data.rs index da6a17b..d134e85 100644 --- a/rnex-core/src/rmc/structures/connection_data.rs +++ b/rnex-core/src/rmc/structures/connection_data.rs @@ -1,13 +1,19 @@ - use macros::RmcSerialize; use rnex_core::kerberos::KerberosDateTime; #[derive(Debug, RmcSerialize)] #[rmc_struct(1)] -pub struct ConnectionData{ +pub struct ConnectionData { pub station_url: String, pub special_protocols: Vec, pub special_station_url: String, - pub date_time: KerberosDateTime + pub date_time: KerberosDateTime, } +#[derive(Debug, RmcSerialize)] +#[rmc_struct(1)] +pub struct ConnectionDataOld { + pub station_url: String, + pub special_protocols: Vec, + pub special_station_url: String, +} diff --git a/rnex-core/src/rmc/structures/primitives.rs b/rnex-core/src/rmc/structures/primitives.rs index 8918968..3bdd835 100644 --- a/rnex-core/src/rmc/structures/primitives.rs +++ b/rnex-core/src/rmc/structures/primitives.rs @@ -1,9 +1,9 @@ -use std::io::{Read, Write}; -use bytemuck::bytes_of; -use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; use crate::rmc::structures::RmcSerialize; +use bytemuck::bytes_of; +use std::io::{Read, Write}; +use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions}; -impl RmcSerialize for u8{ +impl RmcSerialize for u8 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -19,7 +19,7 @@ impl RmcSerialize for u8{ } } -impl RmcSerialize for i8{ +impl RmcSerialize for i8 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -35,7 +35,7 @@ impl RmcSerialize for i8{ } } -impl RmcSerialize for u16{ +impl RmcSerialize for u16 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -50,7 +50,7 @@ impl RmcSerialize for u16{ } } -impl RmcSerialize for i16{ +impl RmcSerialize for i16 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -65,7 +65,7 @@ impl RmcSerialize for i16{ } } -impl RmcSerialize for u32{ +impl RmcSerialize for u32 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -80,7 +80,7 @@ impl RmcSerialize for u32{ } } -impl RmcSerialize for i32{ +impl RmcSerialize for i32 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -95,7 +95,7 @@ impl RmcSerialize for i32{ } } -impl RmcSerialize for u64{ +impl RmcSerialize for u64 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -110,7 +110,7 @@ impl RmcSerialize for u64{ } } -impl RmcSerialize for i64{ +impl RmcSerialize for i64 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -125,7 +125,7 @@ impl RmcSerialize for i64{ } } -impl RmcSerialize for f64{ +impl RmcSerialize for f64 { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { Ok(writer.write_all(bytes_of(self))?) @@ -141,10 +141,10 @@ impl RmcSerialize for f64{ } } -impl RmcSerialize for bool{ +impl RmcSerialize for bool { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { - match self{ + match self { true => writer.write_all(&[1])?, false => writer.write_all(&[0])?, } @@ -161,8 +161,7 @@ impl RmcSerialize for bool{ } } - -impl RmcSerialize for (T, U){ +impl RmcSerialize for (T, U) { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -178,14 +177,11 @@ impl RmcSerialize for (T, U){ } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + self.1.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V){ +impl RmcSerialize for (T, U, V) { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -203,15 +199,15 @@ impl RmcSerialize for (T, U, } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W){ +impl RmcSerialize + for (T, U, V, W) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -231,16 +227,16 @@ impl RmcSeri } #[inline(always)] fn serialize_write_size(&self) -> crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W, X){ +impl + RmcSerialize for (T, U, V, W, X) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -264,17 +260,23 @@ impl crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W, X, Y){ +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -300,18 +302,25 @@ impl crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? + - self.4.serialize_write_size()? + - self.5.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()?) } } -impl RmcSerialize for (T, U, V, W, X, Y, Z){ +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, + Z: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y, Z) +{ #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.0.serialize(writer)?; @@ -338,19 +347,123 @@ impl crate::rmc::structures::Result { - Ok( - self.0.serialize_write_size()? + - self.1.serialize_write_size()? + - self.2.serialize_write_size()? + - self.3.serialize_write_size()? + - self.4.serialize_write_size()? + - self.5.serialize_write_size()? + - self.6.serialize_write_size()? - ) + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()?) } } -impl RmcSerialize for Box{ +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, + Z: RmcSerialize, + A: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y, Z, A) +{ + #[inline(always)] + fn serialize(&self, writer: &mut impl 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)?; + self.7.serialize(writer)?; + + Ok(()) + } + #[inline(always)] + fn deserialize(reader: &mut impl 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)?; + let eighth = A::deserialize(reader)?; + + Ok((first, second, third, fourth, fifth, sixth, seventh, eighth)) + } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()? + + self.7.serialize_write_size()?) + } +} + +impl< + T: RmcSerialize, + U: RmcSerialize, + V: RmcSerialize, + W: RmcSerialize, + X: RmcSerialize, + Y: RmcSerialize, + Z: RmcSerialize, + A: RmcSerialize, + B: RmcSerialize, +> RmcSerialize for (T, U, V, W, X, Y, Z, A, B) +{ + #[inline(always)] + fn serialize(&self, writer: &mut impl 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)?; + self.7.serialize(writer)?; + self.8.serialize(writer)?; + + Ok(()) + } + #[inline(always)] + fn deserialize(reader: &mut impl 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)?; + let eighth = A::deserialize(reader)?; + let nineth = B::deserialize(reader)?; + + Ok(( + first, second, third, fourth, fifth, sixth, seventh, eighth, nineth, + )) + } + #[inline(always)] + fn serialize_write_size(&self) -> crate::rmc::structures::Result { + Ok(self.0.serialize_write_size()? + + self.1.serialize_write_size()? + + self.2.serialize_write_size()? + + self.3.serialize_write_size()? + + self.4.serialize_write_size()? + + self.5.serialize_write_size()? + + self.6.serialize_write_size()? + + self.7.serialize_write_size()? + + self.8.serialize_write_size()?) + } +} + +impl RmcSerialize for Box { #[inline(always)] fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { self.as_ref().serialize(writer) @@ -363,4 +476,4 @@ impl RmcSerialize for Box{ fn serialize_write_size(&self) -> crate::rmc::structures::Result { T::serialize_write_size(self.as_ref()) } -} \ No newline at end of file +} diff --git a/rnex-core/src/rmc/structures/variant.rs b/rnex-core/src/rmc/structures/variant.rs index 6056f3f..9f705d0 100644 --- a/rnex-core/src/rmc/structures/variant.rs +++ b/rnex-core/src/rmc/structures/variant.rs @@ -1,10 +1,10 @@ +use rnex_core::kerberos::KerberosDateTime; +use rnex_core::rmc::structures; +use rnex_core::rmc::structures::{Result, RmcSerialize}; use std::io::{Read, Write}; -use crate::kerberos::KerberosDateTime; -use crate::rmc::structures; -use crate::rmc::structures::RmcSerialize; #[derive(Debug, Clone, Default)] -pub enum Variant{ +pub enum Variant { #[default] None, SInt64(i64), @@ -15,9 +15,9 @@ pub enum Variant{ UInt64(u64), } -impl RmcSerialize for Variant{ - fn serialize(&self, writer: &mut impl Write) -> crate::rmc::structures::Result<()> { - match self{ +impl RmcSerialize for Variant { + fn serialize(&self, writer: &mut impl Write) -> Result<()> { + match self { Variant::None => { writer.write_all(&[0])?; } @@ -50,8 +50,8 @@ impl RmcSerialize for Variant{ Ok(()) } - fn deserialize(reader: &mut impl Read) -> crate::rmc::structures::Result { - match u8::deserialize(reader)?{ + fn deserialize(reader: &mut impl Read) -> Result { + match u8::deserialize(reader)? { 0 => Ok(Variant::None), 1 => Ok(Variant::SInt64(i64::deserialize(reader)?)), 2 => Ok(Variant::Double(f64::deserialize(reader)?)), @@ -59,7 +59,7 @@ impl RmcSerialize for Variant{ 4 => Ok(Variant::String(String::deserialize(reader)?)), 5 => Ok(Variant::DateTime(KerberosDateTime::deserialize(reader)?)), 6 => Ok(Variant::UInt64(u64::deserialize(reader)?)), - v => Err(structures::Error::UnexpectedValue(v as u64)) + v => Err(structures::Error::UnexpectedValue(v as u64)), } } -} \ No newline at end of file +}