feat(secure): a lot of things

This commit is contained in:
DJMrTV 2025-02-06 17:54:38 +01:00
commit 2b9f55e4d2
24 changed files with 435 additions and 98 deletions

View file

@ -1,7 +1,6 @@
extern crate proc_macro; extern crate proc_macro;
use proc_macro2::TokenTree; use proc_macro2::TokenTree;
use quote::__private::ext::RepToTokensExt;
use proc_macro::TokenStream; use proc_macro::TokenStream;
use syn::{parse_macro_input, DeriveInput, Data}; use syn::{parse_macro_input, DeriveInput, Data};
@ -23,7 +22,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
panic!("rmc struct type MUST be a struct"); panic!("rmc struct type MUST be a struct");
}; };
/// generate base data // generate base data
let serialize_base_content = { let serialize_base_content = {
let mut serialize_content = quote! {}; let mut serialize_content = quote! {};
@ -87,7 +86,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
} }
}; };
/// generate base with extends stuff // generate base with extends stuff
let serialize_base_content = if let Some(attr) = struct_attr{ let serialize_base_content = if let Some(attr) = struct_attr{
let tokens = attr.tokens.clone(); let tokens = attr.tokens.clone();

View file

@ -25,9 +25,9 @@ pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{
key key
} }
#[derive(Pod, Zeroable, Copy, Clone)] #[derive(Pod, Zeroable, Copy, Clone, Debug, Eq, PartialEq)]
#[repr(transparent)] #[repr(transparent)]
pub struct KerberosDateTime(u64); pub struct KerberosDateTime(pub u64);
impl KerberosDateTime{ impl KerberosDateTime{
pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year:u64 ) -> Self { pub fn new(second: u64, minute: u64, hour: u64, day: u64, month: u64, year:u64 ) -> Self {

View file

@ -1,6 +1,7 @@
#![allow(dead_code)] #![allow(dead_code)]
use std::{env, fs}; use std::{env, fs};
use std::collections::BTreeMap;
use std::fs::File; use std::fs::File;
use std::net::{Ipv4Addr, SocketAddrV4}; use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::Arc; use std::sync::Arc;
@ -11,7 +12,7 @@ use once_cell::sync::Lazy;
use rc4::{KeyInit, Rc4, StreamCipher}; use rc4::{KeyInit, Rc4, StreamCipher};
use rc4::consts::U5; use rc4::consts::U5;
use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger}; use simplelog::{ColorChoice, CombinedLogger, Config, LevelFilter, TerminalMode, TermLogger, WriteLogger};
use tokio::sync::Mutex; use tokio::sync::{Mutex, RwLock};
use tokio::task::JoinHandle; use tokio::task::JoinHandle;
use crate::nex::account::Account; use crate::nex::account::Account;
use crate::protocols::{auth, block_if_maintenance}; use crate::protocols::{auth, block_if_maintenance};
@ -151,7 +152,7 @@ async fn start_auth_server() -> AuthServer{
}), }),
Box::new(move |packet, socket, connection|{ Box::new(move |packet, socket, connection|{
let rmcserver = rmcserver.clone(); let rmcserver = rmcserver.clone();
Box::pin(async move { rmcserver.process_message(packet, &socket, connection).await; }) Box::pin(async move { rmcserver.process_message(packet, socket, connection).await; })
}) })
).await.expect("unable to create socket"); ).await.expect("unable to create socket");
@ -177,13 +178,16 @@ async fn start_secure_server() -> SecureServer{
info!("setting up endpoints"); info!("setting up endpoints");
let matchmake_data = Arc::new(Mutex::new( let matchmake_data = Arc::new(RwLock::new(
MatchmakeData{} MatchmakeData{
matchmake_sessions: BTreeMap::new()
}
)); ));
let rmcserver = RMCProtocolServer::new(Box::new([ let rmcserver = RMCProtocolServer::new(Box::new([
Box::new(block_if_maintenance), Box::new(block_if_maintenance),
Box::new(protocols::secure::bound_protocol()), Box::new(protocols::secure::bound_protocol()),
Box::new(protocols::matchmake::bound_protocol(matchmake_data.clone())),
Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data)) Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data))
])); ]));
@ -218,7 +222,7 @@ async fn start_secure_server() -> SecureServer{
}), }),
Box::new(move |packet, socket, connection|{ Box::new(move |packet, socket, connection|{
let rmcserver = rmcserver.clone(); let rmcserver = rmcserver.clone();
Box::pin(async move { rmcserver.process_message(packet, &socket, connection).await; }) Box::pin(async move { rmcserver.process_message(packet, socket, connection).await; })
}) })
).await.expect("unable to create socket"); ).await.expect("unable to create socket");

View file

@ -1,8 +1,10 @@
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc;
use log::error; use log::error;
use tokio::sync::Mutex;
use crate::nex::account::Account; use crate::nex::account::Account;
use crate::protocols::auth::AuthProtocolConfig; use crate::protocols::auth::AuthProtocolConfig;
use crate::prudp::socket::ConnectionData; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult}; use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::structures::RmcSerialize; use crate::rmc::structures::RmcSerialize;
@ -13,7 +15,7 @@ pub async fn login(rmcmessage: &RMCMessage, _name: &str) -> RMCResponseResult{
rmcmessage.error_result_with_code(ErrorCode::Core_NotImplemented) rmcmessage.error_result_with_code(ErrorCode::Core_NotImplemented)
} }
pub async fn login_raw_params(rmcmessage: &RMCMessage, _: &mut ConnectionData, data: AuthProtocolConfig) -> RMCResponseResult{ pub async fn login_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, _: &Arc<Mutex<ConnectionData>>, data: AuthProtocolConfig) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data); let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(str) = String::deserialize(&mut reader) else { let Ok(str) = String::deserialize(&mut reader) else {

View file

@ -1,13 +1,15 @@
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
use std::sync::Arc;
use bytemuck::bytes_of; use bytemuck::bytes_of;
use hex::encode; use hex::encode;
use log::{error}; use log::{error};
use tokio::sync::Mutex;
use crate::grpc::account; use crate::grpc::account;
use crate::kerberos::KerberosDateTime; use crate::kerberos::KerberosDateTime;
use crate::nex::account::Account; use crate::nex::account::Account;
use crate::protocols::auth::AuthProtocolConfig; use crate::protocols::auth::AuthProtocolConfig;
use crate::protocols::auth::ticket_generation::generate_ticket; use crate::protocols::auth::ticket_generation::generate_ticket;
use crate::prudp::socket::ConnectionData; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc; use crate::rmc;
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult}; use crate::rmc::response::{ErrorCode, RMCResponseResult};
@ -51,7 +53,7 @@ pub async fn login_ex(rmcmessage: &RMCMessage, proto_data: AuthProtocolConfig, p
return rmcmessage.success_with_data(response); return rmcmessage.success_with_data(response);
} }
pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, _: &mut ConnectionData, data: AuthProtocolConfig) -> RMCResponseResult{ pub async fn login_ex_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, _: &Arc<Mutex<ConnectionData>>, data: AuthProtocolConfig) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data); let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(str) = String::deserialize(&mut reader) else { let Ok(str) = String::deserialize(&mut reader) else {

View file

@ -1,11 +1,13 @@
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc;
use log::error; use log::error;
use tokio::sync::Mutex;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use crate::grpc::account; use crate::grpc::account;
use crate::protocols::auth::{AuthProtocolConfig, get_login_data_by_pid}; use crate::protocols::auth::{AuthProtocolConfig, get_login_data_by_pid};
use crate::protocols::auth::method_login_ex::login_ex; use crate::protocols::auth::method_login_ex::login_ex;
use crate::protocols::auth::ticket_generation::generate_ticket; use crate::protocols::auth::ticket_generation::generate_ticket;
use crate::prudp::socket::ConnectionData; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult}; use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::response::ErrorCode::Core_Unknown; use crate::rmc::response::ErrorCode::Core_Unknown;
@ -39,7 +41,7 @@ pub async fn request_ticket(rmcmessage: &RMCMessage, data: AuthProtocolConfig, s
rmcmessage.success_with_data(response) rmcmessage.success_with_data(response)
} }
pub async fn request_ticket_raw_params(rmcmessage: &RMCMessage, _: &mut ConnectionData, data: AuthProtocolConfig) -> RMCResponseResult{ pub async fn request_ticket_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, _: &Arc<Mutex<ConnectionData>>, data: AuthProtocolConfig) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data); let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(source_pid) = reader.read_struct(IS_BIG_ENDIAN) else { let Ok(source_pid) = reader.read_struct(IS_BIG_ENDIAN) else {

View file

@ -0,0 +1,37 @@
use std::io::Cursor;
use std::sync::Arc;
use log::info;
use tokio::sync::{Mutex, RwLock};
use crate::protocols::matchmake_common::MatchmakeData;
use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::structures::qresult::QResult;
use crate::rmc::structures::RmcSerialize;
pub async fn unregister_gathering(rmcmessage: &RMCMessage, gid: u32, data: Arc<RwLock<MatchmakeData>>) -> RMCResponseResult{
let mut rd = data.write().await;
rd.matchmake_sessions.remove(&gid);
let result = QResult::success(ErrorCode::Core_Unknown);
let mut response = Vec::new();
result.serialize(&mut response).expect("aaa");
rmcmessage.success_with_data(response)
}
pub async fn unregister_gathering_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, _: &Arc<Mutex<ConnectionData>>, data: Arc<RwLock<MatchmakeData>>) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(gid) = u32::deserialize(&mut reader) else {
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
unregister_gathering(rmcmessage, gid, data).await
}

View file

@ -0,0 +1,13 @@
mod method_unregister_gathering;
use std::sync::Arc;
use tokio::sync::RwLock;
use crate::define_protocol;
use crate::protocols::matchmake::method_unregister_gathering::unregister_gathering_raw_params;
use crate::protocols::matchmake_common::MatchmakeData;
define_protocol!{
21(matchmake_data: Arc<RwLock<MatchmakeData>>) => {
2 => unregister_gathering_raw_params
}
}

View file

@ -1,4 +1,63 @@
pub struct MatchmakeData{ use std::collections::{BTreeMap, HashMap};
use std::sync::Arc;
use log::error;
use tokio::sync::Mutex;
use crate::protocols::notification::Notification;
use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::structures::matchmake::MatchmakeSession;
pub struct ExtendedMatchmakeSession{
pub session: MatchmakeSession,
pub connected_players: Vec<Arc<Mutex<ConnectionData>>>,
} }
pub struct MatchmakeData{
pub(crate) matchmake_sessions: BTreeMap<u32, Arc<Mutex<ExtendedMatchmakeSession>>>
}
impl ExtendedMatchmakeSession{
pub async fn add_player(&mut self, socket: &SocketData, conn: Arc<Mutex<ConnectionData>>, join_msg: String) {
let Some(pid) = conn.lock().await.active_connection_data.as_ref()
.map(|c|
c.active_secure_connection_data.as_ref()
.map(|c| c.pid
)
).flatten() else {
error!("tried to add player without secure connection");
return
};
self.connected_players.push(conn);
for conn in &self.connected_players{
let Some(other_pid) = conn.lock().await.active_connection_data.as_ref()
.map(|c|
c.active_secure_connection_data.as_ref()
.map(|c| c.pid
)
).flatten() else {
error!("tried to send connection notification to player secure connection");
return
};
let mut conn = conn.lock().await;
conn.send_notification(socket, Notification{
pid_source: pid,
notif_type: 3001,
param_1: self.session.gathering.self_gid,
param_2: other_pid,
str_param: join_msg.clone(),
}).await;
}
}
}
impl MatchmakeData {
pub async fn try_find_session_with_criteria(&self, ) -> Option<Arc<Mutex<ExtendedMatchmakeSession>>>{
None
}
}

View file

@ -1,9 +1,89 @@
use std::io::Cursor;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Mutex; use rand::random;
use crate::protocols::matchmake_common::MatchmakeData; use tokio::sync::{Mutex, RwLock};
use crate::prudp::socket::ConnectionData; use crate::protocols::matchmake_common::{ExtendedMatchmakeSession, MatchmakeData};
use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::structures::matchmake::{AutoMatchmakeParam, MatchmakeSession};
use crate::rmc::structures::RmcSerialize;
pub async fn auto_matchmake_with_param_postpone_raw_params(rmcmessage: &RMCMessage, _: &mut ConnectionData, data: Arc<Mutex<MatchmakeData>>){
pub async fn auto_matchmake_with_param_postpone(
rmcmessage: &RMCMessage,
conn: &Arc<Mutex<ConnectionData>>,
socket: &Arc<SocketData>,
mm_data: Arc<RwLock<MatchmakeData>>,
auto_matchmake_param: AutoMatchmakeParam
) -> RMCResponseResult{
println!("auto_matchmake_with_param_postpone: {:?}", auto_matchmake_param);
let locked_conn = conn.lock().await;
let Some(secure_conn) =
locked_conn.active_connection_data.as_ref().map(|a| a.active_secure_connection_data.as_ref()).flatten() else {
return rmcmessage.error_result_with_code(ErrorCode::Core_Exception);
};
let pid = secure_conn.pid;
drop(locked_conn);
let mm_data_read = mm_data.read().await;
//todo: there is a bit of a race condition here, i dont have any idea on how to fix it though...
let session = if let Some(session) = mm_data_read.try_find_session_with_criteria().await{
session
} else {
// drop it first so that we dont cause a deadlock, also drop it right here so we dont hold
// up anything else unnescesarily
drop(mm_data_read);
let gid = random();
let mut matchmake_session = auto_matchmake_param.matchmake_session.clone();
matchmake_session.gathering.self_gid = gid;
matchmake_session.gathering.host_pid = pid;
matchmake_session.gathering.owner_pid = pid;
let mut mm_data = mm_data.write().await;
let session = Arc::new(Mutex::new(ExtendedMatchmakeSession{
session: matchmake_session.clone(),
connected_players: Vec::new()
}));
mm_data.matchmake_sessions.insert(gid, session.clone());
session
};
let mut session = session.lock().await;
//todo: refactor so that this works
session.add_player(socket, conn.clone(), auto_matchmake_param.join_message).await;
let mut response = Vec::new();
session.session.serialize(&mut response).expect("unable to serialize matchmake session");
rmcmessage.success_with_data(response)
}
pub async fn auto_matchmake_with_param_postpone_raw_params(
rmcmessage: &RMCMessage,
socket: &Arc<SocketData>,
connection_data: &Arc<Mutex<ConnectionData>>,
data: Arc<RwLock<MatchmakeData>>
) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(matchmake_param) = AutoMatchmakeParam::deserialize(&mut reader) else {
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
};
auto_matchmake_with_param_postpone(rmcmessage, connection_data, socket, data, matchmake_param).await
} }

View file

@ -1,15 +1,16 @@
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Mutex; use log::info;
use tokio::sync::{Mutex, RwLock};
use crate::protocols::matchmake_common::MatchmakeData; use crate::protocols::matchmake_common::MatchmakeData;
use crate::prudp::socket::ConnectionData; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult}; use crate::rmc::response::{ErrorCode, RMCResponseResult};
use crate::rmc::structures::RmcSerialize; use crate::rmc::structures::RmcSerialize;
type PIDList = Vec<u32>; type PIDList = Vec<u32>;
async fn get_playing_session(rmcmessage: &RMCMessage, data: Arc<Mutex<MatchmakeData>>) -> RMCResponseResult { async fn get_playing_session(rmcmessage: &RMCMessage, data: Arc<RwLock<MatchmakeData>>) -> RMCResponseResult {
//todo: propperly implement this //todo: propperly implement this
let cheeseburger = PIDList::new(); let cheeseburger = PIDList::new();
@ -21,12 +22,14 @@ async fn get_playing_session(rmcmessage: &RMCMessage, data: Arc<Mutex<MatchmakeD
rmcmessage.success_with_data(vec) rmcmessage.success_with_data(vec)
} }
pub async fn get_playing_session_raw_params(rmcmessage: &RMCMessage, _: &mut ConnectionData, data: Arc<Mutex<MatchmakeData>>) -> RMCResponseResult{ pub async fn get_playing_session_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, _: &Arc<Mutex<ConnectionData>>, data: Arc<RwLock<MatchmakeData>>) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data); let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(list) = PIDList::deserialize(&mut reader) else { let Ok(list) = PIDList::deserialize(&mut reader) else {
return rmcmessage.error_result_with_code(ErrorCode::FPD_FriendNotExists); return rmcmessage.error_result_with_code(ErrorCode::FPD_FriendNotExists);
}; };
info!("get_playing_session got called with {:?}", list);
get_playing_session(rmcmessage, data).await get_playing_session(rmcmessage, data).await
} }

View file

@ -2,13 +2,15 @@ mod method_get_playing_session;
mod method_auto_matchmake_with_param_postpone; mod method_auto_matchmake_with_param_postpone;
use std::sync::Arc; use std::sync::Arc;
use tokio::sync::Mutex; use tokio::sync::{Mutex, RwLock};
use crate::define_protocol; use crate::define_protocol;
use crate::protocols::matchmake_common::MatchmakeData; use crate::protocols::matchmake_common::MatchmakeData;
use method_get_playing_session::get_playing_session_raw_params; use method_get_playing_session::get_playing_session_raw_params;
use method_auto_matchmake_with_param_postpone::auto_matchmake_with_param_postpone_raw_params;
define_protocol!{ define_protocol!{
109(matchmake_data: Arc<Mutex<MatchmakeData>>) => { 109(matchmake_data: Arc<RwLock<MatchmakeData>>) => {
16 => get_playing_session_raw_params 16 => get_playing_session_raw_params,
40 => auto_matchmake_with_param_postpone_raw_params
} }
} }

View file

@ -1,10 +1,12 @@
use std::env; use std::env;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc;
use log::warn; use log::warn;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use tokio::sync::Mutex;
use crate::grpc; use crate::grpc;
use crate::prudp::socket::ConnectionData; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponse}; use crate::rmc::response::{ErrorCode, RMCResponse};
@ -14,7 +16,8 @@ pub mod server;
pub mod secure; pub mod secure;
pub mod matchmake_extension; pub mod matchmake_extension;
pub mod matchmake_common; pub mod matchmake_common;
pub mod matchmake;
mod notification;
static IS_MAINTENANCE: Lazy<bool> = Lazy::new(|| { static IS_MAINTENANCE: Lazy<bool> = Lazy::new(|| {
env::var("IS_MAINTENANCE") env::var("IS_MAINTENANCE")
@ -30,8 +33,10 @@ static BYPASS_LEVEL: Lazy<i32> = Lazy::new(|| {
}); });
pub fn block_if_maintenance<'a>(rmcmessage: &'a RMCMessage, conn: &'a mut ConnectionData) -> Pin<Box<(dyn Future<Output=Option<RMCResponse>> + Send + 'a)>> { pub fn block_if_maintenance<'a>(rmcmessage: &'a RMCMessage, _: &'a Arc<SocketData> , conn: &'a Arc<Mutex<ConnectionData>>) -> Pin<Box<(dyn Future<Output=Option<RMCResponse>> + Send + 'a)>> {
Box::pin(async move { Box::pin(async move {
let mut conn = conn.lock().await;
if let Some(active_conn) = conn.active_connection_data.as_ref() { if let Some(active_conn) = conn.active_connection_data.as_ref() {
if let Some(secure_conn) = active_conn.active_secure_connection_data.as_ref() { if let Some(secure_conn) = active_conn.active_secure_connection_data.as_ref() {
if let Ok(mut client) = grpc::account::Client::new().await { if let Ok(mut client) = grpc::account::Client::new().await {
@ -62,7 +67,7 @@ pub fn block_if_maintenance<'a>(rmcmessage: &'a RMCMessage, conn: &'a mut Connec
macro_rules! define_protocol { macro_rules! define_protocol {
($id:literal ($($varname:ident : $ty:ty),*) => {$($func_id:literal => $func:path),*} ) => { ($id:literal ($($varname:ident : $ty:ty),*) => {$($func_id:literal => $func:path),*} ) => {
#[allow(unused_parens)] #[allow(unused_parens)]
async fn protocol (rmcmessage: &crate::RMCMessage, connection: &mut crate::protocols::ConnectionData, $($varname : $ty),*) -> Option<crate::rmc::response::RMCResponse>{ async fn protocol (rmcmessage: &crate::RMCMessage, socket: &::std::sync::Arc<crate::prudp::socket::SocketData>, connection: &::std::sync::Arc<::tokio::sync::Mutex<crate::protocols::ConnectionData>>, $($varname : $ty),*) -> Option<crate::rmc::response::RMCResponse>{
if rmcmessage.protocol_id != $id{ if rmcmessage.protocol_id != $id{
return None; return None;
} }
@ -71,7 +76,7 @@ macro_rules! define_protocol {
let response_result = match rmcmessage.method_id{ let response_result = match rmcmessage.method_id{
$( $(
$func_id => $func ( rmcmessage, connection, self_data).await, $func_id => $func ( rmcmessage, socket, connection, self_data).await,
)* )*
_ => { _ => {
log::error!("invalid method id sent to protocol {}: {:?}", $id, rmcmessage.method_id); log::error!("invalid method id sent to protocol {}: {:?}", $id, rmcmessage.method_id);
@ -90,10 +95,10 @@ macro_rules! define_protocol {
}) })
} }
#[allow(unused_parens)] #[allow(unused_parens)]
pub fn bound_protocol($($varname : $ty,)*) -> Box<dyn for<'message_lifetime> Fn(&'message_lifetime crate::RMCMessage, &'message_lifetime mut crate::protocols::ConnectionData) pub fn bound_protocol($($varname : $ty,)*) -> Box<dyn for<'message_lifetime> Fn(&'message_lifetime crate::RMCMessage, &'message_lifetime ::std::sync::Arc<crate::prudp::socket::SocketData>, &'message_lifetime ::std::sync::Arc<::tokio::sync::Mutex<crate::protocols::ConnectionData>>)
-> ::std::pin::Pin<Box<dyn ::std::future::Future<Output = Option<crate::rmc::response::RMCResponse>> + Send + 'message_lifetime>> + Send + Sync>{ -> ::std::pin::Pin<Box<dyn ::std::future::Future<Output = Option<crate::rmc::response::RMCResponse>> + Send + 'message_lifetime>> + Send + Sync>{
Box::new( Box::new(
move |v, cd| { move |v, s, cd| {
Box::pin({ Box::pin({
$( $(
let $varname = $varname.clone(); let $varname = $varname.clone();
@ -103,7 +108,7 @@ macro_rules! define_protocol {
$( $(
let $varname = $varname.clone(); let $varname = $varname.clone();
)* )*
protocol(v, cd, $($varname,)*).await protocol(v, s, cd, $($varname,)*).await
} }
}) })
} }

View file

@ -0,0 +1,48 @@
use macros::RmcSerialize;
use rand::random;
use crate::prudp::packet::{PRUDPHeader, PRUDPPacket, TypesFlags};
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
use crate::prudp::packet::types::DATA;
use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage;
use crate::rmc::structures::RmcSerialize;
#[derive(RmcSerialize)]
#[rmc_struct(0)]
pub struct Notification{
pub pid_source: u32,
pub notif_type: u32,
pub param_1: u32,
pub param_2: u32,
pub str_param: String,
}
impl ConnectionData{
pub async fn send_notification(&mut self, socket: &SocketData, notif: Notification){
let mut data = Vec::new();
notif.serialize(&mut data).expect("unable to write");
let message = RMCMessage{
protocol_id: 0xE,
method_id: 1,
call_id: random(),
rest_of_data: data
};
let prudp_packet = PRUDPPacket{
header: PRUDPHeader{
types_and_flags: TypesFlags::default().types(DATA).flags(NEED_ACK | RELIABLE),
source_port: socket.get_virual_port(),
destination_port: self.sock_addr.virtual_port,
..Default::default()
},
options: Vec::new(),
payload: message.to_data(),
packet_signature: [0;16]
};
self.finish_and_send_packet_to(socket, prudp_packet).await;
}
}

View file

@ -1,8 +1,10 @@
use std::io::{Cursor, Write}; use std::io::{Cursor, Write};
use std::sync::Arc;
use bytemuck::bytes_of; use bytemuck::bytes_of;
use log::{error, warn}; use log::{error, warn};
use tokio::sync::Mutex;
use crate::protocols::auth::AuthProtocolConfig; use crate::protocols::auth::AuthProtocolConfig;
use crate::prudp::socket::ConnectionData; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::prudp::station_url::{nat_types, StationUrl}; use crate::prudp::station_url::{nat_types, StationUrl};
use crate::prudp::station_url::Type::PRUDPS; use crate::prudp::station_url::Type::PRUDPS;
use crate::prudp::station_url::UrlOptions::{Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID}; use crate::prudp::station_url::UrlOptions::{Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID};
@ -14,9 +16,9 @@ use crate::rmc::structures::RmcSerialize;
type StringList = Vec<String>; type StringList = Vec<String>;
pub async fn register(rmcmessage: &RMCMessage, station_urls: Vec<StationUrl>, conn_data: &mut ConnectionData) -> RMCResponseResult{ pub async fn register(rmcmessage: &RMCMessage, station_urls: Vec<StationUrl>, conn_data: &Arc<Mutex<ConnectionData>>) -> RMCResponseResult{
let locked = conn_data.lock().await;
let Some(active_connection_data) = conn_data.active_connection_data.as_ref() else { let Some(active_connection_data) = locked.active_connection_data.as_ref() else {
return rmcmessage.error_result_with_code(ErrorCode::RendezVous_NotAuthenticated) return rmcmessage.error_result_with_code(ErrorCode::RendezVous_NotAuthenticated)
}; };
@ -28,8 +30,8 @@ pub async fn register(rmcmessage: &RMCMessage, station_urls: Vec<StationUrl>, co
url_type: PRUDPS, url_type: PRUDPS,
options: vec![ options: vec![
RVConnectionID(active_connection_data.connection_id), RVConnectionID(active_connection_data.connection_id),
Address(*conn_data.sock_addr.regular_socket_addr.ip()), Address(*locked.sock_addr.regular_socket_addr.ip()),
Port(conn_data.sock_addr.regular_socket_addr.port()), Port(locked.sock_addr.regular_socket_addr.port()),
NatFiltering(0), NatFiltering(0),
NatMapping(0), NatMapping(0),
NatType(nat_types::BEHIND_NAT), NatType(nat_types::BEHIND_NAT),
@ -50,7 +52,7 @@ pub async fn register(rmcmessage: &RMCMessage, station_urls: Vec<StationUrl>, co
rmcmessage.success_with_data(response) rmcmessage.success_with_data(response)
} }
pub async fn register_raw_params(rmcmessage: &RMCMessage, conn_data: &mut ConnectionData, _: ()) -> RMCResponseResult{ pub async fn register_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, conn_data: &Arc<Mutex<ConnectionData>>, _: ()) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data); let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(station_urls) = StringList::deserialize(&mut reader) else { let Ok(station_urls) = StringList::deserialize(&mut reader) else {

View file

@ -1,8 +1,10 @@
use std::io::Cursor; use std::io::Cursor;
use std::sync::Arc;
use log::error; use log::error;
use tokio::sync::Mutex;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use crate::protocols::secure::method_register::register; use crate::protocols::secure::method_register::register;
use crate::prudp::socket::ConnectionData; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::prudp::station_url::StationUrl; use crate::prudp::station_url::StationUrl;
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{ErrorCode, RMCResponseResult}; use crate::rmc::response::{ErrorCode, RMCResponseResult};
@ -20,7 +22,7 @@ pub async fn send_report(rmcmessage: &RMCMessage, report_id: u32, data: Vec<u8>)
return rmcmessage.success_with_data(Vec::new()); return rmcmessage.success_with_data(Vec::new());
} }
pub async fn send_report_raw_params(rmcmessage: &RMCMessage, conn_data: &mut ConnectionData, _: ()) -> RMCResponseResult{ pub async fn send_report_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, conn_data: &Arc<Mutex<ConnectionData>>, _: ()) -> RMCResponseResult{
let mut reader = Cursor::new(&rmcmessage.rest_of_data); let mut reader = Cursor::new(&rmcmessage.rest_of_data);
let Ok(error_id) = reader.read_struct(IS_BIG_ENDIAN) else { let Ok(error_id) = reader.read_struct(IS_BIG_ENDIAN) else {

View file

@ -3,13 +3,14 @@ use std::io::Cursor;
use std::pin::Pin; use std::pin::Pin;
use std::sync::Arc; use std::sync::Arc;
use log::error; use log::error;
use tokio::sync::Mutex;
use crate::prudp::packet::PRUDPPacket; use crate::prudp::packet::PRUDPPacket;
use crate::prudp::socket::{ConnectionData, SocketData}; use crate::prudp::socket::{ConnectionData, SocketData};
use crate::rmc::message::RMCMessage; use crate::rmc::message::RMCMessage;
use crate::rmc::response::{RMCResponse, RMCResponseResult, send_response}; use crate::rmc::response::{RMCResponse, RMCResponseResult, send_response};
use crate::rmc::response::ErrorCode::Core_NotImplemented; use crate::rmc::response::ErrorCode::Core_NotImplemented;
type ContainedProtocolList = Box<[Box<dyn for<'a> Fn(&'a RMCMessage, &'a mut ConnectionData) -> Pin<Box<dyn Future<Output = Option<RMCResponse>> + Send + 'a>> + Send + Sync>]>; type ContainedProtocolList = Box<[Box<dyn for<'a> Fn(&'a RMCMessage, &'a Arc<SocketData>, &'a Arc<Mutex<ConnectionData>>) -> Pin<Box<dyn Future<Output = Option<RMCResponse>> + Send + 'a>> + Send + Sync>]>;
pub struct RMCProtocolServer(ContainedProtocolList); pub struct RMCProtocolServer(ContainedProtocolList);
@ -18,27 +19,33 @@ impl RMCProtocolServer{
Arc::new(Self(protocols)) Arc::new(Self(protocols))
} }
pub async fn process_message(&self, packet: PRUDPPacket, socket: &SocketData, connection: &mut ConnectionData){ pub async fn process_message(&self, packet: PRUDPPacket, socket: Arc<SocketData>, connection: Arc<Mutex<ConnectionData>>){
let Ok(rmc) = RMCMessage::new(&mut Cursor::new(&packet.payload)) else { let Ok(rmc) = RMCMessage::new(&mut Cursor::new(&packet.payload)) else {
error!("error reading rmc message"); error!("error reading rmc message");
return; return;
}; };
println!("got rmc message {},{}", rmc.protocol_id, rmc.method_id);
for proto in &self.0 { for proto in &self.0 {
if let Some(response) = proto(&rmc, connection).await { if let Some(response) = proto(&rmc, &socket, &connection).await {
send_response(&packet, &socket, connection, response).await;
let mut locked = connection.lock().await;
send_response(&packet, &socket, &mut locked, response).await;
drop(locked);
return; return;
} }
} }
error!("tried to send message to unimplemented protocol {} with method id {}", rmc.protocol_id, rmc.method_id); error!("tried to send message to unimplemented protocol {} with method id {}", rmc.protocol_id, rmc.method_id);
let mut locked = connection.lock().await;
send_response(&packet, &socket, connection, RMCResponse{ send_response(&packet, &socket, &mut locked, RMCResponse{
protocol_id: rmc.protocol_id as u8, protocol_id: rmc.protocol_id as u8,
response_result: RMCResponseResult::Error { response_result: RMCResponseResult::Error {
call_id: rmc.call_id, call_id: rmc.call_id,
error_code: Core_NotImplemented error_code: Core_NotImplemented
} }
}).await; }).await;
} }
} }

View file

@ -27,7 +27,7 @@ pub struct Socket {
type OnConnectHandlerFn = Box<dyn Fn(PRUDPPacket, u8) -> Pin<Box<dyn Future<Output=Option<(Vec<u8>, Vec<EncryptionPair>, Option<ActiveSecureConnectionData>)>> + Send>> + Send + Sync>; type OnConnectHandlerFn = Box<dyn Fn(PRUDPPacket, u8) -> Pin<Box<dyn Future<Output=Option<(Vec<u8>, Vec<EncryptionPair>, Option<ActiveSecureConnectionData>)>> + Send>> + Send + Sync>;
type OnDataHandlerFn = Box<dyn for<'a> Fn(PRUDPPacket, Arc<SocketData>, &'a mut MutexGuard<'_, ConnectionData>) -> Pin<Box<dyn Future<Output=()> + 'a + Send>> + Send + Sync>; type OnDataHandlerFn = Box<dyn Fn(PRUDPPacket, Arc<SocketData>, Arc<Mutex<ConnectionData>>) -> Pin<Box<dyn Future<Output=()> + Send>> + Send + Sync>;
pub struct ActiveSecureConnectionData { pub struct ActiveSecureConnectionData {
pub(crate) pid: u32, pub(crate) pid: u32,
@ -38,7 +38,7 @@ pub struct SocketData {
virtual_port: VirtualPort, virtual_port: VirtualPort,
pub socket: Arc<UdpSocket>, pub socket: Arc<UdpSocket>,
pub access_key: &'static str, pub access_key: &'static str,
connections: RwLock<HashMap<PRUDPSockAddr, Arc<Mutex<ConnectionData>>>>, connections: RwLock<HashMap<PRUDPSockAddr, (Arc<Mutex<ConnectionData>>, Arc<Mutex<()>>)>>,
on_connect_handler: OnConnectHandlerFn, on_connect_handler: OnConnectHandlerFn,
on_data_handler: OnDataHandlerFn, on_data_handler: OnDataHandlerFn,
@ -69,6 +69,8 @@ pub struct ConnectionData {
} }
impl Socket { impl Socket {
pub async fn new( pub async fn new(
router: Arc<Router>, router: Arc<Router>,
@ -146,14 +148,14 @@ impl SocketData {
let mut conn = self.connections.write().await; let mut conn = self.connections.write().await;
//only insert if we STILL dont have the connection preventing double insertion //only insert if we STILL dont have the connection preventing double insertion
if !conn.contains_key(&client_address) { if !conn.contains_key(&client_address) {
conn.insert(client_address, Arc::new(Mutex::new(ConnectionData { conn.insert(client_address, (Arc::new(Mutex::new(ConnectionData {
sock_addr: client_address, sock_addr: client_address,
id: random(), id: random(),
signature: [0; 16], signature: [0; 16],
server_signature: [0; 16], server_signature: [0; 16],
active_connection_data: None, active_connection_data: None,
}))); })), Arc::new(Mutex::new(()))));
} }
drop(conn); drop(conn);
} else { } else {
@ -172,20 +174,24 @@ impl SocketData {
// dont keep holding the connections list unnescesarily // dont keep holding the connections list unnescesarily
drop(connections); drop(connections);
let mut connection = conn.lock().await; let mut connection = conn.0.lock().await;
//let _mutual_exclusion_packet_handeling_mtx = conn.1.lock().await;
if (packet.header.types_and_flags.get_flags() & ACK) != 0 { if (packet.header.types_and_flags.get_flags() & ACK) != 0 {
//todo: handle acknowledgements and resending packets propperly //todo: handle acknowledgements and resending packets propperly
println!("got ack");
return; return;
} }
if (packet.header.types_and_flags.get_flags() & MULTI_ACK) != 0 { if (packet.header.types_and_flags.get_flags() & MULTI_ACK) != 0 {
println!("got ack");
return; return;
} }
match packet.header.types_and_flags.get_types() { match packet.header.types_and_flags.get_types() {
SYN => { SYN => {
println!("got syn");
// reset heartbeat? // reset heartbeat?
let mut response_packet = packet.base_response_packet(); let mut response_packet = packet.base_response_packet();
@ -220,6 +226,7 @@ impl SocketData {
self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back"); self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back");
} }
CONNECT => { CONNECT => {
println!("got connect");
let Some(MaximumSubstreamId(max_substream)) = packet.options.iter().find(|v| matches!(v, MaximumSubstreamId(_))) else { let Some(MaximumSubstreamId(max_substream)) = packet.options.iter().find(|v| matches!(v, MaximumSubstreamId(_))) else {
return; return;
}; };
@ -328,13 +335,18 @@ impl SocketData {
self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back"); self.socket.send_to(&vec, client_address.regular_socket_addr).await.expect("failed to send data back");
} }
drop(connection);
while let Some(mut packet) = { while let Some(mut packet) = {
connection.active_connection_data.as_mut().map(|a| let mut locked = conn.0.lock().await;
let packet = locked.active_connection_data.as_mut().map(|a|
a.reliable_client_queue a.reliable_client_queue
.front() .front()
.is_some_and(|v| v.header.sequence_id == a.reliable_client_counter) .is_some_and(|v| v.header.sequence_id == a.reliable_client_counter)
.then(|| a.reliable_client_queue.pop_front())).flatten().flatten() .then(|| a.reliable_client_queue.pop_front())).flatten().flatten();
drop(locked);
packet
} { } {
if packet.options.iter().any(|v| match v{ if packet.options.iter().any(|v| match v{
PacketOption::FragmentId(f) => *f != 0, PacketOption::FragmentId(f) => *f != 0,
@ -343,7 +355,9 @@ impl SocketData {
error!("fragmented packets are unsupported right now") error!("fragmented packets are unsupported right now")
} }
let active_connection = connection.active_connection_data.as_mut() let mut locked = conn.0.lock().await;
let active_connection = locked.active_connection_data.as_mut()
.expect("we litterally just recieved a packet which requires the connection to be active, failing this should be impossible"); .expect("we litterally just recieved a packet which requires the connection to be active, failing this should be impossible");
active_connection.reliable_client_counter = active_connection.reliable_client_counter.overflowing_add(1).0; active_connection.reliable_client_counter = active_connection.reliable_client_counter.overflowing_add(1).0;
@ -354,9 +368,10 @@ impl SocketData {
stream.apply_keystream(&mut packet.payload); stream.apply_keystream(&mut packet.payload);
drop(locked);
// we cant divert this off to another thread we HAVE to process it now to keep order // we cant divert this off to another thread we HAVE to process it now to keep order
(self.on_data_handler)(packet, self.clone(), &mut connection).await; (self.on_data_handler)(packet, self.clone(), conn.0.clone()).await;
// ignored for now // ignored for now
} }
} else { } else {
@ -397,7 +412,7 @@ impl SocketData {
} }
} }
DISCONNECT => { DISCONNECT => {
println!("got disconnect");
let Some(active_connection) = &connection.active_connection_data else { let Some(active_connection) = &connection.active_connection_data else {
return; return;
}; };
@ -466,6 +481,8 @@ impl ConnectionData{
error!("unable to send packet to destination: {}", e); error!("unable to send packet to destination: {}", e);
} }
} }
} }
#[cfg(test)] #[cfg(test)]

View file

@ -1,10 +1,11 @@
use std::io; use std::io;
use std::io::{Read, Seek}; use std::io::{Read, Seek, Write};
use bytemuck::bytes_of;
use log::error; use log::error;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions}; use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use crate::rmc::response::{ErrorCode, RMCResponseResult}; use crate::rmc::response::{ErrorCode, RMCResponseResult};
#[derive(Debug)] #[derive(Debug, Clone)]
pub struct RMCMessage{ pub struct RMCMessage{
pub protocol_id: u16, pub protocol_id: u16,
pub call_id: u32, pub call_id: u32,
@ -52,6 +53,23 @@ impl RMCMessage{
}) })
} }
pub fn to_data(&self) -> Vec<u8>{
let size = (1 + 4 + 4 + self.rest_of_data.len()) as u32;
let mut output = Vec::new();
output.write_all(bytes_of(&size)).expect("unable to write size");
let proto_id = self.protocol_id as u8;
output.write_all(bytes_of(&proto_id)).expect("unable to write size");
output.write_all(bytes_of(&self.call_id)).expect("unable to write size");
output.write_all(bytes_of(&self.method_id)).expect("unable to write size");
output
}
pub fn error_result_with_code(&self, error_code: ErrorCode) -> RMCResponseResult{ pub fn error_result_with_code(&self, error_code: ErrorCode) -> RMCResponseResult{
RMCResponseResult::Error { RMCResponseResult::Error {
call_id: self.call_id, call_id: self.call_id,

View file

@ -1,6 +1,7 @@
use std::io; use std::io;
use std::io::{Write}; use std::io::{Write};
use std::mem::transmute; use std::mem::transmute;
use std::time::Duration;
use bytemuck::bytes_of; use bytemuck::bytes_of;
use crate::prudp::packet::{PRUDPPacket}; use crate::prudp::packet::{PRUDPPacket};
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE}; use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
@ -100,6 +101,8 @@ pub async fn send_response(original_packet: &PRUDPPacket, socket: &SocketData, c
packet.payload = rmcresponse.to_data(); packet.payload = rmcresponse.to_data();
//tokio::time::sleep(Duration::from_millis(500)).await;
connection.finish_and_send_packet_to(socket, packet).await; connection.finish_and_send_packet_to(socket, packet).await;
} }

View file

@ -6,7 +6,7 @@ use crate::rmc::structures::RmcSerialize;
impl<T: RmcSerialize> RmcSerialize for Vec<T>{ impl<T: RmcSerialize> RmcSerialize for Vec<T>{
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> { fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
let u32_len = self.len(); let u32_len = self.len() as u32;
writer.write_all(bytes_of(&u32_len))?; writer.write_all(bytes_of(&u32_len))?;
for e in self{ for e in self{

View file

@ -4,51 +4,82 @@ use crate::rmc::structures::RmcSerialize;
use crate::rmc::structures::variant::Variant; use crate::rmc::structures::variant::Variant;
// rmc structure // rmc structure
#[derive(RmcSerialize)] #[derive(RmcSerialize, Debug, Clone)]
#[rmc_struct(0)] #[rmc_struct(0)]
struct Gathering{ pub struct Gathering {
self_gid: u32, pub self_gid: u32,
owner_pid: u32, pub owner_pid: u32,
host_pid: u32, pub host_pid: u32,
minimum_participants: u16, pub minimum_participants: u16,
maximum_participants: u16, pub maximum_participants: u16,
participant_policy: u32, pub participant_policy: u32,
policy_argument: u32, pub policy_argument: u32,
flags: u32, pub flags: u32,
state: u32, pub state: u32,
description: String pub description: String,
} }
// rmc structure // rmc structure
#[derive(RmcSerialize)] #[derive(RmcSerialize, Debug, Clone)]
#[rmc_struct(0)] #[rmc_struct(0)]
struct MatchmakeParam{ pub struct MatchmakeParam {
params: Vec<(String, Variant)> pub params: Vec<(String, Variant)>,
} }
// rmc structure // rmc structure
#[derive(RmcSerialize)] #[derive(RmcSerialize, Debug, Clone)]
#[rmc_struct(3)] #[rmc_struct(3)]
struct MatchmakeSession{ pub struct MatchmakeSession {
//inherits from //inherits from
#[extends] #[extends]
gathering: Gathering, pub gathering: Gathering,
gamemode: u32, pub gamemode: u32,
attributes: Vec<u32>, pub attributes: Vec<u32>,
open_participation: bool, pub open_participation: bool,
matchmake_system_type: u32, pub matchmake_system_type: u32,
application_buffer: Vec<u8>, pub application_buffer: Vec<u8>,
participation_count: u32, pub participation_count: u32,
progress_score: u8, pub progress_score: u8,
session_key: Vec<u8>, pub session_key: Vec<u8>,
option0: u32, pub option0: u32,
matchmake_param: MatchmakeParam, pub matchmake_param: MatchmakeParam,
datetime: KerberosDateTime, pub datetime: KerberosDateTime,
user_password: String, pub user_password: String,
refer_gid: u32, pub refer_gid: u32,
user_password_enabled: bool, pub user_password_enabled: bool,
system_password_enabled: bool pub system_password_enabled: bool,
} }
#[derive(RmcSerialize, Debug, Clone)]
#[rmc_struct(3)]
pub struct MatchmakeSessionSearchCriteria {
pub attribs: Vec<String>,
pub game_mode: String,
pub minimum_participants: String,
pub maximum_participants: String,
pub matchmake_system_type: String,
pub vacant_only: bool,
pub exclude_locked: bool,
pub exclude_non_host_pid: bool,
pub selection_method: u32,
pub vacant_participants: u16,
pub matchmake_param: MatchmakeParam,
pub exclude_user_password_set: bool,
pub exclude_system_password_set: bool,
pub refer_gid: u32,
}
#[derive(RmcSerialize, Debug, Clone)]
#[rmc_struct(0)]
pub struct AutoMatchmakeParam {
pub matchmake_session: MatchmakeSession,
pub additional_participants: Vec<u32>,
pub gid_for_participation_check: u32,
pub auto_matchmake_option: u32,
pub join_message: String,
pub participation_count: u16,
pub search_criteria: Vec<MatchmakeSessionSearchCriteria>,
pub target_gids: Vec<u32>,
}

View file

@ -27,7 +27,7 @@ impl RmcSerialize for &str{
panic!("cannot serialize to &str") panic!("cannot serialize to &str")
} }
fn serialize(&self, writer: &mut dyn Write) -> Result<()> { fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
let u16_len: u16 = self.len() as u16; let u16_len: u16 = (self.len() + 1) as u16;
writer.write(bytes_of(&u16_len))?; writer.write(bytes_of(&u16_len))?;
writer.write(self.as_bytes())?; writer.write(self.as_bytes())?;

View file

@ -3,6 +3,7 @@ use crate::kerberos::KerberosDateTime;
use crate::rmc::structures; use crate::rmc::structures;
use crate::rmc::structures::RmcSerialize; use crate::rmc::structures::RmcSerialize;
#[derive(Debug, Clone)]
pub enum Variant{ pub enum Variant{
None, None,
SInt64(i64), SInt64(i64),