Merge branch 'feat/gatherings' into 'main'
Core Rewrite See merge request perditum/rnex-splatoon!10
This commit is contained in:
commit
c9fa7f48cd
65 changed files with 4011 additions and 939 deletions
30
.github/workflows/build.yml
vendored
30
.github/workflows/build.yml
vendored
|
|
@ -1,30 +0,0 @@
|
||||||
name: Build
|
|
||||||
|
|
||||||
on:
|
|
||||||
push:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
pull_request:
|
|
||||||
branches:
|
|
||||||
- main
|
|
||||||
|
|
||||||
env:
|
|
||||||
CARGO_TERM_COLOR: always
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
build:
|
|
||||||
runs-on: self-hosted
|
|
||||||
steps:
|
|
||||||
- name: Checkout Repository And Submodules
|
|
||||||
uses: actions/checkout@v1
|
|
||||||
with:
|
|
||||||
submodules: recursive
|
|
||||||
|
|
||||||
- name: Setup Rust
|
|
||||||
run: curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -q -y
|
|
||||||
|
|
||||||
- name: Build
|
|
||||||
run: . "$HOME/.cargo/env" && cargo build --verbose
|
|
||||||
|
|
||||||
- name: Run tests
|
|
||||||
run: . "$HOME/.cargo/env" && cargo test --verbose
|
|
||||||
14
.github/workflows/stale.yml
vendored
14
.github/workflows/stale.yml
vendored
|
|
@ -1,14 +0,0 @@
|
||||||
name: 'Close stale issues and PRs'
|
|
||||||
on:
|
|
||||||
schedule:
|
|
||||||
- cron: '30 1 * * *'
|
|
||||||
|
|
||||||
jobs:
|
|
||||||
stale:
|
|
||||||
runs-on: debian-latest
|
|
||||||
steps:
|
|
||||||
- uses: actions/stale@v9
|
|
||||||
with:
|
|
||||||
stale-issue-message: 'This issue is stale because it has been open 30 days with no activity. Remove stale label or comment or this will be closed in 5 days.'
|
|
||||||
days-before-stale: 10
|
|
||||||
days-before-close: 5
|
|
||||||
943
Cargo.lock
generated
943
Cargo.lock
generated
File diff suppressed because it is too large
Load diff
|
|
@ -36,6 +36,11 @@ prost = "0.13.4"
|
||||||
hex = "0.4.3"
|
hex = "0.4.3"
|
||||||
|
|
||||||
macros = { path = "macros" }
|
macros = { path = "macros" }
|
||||||
|
rocket = { version = "0.5.1", features = ["json", "serde_json"] }
|
||||||
|
serde = { version = "1.0.217", features = ["derive"] }
|
||||||
|
async-trait = "0.1.86"
|
||||||
|
paste = "1.0.15"
|
||||||
|
typenum = "1.18.0"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
tonic-build = "0.12.3"
|
tonic-build = "0.12.3"
|
||||||
|
|
@ -43,4 +48,4 @@ tonic-build = "0.12.3"
|
||||||
[features]
|
[features]
|
||||||
default = ["secure", "auth"]
|
default = ["secure", "auth"]
|
||||||
secure = []
|
secure = []
|
||||||
auth = []
|
auth = []
|
||||||
|
|
|
||||||
4
macros/Cargo.lock
generated
4
macros/Cargo.lock
generated
|
|
@ -31,9 +31,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "syn"
|
name = "syn"
|
||||||
version = "1.0.109"
|
version = "2.0.98"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "72b64191b275b66ffe2469e8af2c1cfe3bafa67b529ead792a6d0160888b4237"
|
checksum = "36147f1a48ae0ec2b5b3bc5b537d267457555a10dc06f3dbc8cb11ba3006d3b1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"proc-macro2",
|
"proc-macro2",
|
||||||
"quote",
|
"quote",
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,8 @@ edition = "2018"
|
||||||
proc-macro = true
|
proc-macro = true
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
quote = "1"
|
quote = "1.0.38"
|
||||||
proc-macro2 = "1.0"
|
proc-macro2 = "1.0.93"
|
||||||
syn = "1.0"
|
syn = { version = "2.0.98", features = ["full"] }
|
||||||
|
rand = "0.9.0"
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,22 +1,105 @@
|
||||||
|
mod protos;
|
||||||
|
|
||||||
extern crate proc_macro;
|
extern crate proc_macro;
|
||||||
|
|
||||||
use proc_macro2::TokenTree;
|
use proc_macro2::{Ident, Literal, Span, TokenTree};
|
||||||
use proc_macro::TokenStream;
|
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, ReturnType};
|
||||||
|
use quote::{quote, ToTokens, TokenStreamExt};
|
||||||
|
use syn::buffer::TokenBuffer;
|
||||||
|
use syn::parse::{Parse, ParseBuffer, ParseStream};
|
||||||
|
use syn::punctuated::Punctuated;
|
||||||
|
use syn::spanned::Spanned;
|
||||||
|
use syn::token::Comma;
|
||||||
|
use syn::Visibility::Public;
|
||||||
|
use crate::protos::{ProtoMethodData, RmcProtocolData};
|
||||||
|
|
||||||
use syn::{parse_macro_input, DeriveInput, Data};
|
fn self_referece_type() -> Type {
|
||||||
use quote::{quote, TokenStreamExt};
|
Type::Reference(
|
||||||
|
TypeReference {
|
||||||
|
and_token: Default::default(),
|
||||||
|
lifetime: None,
|
||||||
|
mutability: None,
|
||||||
|
elem: Box::new(Type::Path(
|
||||||
|
TypePath {
|
||||||
|
qself: None,
|
||||||
|
path: Path {
|
||||||
|
leading_colon: None,
|
||||||
|
segments: {
|
||||||
|
let mut punct = Punctuated::new();
|
||||||
|
|
||||||
|
punct.push_value(PathSegment{
|
||||||
|
ident: Ident::new("Self", Span::call_site()),
|
||||||
|
arguments: PathArguments::None
|
||||||
|
});
|
||||||
|
|
||||||
|
punct
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ProtoInputParams{
|
||||||
|
proto_num: LitInt,
|
||||||
|
properties: Option<(Token![,], Punctuated<Ident, Token![,]>)>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Parse for ProtoInputParams{
|
||||||
|
fn parse(input: ParseStream) -> syn::Result<Self> {
|
||||||
|
let proto_num = input.parse()?;
|
||||||
|
|
||||||
|
if let Some(seperator) = input.parse()?{
|
||||||
|
let mut punctuated = Punctuated::new();
|
||||||
|
loop {
|
||||||
|
punctuated.push_value(
|
||||||
|
input.parse()?
|
||||||
|
);
|
||||||
|
if let Some(punct) = input.parse()? {
|
||||||
|
punctuated.push_punct(punct);
|
||||||
|
} else {
|
||||||
|
return Ok(
|
||||||
|
Self{
|
||||||
|
proto_num,
|
||||||
|
properties: Some((seperator, punctuated))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Ok(
|
||||||
|
Self{
|
||||||
|
proto_num,
|
||||||
|
properties: None
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn single_ident_path(ident: Ident) -> Path{
|
||||||
|
Path{
|
||||||
|
segments: {
|
||||||
|
let mut punc = Punctuated::new();
|
||||||
|
punc.push(PathSegment::from(ident));
|
||||||
|
punc
|
||||||
|
},
|
||||||
|
leading_colon: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/// 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))]
|
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
|
||||||
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
let derive_input = parse_macro_input!(input as DeriveInput);
|
let derive_input = parse_macro_input!(input as DeriveInput);
|
||||||
|
|
||||||
let struct_attr = derive_input.attrs.iter()
|
let struct_attr = derive_input.attrs.iter()
|
||||||
.find(|a| a.path.segments.len() == 1 &&
|
.find(|a| a.path().segments.len() == 1 &&
|
||||||
a.path.segments.first().is_some_and(|p| p.ident.to_string() == "rmc_struct"));
|
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "rmc_struct"));
|
||||||
|
|
||||||
let Data::Struct(s) = derive_input.data else {
|
let Data::Struct(s) = derive_input.data else {
|
||||||
panic!("rmc struct type MUST be a struct");
|
panic!("rmc struct type MUST be a struct");
|
||||||
|
|
@ -29,8 +112,8 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
for f in &s.fields{
|
for f in &s.fields{
|
||||||
if f.attrs.iter()
|
if f.attrs.iter()
|
||||||
.any(|a| a.path.segments.len() == 1 &&
|
.any(|a| a.path().segments.len() == 1 &&
|
||||||
a.path.segments.first().is_some_and(|p| p.ident.to_string() == "extends")){
|
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends")){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let ident = f.ident.as_ref().unwrap();
|
let ident = f.ident.as_ref().unwrap();
|
||||||
|
|
@ -67,8 +150,8 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
|
|
||||||
for f in &s.fields{
|
for f in &s.fields{
|
||||||
if f.attrs.iter()
|
if f.attrs.iter()
|
||||||
.any(|a| a.path.segments.len() == 1 &&
|
.any(|a| a.path().segments.len() == 1 &&
|
||||||
a.path.segments.first().is_some_and(|p| p.ident.to_string() == "extends")){
|
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends")){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -89,23 +172,12 @@ 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 version: Literal = attr.parse_args().expect("has to be a literal");
|
||||||
let token = tokens.into_iter().next().unwrap();
|
|
||||||
|
|
||||||
let version = match token {
|
|
||||||
TokenTree::Group(g) => {
|
|
||||||
match g.stream().into_iter().next().unwrap(){
|
|
||||||
TokenTree::Literal(l) => l,
|
|
||||||
_ => panic!("expected literal")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => panic!("expected group")
|
|
||||||
};
|
|
||||||
|
|
||||||
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
||||||
f.attrs.iter()
|
f.attrs.iter()
|
||||||
.any(|a| a.path.segments.len() == 1 &&
|
.any(|a| a.path().segments.len() == 1 &&
|
||||||
a.path.segments.first().is_some_and(|p| p.ident.to_string() == "extends"))
|
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends"))
|
||||||
}){
|
}){
|
||||||
let ident= f.ident.as_ref().unwrap();
|
let ident= f.ident.as_ref().unwrap();
|
||||||
quote! {
|
quote! {
|
||||||
|
|
@ -128,22 +200,12 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
};
|
};
|
||||||
|
|
||||||
let deserialize_base_content = if let Some(attr) = struct_attr{
|
let deserialize_base_content = if let Some(attr) = struct_attr{
|
||||||
let tokens = attr.tokens.clone();
|
let version: Literal = attr.parse_args().expect("has to be a literal");
|
||||||
let token = tokens.into_iter().next().unwrap();
|
|
||||||
|
|
||||||
let version = match token {
|
|
||||||
TokenTree::Group(g) => {
|
|
||||||
match g.stream().into_iter().next().unwrap(){
|
|
||||||
TokenTree::Literal(l) => l,
|
|
||||||
_ => panic!("expected literal")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
_ => panic!("expected group")
|
|
||||||
};
|
|
||||||
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
|
||||||
f.attrs.iter()
|
f.attrs.iter()
|
||||||
.any(|a| a.path.segments.len() == 1 &&
|
.any(|a| a.path().segments.len() == 1 &&
|
||||||
a.path.segments.first().is_some_and(|p| p.ident.to_string() == "extends"))
|
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends"))
|
||||||
}){
|
}){
|
||||||
let ident= f.ident.as_ref().unwrap();
|
let ident= f.ident.as_ref().unwrap();
|
||||||
let ty= &f.ty;
|
let ty= &f.ty;
|
||||||
|
|
@ -181,4 +243,142 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
|
||||||
};
|
};
|
||||||
|
|
||||||
tokens.into()
|
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<String, ErrorCode>;
|
||||||
|
/// }
|
||||||
|
/// ```
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
|
|
||||||
|
let mut params = parse_macro_input!(attr as ProtoInputParams);
|
||||||
|
|
||||||
|
let ProtoInputParams{
|
||||||
|
proto_num,
|
||||||
|
properties
|
||||||
|
} = params;
|
||||||
|
|
||||||
|
let no_return_data = properties.is_some_and(|p| p.1.iter().any(|i|{
|
||||||
|
i.to_string() == "NoReturn"
|
||||||
|
}));
|
||||||
|
|
||||||
|
let mut input = parse_macro_input!(input as syn::ItemTrait);
|
||||||
|
|
||||||
|
// 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");
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(id): Result<LitInt, _> = attr.parse_args() else {
|
||||||
|
panic!("todo: put a propper error message here");
|
||||||
|
};
|
||||||
|
|
||||||
|
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");
|
||||||
|
};
|
||||||
|
|
||||||
|
(i.ident.clone(), t.ty.as_ref().clone())
|
||||||
|
}).collect();
|
||||||
|
|
||||||
|
ProtoMethodData{
|
||||||
|
id,
|
||||||
|
name: func.sig.ident.clone(),
|
||||||
|
parameters: funcs,
|
||||||
|
ret_val: func.sig.output.clone()
|
||||||
|
}
|
||||||
|
}).collect()
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
#input
|
||||||
|
#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`
|
||||||
|
input
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
|
let mut type_data = parse_macro_input!(input as DeriveInput);
|
||||||
|
let mut ident = parse_macro_input!(attr as syn::Path);
|
||||||
|
let last_token = ident.segments.last_mut().expect("empty path?");
|
||||||
|
|
||||||
|
last_token.ident = Ident::new(&("Local".to_owned() + &last_token.ident.to_string()), last_token.span());
|
||||||
|
|
||||||
|
|
||||||
|
let struct_name = &type_data.ident;
|
||||||
|
|
||||||
|
let out = quote!{
|
||||||
|
#type_data
|
||||||
|
|
||||||
|
impl #ident for #struct_name{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::rmc::protocols::RmcCallable for #struct_name{
|
||||||
|
async fn rmc_call(&self, remote_response_connection: &crate::prudp::socket::SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>){
|
||||||
|
<Self as #ident>::rmc_call(self, remote_response_connection, protocol_id, method_id, call_id, rest).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
out.into()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[proc_macro_attribute]
|
||||||
|
pub fn connection(_attr: TokenStream, input: TokenStream) -> TokenStream{
|
||||||
|
// this attribute doesnt do anything by itself, see `rmc_struct`
|
||||||
|
input
|
||||||
}
|
}
|
||||||
291
macros/src/protos.rs
Normal file
291
macros/src/protos.rs
Normal file
|
|
@ -0,0 +1,291 @@
|
||||||
|
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
|
||||||
|
use quote::{quote, ToTokens};
|
||||||
|
use syn::{LitInt, ReturnType, Token, Type};
|
||||||
|
use syn::token::{Brace, Paren, Semi};
|
||||||
|
|
||||||
|
pub struct ProtoMethodData{
|
||||||
|
pub id: LitInt,
|
||||||
|
pub name: Ident,
|
||||||
|
pub parameters: Vec<(Ident, Type)>,
|
||||||
|
pub ret_val: ReturnType,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// 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<ProtoMethodData>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RmcProtocolData{
|
||||||
|
fn generate_raw_trait(&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<u8> }.to_tokens(tokens);
|
||||||
|
});
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
-> ::core::result::Result<Vec<u8>, 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(crate::rmc::response::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<u8>,
|
||||||
|
)
|
||||||
|
}.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<T: #name> RawAuth for T{}
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_raw_remote_trait(&self, tokens: &mut TokenStream) {
|
||||||
|
let Self {
|
||||||
|
has_returns,
|
||||||
|
name,
|
||||||
|
id: proto_id,
|
||||||
|
methods,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
// this gives us the name which the identifier of the corresponding Raw trait
|
||||||
|
let remote_name = Ident::new(&format!("Remote{}", name), name.span());
|
||||||
|
|
||||||
|
|
||||||
|
// boilerplate tokens which all raw traits need
|
||||||
|
quote!{
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub trait #remote_name: crate::rmc::protocols::HasRmcConnection
|
||||||
|
}.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,
|
||||||
|
ret_val,
|
||||||
|
id: method_id,
|
||||||
|
..
|
||||||
|
} = method;
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
async fn #name
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
Paren::default().surround(tokens, |tokens|{
|
||||||
|
quote!{ &self, }.to_tokens(tokens);
|
||||||
|
for (param_ident, param_type) in parameters{
|
||||||
|
quote!{ #param_ident: #param_type, }.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
#ret_val
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
Brace::default().surround(tokens, |tokens|{
|
||||||
|
quote! {
|
||||||
|
let mut send_data = Vec::new();
|
||||||
|
let mut cursor = ::std::io::Cursor::new(&mut send_data);
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
for (param_name, param_type) in parameters{
|
||||||
|
quote!{
|
||||||
|
crate::result::ResultExtension::display_err_or_some(
|
||||||
|
<#param_type as crate::rmc::structures::RmcSerialize>::serialize(
|
||||||
|
&#param_name,
|
||||||
|
&mut cursor
|
||||||
|
)
|
||||||
|
).ok_or(crate::rmc::response::ErrorCode::Core_InvalidArgument)?;
|
||||||
|
}.to_tokens(tokens)
|
||||||
|
}
|
||||||
|
|
||||||
|
quote!{
|
||||||
|
let call_id = rand::random();
|
||||||
|
|
||||||
|
let message = crate::rmc::message::RMCMessage{
|
||||||
|
call_id,
|
||||||
|
method_id: #method_id,
|
||||||
|
protocol_id: #proto_id,
|
||||||
|
rest_of_data: send_data
|
||||||
|
};
|
||||||
|
|
||||||
|
let rmc_conn = <Self as crate::rmc::protocols::HasRmcConnection>::get_connection(self);
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
|
||||||
|
if *has_returns{
|
||||||
|
quote!{
|
||||||
|
crate::result::ResultExtension::display_err_or_some(
|
||||||
|
rmc_conn.make_raw_call(&message).await
|
||||||
|
).ok_or(crate::rmc::response::ErrorCode::Core_Exception)
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
} else {
|
||||||
|
quote!{
|
||||||
|
crate::result::ResultExtension::display_err_or_some(
|
||||||
|
rmc_conn.make_raw_call_no_response(&message).await
|
||||||
|
);
|
||||||
|
}.to_tokens(tokens);
|
||||||
|
}
|
||||||
|
|
||||||
|
})
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
fn generate_raw_info(&self, tokens: &mut TokenStream){
|
||||||
|
let Self{
|
||||||
|
name,
|
||||||
|
id,
|
||||||
|
..
|
||||||
|
} = self;
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ToTokens for RmcProtocolData{
|
||||||
|
fn to_tokens(&self, tokens: &mut TokenStream) {
|
||||||
|
self.generate_raw_trait(tokens);
|
||||||
|
self.generate_raw_info(tokens);
|
||||||
|
self.generate_raw_remote_trait(tokens);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
@ -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};
|
use tonic::{Request, Status};
|
||||||
|
|
||||||
type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result<Request<()>, Status> + Send)>;
|
type InterceptorFunc = Box<(dyn Fn(Request<()>) -> Result<Request<()>, Status> + Send)>;
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ pub fn derive_key(pid: u32, password: [u8; 16]) -> [u8; 16]{
|
||||||
|
|
||||||
key
|
key
|
||||||
}
|
}
|
||||||
#[derive(Pod, Zeroable, Copy, Clone, Debug, Eq, PartialEq)]
|
#[derive(Pod, Zeroable, Copy, Clone, Debug, Eq, PartialEq, Default)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct KerberosDateTime(pub u64);
|
pub struct KerberosDateTime(pub u64);
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ impl KerberosDateTime{
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn get_month(&self) -> u8{
|
pub fn get_month(&self) -> u8{
|
||||||
((self.0 >> 22) & 0b111111) as u8
|
((self.0 >> 22) & 0b1111) as u8
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -154,3 +154,17 @@ impl Ticket{
|
||||||
data.into_boxed_slice()
|
data.into_boxed_slice()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test{
|
||||||
|
use chrono::{Datelike, Utc};
|
||||||
|
use crate::kerberos::KerberosDateTime;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn kerberos_time_convert_test(){
|
||||||
|
let time = KerberosDateTime(135904948834);
|
||||||
|
|
||||||
|
println!("{}", time.to_regular_time().to_rfc2822());
|
||||||
|
}
|
||||||
|
}
|
||||||
310
src/main.rs
310
src/main.rs
|
|
@ -1,104 +1,127 @@
|
||||||
#![allow(dead_code)]
|
#![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::nex::account::Account;
|
||||||
use crate::protocols::{auth, block_if_maintenance};
|
use crate::nex::auth_handler::{AuthHandler, RemoteAuthClientProtocol};
|
||||||
use crate::protocols::auth::AuthProtocolConfig;
|
use crate::prudp::packet::VirtualPort;
|
||||||
use crate::protocols::matchmake_common::MatchmakeData;
|
|
||||||
use crate::protocols::server::RMCProtocolServer;
|
|
||||||
use crate::prudp::socket::{ActiveSecureConnectionData, EncryptionPair, Socket};
|
|
||||||
use crate::prudp::packet::{VirtualPort};
|
|
||||||
use crate::prudp::router::Router;
|
use crate::prudp::router::Router;
|
||||||
use crate::prudp::secure::{generate_secure_encryption_pairs, read_secure_connection_data};
|
use crate::prudp::secure::Secure;
|
||||||
use crate::rmc::message::RMCMessage;
|
use crate::prudp::sockaddr::PRUDPSockAddr;
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::prudp::unsecure::Unsecure;
|
||||||
|
use crate::rmc::protocols::auth::Auth;
|
||||||
|
use crate::rmc::protocols::auth::RawAuth;
|
||||||
|
use crate::rmc::protocols::auth::RawAuthInfo;
|
||||||
|
use crate::rmc::protocols::auth::RemoteAuth;
|
||||||
|
use crate::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote};
|
||||||
|
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 chrono::{Local, SecondsFormat};
|
||||||
|
use log::{error, info};
|
||||||
|
use macros::rmc_struct;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use simplelog::{
|
||||||
|
ColorChoice, CombinedLogger, Config, LevelFilter, TermLogger, TerminalMode, WriteLogger,
|
||||||
|
};
|
||||||
|
use std::fs::File;
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
|
use std::ops::{BitAnd, BitOr};
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::time::Duration;
|
||||||
|
use std::{env, fs};
|
||||||
|
use tokio::task::JoinHandle;
|
||||||
|
use crate::nex::user::User;
|
||||||
|
|
||||||
mod endianness;
|
mod endianness;
|
||||||
mod prudp;
|
mod prudp;
|
||||||
pub mod rmc;
|
pub mod rmc;
|
||||||
mod protocols;
|
//mod protocols;
|
||||||
|
|
||||||
mod nex;
|
|
||||||
mod grpc;
|
mod grpc;
|
||||||
mod kerberos;
|
mod kerberos;
|
||||||
|
mod nex;
|
||||||
|
mod result;
|
||||||
|
mod versions;
|
||||||
|
mod web;
|
||||||
|
|
||||||
static KERBEROS_SERVER_PASSWORD: Lazy<String> = Lazy::new(||{
|
static KERBEROS_SERVER_PASSWORD: Lazy<String> = Lazy::new(|| {
|
||||||
env::var("AUTH_SERVER_PASSWORD")
|
env::var("AUTH_SERVER_PASSWORD")
|
||||||
.ok()
|
.ok()
|
||||||
.unwrap_or("password".to_owned())
|
.unwrap_or("password".to_owned())
|
||||||
});
|
});
|
||||||
|
|
||||||
|
static AUTH_SERVER_ACCOUNT: Lazy<Account> =
|
||||||
|
Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD));
|
||||||
|
static SECURE_SERVER_ACCOUNT: Lazy<Account> =
|
||||||
|
Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
|
||||||
|
|
||||||
static AUTH_SERVER_ACCOUNT: Lazy<Account> = Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD));
|
static AUTH_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
|
||||||
static SECURE_SERVER_ACCOUNT: Lazy<Account> = Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
|
|
||||||
|
|
||||||
static AUTH_SERVER_PORT: Lazy<u16> = Lazy::new(||{
|
|
||||||
env::var("AUTH_SERVER_PORT")
|
env::var("AUTH_SERVER_PORT")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.unwrap_or(10000)
|
.unwrap_or(10000)
|
||||||
});
|
});
|
||||||
static SECURE_SERVER_PORT: Lazy<u16> = Lazy::new(||{
|
static SECURE_SERVER_PORT: Lazy<u16> = Lazy::new(|| {
|
||||||
env::var("SECURE_SERVER_PORT")
|
env::var("SECURE_SERVER_PORT")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.unwrap_or(10001)
|
.unwrap_or(10001)
|
||||||
});
|
});
|
||||||
|
|
||||||
static OWN_IP_PRIVATE: Lazy<Ipv4Addr> = Lazy::new(||{
|
static OWN_IP_PRIVATE: Lazy<Ipv4Addr> = Lazy::new(|| {
|
||||||
env::var("SERVER_IP")
|
env::var("SERVER_IP")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.expect("no public ip specified")
|
.expect("no public ip specified")
|
||||||
});
|
});
|
||||||
|
|
||||||
static OWN_IP_PUBLIC: Lazy<Ipv4Addr> = Lazy::new(||{
|
static OWN_IP_PUBLIC: Lazy<String> =
|
||||||
env::var("SERVER_IP_PUBLIC")
|
Lazy::new(|| env::var("SERVER_IP_PUBLIC").unwrap_or(OWN_IP_PRIVATE.to_string()));
|
||||||
.ok()
|
|
||||||
.and_then(|s| s.parse().ok())
|
|
||||||
.unwrap_or(*OWN_IP_PRIVATE)
|
|
||||||
});
|
|
||||||
|
|
||||||
static SECURE_STATION_URL: Lazy<String> = Lazy::new(||
|
static SECURE_STATION_URL: Lazy<String> = Lazy::new(|| {
|
||||||
format!("prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1", *OWN_IP_PUBLIC, *SECURE_SERVER_PORT)
|
format!(
|
||||||
);
|
"prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1",
|
||||||
|
*OWN_IP_PUBLIC, *SECURE_SERVER_PORT
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
CombinedLogger::init(
|
CombinedLogger::init(vec![
|
||||||
vec![
|
TermLogger::new(
|
||||||
TermLogger::new(LevelFilter::Info, Config::default(), TerminalMode::Mixed, ColorChoice::Auto),
|
LevelFilter::Info,
|
||||||
WriteLogger::new(LevelFilter::max(), Config::default(), {
|
Config::default(),
|
||||||
fs::create_dir_all("log").unwrap();
|
TerminalMode::Mixed,
|
||||||
let date = Local::now().to_rfc3339_opts(SecondsFormat::Secs, false);
|
ColorChoice::Auto,
|
||||||
// this fixes windows being windows
|
),
|
||||||
let date = date.replace(":", "-");
|
WriteLogger::new(LevelFilter::max(), Config::default(), {
|
||||||
let filename = format!("{}.log", date);
|
fs::create_dir_all("log").unwrap();
|
||||||
if cfg!(windows) {
|
let date = Local::now().to_rfc3339_opts(SecondsFormat::Secs, false);
|
||||||
File::create(format!("log\\{}", filename)).unwrap()
|
// this fixes windows being windows
|
||||||
} else {
|
let date = date.replace(":", "-");
|
||||||
File::create(format!("log/{}", filename)).unwrap()
|
let filename = format!("{}.log", date);
|
||||||
}
|
if cfg!(windows) {
|
||||||
})
|
File::create(format!("log\\{}", filename)).unwrap()
|
||||||
]
|
} else {
|
||||||
).unwrap();
|
File::create(format!("log/{}", filename)).unwrap()
|
||||||
|
}
|
||||||
|
}),
|
||||||
|
])
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
dotenv::dotenv().ok();
|
dotenv::dotenv().ok();
|
||||||
|
|
||||||
start_servers().await;
|
start_servers().await;
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
|
||||||
struct AuthServer{
|
struct AuthServer{
|
||||||
router: Arc<Router>,
|
router: Arc<Router>,
|
||||||
|
|
@ -194,7 +217,8 @@ async fn start_secure_server() -> SecureServer{
|
||||||
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::bound_protocol(matchmake_data.clone())),
|
||||||
Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data))
|
Box::new(protocols::matchmake_extension::bound_protocol(matchmake_data)),
|
||||||
|
Box::new(protocols::nat_traversal::bound_protocol())
|
||||||
]));
|
]));
|
||||||
|
|
||||||
let socket =
|
let socket =
|
||||||
|
|
@ -237,74 +261,116 @@ async fn start_secure_server() -> SecureServer{
|
||||||
router,
|
router,
|
||||||
socket,
|
socket,
|
||||||
}
|
}
|
||||||
|
}*/
|
||||||
|
|
||||||
|
async fn start_auth() -> JoinHandle<()> {
|
||||||
|
tokio::spawn(async {
|
||||||
|
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *AUTH_SERVER_PORT))
|
||||||
|
.await
|
||||||
|
.expect("unable to start router");
|
||||||
|
|
||||||
|
let mut socket_secure = router_secure
|
||||||
|
.add_socket(VirtualPort::new(1, 10), Unsecure("6f599f81"))
|
||||||
|
.await
|
||||||
|
.expect("unable to add socket");
|
||||||
|
|
||||||
|
// let conn = socket_secure.connect(auth_sockaddr).await.unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let Some(conn) = socket_secure.accept().await else {
|
||||||
|
error!("server crashed");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("new connected user!");
|
||||||
|
|
||||||
|
let _ = new_rmc_gateway_connection(conn, |_| AuthHandler {
|
||||||
|
destination_server_acct: &SECURE_SERVER_ACCOUNT,
|
||||||
|
build_name: "branch:origin/project/wup-agmj build:3_8_15_2004_0",
|
||||||
|
station_url: &SECURE_STATION_URL,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn start_servers(){
|
async fn start_secure() -> JoinHandle<()> {
|
||||||
|
tokio::spawn(async {
|
||||||
|
let (router_secure, _) =
|
||||||
|
Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SECURE_SERVER_PORT))
|
||||||
|
.await
|
||||||
|
.expect("unable to start router");
|
||||||
|
|
||||||
|
let mut socket_secure = router_secure
|
||||||
|
.add_socket(
|
||||||
|
VirtualPort::new(1, 10),
|
||||||
|
Secure("6f599f81", &SECURE_SERVER_ACCOUNT),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.expect("unable to add socket");
|
||||||
|
|
||||||
|
// let conn = socket_secure.connect(auth_sockaddr).await.unwrap();
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let Some(conn) = socket_secure.accept().await else {
|
||||||
|
error!("server crashed");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("new connected user on secure :D!");
|
||||||
|
|
||||||
|
let ip = conn.socket_addr.regular_socket_addr;
|
||||||
|
let pid = conn.user_id;
|
||||||
|
|
||||||
|
let _ = new_rmc_gateway_connection(conn, |_| User {
|
||||||
|
ip,
|
||||||
|
pid
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_test() {
|
||||||
|
let addr = SocketAddrV4::new(*OWN_IP_PRIVATE, *AUTH_SERVER_PORT);
|
||||||
|
|
||||||
|
let virt_addr = VirtualPort::new(1, 10);
|
||||||
|
let prudp_addr = PRUDPSockAddr::new(addr, virt_addr);
|
||||||
|
|
||||||
|
let (router_test, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, 26969))
|
||||||
|
.await
|
||||||
|
.expect("unable to start router");
|
||||||
|
|
||||||
|
let mut socket_secure = router_test
|
||||||
|
.add_socket(VirtualPort::new(1, 10), Unsecure("6f599f81"))
|
||||||
|
.await
|
||||||
|
.expect("unable to add socket");
|
||||||
|
|
||||||
|
let conn = socket_secure.connect(prudp_addr).await.unwrap();
|
||||||
|
|
||||||
|
let remote =
|
||||||
|
new_rmc_gateway_connection(conn, |r| OnlyRemote::<RemoteAuthClientProtocol>::new(r));
|
||||||
|
|
||||||
|
let v = remote
|
||||||
|
.login_ex("1469690705".to_string(), Any::default())
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
println!("got it");
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn start_servers() {
|
||||||
|
#[cfg(feature = "auth")]
|
||||||
|
let auth_server = start_auth().await;
|
||||||
|
#[cfg(feature = "secure")]
|
||||||
|
let secure_server = start_secure().await;
|
||||||
|
//let web_server = web::start_web().await;
|
||||||
|
|
||||||
|
//tokio::time::sleep(Duration::from_secs(1)).await;
|
||||||
|
|
||||||
|
//start_test().await;
|
||||||
|
|
||||||
#[cfg(feature = "auth")]
|
#[cfg(feature = "auth")]
|
||||||
let auth_server = start_auth_server().await;
|
auth_server.await.expect("auth server crashed");
|
||||||
#[cfg(feature = "secure")]
|
#[cfg(feature = "secure")]
|
||||||
let secure_server = start_secure_server().await;
|
secure_server.await.expect("auth server crashed");
|
||||||
|
//web_server.await.expect("webserver crashed");
|
||||||
#[cfg(feature = "auth")]
|
|
||||||
auth_server.join_handle.await.expect("auth server crashed");
|
|
||||||
#[cfg(feature = "secure")]
|
|
||||||
secure_server.join_handle.await.expect("auth server crashed");
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#[cfg(test)]
|
|
||||||
mod test{
|
|
||||||
use std::io::Cursor;
|
|
||||||
use std::num::ParseIntError;
|
|
||||||
use std::str::from_utf8;
|
|
||||||
use hmac::digest::consts::U5;
|
|
||||||
use rc4::{KeyInit, Rc4, StreamCipher};
|
|
||||||
use crate::prudp::packet::PRUDPPacket;
|
|
||||||
use crate::rmc;
|
|
||||||
|
|
||||||
fn from_hex_stream(val: &str) -> Result<Vec<u8>, ParseIntError> {
|
|
||||||
let res: Result<Vec<u8>, _> = val.as_bytes()
|
|
||||||
.chunks_exact(2)
|
|
||||||
.map(|c| from_utf8(c).expect("unable to convert back to string"))
|
|
||||||
.map(|s| u8::from_str_radix(s, 16))
|
|
||||||
.collect();
|
|
||||||
|
|
||||||
res
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn simulate_packets(){
|
|
||||||
let val = from_hex_stream("ead001037d00afa1e200a5000200d9e4a4050368c18c6de4e2fb1cc40f0c020100768744db99f92c5005a061fd2a1df280cd64d5c1a565952c6befa607cbaf34661312b16db0fa6fccfb81e28b5a3a9bed02b49152bbc99cc112b7e29b9e45ec3d4b89df0fe71390883d9a927c264d07ada0de9cd28499e3ccdf3fd079e4a9848d4d783778c42da2af06106a7326634dc5bec5c3438ef18e30109839ffcc").expect("uuuuh");
|
|
||||||
|
|
||||||
let mut packet = PRUDPPacket::new(&mut Cursor::new(&val)).expect("invalid packet");
|
|
||||||
|
|
||||||
let mut rc4: Rc4<U5> =
|
|
||||||
Rc4::new_from_slice("CD&ML".as_bytes().into()).expect("invalid key");
|
|
||||||
|
|
||||||
rc4.apply_keystream(&mut packet.payload);
|
|
||||||
|
|
||||||
println!("packet: {:?}", packet);
|
|
||||||
|
|
||||||
let rmc_packet = rmc::message::RMCMessage::new(&mut Cursor::new(&packet.payload)).expect("unable to read message");
|
|
||||||
|
|
||||||
let mut a = Cursor::new(&rmc_packet.rest_of_data);
|
|
||||||
|
|
||||||
//let pid = rmc::structures::string::read(&mut a).expect("unable to read pid");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[tokio::test]
|
|
||||||
async fn simulate_packets_response(){
|
|
||||||
let val = from_hex_stream("ead001032501a1af6200a500010013ffcdbc3a2ebc44efc6e38ea32a72b40201002e8644db19fe2a5005a2637d2a16f3b1fe5633037c1ed61c5aefad8afebdf2ff8600e9350fba1298b570c70f6dd647eac2d3faf0ab74ef761e2ee43dc10e249e5f91aed6813dcc04b3c707d9442b6e353b9b0b654e98f860fe5379c41d3c2a1874b7dd37ebf499e03bd2fd3e9a9203c0959feb760c38f504dcd0c9e99b17fd410657da4efa3e01c8a68ab3042d6d489788d5580778d32249cdf1fba8bf68cf4019d116ea7c580622ea1e3635139d91b44635d5e95b6c35b33898fdc0117fa6fc7162840d07a49f1e7089aa0ea65409a8ddeb2334449ba73a0ff7de462cf4a706a696de0f0521b84ae5a3f8587f3585d202d3cc0fb0451519c1b830b5e3cdd6de52e9add7325cbbf08a7c2f8b875934942b226703a22b4bc8931932dab055049051e4144b02").expect("uuuuh");
|
|
||||||
|
|
||||||
let mut packet = PRUDPPacket::new(&mut Cursor::new(&val)).expect("invalid packet");
|
|
||||||
|
|
||||||
let mut rc4: Rc4<U5> =
|
|
||||||
Rc4::new_from_slice("CD&ML".as_bytes().into()).expect("invalid key");
|
|
||||||
|
|
||||||
rc4.apply_keystream(&mut packet.payload);
|
|
||||||
|
|
||||||
println!("packet: {:?}", packet);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@ use std::sync::Arc;
|
||||||
use log::error;
|
use log::error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use crate::protocols::auth::AuthProtocolConfig;
|
use crate::protocols::auth::AuthProtocolConfig;
|
||||||
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;
|
||||||
|
|
@ -7,7 +7,6 @@ use crate::grpc::account;
|
||||||
use crate::kerberos::KerberosDateTime;
|
use crate::kerberos::KerberosDateTime;
|
||||||
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, 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};
|
||||||
|
|
@ -4,7 +4,6 @@ use tokio::sync::Mutex;
|
||||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use crate::protocols::auth::{AuthProtocolConfig, get_login_data_by_pid};
|
use crate::protocols::auth::{AuthProtocolConfig, get_login_data_by_pid};
|
||||||
use crate::protocols::auth::ticket_generation::generate_ticket;
|
use crate::protocols::auth::ticket_generation::generate_ticket;
|
||||||
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;
|
||||||
|
|
@ -2,7 +2,6 @@ use std::io::Cursor;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{Mutex, RwLock};
|
use tokio::sync::{Mutex, RwLock};
|
||||||
use crate::protocols::matchmake_common::MatchmakeData;
|
use crate::protocols::matchmake_common::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::response::{ErrorCode, RMCResponseResult};
|
||||||
use crate::rmc::structures::qresult::QResult;
|
use crate::rmc::structures::qresult::QResult;
|
||||||
136
src/nex-implementation/matchmake_common/mod.rs
Normal file
136
src/nex-implementation/matchmake_common/mod.rs
Normal file
|
|
@ -0,0 +1,136 @@
|
||||||
|
use std::collections::{BTreeMap};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use log::error;
|
||||||
|
use rand::random;
|
||||||
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
use crate::kerberos::KerberosDateTime;
|
||||||
|
use crate::protocols::notification::Notification;
|
||||||
|
use crate::rmc::structures::matchmake::{Gathering, MatchmakeParam, MatchmakeSession};
|
||||||
|
use crate::rmc::structures::variant::Variant;
|
||||||
|
|
||||||
|
#[derive(Default, Debug)]
|
||||||
|
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 from_matchmake_session(session: MatchmakeSession, host: &Mutex<ConnectionData>) -> Self{
|
||||||
|
let host = host.lock().await;
|
||||||
|
|
||||||
|
let ConnectionData{
|
||||||
|
active_connection_data,
|
||||||
|
..
|
||||||
|
} = &*host;
|
||||||
|
|
||||||
|
let Some(active_connection_data) = active_connection_data else{
|
||||||
|
return Default::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
let ActiveConnectionData{
|
||||||
|
active_secure_connection_data,
|
||||||
|
..
|
||||||
|
} = active_connection_data;
|
||||||
|
|
||||||
|
let Some(active_secure_connection_data) = active_secure_connection_data else{
|
||||||
|
return Default::default();
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
let mm_session = MatchmakeSession{
|
||||||
|
gathering: Gathering{
|
||||||
|
self_gid: 1,
|
||||||
|
owner_pid: active_secure_connection_data.pid,
|
||||||
|
host_pid: active_secure_connection_data.pid,
|
||||||
|
..session.gathering.clone()
|
||||||
|
},
|
||||||
|
datetime: KerberosDateTime::now(),
|
||||||
|
session_key: (0..32).map(|_| random()).collect(),
|
||||||
|
matchmake_param: MatchmakeParam{
|
||||||
|
params: vec![
|
||||||
|
("@SR".to_owned(), Variant::Bool(true)),
|
||||||
|
("@GIR".to_owned(), Variant::SInt64(3))
|
||||||
|
]
|
||||||
|
},
|
||||||
|
system_password_enabled: false,
|
||||||
|
..session
|
||||||
|
};
|
||||||
|
|
||||||
|
Self{
|
||||||
|
session: mm_session,
|
||||||
|
connected_players: Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn add_player(&mut self, socket: &SocketData, conn: Arc<Mutex<ConnectionData>>, join_msg: String) {
|
||||||
|
let locked = conn.lock().await;
|
||||||
|
|
||||||
|
let Some(joining_pid) = locked.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
|
||||||
|
};
|
||||||
|
|
||||||
|
drop(locked);
|
||||||
|
|
||||||
|
self.connected_players.push(conn);
|
||||||
|
self.session.participation_count = self.connected_players.len() as u32;
|
||||||
|
|
||||||
|
|
||||||
|
for other_connection in &self.connected_players{
|
||||||
|
let mut conn = other_connection.lock().await;
|
||||||
|
|
||||||
|
|
||||||
|
let Some(other_pid) = conn.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
|
||||||
|
};
|
||||||
|
|
||||||
|
/*if other_pid == self.session.gathering.owner_pid &&
|
||||||
|
joining_pid == self.session.gathering.owner_pid{
|
||||||
|
continue;
|
||||||
|
}*/
|
||||||
|
|
||||||
|
conn.send_notification(socket, Notification{
|
||||||
|
pid_source: joining_pid,
|
||||||
|
notif_type: 3001,
|
||||||
|
param_1: self.session.gathering.self_gid,
|
||||||
|
param_2: other_pid,
|
||||||
|
str_param: join_msg.clone(),
|
||||||
|
param_3: self.session.participation_count
|
||||||
|
}).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn add_matchmake_session(mm_data: Arc<RwLock<MatchmakeData>>,session: ExtendedMatchmakeSession) -> Arc<Mutex<ExtendedMatchmakeSession>> {
|
||||||
|
let gid = session.session.gathering.self_gid;
|
||||||
|
|
||||||
|
let mut mm_data = mm_data.write().await;
|
||||||
|
|
||||||
|
let session = Arc::new(Mutex::new(session));
|
||||||
|
|
||||||
|
mm_data.matchmake_sessions.insert(gid, session.clone());
|
||||||
|
|
||||||
|
session
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MatchmakeData {
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub async fn try_find_session_with_criteria(&self, ) -> Option<Arc<Mutex<ExtendedMatchmakeSession>>>{
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,12 +1,15 @@
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use chrono::SecondsFormat::Millis;
|
||||||
|
use log::info;
|
||||||
use rand::random;
|
use rand::random;
|
||||||
use tokio::sync::{Mutex, RwLock};
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
use tokio::time::sleep;
|
||||||
use crate::protocols::matchmake_common::{ExtendedMatchmakeSession, MatchmakeData};
|
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::response::{ErrorCode, RMCResponseResult};
|
||||||
use crate::rmc::structures::matchmake::{AutoMatchmakeParam};
|
use crate::rmc::structures::matchmake::{AutoMatchmakeParam, MatchmakeSession};
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -18,7 +21,7 @@ pub async fn auto_matchmake_with_param_postpone(
|
||||||
mm_data: Arc<RwLock<MatchmakeData>>,
|
mm_data: Arc<RwLock<MatchmakeData>>,
|
||||||
auto_matchmake_param: AutoMatchmakeParam
|
auto_matchmake_param: AutoMatchmakeParam
|
||||||
) -> RMCResponseResult{
|
) -> RMCResponseResult{
|
||||||
println!("auto_matchmake_with_param_postpone: {:?}", auto_matchmake_param);
|
//println!("auto_matchmake_with_param_postpone: {:?}", auto_matchmake_param);
|
||||||
let locked_conn = conn.lock().await;
|
let locked_conn = conn.lock().await;
|
||||||
let Some(secure_conn) =
|
let Some(secure_conn) =
|
||||||
locked_conn.active_connection_data.as_ref().map(|a| a.active_secure_connection_data.as_ref()).flatten() else {
|
locked_conn.active_connection_data.as_ref().map(|a| a.active_secure_connection_data.as_ref()).flatten() else {
|
||||||
|
|
@ -38,35 +41,41 @@ pub async fn auto_matchmake_with_param_postpone(
|
||||||
// up anything else unnescesarily
|
// up anything else unnescesarily
|
||||||
drop(mm_data_read);
|
drop(mm_data_read);
|
||||||
|
|
||||||
let gid = random();
|
let session =
|
||||||
|
ExtendedMatchmakeSession::from_matchmake_session(auto_matchmake_param.matchmake_session, &conn).await;
|
||||||
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 gid = session.session.gathering.self_gid;
|
||||||
|
|
||||||
let mut mm_data = mm_data.write().await;
|
let mut mm_data = mm_data.write().await;
|
||||||
|
|
||||||
let session = Arc::new(Mutex::new(ExtendedMatchmakeSession{
|
let session = Arc::new(Mutex::new(session));
|
||||||
session: matchmake_session.clone(),
|
|
||||||
connected_players: Vec::new()
|
|
||||||
}));
|
|
||||||
|
|
||||||
mm_data.matchmake_sessions.insert(gid, session.clone());
|
mm_data.matchmake_sessions.insert(gid, session.clone());
|
||||||
|
|
||||||
session
|
session
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut session = session.lock().await;
|
let mut locked_session = session.lock().await;
|
||||||
|
|
||||||
//todo: refactor so that this works
|
//todo: refactor so that this works
|
||||||
session.add_player(socket, conn.clone(), auto_matchmake_param.join_message).await;
|
{
|
||||||
|
let session = session.clone();
|
||||||
|
let socket = socket.clone();
|
||||||
|
let connection = conn.clone();
|
||||||
|
let join_msg = auto_matchmake_param.join_message.clone();
|
||||||
|
tokio::spawn(async move{
|
||||||
|
sleep(Duration::from_millis(500)).await;
|
||||||
|
println!("adding player");
|
||||||
|
let mut session = session.lock().await;
|
||||||
|
session.add_player(&socket, connection, join_msg).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
info!("new session: {:?}", locked_session);
|
||||||
|
|
||||||
let mut response = Vec::new();
|
let mut response = Vec::new();
|
||||||
|
|
||||||
session.session.serialize(&mut response).expect("unable to serialize matchmake session");
|
locked_session.session.serialize(&mut response).expect("unable to serialize matchmake session");
|
||||||
|
|
||||||
rmcmessage.success_with_data(response)
|
rmcmessage.success_with_data(response)
|
||||||
}
|
}
|
||||||
|
|
@ -0,0 +1,87 @@
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use log::info;
|
||||||
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
use tokio::time::sleep;
|
||||||
|
use crate::protocols::matchmake_common::{add_matchmake_session, ExtendedMatchmakeSession, MatchmakeData};
|
||||||
|
use crate::protocols::matchmake_extension::method_auto_matchmake_with_param_postpone::auto_matchmake_with_param_postpone;
|
||||||
|
use crate::rmc::message::RMCMessage;
|
||||||
|
use crate::rmc::response::{ErrorCode, RMCResponseResult};
|
||||||
|
use crate::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam};
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
pub async fn create_matchmake_session_with_param(
|
||||||
|
rmcmessage: &RMCMessage,
|
||||||
|
conn: &Arc<Mutex<ConnectionData>>,
|
||||||
|
socket: &Arc<SocketData>,
|
||||||
|
mm_data: Arc<RwLock<MatchmakeData>>,
|
||||||
|
create_matchmake_session: CreateMatchmakeSessionParam
|
||||||
|
) -> RMCResponseResult {
|
||||||
|
|
||||||
|
let mut session =
|
||||||
|
ExtendedMatchmakeSession::from_matchmake_session(create_matchmake_session.matchmake_session, &conn).await;
|
||||||
|
|
||||||
|
session.session.participation_count = create_matchmake_session.participation_count as u32;
|
||||||
|
|
||||||
|
let session = add_matchmake_session(mm_data, session).await;
|
||||||
|
|
||||||
|
let mut session = session.lock().await;
|
||||||
|
|
||||||
|
session.add_player(&socket, conn.clone(), create_matchmake_session.join_message).await;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let mut response = Vec::new();
|
||||||
|
|
||||||
|
|
||||||
|
session.session.serialize(&mut response).expect("unable to serialize session");
|
||||||
|
|
||||||
|
println!("{}", hex::encode(&response));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
rmcmessage.success_with_data(response)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_matchmake_session_with_param_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) = CreateMatchmakeSessionParam::deserialize(&mut reader) else {
|
||||||
|
return rmcmessage.error_result_with_code(ErrorCode::Core_InvalidArgument);
|
||||||
|
};
|
||||||
|
|
||||||
|
create_matchmake_session_with_param(rmcmessage, connection_data, socket, data, matchmake_param).await
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test{
|
||||||
|
use std::io::Cursor;
|
||||||
|
use crate::prudp::packet::PRUDPPacket;
|
||||||
|
use crate::rmc::message::RMCMessage;
|
||||||
|
use crate::rmc::structures::matchmake::MatchmakeSession;
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test(){
|
||||||
|
let data = hex::decode("ead001030000a1af12001800050002010000000000000000000000000000000000").unwrap();
|
||||||
|
|
||||||
|
let packet = PRUDPPacket::new(&mut Cursor::new(data)).unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", packet);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_2(){
|
||||||
|
let data = hex::decode("250000008e0100000001000000001700000051b39957b90b00000100000051b3995701000001000000").unwrap();
|
||||||
|
|
||||||
|
let msg = RMCMessage::new(&mut Cursor::new(data)).unwrap();
|
||||||
|
|
||||||
|
println!("{:?}", msg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -3,7 +3,6 @@ use std::sync::Arc;
|
||||||
use log::info;
|
use log::info;
|
||||||
use tokio::sync::{Mutex, RwLock};
|
use tokio::sync::{Mutex, RwLock};
|
||||||
use crate::protocols::matchmake_common::MatchmakeData;
|
use crate::protocols::matchmake_common::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::response::{ErrorCode, RMCResponseResult};
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
mod method_get_playing_session;
|
mod method_get_playing_session;
|
||||||
mod method_auto_matchmake_with_param_postpone;
|
mod method_auto_matchmake_with_param_postpone;
|
||||||
|
mod method_create_matchmake_session_with_param;
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use tokio::sync::{RwLock};
|
use tokio::sync::{RwLock};
|
||||||
|
|
@ -7,10 +8,12 @@ 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;
|
use method_auto_matchmake_with_param_postpone::auto_matchmake_with_param_postpone_raw_params;
|
||||||
|
use crate::protocols::matchmake_extension::method_create_matchmake_session_with_param::create_matchmake_session_with_param_raw_params;
|
||||||
|
|
||||||
define_protocol!{
|
define_protocol!{
|
||||||
109(matchmake_data: Arc<RwLock<MatchmakeData>>) => {
|
109(matchmake_data: Arc<RwLock<MatchmakeData>>) => {
|
||||||
16 => get_playing_session_raw_params,
|
16 => get_playing_session_raw_params,
|
||||||
|
38 => create_matchmake_session_with_param_raw_params,
|
||||||
40 => auto_matchmake_with_param_postpone_raw_params
|
40 => auto_matchmake_with_param_postpone_raw_params
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -6,7 +6,6 @@ use log::warn;
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use crate::grpc;
|
use crate::grpc;
|
||||||
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};
|
||||||
|
|
||||||
|
|
@ -17,7 +16,8 @@ pub mod secure;
|
||||||
pub mod matchmake_extension;
|
pub mod matchmake_extension;
|
||||||
pub mod matchmake_common;
|
pub mod matchmake_common;
|
||||||
pub mod matchmake;
|
pub mod matchmake;
|
||||||
mod notification;
|
pub mod notification;
|
||||||
|
pub mod nat_traversal;
|
||||||
|
|
||||||
static IS_MAINTENANCE: Lazy<bool> = Lazy::new(|| {
|
static IS_MAINTENANCE: Lazy<bool> = Lazy::new(|| {
|
||||||
env::var("IS_MAINTENANCE")
|
env::var("IS_MAINTENANCE")
|
||||||
|
|
@ -0,0 +1,29 @@
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
use tokio::time::sleep;
|
||||||
|
use crate::protocols::matchmake_common::MatchmakeData;
|
||||||
|
use crate::rmc::message::RMCMessage;
|
||||||
|
use crate::rmc::response::{ErrorCode, RMCResponseResult};
|
||||||
|
use crate::rmc::structures::matchmake::CreateMatchmakeSessionParam;
|
||||||
|
|
||||||
|
pub async fn report_nat_properties(
|
||||||
|
rmcmessage: &RMCMessage,
|
||||||
|
socket: &Arc<SocketData>,
|
||||||
|
connection_data: &Arc<Mutex<ConnectionData>>,
|
||||||
|
) -> RMCResponseResult{
|
||||||
|
sleep(Duration::from_millis(50)).await;
|
||||||
|
rmcmessage.success_with_data(Vec::new())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn report_nat_properties_raw_params(
|
||||||
|
rmcmessage: &RMCMessage,
|
||||||
|
socket: &Arc<SocketData>,
|
||||||
|
connection_data: &Arc<Mutex<ConnectionData>>,
|
||||||
|
_: ()
|
||||||
|
) -> RMCResponseResult{
|
||||||
|
let mut reader = Cursor::new(&rmcmessage.rest_of_data);
|
||||||
|
|
||||||
|
report_nat_properties(rmcmessage, socket, connection_data).await
|
||||||
|
}
|
||||||
10
src/nex-implementation/nat_traversal/mod.rs
Normal file
10
src/nex-implementation/nat_traversal/mod.rs
Normal file
|
|
@ -0,0 +1,10 @@
|
||||||
|
mod method_report_nat_properties;
|
||||||
|
|
||||||
|
use crate::define_protocol;
|
||||||
|
use crate::protocols::nat_traversal::method_report_nat_properties::report_nat_properties_raw_params;
|
||||||
|
|
||||||
|
define_protocol!{
|
||||||
|
3() => {
|
||||||
|
5 => report_nat_properties_raw_params
|
||||||
|
}
|
||||||
|
}
|
||||||
159
src/nex-implementation/notification/mod.rs
Normal file
159
src/nex-implementation/notification/mod.rs
Normal file
|
|
@ -0,0 +1,159 @@
|
||||||
|
use macros::RmcSerialize;
|
||||||
|
use rand::random;
|
||||||
|
use crate::prudp::packet::{PRUDPHeader, PRUDPPacket, PacketOption, TypesFlags};
|
||||||
|
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
|
||||||
|
use crate::prudp::packet::types::DATA;
|
||||||
|
use crate::rmc::message::RMCMessage;
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
#[derive(Debug, Eq, PartialEq, 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,
|
||||||
|
pub param_3: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl ConnectionData{
|
||||||
|
pub async fn send_notification(&mut self, socket: &SocketData, notif: Notification){
|
||||||
|
println!("sending notification");
|
||||||
|
|
||||||
|
let mut data = Vec::new();
|
||||||
|
|
||||||
|
notif.serialize(&mut data).expect("unable to write");
|
||||||
|
|
||||||
|
let message = RMCMessage{
|
||||||
|
protocol_id: 14,
|
||||||
|
method_id: 1,
|
||||||
|
call_id: 1,
|
||||||
|
rest_of_data: data
|
||||||
|
};
|
||||||
|
|
||||||
|
println!("notif: {}", hex::encode(message.to_data()));
|
||||||
|
|
||||||
|
|
||||||
|
let mut 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![
|
||||||
|
PacketOption::FragmentId(0),
|
||||||
|
],
|
||||||
|
payload: message.to_data(),
|
||||||
|
packet_signature: [0;16]
|
||||||
|
};
|
||||||
|
|
||||||
|
self.finish_and_send_packet_to(socket, prudp_packet).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test{
|
||||||
|
use std::io::Cursor;
|
||||||
|
use rand::random;
|
||||||
|
use crate::protocols::notification::Notification;
|
||||||
|
use crate::prudp::packet::{PRUDPHeader, PRUDPPacket, PacketOption, TypesFlags};
|
||||||
|
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
|
||||||
|
use crate::prudp::packet::types::DATA;
|
||||||
|
use crate::rmc::message::RMCMessage;
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test(){
|
||||||
|
let data = hex::decode("ead001032900a1af62000000000000000000000000000000000000000000020100250000000e57238a6601000000001700000051b39957b90b00003661636851b3995701000001000000").unwrap();
|
||||||
|
|
||||||
|
|
||||||
|
let packet = PRUDPPacket::new(&mut Cursor::new(data)).expect("invalid packet");
|
||||||
|
|
||||||
|
println!("{:?}", packet);
|
||||||
|
|
||||||
|
let rmc = RMCMessage::new(&mut Cursor::new(packet.payload)).expect("invalid rmc message");
|
||||||
|
|
||||||
|
println!("{:?}", rmc);
|
||||||
|
|
||||||
|
let notif = Notification::deserialize(&mut Cursor::new(rmc.rest_of_data)).expect("invalid notification");
|
||||||
|
|
||||||
|
println!("{:?}", notif);
|
||||||
|
}
|
||||||
|
#[test]
|
||||||
|
fn test2(){
|
||||||
|
|
||||||
|
let data = hex::decode("250000000e57b6801001000000001700000051b39957b90b0000248a5a9851b3995701000001000000").unwrap();
|
||||||
|
//let packet = PRUDPPacket::new(&mut Cursor::new(data)).expect("invalid packet");
|
||||||
|
|
||||||
|
//println!("{:?}", packet);
|
||||||
|
|
||||||
|
let rmc = RMCMessage::new(&mut Cursor::new(data)).expect("invalid rmc message");
|
||||||
|
|
||||||
|
println!("{:?}", rmc);
|
||||||
|
|
||||||
|
let notif = Notification::deserialize(&mut Cursor::new(rmc.rest_of_data)).expect("invalid notification");
|
||||||
|
|
||||||
|
println!("{:?}", notif);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_rmc_serialization(){
|
||||||
|
let notif = Notification{
|
||||||
|
pid_source: random(),
|
||||||
|
notif_type: random(),
|
||||||
|
param_1: random(),
|
||||||
|
param_2: random(),
|
||||||
|
str_param: "".to_string(),
|
||||||
|
param_3: random(),
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut notif_data = Vec::new();
|
||||||
|
|
||||||
|
notif.serialize(&mut notif_data).unwrap();
|
||||||
|
|
||||||
|
let message = RMCMessage{
|
||||||
|
protocol_id: 14,
|
||||||
|
method_id: 1,
|
||||||
|
call_id: random(),
|
||||||
|
rest_of_data: notif_data
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut prudp_packet = PRUDPPacket{
|
||||||
|
header: PRUDPHeader{
|
||||||
|
..Default::default()
|
||||||
|
},
|
||||||
|
options: vec![
|
||||||
|
PacketOption::FragmentId(0),
|
||||||
|
],
|
||||||
|
payload: message.to_data(),
|
||||||
|
packet_signature: [0;16]
|
||||||
|
};
|
||||||
|
|
||||||
|
prudp_packet.set_sizes();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
let mut packet_data: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
prudp_packet.write_to(&mut packet_data).expect("what");
|
||||||
|
|
||||||
|
let packet_deserialized = PRUDPPacket::new(&mut Cursor::new(packet_data)).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(prudp_packet, packet_deserialized);
|
||||||
|
|
||||||
|
let message_deserialized = RMCMessage::new(&mut Cursor::new(packet_deserialized.payload)).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(message, message_deserialized);
|
||||||
|
|
||||||
|
let notification_deserialized = Notification::deserialize(&mut Cursor::new(message_deserialized.rest_of_data)).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(notification_deserialized, notif);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -2,7 +2,6 @@ use std::io::{Cursor, Write};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use bytemuck::bytes_of;
|
use bytemuck::bytes_of;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
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};
|
||||||
|
|
@ -3,11 +3,11 @@ use std::sync::Arc;
|
||||||
use log::error;
|
use log::error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use crate::prudp::socket::{ConnectionData, SocketData};
|
|
||||||
use crate::rmc::message::RMCMessage;
|
use crate::rmc::message::RMCMessage;
|
||||||
use crate::rmc::response::{RMCResponseResult};
|
use crate::rmc::response::{RMCResponseResult};
|
||||||
use crate::rmc::response::ErrorCode::Core_InvalidArgument;
|
use crate::rmc::response::ErrorCode::Core_InvalidArgument;
|
||||||
use crate::rmc::structures::qbuffer;
|
use crate::rmc::structures::{qbuffer, RmcSerialize};
|
||||||
|
use crate::rmc::structures::qbuffer::QBuffer;
|
||||||
|
|
||||||
pub async fn send_report(rmcmessage: &RMCMessage, report_id: u32, data: Vec<u8>) -> RMCResponseResult{
|
pub async fn send_report(rmcmessage: &RMCMessage, report_id: u32, data: Vec<u8>) -> RMCResponseResult{
|
||||||
let result = tokio::fs::write(format!("./reports/{}", report_id), data).await;
|
let result = tokio::fs::write(format!("./reports/{}", report_id), data).await;
|
||||||
|
|
@ -17,7 +17,7 @@ pub async fn send_report(rmcmessage: &RMCMessage, report_id: u32, data: Vec<u8>)
|
||||||
Err(e) => error!("{}", e)
|
Err(e) => error!("{}", e)
|
||||||
}
|
}
|
||||||
|
|
||||||
return rmcmessage.success_with_data(Vec::new());
|
rmcmessage.success_with_data(Vec::new())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn send_report_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, _conn_data: &Arc<Mutex<ConnectionData>>, _: ()) -> RMCResponseResult{
|
pub async fn send_report_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>, _conn_data: &Arc<Mutex<ConnectionData>>, _: ()) -> RMCResponseResult{
|
||||||
|
|
@ -27,7 +27,7 @@ pub async fn send_report_raw_params(rmcmessage: &RMCMessage, _: &Arc<SocketData>
|
||||||
return rmcmessage.error_result_with_code(Core_InvalidArgument);
|
return rmcmessage.error_result_with_code(Core_InvalidArgument);
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(data) = qbuffer::read(&mut reader) else {
|
let Ok(QBuffer(data)) = QBuffer::deserialize(&mut reader) else {
|
||||||
return rmcmessage.error_result_with_code(Core_InvalidArgument);
|
return rmcmessage.error_result_with_code(Core_InvalidArgument);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -5,10 +5,11 @@ use std::sync::Arc;
|
||||||
use log::error;
|
use log::error;
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use crate::prudp::packet::PRUDPPacket;
|
use crate::prudp::packet::PRUDPPacket;
|
||||||
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;
|
||||||
|
use crate::web::DirectionalData::Incoming;
|
||||||
|
use crate::web::WEB_DATA;
|
||||||
|
|
||||||
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>]>;
|
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>]>;
|
||||||
|
|
||||||
|
|
@ -20,6 +21,13 @@ impl RMCProtocolServer{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn process_message(&self, packet: PRUDPPacket, socket: Arc<SocketData>, connection: Arc<Mutex<ConnectionData>>){
|
pub async fn process_message(&self, packet: PRUDPPacket, socket: Arc<SocketData>, connection: Arc<Mutex<ConnectionData>>){
|
||||||
|
let locked = connection.lock().await;
|
||||||
|
let addr = locked.sock_addr.regular_socket_addr;
|
||||||
|
drop(locked);
|
||||||
|
let mut web = WEB_DATA.lock().await;
|
||||||
|
web.data.push((addr, Incoming(hex::encode(&packet.payload))));
|
||||||
|
drop(web);
|
||||||
|
|
||||||
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;
|
||||||
|
|
@ -29,7 +37,9 @@ impl RMCProtocolServer{
|
||||||
|
|
||||||
for proto in &self.0 {
|
for proto in &self.0 {
|
||||||
if let Some(response) = proto(&rmc, &socket, &connection).await {
|
if let Some(response) = proto(&rmc, &socket, &connection).await {
|
||||||
|
if matches!(response.response_result, RMCResponseResult::Error {..}){
|
||||||
|
error!("an rmc error occurred")
|
||||||
|
}
|
||||||
let mut locked = connection.lock().await;
|
let mut locked = connection.lock().await;
|
||||||
send_response(&packet, &socket, &mut locked, response).await;
|
send_response(&packet, &socket, &mut locked, response).await;
|
||||||
drop(locked);
|
drop(locked);
|
||||||
167
src/nex/auth_handler.rs
Normal file
167
src/nex/auth_handler.rs
Normal file
|
|
@ -0,0 +1,167 @@
|
||||||
|
use crate::grpc::account;
|
||||||
|
use crate::kerberos::{derive_key, KerberosDateTime, Ticket};
|
||||||
|
use crate::nex::account::Account;
|
||||||
|
use crate::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth};
|
||||||
|
use crate::rmc::response::ErrorCode;
|
||||||
|
use crate::rmc::response::ErrorCode::Core_Unknown;
|
||||||
|
use crate::rmc::structures::any::Any;
|
||||||
|
use crate::rmc::structures::connection_data::ConnectionData;
|
||||||
|
use crate::rmc::structures::qresult::QResult;
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
use crate::{define_rmc_proto, kerberos, rmc};
|
||||||
|
use macros::rmc_struct;
|
||||||
|
|
||||||
|
define_rmc_proto!(
|
||||||
|
proto AuthClientProtocol{
|
||||||
|
Auth
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[rmc_struct(AuthClientProtocol)]
|
||||||
|
pub struct AuthHandler {
|
||||||
|
pub destination_server_acct: &'static Account,
|
||||||
|
pub build_name: &'static str,
|
||||||
|
pub station_url: &'static str,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn generate_ticket(
|
||||||
|
source_act_login_data: (u32, [u8; 16]),
|
||||||
|
dest_act_login_data: (u32, [u8; 16]),
|
||||||
|
) -> Box<[u8]> {
|
||||||
|
let source_key = derive_key(source_act_login_data.0, source_act_login_data.1);
|
||||||
|
let dest_key = derive_key(dest_act_login_data.0, dest_act_login_data.1);
|
||||||
|
|
||||||
|
let internal_data = kerberos::TicketInternalData::new(source_act_login_data.0);
|
||||||
|
|
||||||
|
let encrypted_inner = internal_data.encrypt(dest_key);
|
||||||
|
let encrypted_session_ticket = Ticket {
|
||||||
|
pid: dest_act_login_data.0,
|
||||||
|
session_key: internal_data.session_key,
|
||||||
|
}
|
||||||
|
.encrypt(source_key, &encrypted_inner);
|
||||||
|
|
||||||
|
encrypted_session_ticket
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> {
|
||||||
|
let Ok(mut client) = account::Client::new().await else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(passwd) = client.get_nex_password(pid).await else {
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
Some((pid, passwd))
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Auth for AuthHandler {
|
||||||
|
async fn login(&self, name: String) -> Result<(), ErrorCode> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn login_ex(
|
||||||
|
&self,
|
||||||
|
name: String,
|
||||||
|
extra_data: Any,
|
||||||
|
) -> Result<(QResult, u32, Vec<u8>, ConnectionData, String), ErrorCode> {
|
||||||
|
let Ok(pid) = name.parse() else {
|
||||||
|
return Err(ErrorCode::Core_InvalidArgument);
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(mut client) = account::Client::new().await else {
|
||||||
|
return Err(ErrorCode::Core_Exception);
|
||||||
|
};
|
||||||
|
|
||||||
|
let Ok(passwd) = client.get_nex_password(pid).await else {
|
||||||
|
return Err(ErrorCode::Core_Exception);
|
||||||
|
};
|
||||||
|
|
||||||
|
let source_login_data = (pid, passwd);
|
||||||
|
let destination_login_data = self.destination_server_acct.get_login_data();
|
||||||
|
|
||||||
|
let ticket = generate_ticket(source_login_data, destination_login_data);
|
||||||
|
|
||||||
|
let result = QResult::success(Core_Unknown);
|
||||||
|
|
||||||
|
let connection_data = ConnectionData {
|
||||||
|
station_url: self.station_url.to_string(),
|
||||||
|
special_station_url: "".to_string(),
|
||||||
|
//date_time: KerberosDateTime::new(1,1,1,1,1,1),
|
||||||
|
date_time: KerberosDateTime::now(),
|
||||||
|
special_protocols: Vec::new(),
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok((
|
||||||
|
result,
|
||||||
|
source_login_data.0,
|
||||||
|
ticket.into(),
|
||||||
|
connection_data,
|
||||||
|
self.build_name.to_owned(),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn request_ticket(
|
||||||
|
&self,
|
||||||
|
source_pid: u32,
|
||||||
|
destination_pid: u32,
|
||||||
|
) -> Result<(QResult, Vec<u8>), ErrorCode> {
|
||||||
|
let Some(source_login_data) = get_login_data_by_pid(source_pid).await else {
|
||||||
|
return Err(ErrorCode::Core_Exception);
|
||||||
|
};
|
||||||
|
|
||||||
|
let desgination_login_data = if destination_pid == self.destination_server_acct.pid {
|
||||||
|
self.destination_server_acct.get_login_data()
|
||||||
|
} else {
|
||||||
|
let Some(login) = get_login_data_by_pid(destination_pid).await else {
|
||||||
|
return Err(ErrorCode::Core_Exception);
|
||||||
|
};
|
||||||
|
login
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = QResult::success(Core_Unknown);
|
||||||
|
|
||||||
|
let ticket = generate_ticket(source_login_data, desgination_login_data);
|
||||||
|
|
||||||
|
Ok((result, ticket.into()))
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_pid(&self, username: String) -> Result<u32, ErrorCode> {
|
||||||
|
Err(ErrorCode::Core_Exception)
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn get_name(&self, pid: u32) -> Result<String, ErrorCode> {
|
||||||
|
Err(ErrorCode::Core_Exception)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::rmc::structures::connection_data::ConnectionData;
|
||||||
|
use crate::rmc::structures::qresult::QResult;
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
use crate::rmc::response::RMCResponse;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
|
||||||
|
let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
||||||
|
let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap();
|
||||||
|
|
||||||
|
let crate::rmc::response::RMCResponseResult::Success { call_id, method_id, data: stuff} = stuff.response_result else {
|
||||||
|
panic!()
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// let stuff = hex::decode("0100010051B399577400000085F1736FCFBE93660275A3FE36FED6C2EFC57222AC99A9219CF54170A415B02DF1463AC48AD42A6307813FDE67041554B177097832ED000F892D9551A09F88E9CB0388DC1BC9527CC7384556A3287B2A349ABBF7E34A5A3EC14C2287CC7F78DA616BC3B03A035347FBD2E9A505C8EF42447CD809015F0000004E007072756470733A2F73747265616D3D31303B747970653D323B616464726573733D3139322E3136382E3137382E3132303B706F72743D31303030313B4349443D313B5049443D323B7369643D310000000000010000CDF53AA51F00000033006272616E63683A6F726967696E2F70726F6A6563742F7775702D61676D6A206275696C643A335F385F31355F323030345F3000").unwrap();
|
||||||
|
// let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
||||||
|
|
||||||
|
let data = <(QResult, u32, Vec<u8>, ConnectionData, String) as RmcSerialize>::deserialize(
|
||||||
|
&mut Cursor::new(stuff),
|
||||||
|
).unwrap();
|
||||||
|
|
||||||
|
println!("data: {:?}", data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1 +1,3 @@
|
||||||
pub mod account;
|
pub mod account;
|
||||||
|
pub mod auth_handler;
|
||||||
|
pub mod user;
|
||||||
45
src/nex/user.rs
Normal file
45
src/nex/user.rs
Normal file
|
|
@ -0,0 +1,45 @@
|
||||||
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
|
use macros::rmc_struct;
|
||||||
|
use crate::define_rmc_proto;
|
||||||
|
use crate::prudp::station_url::{nat_types, StationUrl};
|
||||||
|
use crate::prudp::station_url::Type::PRUDPS;
|
||||||
|
use crate::prudp::station_url::UrlOptions::{Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID};
|
||||||
|
use crate::rmc::protocols::secure::{RemoteAuth, RawAuthInfo, RawAuth, Auth};
|
||||||
|
use crate::rmc::response::ErrorCode;
|
||||||
|
use crate::rmc::structures::qresult::QResult;
|
||||||
|
|
||||||
|
define_rmc_proto!(
|
||||||
|
proto UserProtocol{
|
||||||
|
Auth
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
#[rmc_struct(UserProtocol)]
|
||||||
|
pub struct User {
|
||||||
|
pub pid: u32,
|
||||||
|
pub ip: SocketAddrV4,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Auth for User{
|
||||||
|
async fn register(&self, station_urls: Vec<String>) -> Result<(QResult, u32, String), ErrorCode> {
|
||||||
|
let public_station = StationUrl{
|
||||||
|
url_type: PRUDPS,
|
||||||
|
options: vec![
|
||||||
|
RVConnectionID(0),
|
||||||
|
Address(*self.ip.ip()),
|
||||||
|
Port(self.ip.port()),
|
||||||
|
NatFiltering(0),
|
||||||
|
NatMapping(0),
|
||||||
|
NatType(nat_types::BEHIND_NAT),
|
||||||
|
PrincipalID(self.pid),
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
|
let result = QResult::success(ErrorCode::Core_Unknown);
|
||||||
|
|
||||||
|
Ok((result, 0, public_station.to_string()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -1,63 +0,0 @@
|
||||||
use std::collections::{BTreeMap};
|
|
||||||
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
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -1,48 +0,0 @@
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -2,6 +2,7 @@ pub mod packet;
|
||||||
pub mod router;
|
pub mod router;
|
||||||
pub mod socket;
|
pub mod socket;
|
||||||
mod auth_module;
|
mod auth_module;
|
||||||
mod sockaddr;
|
pub mod sockaddr;
|
||||||
|
pub mod station_url;
|
||||||
pub mod secure;
|
pub mod secure;
|
||||||
pub mod station_url;
|
pub mod unsecure;
|
||||||
|
|
@ -40,7 +40,7 @@ pub enum Error {
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default)]
|
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)]
|
||||||
pub struct TypesFlags(u16);
|
pub struct TypesFlags(u16);
|
||||||
|
|
||||||
impl TypesFlags {
|
impl TypesFlags {
|
||||||
|
|
@ -96,10 +96,11 @@ impl Debug for TypesFlags {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
#[derive(PartialEq, Eq, Copy, Clone, Pod, Zeroable, SwapEndian, Hash)]
|
#[derive(PartialEq, Eq, Ord, PartialOrd, Copy, Clone, Pod, Zeroable, SwapEndian, Hash)]
|
||||||
pub struct VirtualPort(pub(crate) u8);
|
pub struct VirtualPort(pub(crate) u8);
|
||||||
|
|
||||||
impl VirtualPort {
|
impl VirtualPort {
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub const fn get_stream_type(self) -> u8 {
|
pub const fn get_stream_type(self) -> u8 {
|
||||||
(self.0 & 0xF0) >> 4
|
(self.0 & 0xF0) >> 4
|
||||||
|
|
@ -141,7 +142,7 @@ impl Debug for VirtualPort {
|
||||||
}
|
}
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian)]
|
#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian, Eq, PartialEq)]
|
||||||
pub struct PRUDPHeader {
|
pub struct PRUDPHeader {
|
||||||
pub magic: [u8; 2],
|
pub magic: [u8; 2],
|
||||||
pub version: u8,
|
pub version: u8,
|
||||||
|
|
@ -173,7 +174,7 @@ impl Default for PRUDPHeader{
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum PacketOption{
|
pub enum PacketOption{
|
||||||
SupportedFunctions(u32),
|
SupportedFunctions(u32),
|
||||||
ConnectionSignature([u8; 16]),
|
ConnectionSignature([u8; 16]),
|
||||||
|
|
@ -236,7 +237,7 @@ impl PacketOption{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Default, Clone, Eq, PartialEq)]
|
||||||
pub struct PRUDPPacket {
|
pub struct PRUDPPacket {
|
||||||
pub header: PRUDPHeader,
|
pub header: PRUDPHeader,
|
||||||
pub packet_signature: [u8; 16],
|
pub packet_signature: [u8; 16],
|
||||||
|
|
@ -290,9 +291,12 @@ impl PRUDPPacket {
|
||||||
|
|
||||||
|
|
||||||
let packet_signature: [u8; 16] = reader.read_struct(IS_BIG_ENDIAN)?;
|
let packet_signature: [u8; 16] = reader.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
//let packet_signature: [u8; 16] = [0; 16];
|
||||||
|
|
||||||
assert_eq!(reader.stream_position().ok(), Some(14 + 16));
|
assert_eq!(reader.stream_position().ok(), Some(14 + 16));
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
let mut packet_specific_buffer = vec![0u8; header.packet_specific_size as usize];
|
let mut packet_specific_buffer = vec![0u8; header.packet_specific_size as usize];
|
||||||
|
|
||||||
reader.read_exact(&mut packet_specific_buffer)?;
|
reader.read_exact(&mut packet_specific_buffer)?;
|
||||||
|
|
@ -372,6 +376,7 @@ impl PRUDPPacket {
|
||||||
types_and_flags: flags,
|
types_and_flags: flags,
|
||||||
sequence_id: self.header.sequence_id,
|
sequence_id: self.header.sequence_id,
|
||||||
substream_id: self.header.substream_id,
|
substream_id: self.header.substream_id,
|
||||||
|
session_id: self.header.session_id,
|
||||||
..base.header
|
..base.header
|
||||||
},
|
},
|
||||||
options,
|
options,
|
||||||
|
|
@ -474,6 +479,8 @@ impl PRUDPPacket {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
|
||||||
|
use crate::prudp::packet::types::DATA;
|
||||||
use super::{OptionId, PacketOption, PRUDPHeader, TypesFlags, VirtualPort};
|
use super::{OptionId, PacketOption, PRUDPHeader, TypesFlags, VirtualPort};
|
||||||
#[test]
|
#[test]
|
||||||
fn size_test() {
|
fn size_test() {
|
||||||
|
|
@ -523,4 +530,13 @@ mod test {
|
||||||
|
|
||||||
let header_data: [u8; 8] = bytes.try_into().unwrap();
|
let header_data: [u8; 8] = bytes.try_into().unwrap();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_types_flags(){
|
||||||
|
let types = TypesFlags::default().types(DATA).flags(NEED_ACK | RELIABLE);
|
||||||
|
|
||||||
|
assert_ne!((types.0 >> 4) & NEED_ACK, 0);
|
||||||
|
assert_ne!((types.0 >> 4) & RELIABLE, 0);
|
||||||
|
assert_ne!((types.0 & 0xFF) as u8 & DATA, 0);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -11,7 +11,7 @@ use once_cell::sync::Lazy;
|
||||||
use log::{error, info, trace};
|
use log::{error, info, trace};
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::RwLock;
|
use tokio::sync::RwLock;
|
||||||
use crate::prudp::socket::SocketData;
|
use crate::prudp::socket::{new_socket_pair, AnyInternalSocket, CryptoHandler, ExternalSocket};
|
||||||
use crate::prudp::packet::{PRUDPPacket, VirtualPort};
|
use crate::prudp::packet::{PRUDPPacket, VirtualPort};
|
||||||
use crate::prudp::router::Error::VirtualPortTaken;
|
use crate::prudp::router::Error::VirtualPortTaken;
|
||||||
|
|
||||||
|
|
@ -22,10 +22,9 @@ static SERVER_DATAGRAMS: Lazy<u8> = Lazy::new(||{
|
||||||
});
|
});
|
||||||
|
|
||||||
pub struct Router {
|
pub struct Router {
|
||||||
endpoints: RwLock<[Option<Arc<SocketData>>; 16]>,
|
endpoints: RwLock<[Option<Arc<dyn AnyInternalSocket>>; 16]>,
|
||||||
running: AtomicBool,
|
running: AtomicBool,
|
||||||
socket: Arc<UdpSocket>,
|
socket: Arc<UdpSocket>,
|
||||||
//pub auth_module: Arc<dyn AuthModule>
|
|
||||||
_no_outside_construction: PhantomData<()>
|
_no_outside_construction: PhantomData<()>
|
||||||
}
|
}
|
||||||
#[derive(Debug, Error)]
|
#[derive(Debug, Error)]
|
||||||
|
|
@ -36,9 +35,6 @@ pub enum Error{
|
||||||
|
|
||||||
|
|
||||||
impl Router {
|
impl Router {
|
||||||
fn process_prudp_packet(&self, _packet: &PRUDPPacket){
|
|
||||||
|
|
||||||
}
|
|
||||||
async fn process_prudp_packets<'a>(self: Arc<Self>, _socket: Arc<UdpSocket>, addr: SocketAddrV4, udp_message: Vec<u8>){
|
async fn process_prudp_packets<'a>(self: Arc<Self>, _socket: Arc<UdpSocket>, addr: SocketAddrV4, udp_message: Vec<u8>){
|
||||||
let mut stream = Cursor::new(&udp_message);
|
let mut stream = Cursor::new(&udp_message);
|
||||||
|
|
||||||
|
|
@ -54,6 +50,7 @@ impl Router {
|
||||||
trace!("got valid prudp packet from someone({}): \n{:?}", addr, packet);
|
trace!("got valid prudp packet from someone({}): \n{:?}", addr, packet);
|
||||||
|
|
||||||
let connection = packet.source_sockaddr(addr);
|
let connection = packet.source_sockaddr(addr);
|
||||||
|
|
||||||
|
|
||||||
let endpoints = self.endpoints.read().await;
|
let endpoints = self.endpoints.read().await;
|
||||||
|
|
||||||
|
|
@ -69,7 +66,9 @@ impl Router {
|
||||||
|
|
||||||
trace!("sending packet to endpoint");
|
trace!("sending packet to endpoint");
|
||||||
|
|
||||||
endpoint.process_packet(connection, &packet).await;
|
tokio::spawn(async move {
|
||||||
|
endpoint.recieve_packet(connection, packet).await
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -88,6 +87,7 @@ impl Router {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let current_msg = &msg_buffer[0..len];
|
let current_msg = &msg_buffer[0..len];
|
||||||
|
|
||||||
tokio::spawn(self.clone().process_prudp_packets(socket.clone(), addr, current_msg.to_vec()));
|
tokio::spawn(self.clone().process_prudp_packets(socket.clone(), addr, current_msg.to_vec()));
|
||||||
|
|
@ -144,18 +144,22 @@ impl Router {
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns Some(()) i
|
// returns Some(()) i
|
||||||
pub(crate) async fn add_socket(&self, socket: Arc<SocketData>) -> Result<(), Error>{
|
pub(crate) async fn add_socket<E: CryptoHandler>(&self, virtual_port: VirtualPort, encryption: E)
|
||||||
|
-> Result<ExternalSocket, Error>{
|
||||||
let mut endpoints = self.endpoints.write().await;
|
let mut endpoints = self.endpoints.write().await;
|
||||||
|
|
||||||
let idx = socket.get_virual_port().get_port_number() as usize;
|
let idx = virtual_port.get_port_number() as usize;
|
||||||
|
|
||||||
if endpoints[idx].is_none() {
|
// dont create the socket if we dont need to
|
||||||
endpoints[idx] = Some(socket);
|
if !endpoints[idx].is_none(){
|
||||||
} else {
|
|
||||||
return Err(VirtualPortTaken(idx as u8));
|
return Err(VirtualPortTaken(idx as u8));
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
let (internal, external) = new_socket_pair(virtual_port, encryption, self.socket.clone());
|
||||||
|
|
||||||
|
endpoints[idx] = Some(internal);
|
||||||
|
|
||||||
|
Ok(external)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_own_address(&self) -> SocketAddrV4{
|
pub fn get_own_address(&self) -> SocketAddrV4{
|
||||||
|
|
|
||||||
|
|
@ -4,10 +4,13 @@ use log::error;
|
||||||
use rc4::cipher::StreamCipherCoreWrapper;
|
use rc4::cipher::StreamCipherCoreWrapper;
|
||||||
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
||||||
use rc4::consts::U16;
|
use rc4::consts::U16;
|
||||||
|
use typenum::U5;
|
||||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use crate::kerberos::{derive_key, TicketInternalData};
|
use crate::kerberos::{derive_key, TicketInternalData};
|
||||||
use crate::nex::account::Account;
|
use crate::nex::account::Account;
|
||||||
use crate::prudp::socket::EncryptionPair;
|
use crate::prudp::packet::PRUDPPacket;
|
||||||
|
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair};
|
||||||
|
use crate::prudp::unsecure::UnsecureInstance;
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)>{
|
pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)>{
|
||||||
|
|
@ -73,12 +76,12 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3
|
||||||
|
|
||||||
type Rc4U32 = StreamCipherCoreWrapper<Rc4Core<U32>>;
|
type Rc4U32 = StreamCipherCoreWrapper<Rc4Core<U32>>;
|
||||||
|
|
||||||
pub fn generate_secure_encryption_pairs(mut session_key: [u8; 32], count: u8) -> Vec<EncryptionPair>{
|
pub fn generate_secure_encryption_pairs(mut session_key: [u8; 32], count: u8) -> Vec<EncryptionPair<Rc4<U32>>>{
|
||||||
let mut vec = Vec::with_capacity(count as usize);
|
let mut vec = Vec::with_capacity(count as usize);
|
||||||
|
|
||||||
vec.push(EncryptionPair{
|
vec.push(EncryptionPair{
|
||||||
send: Box::new(Rc4U32::new_from_slice(&session_key).expect("unable to create rc4")),
|
send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
||||||
recv: Box::new(Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"))
|
recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4")
|
||||||
});
|
});
|
||||||
|
|
||||||
for _ in 1..=count{
|
for _ in 1..=count{
|
||||||
|
|
@ -91,10 +94,99 @@ pub fn generate_secure_encryption_pairs(mut session_key: [u8; 32], count: u8) ->
|
||||||
}
|
}
|
||||||
|
|
||||||
vec.push(EncryptionPair{
|
vec.push(EncryptionPair{
|
||||||
send: Box::new(Rc4U32::new_from_slice(&session_key).expect("unable to create rc4")),
|
send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
||||||
recv: Box::new(Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"))
|
recv: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4")
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
vec
|
vec
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
pub struct Secure(pub &'static str, pub &'static Account);
|
||||||
|
|
||||||
|
|
||||||
|
pub struct SecureInstance {
|
||||||
|
access_key: &'static str,
|
||||||
|
session_key: [u8; 32],
|
||||||
|
streams: Vec<EncryptionPair<Rc4<U32>>>,
|
||||||
|
self_signature: [u8; 16],
|
||||||
|
remote_signature: [u8; 16],
|
||||||
|
pid: u32,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CryptoHandler for Secure {
|
||||||
|
type CryptoConnectionInstance = SecureInstance;
|
||||||
|
|
||||||
|
fn instantiate(
|
||||||
|
&self,
|
||||||
|
remote_signature: [u8; 16],
|
||||||
|
self_signature: [u8; 16],
|
||||||
|
payload: &[u8],
|
||||||
|
substream_count: u8,
|
||||||
|
) -> Option<(Vec<u8>, Self::CryptoConnectionInstance)> {
|
||||||
|
let (session_key, pid, check_value) = read_secure_connection_data(payload, &self.1)?;
|
||||||
|
|
||||||
|
let check_value_response = check_value + 1;
|
||||||
|
|
||||||
|
let data = bytemuck::bytes_of(&check_value_response);
|
||||||
|
|
||||||
|
let mut response = Vec::new();
|
||||||
|
|
||||||
|
data.serialize(&mut response).ok()?;
|
||||||
|
|
||||||
|
let encryption_pairs = generate_secure_encryption_pairs(session_key, substream_count);
|
||||||
|
|
||||||
|
Some((
|
||||||
|
response,
|
||||||
|
SecureInstance {
|
||||||
|
pid,
|
||||||
|
streams: encryption_pairs,
|
||||||
|
session_key,
|
||||||
|
access_key: self.0,
|
||||||
|
remote_signature,
|
||||||
|
self_signature,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_pre_handshake(&self, packet: &mut PRUDPPacket) {
|
||||||
|
packet.set_sizes();
|
||||||
|
packet.calculate_and_assign_signature(self.0, None, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl CryptoHandlerConnectionInstance for SecureInstance {
|
||||||
|
type Encryption = Rc4<U5>;
|
||||||
|
|
||||||
|
fn decrypt_incoming(&mut self, substream: u8, data: &mut [u8]) {
|
||||||
|
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||||
|
crypt_pair.recv.apply_keystream(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt_outgoing(&mut self, substream: u8, data: &mut [u8]) {
|
||||||
|
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||||
|
crypt_pair.send.apply_keystream(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_user_id(&self) -> u32 {
|
||||||
|
self.pid
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_connect(&self, packet: &mut PRUDPPacket) {
|
||||||
|
packet.set_sizes();
|
||||||
|
packet.calculate_and_assign_signature(self.access_key, None, Some(self.self_signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_packet(&self, packet: &mut PRUDPPacket) {
|
||||||
|
packet.set_sizes();
|
||||||
|
packet.calculate_and_assign_signature(self.access_key, Some(self.session_key), Some(self.self_signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_packet(&self, packet: &PRUDPPacket) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -5,18 +5,28 @@ use crate::prudp::packet::VirtualPort;
|
||||||
|
|
||||||
type Md5Hmac = Hmac<md5::Md5>;
|
type Md5Hmac = Hmac<md5::Md5>;
|
||||||
|
|
||||||
#[derive(Eq, PartialEq, Hash, Debug, Copy, Clone)]
|
#[derive(Eq, PartialEq, Hash, Debug, Copy, Clone, Ord, PartialOrd)]
|
||||||
pub struct PRUDPSockAddr{
|
pub struct PRUDPSockAddr{
|
||||||
pub regular_socket_addr: SocketAddrV4,
|
pub regular_socket_addr: SocketAddrV4,
|
||||||
pub virtual_port: VirtualPort
|
pub virtual_port: VirtualPort
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl PRUDPSockAddr{
|
impl PRUDPSockAddr{
|
||||||
pub fn calculate_connection_signature(&self) -> [u8; 16] {
|
|
||||||
|
pub fn new(regular_socket_addr: SocketAddrV4, virtual_port: VirtualPort) -> Self{
|
||||||
|
Self{
|
||||||
|
regular_socket_addr,
|
||||||
|
virtual_port
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn calculate_connection_signature(&self) -> [u8; 16] {
|
||||||
let mut hmac = Md5Hmac::new_from_slice(&[0; 16]).expect("fuck");
|
let mut hmac = Md5Hmac::new_from_slice(&[0; 16]).expect("fuck");
|
||||||
|
|
||||||
let mut data = self.regular_socket_addr.ip().octets().to_vec();
|
let mut data = self.regular_socket_addr.ip().octets().to_vec();
|
||||||
data.extend_from_slice(&self.regular_socket_addr.port().to_be_bytes());
|
//data.extend_from_slice(&self.regular_socket_addr.port().to_be_bytes());
|
||||||
|
|
||||||
hmac.write_all(&data).expect("figuring this out was complete ass");
|
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");
|
let result: [u8; 16] = hmac.finalize().into_bytes()[0..16].try_into().expect("fuck");
|
||||||
|
|
|
||||||
1117
src/prudp/socket.rs
1117
src/prudp/socket.rs
File diff suppressed because it is too large
Load diff
84
src/prudp/unsecure.rs
Normal file
84
src/prudp/unsecure.rs
Normal file
|
|
@ -0,0 +1,84 @@
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use rc4::{Key, KeyInit, Rc4, StreamCipher};
|
||||||
|
use typenum::U5;
|
||||||
|
use crate::prudp::packet::PRUDPPacket;
|
||||||
|
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair};
|
||||||
|
|
||||||
|
pub struct Unsecure(pub &'static str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
pub struct UnsecureInstance {
|
||||||
|
key: &'static str,
|
||||||
|
streams: Vec<EncryptionPair<Rc4<U5>>>,
|
||||||
|
self_signature: [u8; 16],
|
||||||
|
remote_signature: [u8; 16],
|
||||||
|
}
|
||||||
|
|
||||||
|
// my hand was forced to use lazy so that we can guarantee this code
|
||||||
|
// only runs once and so that i can put it here as a "constant" (for performance and readability)
|
||||||
|
// since for some reason rust crypto doesn't have any const time key initialization
|
||||||
|
static DEFAULT_KEY: Lazy<Key<U5>> = Lazy::new(|| Key::from(*b"CD&ML"));
|
||||||
|
|
||||||
|
impl CryptoHandler for Unsecure {
|
||||||
|
type CryptoConnectionInstance = UnsecureInstance;
|
||||||
|
|
||||||
|
fn instantiate(
|
||||||
|
&self,
|
||||||
|
remote_signature: [u8; 16],
|
||||||
|
self_signature: [u8; 16],
|
||||||
|
_: &[u8],
|
||||||
|
substream_count: u8,
|
||||||
|
) -> Option<(Vec<u8>, Self::CryptoConnectionInstance)> {
|
||||||
|
Some((
|
||||||
|
Vec::new(),
|
||||||
|
UnsecureInstance {
|
||||||
|
streams: (0..substream_count)
|
||||||
|
.map(|_| EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)))
|
||||||
|
.collect(),
|
||||||
|
key: self.0,
|
||||||
|
remote_signature,
|
||||||
|
self_signature,
|
||||||
|
},
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_pre_handshake(&self, packet: &mut PRUDPPacket) {
|
||||||
|
packet.set_sizes();
|
||||||
|
packet.calculate_and_assign_signature(self.0, None, None);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CryptoHandlerConnectionInstance for UnsecureInstance {
|
||||||
|
type Encryption = Rc4<U5>;
|
||||||
|
|
||||||
|
fn decrypt_incoming(&mut self, substream: u8, data: &mut [u8]) {
|
||||||
|
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||||
|
crypt_pair.recv.apply_keystream(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn encrypt_outgoing(&mut self, substream: u8, data: &mut [u8]) {
|
||||||
|
if let Some(crypt_pair) = self.streams.get_mut(substream as usize){
|
||||||
|
crypt_pair.send.apply_keystream(data);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_user_id(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_connect(&self, packet: &mut PRUDPPacket) {
|
||||||
|
packet.set_sizes();
|
||||||
|
packet.calculate_and_assign_signature(self.key, None, Some(self.self_signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sign_packet(&self, packet: &mut PRUDPPacket) {
|
||||||
|
packet.set_sizes();
|
||||||
|
packet.calculate_and_assign_signature(self.key, None, Some(self.self_signature));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn verify_packet(&self, packet: &PRUDPPacket) -> bool {
|
||||||
|
true
|
||||||
|
}
|
||||||
|
}
|
||||||
23
src/result.rs
Normal file
23
src/result.rs
Normal file
|
|
@ -0,0 +1,23 @@
|
||||||
|
use std::error::Error;
|
||||||
|
use log::error;
|
||||||
|
|
||||||
|
pub trait ResultExtension{
|
||||||
|
type Output;
|
||||||
|
|
||||||
|
fn display_err_or_some(self) -> Option<Self::Output>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, U: Error> ResultExtension for Result<T, U>{
|
||||||
|
type Output = T;
|
||||||
|
|
||||||
|
fn display_err_or_some(self) -> Option<Self::Output> {
|
||||||
|
match self{
|
||||||
|
Ok(v) => Some(v),
|
||||||
|
Err(e) => {
|
||||||
|
error!("{}", e);
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,7 +5,7 @@ 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, Clone)]
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
pub struct RMCMessage{
|
pub struct RMCMessage{
|
||||||
pub protocol_id: u16,
|
pub protocol_id: u16,
|
||||||
pub call_id: u32,
|
pub call_id: u32,
|
||||||
|
|
@ -60,13 +60,15 @@ impl RMCMessage{
|
||||||
|
|
||||||
output.write_all(bytes_of(&size)).expect("unable to write size");
|
output.write_all(bytes_of(&size)).expect("unable to write size");
|
||||||
|
|
||||||
let proto_id = self.protocol_id as u8;
|
let proto_id = self.protocol_id as u8 | 0x80;
|
||||||
|
|
||||||
output.write_all(bytes_of(&proto_id)).expect("unable to write size");
|
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.call_id)).expect("unable to write size");
|
||||||
output.write_all(bytes_of(&self.method_id)).expect("unable to write size");
|
output.write_all(bytes_of(&self.method_id)).expect("unable to write size");
|
||||||
|
|
||||||
|
output.write_all(&self.rest_of_data).expect("unable to write data");
|
||||||
|
|
||||||
output
|
output
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
pub mod message;
|
pub mod message;
|
||||||
pub mod structures;
|
pub mod structures;
|
||||||
pub mod response;
|
pub mod response;
|
||||||
|
pub mod protocols;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
47
src/rmc/protocols/auth.rs
Normal file
47
src/rmc/protocols/auth.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
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 {
|
||||||
|
/// representation of the `Login` method(for details see the
|
||||||
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
|
#[method_id(1)]
|
||||||
|
async fn login(&self, name: String) -> Result<(), ErrorCode>;
|
||||||
|
|
||||||
|
/// representation of the `LoginEx` method(for details see the
|
||||||
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
|
#[method_id(2)]
|
||||||
|
async fn login_ex(
|
||||||
|
&self,
|
||||||
|
name: String,
|
||||||
|
extra_data: Any,
|
||||||
|
) -> Result<(QResult, u32, Vec<u8>, ConnectionData, String), ErrorCode>;
|
||||||
|
|
||||||
|
/// representation of the `RequestTicket` method(for details see the
|
||||||
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
|
#[method_id(3)]
|
||||||
|
async fn request_ticket(
|
||||||
|
&self,
|
||||||
|
source_pid: u32,
|
||||||
|
destination_pid: u32,
|
||||||
|
) -> Result<(QResult, Vec<u8>), ErrorCode>;
|
||||||
|
|
||||||
|
/// representation of the `GetPID` method(for details see the
|
||||||
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
|
#[method_id(4)]
|
||||||
|
async fn get_pid(&self, username: String) -> Result<u32, ErrorCode>;
|
||||||
|
|
||||||
|
/// representation of the `LoginWithContext` method(for details see the
|
||||||
|
/// [kinnay wiki entry](https://github.com/kinnay/NintendoClients/wiki/Authentication-Protocol))
|
||||||
|
#[method_id(5)]
|
||||||
|
async fn get_name(&self, pid: u32) -> Result<String, ErrorCode>;
|
||||||
|
|
||||||
|
// `LoginWithContext` is left out here because we don't need it right now and versioning still
|
||||||
|
// needs to be figured out
|
||||||
|
}
|
||||||
303
src/rmc/protocols/mod.rs
Normal file
303
src/rmc/protocols/mod.rs
Normal file
|
|
@ -0,0 +1,303 @@
|
||||||
|
#![allow(async_fn_in_trait)]
|
||||||
|
|
||||||
|
pub mod auth;
|
||||||
|
pub mod secure;
|
||||||
|
|
||||||
|
use crate::prudp::socket::{ExternalConnection, SendingConnection};
|
||||||
|
use crate::rmc::message::RMCMessage;
|
||||||
|
use crate::rmc::protocols::RemoteCallError::ConnectionBroke;
|
||||||
|
use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
|
||||||
|
use crate::rmc::structures;
|
||||||
|
use crate::rmc::structures::connection_data::ConnectionData;
|
||||||
|
use crate::rmc::structures::matchmake::AutoMatchmakeParam;
|
||||||
|
use crate::rmc::structures::{Error, RmcSerialize};
|
||||||
|
use async_trait::async_trait;
|
||||||
|
use chrono::TimeDelta;
|
||||||
|
use log::{error, info};
|
||||||
|
use macros::method_id;
|
||||||
|
use macros::{rmc_proto, rmc_struct};
|
||||||
|
use paste::paste;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::io::Cursor;
|
||||||
|
use std::ops::{Add, Deref};
|
||||||
|
use std::sync::{Arc, Condvar};
|
||||||
|
use std::time::Duration;
|
||||||
|
use thiserror::Error;
|
||||||
|
use tokio::sync::{Mutex, Notify};
|
||||||
|
use tokio::time::{sleep_until, Instant};
|
||||||
|
use crate::result::ResultExtension;
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum RemoteCallError {
|
||||||
|
#[error("Call to remote timed out whilest waiting on response.")]
|
||||||
|
Timeout,
|
||||||
|
#[error("A server side rmc error occurred: {0:?}")]
|
||||||
|
ServerError(ErrorCode),
|
||||||
|
#[error("Connection broke")]
|
||||||
|
ConnectionBroke,
|
||||||
|
#[error("Error reading response data: {0}")]
|
||||||
|
InvalidResponse(#[from] structures::Error),
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct RmcConnection(pub SendingConnection, pub RmcResponseReceiver);
|
||||||
|
|
||||||
|
pub struct RmcResponseReceiver(Arc<Notify>, Arc<Mutex<HashMap<u32, RMCResponse>>>);
|
||||||
|
|
||||||
|
impl RmcConnection {
|
||||||
|
pub async fn make_raw_call<T: RmcSerialize>(
|
||||||
|
&self,
|
||||||
|
message: &RMCMessage,
|
||||||
|
) -> Result<T, RemoteCallError> {
|
||||||
|
self.make_raw_call_no_response(message).await?;
|
||||||
|
|
||||||
|
let data = self.1.get_response_data(message.call_id).await?;
|
||||||
|
|
||||||
|
let out = <T as RmcSerialize>::deserialize(&mut Cursor::new(data))?;
|
||||||
|
|
||||||
|
Ok(out)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn make_raw_call_no_response(
|
||||||
|
&self,
|
||||||
|
message: &RMCMessage,
|
||||||
|
) -> Result<(), RemoteCallError> {
|
||||||
|
let message_data = message.to_data();
|
||||||
|
|
||||||
|
self.0.send(message_data).await.ok_or(ConnectionBroke)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RmcResponseReceiver {
|
||||||
|
// returns none if timed out
|
||||||
|
pub async fn get_response_data(&self, call_id: u32) -> Result<Vec<u8>, RemoteCallError> {
|
||||||
|
let mut end_wait_time = Instant::now();
|
||||||
|
end_wait_time += Duration::from_secs(5);
|
||||||
|
|
||||||
|
let sleep_fut = sleep_until(end_wait_time);
|
||||||
|
tokio::pin!(sleep_fut);
|
||||||
|
|
||||||
|
let mut sleep_manual_unlock_fut = Instant::now();
|
||||||
|
sleep_manual_unlock_fut += Duration::from_secs(4);
|
||||||
|
|
||||||
|
let sleep_manual_unlock_fut = sleep_until(sleep_manual_unlock_fut);
|
||||||
|
tokio::pin!(sleep_manual_unlock_fut);
|
||||||
|
|
||||||
|
loop {
|
||||||
|
let mut locked = self.1.lock().await;
|
||||||
|
|
||||||
|
if let Some(v) = locked.remove(&call_id) {
|
||||||
|
match v.response_result{
|
||||||
|
RMCResponseResult::Success {
|
||||||
|
data,
|
||||||
|
..
|
||||||
|
} => return Ok(data),
|
||||||
|
RMCResponseResult::Error {
|
||||||
|
error_code,
|
||||||
|
..
|
||||||
|
} => return Err(RemoteCallError::ServerError(error_code))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(locked);
|
||||||
|
|
||||||
|
let notif_fut = self.0.notified();
|
||||||
|
|
||||||
|
tokio::select! {
|
||||||
|
_ = &mut sleep_manual_unlock_fut => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
_ = &mut sleep_fut => {
|
||||||
|
return Err(RemoteCallError::Timeout);
|
||||||
|
}
|
||||||
|
_ = notif_fut => {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait HasRmcConnection {
|
||||||
|
fn get_connection(&self) -> &RmcConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RemoteObject {
|
||||||
|
fn new(conn: RmcConnection) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RemoteObject for () {
|
||||||
|
fn new(_: RmcConnection) -> Self {}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RmcCallable {
|
||||||
|
//type Remote: RemoteObject;
|
||||||
|
fn rmc_call(
|
||||||
|
&self,
|
||||||
|
responder: &SendingConnection,
|
||||||
|
protocol_id: u16,
|
||||||
|
method_id: u32,
|
||||||
|
call_id: u32,
|
||||||
|
rest: Vec<u8>,
|
||||||
|
) -> impl std::future::Future<Output = ()> + Send;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[macro_export]
|
||||||
|
macro_rules! define_rmc_proto {
|
||||||
|
(proto $name:ident{
|
||||||
|
$($protocol:path),*
|
||||||
|
}) => {
|
||||||
|
paste::paste!{
|
||||||
|
pub trait [<Local $name>]: std::any::Any $( + [<Raw $protocol>] + $protocol)* {
|
||||||
|
async fn rmc_call(&self, remote_response_connection: &crate::prudp::socket::SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>){
|
||||||
|
match protocol_id{
|
||||||
|
$(
|
||||||
|
[<Raw $protocol Info>]::PROTOCOL_ID => <Self as [<Raw $protocol>]>::rmc_call_proto(self, remote_response_connection, method_id, call_id, rest).await,
|
||||||
|
)*
|
||||||
|
v => log::error!("invalid protocol called on rmc object {}", v)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct [<Remote $name>](crate::rmc::protocols::RmcConnection);
|
||||||
|
|
||||||
|
impl crate::rmc::protocols::RemoteInstantiatable for [<Remote $name>]{
|
||||||
|
fn new(conn: crate::rmc::protocols::RmcConnection) -> Self{
|
||||||
|
Self(conn)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl crate::rmc::protocols::HasRmcConnection for [<Remote $name>]{
|
||||||
|
fn get_connection(&self) -> &crate::rmc::protocols::RmcConnection{
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$(
|
||||||
|
impl [<Remote $protocol>] for [<Remote $name>]{}
|
||||||
|
)*
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This is a special case to allow unit to represent the fact that no object is represented.
|
||||||
|
impl RmcCallable for () {
|
||||||
|
async fn rmc_call(
|
||||||
|
&self,
|
||||||
|
remote_response_connection: &crate::prudp::socket::SendingConnection,
|
||||||
|
protocol_id: u16,
|
||||||
|
method_id: u32,
|
||||||
|
call_id: u32,
|
||||||
|
rest: Vec<u8>,
|
||||||
|
) {
|
||||||
|
//todo: maybe reply with not implemented(?)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RemoteInstantiatable{
|
||||||
|
fn new(conn: RmcConnection) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct OnlyRemote<T: RemoteInstantiatable>(T);
|
||||||
|
|
||||||
|
impl<T: RemoteInstantiatable> Deref for OnlyRemote<T>{
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RemoteInstantiatable> OnlyRemote<T>{
|
||||||
|
pub fn new(conn: RmcConnection) -> Self{
|
||||||
|
Self(T::new(conn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RemoteInstantiatable> RmcCallable for OnlyRemote<T>{
|
||||||
|
fn rmc_call(&self, responder: &SendingConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>) -> impl std::future::Future<Output = ()> + Send {
|
||||||
|
async{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
|
||||||
|
mut connection: ExternalConnection,
|
||||||
|
remote: Arc<T>,
|
||||||
|
notify: Arc<Notify>,
|
||||||
|
incoming: Arc<Mutex<HashMap<u32, RMCResponse>>>,
|
||||||
|
) {
|
||||||
|
let sending_conn = connection.duplicate_sender();
|
||||||
|
|
||||||
|
while let Some(v) = connection.recv().await{
|
||||||
|
let Some(proto_id) = v.get(4) else {
|
||||||
|
error!("received too small rmc message.");
|
||||||
|
error!("ending rmc gateway.");
|
||||||
|
return
|
||||||
|
};
|
||||||
|
|
||||||
|
if (proto_id & 0x80) == 0{
|
||||||
|
let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||||
|
error!("ending rmc gateway.");
|
||||||
|
return
|
||||||
|
};
|
||||||
|
|
||||||
|
info!("got rmc response");
|
||||||
|
|
||||||
|
let mut locked = incoming.lock().await;
|
||||||
|
|
||||||
|
locked.insert(response.get_call_id(), response);
|
||||||
|
notify.notify_waiters();
|
||||||
|
} else {
|
||||||
|
let Some(message) = RMCMessage::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||||
|
error!("ending rmc gateway.");
|
||||||
|
return
|
||||||
|
};
|
||||||
|
|
||||||
|
let RMCMessage{
|
||||||
|
protocol_id,
|
||||||
|
method_id,
|
||||||
|
call_id,
|
||||||
|
rest_of_data
|
||||||
|
} = message;
|
||||||
|
|
||||||
|
info!("got rmc request, handeling it now...");
|
||||||
|
|
||||||
|
remote.rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data).await;
|
||||||
|
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new_rmc_gateway_connection<T: RmcCallable + Sync + Send + 'static,F>(conn: ExternalConnection, create_internal: F) -> Arc<T>
|
||||||
|
where
|
||||||
|
F: FnOnce(RmcConnection) -> T,
|
||||||
|
{
|
||||||
|
let notify = Arc::new(Notify::new());
|
||||||
|
let incoming: Arc<Mutex<HashMap<u32, RMCResponse>>> = Default::default();
|
||||||
|
|
||||||
|
let response_recv = RmcResponseReceiver(notify.clone(), incoming.clone());
|
||||||
|
|
||||||
|
let sending_conn = conn.duplicate_sender();
|
||||||
|
|
||||||
|
let rmc_conn = RmcConnection(sending_conn, response_recv);
|
||||||
|
|
||||||
|
let exposed_object = (create_internal)(rmc_conn);
|
||||||
|
|
||||||
|
let exposed_object = Arc::new(exposed_object);
|
||||||
|
|
||||||
|
{
|
||||||
|
let exposed_object = exposed_object.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
handle_incoming(
|
||||||
|
conn,
|
||||||
|
exposed_object,
|
||||||
|
notify,
|
||||||
|
incoming
|
||||||
|
).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
exposed_object
|
||||||
|
}
|
||||||
12
src/rmc/protocols/secure.rs
Normal file
12
src/rmc/protocols/secure.rs
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
use macros::{method_id, rmc_proto};
|
||||||
|
use crate::prudp::station_url::StationUrl;
|
||||||
|
use crate::rmc::response::ErrorCode;
|
||||||
|
use crate::rmc::structures::any::Any;
|
||||||
|
use crate::rmc::structures::connection_data::ConnectionData;
|
||||||
|
use crate::rmc::structures::qresult::QResult;
|
||||||
|
|
||||||
|
#[rmc_proto(11)]
|
||||||
|
pub trait Auth {
|
||||||
|
#[method_id(1)]
|
||||||
|
async fn register(&self, station_urls: Vec<String>) -> Result<(QResult, u32, String), ErrorCode>;
|
||||||
|
}
|
||||||
|
|
@ -1,44 +1,114 @@
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Write};
|
use std::io::{Read, Seek, Write};
|
||||||
use std::mem::transmute;
|
use std::mem::transmute;
|
||||||
use bytemuck::bytes_of;
|
use bytemuck::bytes_of;
|
||||||
|
use log::error;
|
||||||
|
use v_byte_macros::EnumTryInto;
|
||||||
|
use crate::endianness::{ReadExtensions, IS_BIG_ENDIAN};
|
||||||
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};
|
||||||
use crate::prudp::packet::PacketOption::FragmentId;
|
use crate::prudp::packet::PacketOption::FragmentId;
|
||||||
use crate::prudp::packet::types::DATA;
|
use crate::prudp::packet::types::DATA;
|
||||||
use crate::prudp::socket::{ConnectionData, SocketData};
|
use crate::prudp::socket::{ExternalConnection, SendingConnection};
|
||||||
|
use crate::rmc::response::ErrorCode::Core_Exception;
|
||||||
use crate::rmc::structures::qresult::ERROR_MASK;
|
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 {
|
pub enum RMCResponseResult {
|
||||||
Success{
|
Success {
|
||||||
call_id: u32,
|
call_id: u32,
|
||||||
method_id: u32,
|
method_id: u32,
|
||||||
data: Vec<u8>,
|
data: Vec<u8>,
|
||||||
},
|
},
|
||||||
Error{
|
Error {
|
||||||
error_code: ErrorCode,
|
error_code: ErrorCode,
|
||||||
call_id: u32,
|
call_id: u32,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct RMCResponse {
|
pub struct RMCResponse {
|
||||||
pub protocol_id: u8,
|
pub protocol_id: u8,
|
||||||
pub response_result: RMCResponseResult
|
pub response_result: RMCResponseResult,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RMCResponse {
|
impl RMCResponse {
|
||||||
pub fn to_data(self) -> Vec<u8>{
|
pub fn new(stream: &mut (impl Seek + Read)) -> io::Result<Self>{
|
||||||
|
// ignore the size for now this will only be used for checking
|
||||||
|
let size: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
|
||||||
|
let protocol_id: u8 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
|
||||||
|
/*let protocol_id: u16 = match protocol_id{
|
||||||
|
0x7F => {
|
||||||
|
stream.read_struct(IS_BIG_ENDIAN)?
|
||||||
|
},
|
||||||
|
_ => protocol_id as u16
|
||||||
|
};*/
|
||||||
|
|
||||||
|
let is_success: u8 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
|
||||||
|
let response_result = if is_success == 0x01{
|
||||||
|
let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
let method_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
let method_id = method_id & (!0x8000);
|
||||||
|
|
||||||
|
let mut data: Vec<u8> = vec![0u8; (size - 2 - 4 - 4) as _];
|
||||||
|
|
||||||
|
stream.read(&mut data)?;
|
||||||
|
|
||||||
|
|
||||||
|
RMCResponseResult::Success {
|
||||||
|
call_id,
|
||||||
|
method_id,
|
||||||
|
data
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
let error_code: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
let error_code = error_code & (!0x80000000);
|
||||||
|
let call_id: u32 = stream.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
|
||||||
|
RMCResponseResult::Error {
|
||||||
|
error_code: {
|
||||||
|
match ErrorCode::try_from(error_code){
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
error!("invalid error code {:#010x}", error_code);
|
||||||
|
Core_Exception
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
call_id,
|
||||||
|
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self{
|
||||||
|
protocol_id,
|
||||||
|
response_result
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_call_id(&self) -> u32{
|
||||||
|
match &self.response_result{
|
||||||
|
RMCResponseResult::Success { call_id, ..} => *call_id,
|
||||||
|
RMCResponseResult::Error { call_id, .. } => *call_id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn to_data(self) -> Vec<u8> {
|
||||||
generate_response(self.protocol_id, self.response_result).expect("failed to generate response")
|
generate_response(self.protocol_id, self.response_result).expect("failed to generate response")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result<Vec<u8>>{
|
pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Result<Vec<u8>> {
|
||||||
let size = 1 + 1 + match &response{
|
let size = 1 + 1 + match &response {
|
||||||
RMCResponseResult::Success {
|
RMCResponseResult::Success {
|
||||||
data,
|
data,
|
||||||
..
|
..
|
||||||
} => 4 + 4 + data.len(),
|
} => 4 + 4 + data.len(),
|
||||||
RMCResponseResult::Error{..} => 4 + 4,
|
RMCResponseResult::Error { .. } => 4 + 4,
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut data_out = Vec::with_capacity(size + 4);
|
let mut data_out = Vec::with_capacity(size + 4);
|
||||||
|
|
@ -48,7 +118,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re
|
||||||
data_out.write_all(bytes_of(&u32_size))?;
|
data_out.write_all(bytes_of(&u32_size))?;
|
||||||
data_out.push(protocol_id);
|
data_out.push(protocol_id);
|
||||||
|
|
||||||
match response{
|
match response {
|
||||||
RMCResponseResult::Success {
|
RMCResponseResult::Success {
|
||||||
call_id,
|
call_id,
|
||||||
method_id,
|
method_id,
|
||||||
|
|
@ -59,7 +129,7 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re
|
||||||
let ored_method_id = method_id | 0x8000;
|
let ored_method_id = method_id | 0x8000;
|
||||||
data_out.write_all(bytes_of(&ored_method_id))?;
|
data_out.write_all(bytes_of(&ored_method_id))?;
|
||||||
data_out.write_all(&data)?;
|
data_out.write_all(&data)?;
|
||||||
},
|
}
|
||||||
RMCResponseResult::Error {
|
RMCResponseResult::Error {
|
||||||
call_id,
|
call_id,
|
||||||
error_code
|
error_code
|
||||||
|
|
@ -76,38 +146,46 @@ pub fn generate_response(protocol_id: u8, response: RMCResponseResult) -> io::Re
|
||||||
|
|
||||||
Ok(data_out)
|
Ok(data_out)
|
||||||
}
|
}
|
||||||
pub async fn send_response(original_packet: &PRUDPPacket, socket: &SocketData, connection: &mut ConnectionData, rmcresponse: RMCResponse){
|
|
||||||
|
|
||||||
let ConnectionData{
|
pub async fn send_result(
|
||||||
active_connection_data,
|
connection: &SendingConnection,
|
||||||
..
|
result: Result<Vec<u8>, ErrorCode>,
|
||||||
} = connection;
|
protocol_id: u8,
|
||||||
|
method_id: u32,
|
||||||
let Some(active_connection) = active_connection_data else {
|
call_id: u32,
|
||||||
return;
|
) {
|
||||||
|
|
||||||
|
println!("{}", hex::encode(result.clone().unwrap()));
|
||||||
|
let response_result = match result {
|
||||||
|
Ok(v) => RMCResponseResult::Success {
|
||||||
|
call_id,
|
||||||
|
method_id,
|
||||||
|
data: v
|
||||||
|
},
|
||||||
|
Err(e) =>
|
||||||
|
RMCResponseResult::Error {
|
||||||
|
call_id,
|
||||||
|
error_code: e.into()
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let mut packet = original_packet.base_response_packet();
|
let response = RMCResponse{
|
||||||
|
response_result,
|
||||||
|
protocol_id
|
||||||
|
};
|
||||||
|
|
||||||
|
send_response(connection, response).await
|
||||||
packet.header.types_and_flags.set_types(DATA);
|
|
||||||
packet.header.types_and_flags.set_flag((original_packet.header.types_and_flags.get_flags() & RELIABLE) | NEED_ACK);
|
|
||||||
|
|
||||||
packet.header.session_id = active_connection.server_session_id;
|
|
||||||
packet.header.substream_id = 0;
|
|
||||||
|
|
||||||
packet.options.push(FragmentId(0));
|
|
||||||
|
|
||||||
packet.payload = rmcresponse.to_data();
|
|
||||||
|
|
||||||
//tokio::time::sleep(Duration::from_millis(500)).await;
|
|
||||||
|
|
||||||
connection.finish_and_send_packet_to(socket, packet).await;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn send_response(connection: &SendingConnection, rmcresponse: RMCResponse) {
|
||||||
|
connection.send(rmcresponse.to_data()).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//taken from kinnays error list directly
|
//taken from kinnays error list directly
|
||||||
#[allow(nonstandard_style)]
|
#[allow(nonstandard_style)]
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
|
#[derive(Debug, EnumTryInto, Clone, Copy)]
|
||||||
pub enum ErrorCode {
|
pub enum ErrorCode {
|
||||||
Core_Unknown = 0x00010001,
|
Core_Unknown = 0x00010001,
|
||||||
Core_NotImplemented = 0x00010002,
|
Core_NotImplemented = 0x00010002,
|
||||||
|
|
@ -379,25 +457,25 @@ pub enum ErrorCode {
|
||||||
Custom_Unknown = 0x00740001,
|
Custom_Unknown = 0x00740001,
|
||||||
Ess_Unknown = 0x00750001,
|
Ess_Unknown = 0x00750001,
|
||||||
Ess_GameSessionError = 0x00750002,
|
Ess_GameSessionError = 0x00750002,
|
||||||
Ess_GameSessionMaintenance = 0x00750003
|
Ess_GameSessionMaintenance = 0x00750003,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Into<u32> for ErrorCode {
|
impl Into<u32> for ErrorCode {
|
||||||
fn into(self) -> u32 {
|
fn into(self) -> u32 {
|
||||||
unsafe{ transmute(self) }
|
unsafe { transmute(self) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test{
|
mod test {
|
||||||
use hmac::digest::consts::U5;
|
use hmac::digest::consts::U5;
|
||||||
use hmac::digest::KeyInit;
|
use hmac::digest::KeyInit;
|
||||||
use rc4::{Rc4, StreamCipher};
|
use rc4::{Rc4, StreamCipher};
|
||||||
use crate::rmc::response::ErrorCode;
|
use crate::rmc::response::ErrorCode;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test(){
|
fn test() {
|
||||||
let mut data_orig = [0,1,2,3,4,5,6,7,8,9,69,4,20];
|
let mut data_orig = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 69, 4, 20];
|
||||||
let mut data = data_orig;
|
let mut data = data_orig;
|
||||||
|
|
||||||
let mut rc4: Rc4<U5> =
|
let mut rc4: Rc4<U5> =
|
||||||
|
|
@ -413,11 +491,10 @@ mod test{
|
||||||
rc4.apply_keystream(&mut data);
|
rc4.apply_keystream(&mut data);
|
||||||
|
|
||||||
assert_eq!(data_orig, data);
|
assert_eq!(data_orig, data);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_enum_equivilance(){
|
fn test_enum_equivilance() {
|
||||||
let val: u32 = ErrorCode::Core_Unknown.into();
|
let val: u32 = ErrorCode::Core_Unknown.into();
|
||||||
assert_eq!(val, 0x00010001)
|
assert_eq!(val, 0x00010001)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,15 +2,24 @@ use std::io::{Read, Write};
|
||||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use super::{Result, RmcSerialize};
|
use super::{Result, RmcSerialize};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct Any{
|
pub struct Any{
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub data: Vec<u8>
|
pub data: Vec<u8>
|
||||||
}
|
}
|
||||||
|
|
||||||
impl RmcSerialize for Any{
|
impl RmcSerialize for Any{
|
||||||
fn serialize(&self, _writer: &mut dyn Write) -> Result<()> {
|
fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
|
||||||
todo!()
|
self.name.serialize(writer)?;
|
||||||
|
|
||||||
|
let u32_len = self.data.len() as u32;
|
||||||
|
|
||||||
|
u32_len.serialize(writer)?;
|
||||||
|
u32_len.serialize(writer)?;
|
||||||
|
|
||||||
|
self.data.serialize(writer)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
}
|
}
|
||||||
fn deserialize(mut reader: &mut dyn Read) -> Result<Self> {
|
fn deserialize(mut reader: &mut dyn Read) -> Result<Self> {
|
||||||
let name = String::deserialize(reader)?;
|
let name = String::deserialize(reader)?;
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,8 @@
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
impl<'a> RmcSerialize for &'a [u8]{
|
impl<'a> RmcSerialize for &'a [u8]{
|
||||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
||||||
let u32_size = self.len() as u32;
|
let u32_size = self.len() as u32;
|
||||||
|
|
|
||||||
|
|
@ -1,29 +1,15 @@
|
||||||
use std::io::{Read, Write};
|
use std::io::{Read, Write};
|
||||||
use bytemuck::bytes_of;
|
use bytemuck::bytes_of;
|
||||||
|
use macros::RmcSerialize;
|
||||||
use crate::kerberos::KerberosDateTime;
|
use crate::kerberos::KerberosDateTime;
|
||||||
use crate::rmc::structures::{rmc_struct, RmcSerialize};
|
use crate::rmc::structures::{rmc_struct, RmcSerialize};
|
||||||
|
|
||||||
pub struct ConnectionData<'a>{
|
#[derive(Debug, RmcSerialize)]
|
||||||
pub station_url: &'a str,
|
#[rmc_struct(1)]
|
||||||
|
pub struct ConnectionData{
|
||||||
|
pub station_url: String,
|
||||||
pub special_protocols: Vec<u8>,
|
pub special_protocols: Vec<u8>,
|
||||||
pub special_station_url: &'a str,
|
pub special_station_url: String,
|
||||||
pub date_time: KerberosDateTime
|
pub date_time: KerberosDateTime
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> RmcSerialize for ConnectionData<'a>{
|
|
||||||
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
|
|
||||||
rmc_struct::write_struct(writer, 1, |v|{
|
|
||||||
self.station_url.serialize(v).expect("unable to write station url");
|
|
||||||
self.special_protocols.serialize(v).expect("unable to write special protocols");
|
|
||||||
self.special_station_url.serialize(v).expect("unable to write special station url");
|
|
||||||
v.write_all(bytes_of(&self.date_time)).expect("unable to write date time");
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
fn deserialize(_reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
|
|
||||||
todo!()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,9 @@ use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use crate::rmc::structures::RmcSerialize;
|
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<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() as u32;
|
let u32_len = self.len() as u32;
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,7 @@ use crate::kerberos::KerberosDateTime;
|
||||||
use crate::rmc::structures::variant::Variant;
|
use crate::rmc::structures::variant::Variant;
|
||||||
|
|
||||||
// rmc structure
|
// rmc structure
|
||||||
#[derive(RmcSerialize, Debug, Clone)]
|
#[derive(RmcSerialize, Debug, Clone, Default)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct Gathering {
|
pub struct Gathering {
|
||||||
pub self_gid: u32,
|
pub self_gid: u32,
|
||||||
|
|
@ -19,7 +19,7 @@ pub struct Gathering {
|
||||||
}
|
}
|
||||||
|
|
||||||
// rmc structure
|
// rmc structure
|
||||||
#[derive(RmcSerialize, Debug, Clone)]
|
#[derive(RmcSerialize, Debug, Clone, Default)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
pub struct MatchmakeParam {
|
pub struct MatchmakeParam {
|
||||||
pub params: Vec<(String, Variant)>,
|
pub params: Vec<(String, Variant)>,
|
||||||
|
|
@ -27,7 +27,7 @@ pub struct MatchmakeParam {
|
||||||
|
|
||||||
|
|
||||||
// rmc structure
|
// rmc structure
|
||||||
#[derive(RmcSerialize, Debug, Clone)]
|
#[derive(RmcSerialize, Debug, Clone, Default)]
|
||||||
#[rmc_struct(3)]
|
#[rmc_struct(3)]
|
||||||
pub struct MatchmakeSession {
|
pub struct MatchmakeSession {
|
||||||
//inherits from
|
//inherits from
|
||||||
|
|
@ -81,4 +81,16 @@ pub struct AutoMatchmakeParam {
|
||||||
pub participation_count: u16,
|
pub participation_count: u16,
|
||||||
pub search_criteria: Vec<MatchmakeSessionSearchCriteria>,
|
pub search_criteria: Vec<MatchmakeSessionSearchCriteria>,
|
||||||
pub target_gids: Vec<u32>,
|
pub target_gids: Vec<u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(RmcSerialize, Debug, Clone)]
|
||||||
|
#[rmc_struct(0)]
|
||||||
|
pub struct CreateMatchmakeSessionParam {
|
||||||
|
pub matchmake_session: MatchmakeSession,
|
||||||
|
pub additional_participants: Vec<u32>,
|
||||||
|
pub gid_for_participation_check: u32,
|
||||||
|
pub create_matchmake_session_option: u32,
|
||||||
|
pub join_message: String,
|
||||||
|
pub participation_count: u16,
|
||||||
|
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ pub enum Error{
|
||||||
VersionMismatch(u8),
|
VersionMismatch(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
pub mod string;
|
pub mod string;
|
||||||
pub mod any;
|
pub mod any;
|
||||||
|
|
@ -30,8 +30,18 @@ pub mod qbuffer;
|
||||||
pub mod primitives;
|
pub mod primitives;
|
||||||
pub mod matchmake;
|
pub mod matchmake;
|
||||||
pub mod variant;
|
pub mod variant;
|
||||||
|
pub mod ranking;
|
||||||
|
|
||||||
pub trait RmcSerialize: Sized{
|
pub trait RmcSerialize: Sized{
|
||||||
fn serialize(&self, writer: &mut dyn Write) -> Result<()>;
|
fn serialize(&self, writer: &mut dyn Write) -> Result<()>;
|
||||||
fn deserialize(reader: &mut dyn Read) -> Result<Self>;
|
fn deserialize(reader: &mut dyn Read) -> Result<Self>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl RmcSerialize for (){
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
fn deserialize(reader: &mut dyn Read) -> Result<Self> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -91,4 +91,112 @@ impl<T: RmcSerialize, U: RmcSerialize> RmcSerialize for (T, U){
|
||||||
|
|
||||||
Ok((first, second))
|
Ok((first, second))
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize> 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<Self> {
|
||||||
|
let first = T::deserialize(reader)?;
|
||||||
|
let second = U::deserialize(reader)?;
|
||||||
|
let third = V::deserialize(reader)?;
|
||||||
|
|
||||||
|
Ok((first, second, third))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize> 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<Self> {
|
||||||
|
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<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcSerialize> 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<Self> {
|
||||||
|
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<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcSerialize, Y: RmcSerialize> 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<Self> {
|
||||||
|
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<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcSerialize, Y: RmcSerialize, Z: RmcSerialize> 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<Self> {
|
||||||
|
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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,12 +1,30 @@
|
||||||
use std::io::Read;
|
use std::io::{Read, Write};
|
||||||
|
use bytemuck::bytes_of;
|
||||||
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use crate::rmc::structures::Result;
|
use crate::rmc::structures::{Result, RmcSerialize};
|
||||||
pub fn read(reader: &mut impl Read) -> Result<Vec<u8>>{
|
use crate::rmc::structures::qresult::QResult;
|
||||||
let size: u16 = reader.read_struct(IS_BIG_ENDIAN)?;
|
|
||||||
|
|
||||||
let mut vec = vec![0; size as usize];
|
|
||||||
|
|
||||||
reader.read_exact(&mut vec)?;
|
#[derive(Debug)]
|
||||||
|
pub struct QBuffer(pub Vec<u8>);
|
||||||
|
|
||||||
Ok(vec)
|
impl RmcSerialize for QBuffer{
|
||||||
|
fn serialize(&self, writer: &mut dyn Write) -> Result<()> {
|
||||||
|
let len_u16 = self.0.len() as u16;
|
||||||
|
|
||||||
|
writer.write(bytes_of(&len_u16))?;
|
||||||
|
writer.write(&self.0)?;
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn deserialize(mut reader: &mut dyn Read) -> Result<Self> {
|
||||||
|
let size: u16 = reader.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
|
||||||
|
let mut vec = vec![0; size as usize];
|
||||||
|
|
||||||
|
reader.read_exact(&mut vec)?;
|
||||||
|
|
||||||
|
Ok(Self(vec))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -7,7 +7,7 @@ use crate::rmc::structures::{RmcSerialize, Result};
|
||||||
|
|
||||||
pub const ERROR_MASK: u32 = 1 << 31;
|
pub const ERROR_MASK: u32 = 1 << 31;
|
||||||
|
|
||||||
#[derive(Pod, Zeroable, Copy, Clone, SwapEndian)]
|
#[derive(Pod, Zeroable, Copy, Clone, SwapEndian, Debug)]
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
pub struct QResult(u32);
|
pub struct QResult(u32);
|
||||||
|
|
||||||
|
|
|
||||||
69
src/rmc/structures/ranking.rs
Normal file
69
src/rmc/structures/ranking.rs
Normal file
|
|
@ -0,0 +1,69 @@
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use macros::RmcSerialize;
|
||||||
|
use crate::rmc::structures::qbuffer::QBuffer;
|
||||||
|
|
||||||
|
#[derive(RmcSerialize, Debug)]
|
||||||
|
#[rmc_struct(0)]
|
||||||
|
struct UploadCompetitionData{
|
||||||
|
winning_team/*?*/: u32,
|
||||||
|
splatfest_id/*?*/: u32,
|
||||||
|
unk_2/*?*/: u32,
|
||||||
|
unk_3: u32,
|
||||||
|
team_id_1: u8,
|
||||||
|
team_id_2: u8,
|
||||||
|
unk_5: u32,
|
||||||
|
player_data/*?*/: QBuffer,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||||
|
#[repr(C)]
|
||||||
|
struct UserData{
|
||||||
|
name: [u16; 0x10],
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test{
|
||||||
|
use std::io::Cursor;
|
||||||
|
use bytemuck::from_bytes;
|
||||||
|
use tokio::io::AsyncReadExt;
|
||||||
|
use crate::rmc::structures::ranking::{UploadCompetitionData, UserData};
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test() {
|
||||||
|
let data: [u8; 0xBD] = [
|
||||||
|
0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00,
|
||||||
|
0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x49, 0x00,
|
||||||
|
0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF2, 0x00, 0x00, 0x00,
|
||||||
|
0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00,
|
||||||
|
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
|
0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
||||||
|
0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
|
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 0x00,
|
||||||
|
];
|
||||||
|
|
||||||
|
let mut cursor = Cursor::new(data);
|
||||||
|
|
||||||
|
let data = UploadCompetitionData::deserialize(&mut cursor).expect("unable to deserialize data");
|
||||||
|
|
||||||
|
let user_data: &UserData = from_bytes(&data.player_data.0[..size_of::<UserData>()]);
|
||||||
|
|
||||||
|
let pos = user_data.name.iter()
|
||||||
|
.position(|v| *v == 0x0000)
|
||||||
|
.unwrap_or(0x10);
|
||||||
|
|
||||||
|
let mut name = user_data.name[0..pos].to_vec();
|
||||||
|
|
||||||
|
name.iter_mut().for_each(|v| *v = v.swap_bytes());
|
||||||
|
|
||||||
|
let name = String::from_utf16(&name).expect("unable to get name");
|
||||||
|
|
||||||
|
println!("{:?}", name);
|
||||||
|
|
||||||
|
assert!(u8::deserialize(&mut cursor).is_err())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ pub fn write_struct(writer: &mut dyn Write, version: u8, pred: impl FnOnce(&mut
|
||||||
|
|
||||||
(pred)(&mut scratch_space)?;
|
(pred)(&mut scratch_space)?;
|
||||||
|
|
||||||
let u32_size= scratch_space.len() as u32;
|
let u32_size = scratch_space.len() as u32;
|
||||||
|
|
||||||
writer.write_all(bytes_of(&u32_size))?;
|
writer.write_all(bytes_of(&u32_size))?;
|
||||||
writer.write_all(&scratch_space)?;
|
writer.write_all(&scratch_space)?;
|
||||||
|
|
|
||||||
|
|
@ -35,4 +35,5 @@ impl RmcSerialize for &str{
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,9 @@ 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)]
|
#[derive(Debug, Clone, Default)]
|
||||||
pub enum Variant{
|
pub enum Variant{
|
||||||
|
#[default]
|
||||||
None,
|
None,
|
||||||
SInt64(i64),
|
SInt64(i64),
|
||||||
Double(f64),
|
Double(f64),
|
||||||
|
|
|
||||||
97
src/versions.rs
Normal file
97
src/versions.rs
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
use std::marker::PhantomData;
|
||||||
|
use std::ops::{BitAnd, BitOr};
|
||||||
|
use typenum::{Cmp, IsEqual, IsLess, IsLessOrEqual, Unsigned, U1, U2, U3};
|
||||||
|
|
||||||
|
/// This trait represents a version at compile time
|
||||||
|
trait Version{
|
||||||
|
type Major: Unsigned;
|
||||||
|
type Minor: Unsigned;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This struct contains nothing and is used to represent specific versions as an instance of
|
||||||
|
/// [`Version`]. It is instances as `Ver<Major, Minor>`
|
||||||
|
struct Ver<MAJ: Unsigned, MIN: Unsigned>{
|
||||||
|
_phantom: PhantomData<(MAJ, MIN)>
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<MAJ: Unsigned, MIN: Unsigned> Version for Ver<MAJ, MIN>{
|
||||||
|
type Major = MAJ;
|
||||||
|
type Minor = MIN;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Represents two versions which can be compared
|
||||||
|
trait ComparableVersion<T: Version>: Version{
|
||||||
|
type IsAtLeast: SameOrUnit;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Version, U: Version> ComparableVersion<T> for U where
|
||||||
|
<T as Version>::Major: Cmp<Self::Major>,
|
||||||
|
<T as Version>::Minor: IsLessOrEqual<Self::Minor>,
|
||||||
|
<T as Version>::Major: IsEqual<
|
||||||
|
Self::Major,
|
||||||
|
Output: BitAnd<
|
||||||
|
typenum::LeEq<T::Minor, Self::Minor>
|
||||||
|
>,
|
||||||
|
>,
|
||||||
|
<T as Version>::Major: IsLess<
|
||||||
|
Self::Major,
|
||||||
|
Output: BitOr<
|
||||||
|
typenum::And<
|
||||||
|
typenum::Eq<T::Major, Self::Major>,
|
||||||
|
typenum::LeEq<T::Minor, Self::Minor>,
|
||||||
|
>,
|
||||||
|
Output: SameOrUnit
|
||||||
|
>
|
||||||
|
> {
|
||||||
|
|
||||||
|
type IsAtLeast = typenum::Or<
|
||||||
|
typenum::Le<T::Major, Self::Major>,
|
||||||
|
typenum::And<
|
||||||
|
typenum::Eq<T::Major, Self::Major>,
|
||||||
|
typenum::LeEq<T::Minor, Self::Minor>,
|
||||||
|
>
|
||||||
|
>;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Simple check for testing if the `TEST` version is at least `REQ` or higher.
|
||||||
|
type VersionAbove<REQ, TEST> = <TEST as ComparableVersion<REQ>>::IsAtLeast;
|
||||||
|
|
||||||
|
trait VersionIsAtLeast<VER: Version>{}
|
||||||
|
|
||||||
|
impl<VER: Version, T: ComparableVersion<VER, IsAtLeast = typenum::True>> VersionIsAtLeast<VER> for T{}
|
||||||
|
|
||||||
|
|
||||||
|
/// Trait for containing the result of elements which only conditionally exist
|
||||||
|
trait CondElemResult{
|
||||||
|
type Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Empty helper struct which only servers to give a concrete type when creating fields in rmc
|
||||||
|
/// structs which have a version requirement. This is not meant to be used directly, use
|
||||||
|
/// [`MinVersion`] instead.
|
||||||
|
struct MinVersionElementHelper<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>>{
|
||||||
|
_phantom: PhantomData<(T, REQUIRED, VER)>
|
||||||
|
}
|
||||||
|
|
||||||
|
/// This should be used either with [`typenum::True`] or [`typenum::False`]. When `True` the [`Self::Output`]
|
||||||
|
/// will be the same as the `T` you put into Output. When `False` it will always be `()`
|
||||||
|
trait SameOrUnit{
|
||||||
|
type Output<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SameOrUnit for typenum::True{
|
||||||
|
type Output<T> = T;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SameOrUnit for typenum::False{
|
||||||
|
type Output<T> = ();
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T, REQUIRED: Version, VER: Version + ComparableVersion<REQUIRED>> CondElemResult for MinVersionElementHelper<T, REQUIRED, VER> where {
|
||||||
|
type Output = <<VER as ComparableVersion<REQUIRED>>::IsAtLeast as SameOrUnit>::Output<T>;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// When the version condition is met the field will exist and will simply be `T` if not it will be
|
||||||
|
/// replaced by `()`. Use this when you need to add versioning to rmc structs.
|
||||||
|
type MinVersion<T, REQUIRED, VER> = <MinVersionElementHelper<T, REQUIRED, VER> as CondElemResult>::Output;
|
||||||
37
src/web/mod.rs
Normal file
37
src/web/mod.rs
Normal file
|
|
@ -0,0 +1,37 @@
|
||||||
|
use std::net::SocketAddrV4;
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use rocket::{get, routes, Rocket};
|
||||||
|
use rocket::serde::json::Json;
|
||||||
|
use tokio::task::JoinHandle;
|
||||||
|
use serde::Serialize;
|
||||||
|
use tokio::sync::Mutex;
|
||||||
|
|
||||||
|
#[get("/")]
|
||||||
|
async fn server_data() -> Json<WebData> {
|
||||||
|
Json(WEB_DATA.lock().await.clone())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_web() -> JoinHandle<()>{
|
||||||
|
tokio::spawn(async{
|
||||||
|
rocket::build()
|
||||||
|
.mount("/",routes![server_data])
|
||||||
|
.launch().await
|
||||||
|
.expect("unable to start webserver");
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[derive(Serialize, Clone)]
|
||||||
|
pub enum DirectionalData{
|
||||||
|
Incoming(String),
|
||||||
|
Outgoing(String)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Default, Clone)]
|
||||||
|
pub struct WebData{
|
||||||
|
pub data: Vec<(SocketAddrV4, DirectionalData)>
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static WEB_DATA: Lazy<Mutex<WebData>> = Lazy::new(|| Mutex::new(
|
||||||
|
WebData{
|
||||||
|
data: Vec::new(),
|
||||||
|
}
|
||||||
|
));
|
||||||
Loading…
Add table
Add a link
Reference in a new issue