feat: a lot of things(i lost track)

This commit is contained in:
DJMrTV 2025-06-29 11:40:42 +02:00
commit 98193a58d8
42 changed files with 1207 additions and 366 deletions

54
Cargo.lock generated
View file

@ -435,6 +435,12 @@ dependencies = [
"windows-sys 0.59.0",
]
[[package]]
name = "data-encoding"
version = "2.9.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a2330da5de22e8a3cb63252ce2abb30116bf5265e89c0e01bc17015ce30a476"
[[package]]
name = "der"
version = "0.7.10"
@ -2239,8 +2245,10 @@ dependencies = [
"tokio",
"tokio-rustls",
"tokio-stream",
"tokio-tungstenite",
"tonic",
"tonic-build",
"tungstenite",
"typenum",
"v_byte_macros",
]
@ -2428,6 +2436,17 @@ dependencies = [
"serde",
]
[[package]]
name = "sha1"
version = "0.10.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e3bf829a2d51ab4a5ddf1352d8470c140cadc8301b2ae1789db023f01cedd6ba"
dependencies = [
"cfg-if",
"cpufeatures",
"digest",
]
[[package]]
name = "sha2"
version = "0.10.9"
@ -2772,6 +2791,18 @@ dependencies = [
"tokio",
]
[[package]]
name = "tokio-tungstenite"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "489a59b6730eda1b0171fcfda8b121f4bee2b35cba8645ca35c5f7ba3eb736c1"
dependencies = [
"futures-util",
"log",
"tokio",
"tungstenite",
]
[[package]]
name = "tokio-util"
version = "0.7.15"
@ -3002,6 +3033,23 @@ version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e421abadd41a4225275504ea4d6566923418b7f05506fbc9c0fe86ba7396114b"
[[package]]
name = "tungstenite"
version = "0.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eadc29d668c91fcc564941132e17b28a7ceb2f3ebf0b9dae3e03fd7a6748eb0d"
dependencies = [
"bytes",
"data-encoding",
"http 1.3.1",
"httparse",
"log",
"rand 0.9.1",
"sha1",
"thiserror",
"utf-8",
]
[[package]]
name = "typenum"
version = "1.18.0"
@ -3056,6 +3104,12 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "utf-8"
version = "0.7.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
[[package]]
name = "utf8_iter"
version = "1.0.4"

View file

@ -54,6 +54,8 @@ rustls = "0.23.27"
rustls-pki-types = "1.12.0"
rustls-webpki = "0.103.3"
tokio-rustls = "0.26.2"
tokio-tungstenite = "0.27.0"
tungstenite = "0.27.0"
@ -65,6 +67,7 @@ tonic-build = "0.12.3"
default = ["secure", "auth"]
secure = []
auth = []
no_tls = []
[[bin]]
name = "proxy_insecure"
@ -82,3 +85,7 @@ path = "src/executables/backend_server_insecure.rs"
[[bin]]
name = "backend_server_secure"
path = "src/executables/backend_server_secure.rs"
[[bin]]
name = "control_server"
path = "src/executables/control_server.rs"

View file

@ -2,128 +2,74 @@ mod protos;
extern crate proc_macro;
use proc_macro2::{Ident, Literal, Span, TokenTree};
use crate::protos::{ProtoMethodData, RmcProtocolData};
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 proc_macro2::{Ident, Literal, Span};
use quote::{quote, TokenStreamExt};
use syn::parse::{Parse, 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, Attribute, Data, DataStruct, DeriveInput, Fields, FnArg, LitInt, Pat, Token,
TraitItem,
};
fn self_referece_type() -> Type {
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{
struct ProtoInputParams {
proto_num: LitInt,
properties: Option<(Token![,], Punctuated<Ident, Token![,]>)>
properties: Option<(Token![,], Punctuated<Ident, Token![,]>)>,
}
impl Parse for ProtoInputParams{
impl Parse for ProtoInputParams {
fn parse(input: ParseStream) -> syn::Result<Self> {
let proto_num = input.parse()?;
if let Some(seperator) = input.parse()?{
if let Some(seperator) = input.parse()? {
let mut punctuated = Punctuated::new();
loop {
punctuated.push_value(
input.parse()?
);
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))
}
)
return Ok(Self {
proto_num,
properties: Some((seperator, punctuated)),
});
}
}
} else {
Ok(
Self{
proto_num,
properties: None
}
)
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,
}
}
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
let derive_input = parse_macro_input!(input as DeriveInput);
let struct_attr = derive_input.attrs.iter()
.find(|a| a.path().segments.len() == 1 &&
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "rmc_struct"));
let Data::Struct(s) = derive_input.data else {
panic!("rmc struct type MUST be a struct");
};
// generate base data
fn gen_serialize_data_struct(
s: DataStruct,
struct_attr: Option<&Attribute>,
) -> (proc_macro2::TokenStream, proc_macro2::TokenStream) {
let serialize_base_content = {
let mut serialize_content = quote! {};
for f in &s.fields{
if f.attrs.iter()
.any(|a| a.path().segments.len() == 1 &&
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends")){
for f in &s.fields {
if f.attrs.iter().any(|a| {
a.path().segments.len() == 1
&& a.path()
.segments
.first()
.is_some_and(|p| p.ident.to_string() == "extends")
}) {
continue;
}
let ident = f.ident.as_ref().unwrap();
serialize_content.append_all(quote!{
serialize_content.append_all(quote! {
self.#ident.serialize(writer)?;
})
}
quote!{
quote! {
#serialize_content
Ok(())
@ -135,10 +81,10 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
for f in &s.fields {
let ident = f.ident.as_ref().unwrap();
structure_content.append_all(quote!{#ident, });
structure_content.append_all(quote! {#ident, });
}
quote!{
quote! {
Ok(Self{
#structure_content
})
@ -148,22 +94,26 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
let deserialize_base_content = {
let mut deserialize_content = quote! {};
for f in &s.fields{
if f.attrs.iter()
.any(|a| a.path().segments.len() == 1 &&
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends")){
for f in &s.fields {
if f.attrs.iter().any(|a| {
a.path().segments.len() == 1
&& a.path()
.segments
.first()
.is_some_and(|p| p.ident.to_string() == "extends")
}) {
continue;
}
let ident = f.ident.as_ref().unwrap();
let ty = &f.ty;
deserialize_content.append_all(quote!{
deserialize_content.append_all(quote! {
let #ident = <#ty> :: deserialize(reader)?;
})
}
quote!{
quote! {
#deserialize_content
#struct_ctor
}
@ -171,15 +121,19 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
// 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 version: Literal = attr.parse_args().expect("has to be a literal");
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
f.attrs.iter()
.any(|a| a.path().segments.len() == 1 &&
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends"))
}){
let ident= f.ident.as_ref().unwrap();
f.attrs.iter().any(|a| {
a.path().segments.len() == 1
&& a.path()
.segments
.first()
.is_some_and(|p| p.ident.to_string() == "extends")
})
}) {
let ident = f.ident.as_ref().unwrap();
quote! {
self.#ident.serialize(writer)?;
}
@ -199,16 +153,20 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
serialize_base_content
};
let deserialize_base_content = if let Some(attr) = struct_attr{
let deserialize_base_content = if let Some(attr) = struct_attr {
let version: Literal = attr.parse_args().expect("has to be a literal");
let pre_inner = if let Some(f) = s.fields.iter().find(|f| {
f.attrs.iter()
.any(|a| a.path().segments.len() == 1 &&
a.path().segments.first().is_some_and(|p| p.ident.to_string() == "extends"))
}){
let ident= f.ident.as_ref().unwrap();
let ty= &f.ty;
f.attrs.iter().any(|a| {
a.path().segments.len() == 1
&& a.path()
.segments
.first()
.is_some_and(|p| p.ident.to_string() == "extends")
})
}) {
let ident = f.ident.as_ref().unwrap();
let ty = &f.ty;
quote! {
let #ident = <#ty> :: deserialize(reader)?;
}
@ -226,6 +184,183 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
deserialize_base_content
};
(serialize_base_content, deserialize_base_content)
}
#[proc_macro_derive(RmcSerialize, attributes(extends, rmc_struct))]
pub fn rmc_serialize(input: TokenStream) -> TokenStream {
let derive_input = parse_macro_input!(input as DeriveInput);
let struct_attr = derive_input.attrs.iter().find(|a| {
a.path().segments.len() == 1
&& a.path()
.segments
.first()
.is_some_and(|p| p.ident.to_string() == "rmc_struct")
});
let repr_attr = derive_input.attrs.iter().find(|a| {
a.path().segments.len() == 1
&& a.path()
.segments
.first()
.is_some_and(|p| p.ident.to_string() == "repr")
});
/*let Data::Struct(s) = derive_input.data else {
panic!("rmc struct type MUST be a struct");
};*/
let (serialize_base_content, deserialize_base_content) = match derive_input.data {
Data::Struct(s) => gen_serialize_data_struct(s, struct_attr),
Data::Enum(e) => {
let Some(repr_attr) = repr_attr else {
panic!("missing repr attribute");
};
let ty: Ident = repr_attr.parse_args().unwrap();
let mut inner_match_de = quote! {};
let mut inner_match_se = quote! {};
for variant in e.variants {
let Some((_, val)) = variant.discriminant else {
panic!("missing discriminant");
};
let field_data_de = match &variant.fields {
Fields::Named(v) => {
let mut base = quote! {};
for field in v.named.iter() {
let ty = &field.ty;
let name = &field.ident;
base.append_all(quote!{
#name: <#ty as rust_nex::rmc::structures::RmcSerialize>::deserialize(reader)?,
});
}
quote! {{#base}}
}
Fields::Unnamed(n) => {
let mut base = quote! {};
for field in n.unnamed.iter() {
let ty = &field.ty;
base.append_all(quote!{
<#ty as rust_nex::rmc::structures::RmcSerialize>::deserialize(reader)?,
});
}
quote! {(#base)}
}
Fields::Unit => {
quote! {}
}
};
let mut se_with_fields = quote! {
<#ty as rust_nex::rmc::structures::RmcSerialize>::serialize(&#val, writer)?;
};
match &variant.fields {
Fields::Named(v) => {
for field in v.named.iter() {
let ty = &field.ty;
let name = &field.ident;
se_with_fields.append_all(quote!{
<#ty as rust_nex::rmc::structures::RmcSerialize>::serialize(#name ,writer)?;
});
}
}
Fields::Unnamed(n) => {
for (i, field) in n.unnamed.iter().enumerate() {
let ty = &field.ty;
let ident = Ident::new(&format!("val_{}", i), Span::call_site());
se_with_fields.append_all(quote!{
<#ty as rust_nex::rmc::structures::RmcSerialize>::serialize(#ident, writer)?;
});
}
}
Fields::Unit => {}
};
let field_match_se = match &variant.fields {
Fields::Named(v) => {
let mut base = quote! {};
for field in v.named.iter() {
let name = &field.ident;
base.append_all(quote! {
#name,
});
}
quote! {{#base}}
}
Fields::Unnamed(n) => {
let mut base = quote! {};
for (i, _field) in n.unnamed.iter().enumerate() {
let ident = Ident::new(&format!("val_{}", i), Span::call_site());
base.append_all(quote! {
#ident,
});
}
quote! {(#base)}
}
Fields::Unit => {
quote! {}
}
};
let name = variant.ident;
inner_match_de.append_all(quote! {
#val => Self::#name #field_data_de,
});
inner_match_se.append_all(quote! {
Self::#name #field_match_se => {
#se_with_fields
},
});
}
let serialize_base_content = quote! {
match self{
#inner_match_se
};
Ok(())
};
let deserialize_base_content = quote! {
let val: Self = match <#ty as rust_nex::rmc::structures::RmcSerialize>::deserialize(reader)?{
#inner_match_de
v => return Err(rust_nex::rmc::structures::Error::UnexpectedValue(v as _))
};
Ok(val)
};
(serialize_base_content, deserialize_base_content)
}
Data::Union(_) => {
unimplemented!()
}
};
// generate base data
let ident = derive_input.ident;
let tokens = quote! {
@ -255,7 +390,7 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
/// [`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)]`
/// the attribute which is just `NoReturn` e.g. `#[rmc_proto(1, NoReturn)]`
///
/// Example
/// ```
@ -270,34 +405,39 @@ pub fn rmc_serialize(input: TokenStream) -> TokenStream {
/// }
/// ```
#[proc_macro_attribute]
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{
pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream {
let params = parse_macro_input!(attr as ProtoInputParams);
let mut params = parse_macro_input!(attr as ProtoInputParams);
let ProtoInputParams{
let ProtoInputParams {
proto_num,
properties
properties,
} = params;
let no_return_data = properties.is_some_and(|p| p.1.iter().any(|i|{
i.to_string() == "NoReturn"
}));
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);
let input = parse_macro_input!(input as syn::ItemTrait);
// gigantic ass struct initializer (to summarize this gets all of the data)
let raw_data = RmcProtocolData{
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");
.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 {
@ -314,26 +454,30 @@ pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{
panic!("what");
};
let Pat::Ident(i) = &*t.pat else {
panic!("unable to handle non identifier patterns as parameter bindings");
panic!(
"unable to handle non identifier patterns as parameter bindings"
);
};
(i.ident.clone(), t.ty.as_ref().clone())
}).collect();
})
.collect();
ProtoMethodData{
ProtoMethodData {
id,
name: func.sig.ident.clone(),
parameters: funcs,
ret_val: func.sig.output.clone()
ret_val: func.sig.output.clone(),
}
}).collect()
})
.collect(),
};
quote!{
quote! {
#input
#raw_data
}.into()
}
.into()
}
/// Used to specify the method id of methods when making rmc protocols.
@ -342,25 +486,25 @@ pub fn rmc_proto(attr: TokenStream, input: TokenStream) -> TokenStream{
/// 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{
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);
pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream {
let 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());
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!{
let out = quote! {
#type_data
impl #ident for #struct_name{
@ -378,7 +522,7 @@ pub fn rmc_struct(attr: TokenStream, input: TokenStream) -> TokenStream{
}
#[proc_macro_attribute]
pub fn connection(_attr: TokenStream, input: TokenStream) -> TokenStream{
pub fn connection(_attr: TokenStream, input: TokenStream) -> TokenStream {
// this attribute doesnt do anything by itself, see `rmc_struct`
input
}

View file

@ -1,7 +1,7 @@
use proc_macro2::{Ident, Span, TokenStream, TokenTree};
use proc_macro2::{Ident, Span, TokenStream};
use quote::{quote, ToTokens};
use syn::{LitInt, LitStr, ReturnType, Token, Type};
use syn::token::{Brace, Bracket, Paren, Semi};
use syn::{LitInt, LitStr, ReturnType, Type};
use syn::token::{Brace, Paren, Semi};
pub struct ProtoMethodData{
pub id: LitInt,

View file

@ -23,9 +23,11 @@ use tokio::net::{TcpListener, TcpSocket};
use tokio::task;
use tokio_rustls::TlsAcceptor;
use rust_nex::define_rmc_proto;
use rust_nex::executables::common::{OWN_IP_PRIVATE, SECURE_SERVER_ACCOUNT, SERVER_PORT};
use rust_nex::executables::common::{RemoteController, OWN_IP_PRIVATE, SECURE_SERVER_ACCOUNT, SERVER_PORT};
use rust_nex::executables::common::ServerCluster::{Auth, Secure};
use rust_nex::executables::common::ServerType::Backend;
use rust_nex::nex::auth_handler::AuthHandler;
use rust_nex::rmc::protocols::new_rmc_gateway_connection;
use rust_nex::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote};
use rust_nex::rmc::response::ErrorCode;
use rust_nex::rmc::structures::RmcSerialize;
use rust_nex::rnex_proxy_common::ConnectionInitData;
@ -44,17 +46,21 @@ pub static SECURE_PROXY_PORT: Lazy<u16> = Lazy::new(|| {
.unwrap_or(10000)
});
static SECURE_STATION_URL: Lazy<String> = Lazy::new(|| {
format!(
"prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1",
*SECURE_PROXY_ADDR, *SECURE_PROXY_PORT
)
});
#[tokio::main]
async fn main() {
setup();
let conn = rust_nex::reggie::rmc_connect_to(
"agmp-control.spfn.net",
Backend{
name: "agmp-auth-1.spfn.net".to_string(),
cluster: Auth
},
|r| Arc::new(OnlyRemote::<RemoteController>::new(r))
).await;
let conn = conn.unwrap();
let acceptor = get_configured_tls_acceptor().await;
let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap();
@ -84,14 +90,14 @@ async fn main() {
continue;
}
};
let controller = conn.clone();
task::spawn(async move {
info!("connection to secure backend established");
new_rmc_gateway_connection(stream.into(), |_| {
Arc::new(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,
control_server: controller
})
});
});

View file

@ -8,12 +8,14 @@ use log::{error, info};
use tokio::net::TcpListener;
use tokio::task;
use rust_nex::common::setup;
use rust_nex::executables::common::{OWN_IP_PRIVATE, SERVER_PORT};
use rust_nex::executables::common::{RemoteController, RemoteControllerManagement, OWN_IP_PRIVATE, SERVER_PORT};
use rust_nex::executables::common::ServerCluster::Secure;
use rust_nex::executables::common::ServerType::Backend;
use rust_nex::nex::matchmake::MatchmakeManager;
use rust_nex::nex::remote_console::RemoteConsole;
use rust_nex::nex::user::User;
use rust_nex::reggie::get_configured_tls_acceptor;
use rust_nex::rmc::protocols::new_rmc_gateway_connection;
use rust_nex::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote};
use rust_nex::rnex_proxy_common::ConnectionInitData;
use rust_nex::rmc::protocols::RemoteInstantiatable;
@ -22,6 +24,16 @@ use rust_nex::rmc::protocols::RemoteInstantiatable;
async fn main() {
setup();
let conn = rust_nex::reggie::rmc_connect_to(
"agmp-control.spfn.net",
Backend{
name: "agmp-secure-1.spfn.net".to_string(),
cluster: Secure
},
|r| Arc::new(OnlyRemote::<RemoteController>::new(r))
).await;
let conn = conn.unwrap();
let acceptor = get_configured_tls_acceptor().await;
let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap();

View file

@ -1,7 +1,12 @@
use std::env;
use std::net::Ipv4Addr;
use std::net::{Ipv4Addr, SocketAddrV4};
use macros::{method_id, rmc_proto, RmcSerialize};
use once_cell::sync::Lazy;
use tonic::transport::Server;
use rust_nex::define_rmc_proto;
use rust_nex::prudp::station_url::StationUrl;
use crate::nex::account::Account;
use crate::rmc::response::ErrorCode;
pub static OWN_IP_PRIVATE: Lazy<Ipv4Addr> = Lazy::new(|| {
env::var("SERVER_IP")
@ -10,6 +15,13 @@ pub static OWN_IP_PRIVATE: Lazy<Ipv4Addr> = Lazy::new(|| {
.expect("no private ip specified")
});
pub static OWN_IP_PUBLIC: Lazy<Ipv4Addr> = Lazy::new(|| {
env::var("SERVER_IP_PUBLIC")
.ok()
.and_then(|s| s.parse().ok())
.expect("no private ip specified")
});
pub static SERVER_PORT: Lazy<u16> = Lazy::new(|| {
env::var("SERVER_PORT")
.ok()
@ -27,3 +39,52 @@ pub static AUTH_SERVER_ACCOUNT: Lazy<Account> =
Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD));
pub static SECURE_SERVER_ACCOUNT: Lazy<Account> =
Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
#[rmc_proto(1)]
pub trait ProxyManagement {
#[method_id(1)]
async fn update_url(&self, url: String) -> Result<(), ErrorCode>;
}
define_rmc_proto!(
proto Proxy{
ProxyManagement
}
);
#[rmc_proto(2)]
pub trait ControllerManagement {
#[method_id(1)]
async fn get_secure_proxy_url(&self) -> Result<String, ErrorCode>;
#[method_id(2)]
async fn get_secure_account(&self) -> Result<Account, ErrorCode>;
}
define_rmc_proto!(
proto Controller{
ControllerManagement
}
);
#[derive(RmcSerialize)]
#[repr(u32)]
pub enum ServerCluster{
Auth = 0,
Secure = 1
}
#[derive(RmcSerialize)]
#[repr(u32)]
pub enum ServerType{
Proxy{
addr: SocketAddrV4,
cluster: ServerCluster
} = 1,
Backend{
name: String,
cluster: ServerCluster
} = 2,
}

View file

@ -0,0 +1,209 @@
use std::future::Future;
use rust_nex::rmc::protocols::{LocalNoProto, RmcCallable};
use rust_nex::rmc::structures::RmcSerialize;
use std::io::Cursor;
use std::net::{Ipv4Addr, SocketAddrV4};
use macros::rmc_struct;
use rust_nex::common::setup;
use rust_nex::executables::common::{ControllerManagement, LocalController, RemoteProxy, RemoteProxyManagement, ServerCluster, ServerType, KERBEROS_SERVER_PASSWORD};
use rust_nex::prudp::station_url::StationUrl;
use rust_nex::reggie::{get_configured_tls_acceptor, TestStruct, WebStreamSocket};
use rust_nex::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote};
use rust_nex::rmc::response::ErrorCode;
use rust_nex::reggie::UnitPacketRead;
use std::sync::{Arc, Weak};
use log::error;
use once_cell::sync::Lazy;
use rand::random;
use tokio::net::TcpListener;
use tokio::sync::RwLock;
use tokio::task;
use tungstenite::client;
use rust_nex::nex::account::Account;
use rust_nex::rmc::response::ErrorCode::{Core_Exception, Core_InvalidIndex};
use rust_nex::rmc::protocols::RemoteInstantiatable;
use rust_nex::util::SendingBufferConnection;
pub static AUTH_SERVER_ACCOUNT: Lazy<Account> =
Lazy::new(|| Account::new(1, "Quazal Authentication", &KERBEROS_SERVER_PASSWORD));
pub static SECURE_SERVER_ACCOUNT: Lazy<Account> =
Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
#[rmc_struct(Controller)]
struct ServerController {
insecure_proxies: RwLock<Vec<Weak<Proxy>>>,
insecure_backend_url: RwLock<String>,
secure_proxies: RwLock<Vec<Weak<Proxy>>>,
secure_backend_url: RwLock<String>,
account: Account
}
impl ServerController{
async fn update_urls(&self, cluster: ServerCluster){
let url = match cluster{
ServerCluster::Auth => {
self.insecure_backend_url.read().await
}
ServerCluster::Secure => {
self.secure_backend_url.read().await
}
}.clone();
let read_lock = match cluster{
ServerCluster::Auth => {
self.insecure_proxies.read().await
}
ServerCluster::Secure => {
self.secure_proxies.read().await
}
};
for proxy in read_lock.iter().filter_map(|v| v.upgrade()){
if let Err(e) = proxy.proxy.update_url(url.clone()).await {
error!("error whilest updating proxy url: {:?}", e);
}
}
}
}
struct Proxy{
proxy: RemoteProxy,
ip: SocketAddrV4,
controller: Arc<ServerController>
}
impl RmcCallable for Proxy{
fn rmc_call(&self, responder: &SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>) -> impl Future<Output=()> + Send {
self.controller.rmc_call(responder, protocol_id, method_id, call_id, rest)
}
}
impl ControllerManagement for ServerController {
async fn get_secure_proxy_url(&self) -> Result<String, ErrorCode> {
let proxy = self.secure_proxies.write().await;
let proxies = proxy.iter().filter_map(|v| v.upgrade());
let idx: usize = random::<usize>() % proxy.len();
// do not switch this to using regular array indexing i specifically wrote it like this as
// to have absolutely now way of panicking, we cant have the control server panicking after
// all
let Some(proxy) = proxies.clone().nth(idx).or_else(|| proxies.clone().nth(0)) else {
return Err(Core_InvalidIndex);
};
let station_url = format!(
"prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1",
proxy.ip.ip(), proxy.ip.port()
);
Ok(station_url)
}
async fn get_secure_account(&self) -> Result<Account, ErrorCode> {
Ok(self.account.clone())
}
}
#[tokio::main]
async fn main() {
setup();
let socket = TcpListener::bind("0.0.0.0:10003").await.unwrap();
let acceptor = get_configured_tls_acceptor().await;
let server_controller = Arc::new(ServerController {
account: SECURE_SERVER_ACCOUNT.clone(),
secure_proxies: Default::default(),
secure_backend_url: Default::default(),
insecure_backend_url: Default::default(),
insecure_proxies: Default::default(),
});
while let Ok((stream, _sock_addr)) = socket.accept().await {
let websocket = tokio_tungstenite::accept_async(stream).await.unwrap();
let stream = WebStreamSocket::new(websocket);
let mut stream = acceptor.accept(stream).await.unwrap();
let server_controller = server_controller.clone();
tokio::spawn(async move {
let server_controller = server_controller;
let Ok(server_type) = stream.read_buffer().await else {
error!("failed to read server type");
return;
};
let Ok(server_type) = ServerType::deserialize(&mut Cursor::new(server_type)) else {
error!("failed to read server type");
return;
};
match server_type {
ServerType::Proxy{
addr,
cluster
} => {
let mut write_lock = match cluster{
ServerCluster::Auth => {
server_controller.insecure_proxies.write().await
}
ServerCluster::Secure => {
server_controller.secure_proxies.write().await
}
};
let server_controller_internal = server_controller.clone();
let remo = new_rmc_gateway_connection(stream.into(), move |r|
Arc::new(Proxy {
proxy: RemoteProxy::new(r),
ip: addr,
controller: server_controller_internal
}));
write_lock.push(Arc::downgrade(&remo));
let url = match cluster{
ServerCluster::Auth => {
server_controller.insecure_backend_url.read().await
}
ServerCluster::Secure => {
server_controller.secure_backend_url.read().await
}
}.clone();
if let Err(e) = remo.proxy.update_url(url.clone()).await {
error!("error whilest updating proxy url: {:?}", e);
}
}
ServerType::Backend{
name,
cluster
} => {
let mut url = match cluster{
ServerCluster::Auth => {
server_controller.insecure_backend_url.write().await
}
ServerCluster::Secure => {
server_controller.secure_backend_url.write().await
}
};
*url = name;
drop(url);
server_controller.update_urls(cluster).await;
new_rmc_gateway_connection(stream.into(), |_| server_controller);
}
}
});
}
}

View file

@ -1,13 +1,17 @@
use rust_nex::executables::common::{LocalProxy, ProxyManagement, RemoteController, OWN_IP_PUBLIC};
use std::env;
use std::ffi::CStr;
use std::io::{Read, Write};
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener, TcpStream};
use std::sync::{Arc, OnceLock};
use std::time::Duration;
use bytemuck::{Pod, Zeroable};
use chacha20::{ChaCha20, Key};
use chacha20::cipher::{Iv, KeyIvInit, StreamCipher};
use log::error;
use log::{error, warn};
use macros::rmc_struct;
use once_cell::sync::Lazy;
use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, Document};
use rsa::{BigUint, Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
@ -16,13 +20,20 @@ use rsa::pss::BlindedSigningKey;
use rsa::signature::{RandomizedSigner, SignatureEncoding};
use sha2::Sha256;
use tokio::net::TcpSocket;
use tokio::sync::RwLock;
use tokio::task;
use tokio::time::sleep;
use rust_nex::common::setup;
use rust_nex::executables::common::{OWN_IP_PRIVATE, SERVER_PORT};
use rust_nex::executables::common::ServerCluster::Auth;
use rust_nex::executables::common::ServerType::{Backend, Proxy};
use rust_nex::prudp::packet::VirtualPort;
use rust_nex::prudp::router::Router;
use rust_nex::prudp::station_url::StationUrl;
use rust_nex::prudp::unsecure::Unsecure;
use rust_nex::reggie::{establish_tls_connection_to, UnitPacketRead, UnitPacketWrite};
use rust_nex::rmc::protocols::OnlyRemote;
use rust_nex::rmc::response::ErrorCode;
use rust_nex::rmc::structures::RmcSerialize;
use rust_nex::rnex_proxy_common::ConnectionInitData;
@ -33,30 +44,41 @@ static FORWARD_DESTINATION: Lazy<String> =
static FORWARD_DESTINATION_NAME: Lazy<String> =
Lazy::new(|| env::var("FORWARD_DESTINATION_NAME").expect("no forward destination name given"));
static RSA_PRIVKEY: Lazy<RsaPrivateKey> = Lazy::new(|| {
let path = env::var("RSA_PRIVKEY")
.expect("RSA_PRIVKEY not set");
#[rmc_struct(Proxy)]
#[derive(Default)]
struct DestinationHolder{
url: RwLock<String>
}
RsaPrivateKey::read_pkcs8_pem_file(&path)
.expect("unable to read private key")
});
impl ProxyManagement for DestinationHolder{
async fn update_url(&self, new_url: String) -> Result<(), ErrorCode> {
println!("updating url");
static RSA_PUBKEY: Lazy<RsaPublicKey> = Lazy::new(|| {
RSA_PRIVKEY.to_public_key()
});
let mut url = self.url.write().await;
static PUBKEY_ENCODED: Lazy<Document> = Lazy::new(|| {
RSA_PUBKEY.to_pkcs1_der().expect("unable to convert pubkey to der")
});
*url = new_url;
Ok(())
}
}
static RSA_SIGNKEY: Lazy<BlindedSigningKey<Sha256>> = Lazy::new(||
BlindedSigningKey::<Sha256>::new(RSA_PRIVKEY.clone())
);
#[tokio::main]
async fn main() {
setup();
let conn =
rust_nex::reggie::rmc_connect_to(
"agmp-control.spfn.net",
Proxy {
addr: SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT),
cluster: Auth
},
|r| Arc::new(DestinationHolder::default())
).await;
let dest_holder = conn.unwrap();
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
.await
.expect("unable to start router");
@ -76,9 +98,18 @@ async fn main() {
return;
};
let dest_holder = dest_holder.clone();
task::spawn(async move {
let dest = dest_holder.url.read().await;
if *dest == ""{
warn!("no destination set yet but connection attempted");
return;
}
let mut stream
= establish_tls_connection_to(FORWARD_DESTINATION.as_str(), FORWARD_DESTINATION_NAME.as_str()).await;
= establish_tls_connection_to(&dest, &dest).await;
if let Err(e) = stream.send_buffer(&ConnectionInitData{
prudpsock_addr: conn.socket_addr,
@ -113,6 +144,9 @@ async fn main() {
return;
}
},
_ = sleep(Duration::from_secs(10)) => {
conn.send([0,0,0,0,0].to_vec()).await;
}
}
}
});

View file

@ -1,43 +1,65 @@
use std::env;
use std::ffi::CStr;
use std::io::{Read, Write};
use std::net::{Ipv4Addr, SocketAddrV4, TcpListener, TcpStream};
use bytemuck::{Pod, Zeroable};
use chacha20::{ChaCha20, Key};
use chacha20::cipher::{Iv, KeyIvInit, StreamCipher};
use log::error;
use once_cell::sync::Lazy;
use rsa::pkcs8::{DecodePrivateKey, DecodePublicKey, Document};
use rsa::{BigUint, Pkcs1v15Encrypt, RsaPrivateKey, RsaPublicKey};
use rsa::pkcs1::EncodeRsaPublicKey;
use rsa::pss::BlindedSigningKey;
use rsa::signature::{RandomizedSigner, SignatureEncoding};
use sha2::Sha256;
use tokio::net::TcpSocket;
use std::net::SocketAddrV4;
use std::sync::Arc;
use std::time::Duration;
use futures::future::Remote;
use log::{error, warn};
use macros::rmc_struct;
use tokio::sync::RwLock;
use tokio::task;
use tokio::time::sleep;
use rust_nex::common::setup;
use rust_nex::executables::common::{OWN_IP_PRIVATE, SECURE_SERVER_ACCOUNT, SERVER_PORT};
use rust_nex::executables::common::{ProxyManagement, RemoteController, RemoteControllerManagement, OWN_IP_PRIVATE, OWN_IP_PUBLIC, SECURE_SERVER_ACCOUNT, SERVER_PORT};
use rust_nex::executables::common::ServerCluster::Auth;
use rust_nex::executables::common::ServerType::Proxy;
use rust_nex::prudp::packet::VirtualPort;
use rust_nex::prudp::router::Router;
use rust_nex::prudp::secure::Secure;
use rust_nex::prudp::unsecure::Unsecure;
use rust_nex::reggie::{establish_tls_connection_to, UnitPacketRead, UnitPacketWrite};
use rust_nex::rmc::structures::RmcSerialize;
use rust_nex::reggie::establish_tls_connection_to;
use rust_nex::rmc::response::ErrorCode;
use rust_nex::rnex_proxy_common::ConnectionInitData;
use rust_nex::executables::common::LocalProxy;
use rust_nex::reggie::UnitPacketWrite;
use rust_nex::rmc::structures::RmcSerialize;
use rust_nex::reggie::UnitPacketRead;
use rust_nex::rmc::protocols::RemoteInstantiatable;
#[rmc_struct(Proxy)]
struct DestinationHolder{
url: RwLock<String>,
controller: RemoteController
}
impl ProxyManagement for DestinationHolder{
async fn update_url(&self, new_url: String) -> Result<(), ErrorCode> {
let mut url = self.url.write().await;
*url = new_url;
Ok(())
}
}
static FORWARD_DESTINATION: Lazy<String> =
Lazy::new(|| env::var("FORWARD_DESTINATION").expect("no forward destination given"));
static FORWARD_DESTINATION_NAME: Lazy<String> =
Lazy::new(|| env::var("FORWARD_DESTINATION_NAME").expect("no forward destination name given"));
#[tokio::main]
async fn main() {
setup();
let conn =
rust_nex::reggie::rmc_connect_to(
"agmp-control.spfn.net",
Proxy {
addr: SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT),
cluster: Auth
},
|r| Arc::new(DestinationHolder{
url: Default::default(),
controller: RemoteController::new(r)
})
).await;
let dest_holder = conn.unwrap();
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
.await
.expect("unable to start router");
@ -45,7 +67,7 @@ async fn main() {
let mut socket_secure = router_secure
.add_socket(VirtualPort::new(1, 10), Secure(
"6f599f81",
&SECURE_SERVER_ACCOUNT
dest_holder.controller.get_secure_account().await.unwrap()
))
.await
.expect("unable to add socket");
@ -58,9 +80,18 @@ async fn main() {
return;
};
let dest_holder = dest_holder.clone();
task::spawn(async move {
let dest = dest_holder.url.read().await;
if *dest == ""{
warn!("no destination set yet but connection attempted");
return;
}
let mut stream
= establish_tls_connection_to(FORWARD_DESTINATION.as_str(), FORWARD_DESTINATION_NAME.as_str()).await;
= establish_tls_connection_to(&dest, &dest).await;
if let Err(e) = stream.send_buffer(&ConnectionInitData{
prudpsock_addr: conn.socket_addr,
@ -70,6 +101,8 @@ async fn main() {
return;
};
loop {
tokio::select! {
data = conn.recv() => {
@ -95,6 +128,9 @@ async fn main() {
return;
}
},
_ = sleep(Duration::from_secs(10)) => {
conn.send([0,0,0,0,0].to_vec()).await;
}
}
}
});

View file

@ -1,23 +1,12 @@
use std::{env, result};
use std::array::TryFromSliceError;
use std::net::{Ipv4Addr};
use std::str::FromStr;
use json::{object, JsonValue};
use once_cell::sync::Lazy;
use reqwest::{Body, Method, Url};
use reqwest::header::HeaderValue;
use rocket::serde::json::Json;
use serde::Serialize;
use thiserror::Error;
use tonic::metadata::{Ascii, MetadataValue};
use tonic::{Request, transport};
use tonic::codegen::InterceptedService;
use tonic::transport::Channel;
use crate::grpc::account::Error::SomethingHappened;
use crate::grpc::InterceptorFunc;
use crate::grpc::protobufs::account::account_client::AccountClient;
use crate::grpc::protobufs::account::{GetNexPasswordRequest, GetUserDataRequest, GetUserDataResponse};
static API_KEY: Lazy<String> = Lazy::new(||{
let key = env::var("ACCOUNT_GQL_API_KEY")
.expect("no graphql ip specified");

View file

@ -1,3 +1,11 @@
#![allow(dead_code)]
// rnex makes extensive use of async functions in public traits
// this is however fine because these traits should never(and i mean NEVER) be used dynamically
#![allow(async_fn_in_trait)]
//#![warn(missing_docs)]
extern crate self as rust_nex;
pub mod endianness;

View file

@ -1,5 +1,6 @@
#![allow(dead_code)]
#![warn(missing_docs)]
#![allow(async_fn_in_trait)]
//#![warn(missing_docs)]
//! # Splatoon RNEX server
//!
@ -63,6 +64,7 @@ mod versions;
mod web;
pub mod reggie;
pub mod util;
pub mod common;

View file

@ -1,10 +1,11 @@
use macros::RmcSerialize;
#[derive(RmcSerialize)]
#[derive(Clone)]
pub struct Account{
pub pid: u32,
pub username: Box<str>,
pub username: String,
pub kerbros_password: [u8; 16],
}
impl Account{

View file

@ -1,3 +1,6 @@
use crate::executables::common::RemoteControllerManagement;
use std::sync::Arc;
use rust_nex::executables::common::RemoteController;
use crate::grpc::account;
use crate::kerberos::{derive_key, KerberosDateTime, Ticket};
use crate::nex::account::Account;
@ -7,9 +10,9 @@ 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 crate::{define_rmc_proto, kerberos};
use macros::rmc_struct;
use crate::rmc::protocols::OnlyRemote;
define_rmc_proto!(
proto AuthClientProtocol{
@ -21,7 +24,8 @@ define_rmc_proto!(
pub struct AuthHandler {
pub destination_server_acct: &'static Account,
pub build_name: &'static str,
pub station_url: &'static str,
//pub station_url: &'static str,
pub control_server: Arc<OnlyRemote<RemoteController>>,
}
pub fn generate_ticket(
@ -56,14 +60,14 @@ async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> {
}
impl Auth for AuthHandler {
async fn login(&self, name: String) -> Result<(), ErrorCode> {
async fn login(&self, _name: String) -> Result<(), ErrorCode> {
todo!()
}
async fn login_ex(
&self,
name: String,
extra_data: Any,
_extra_data: Any,
) -> Result<(QResult, u32, Vec<u8>, ConnectionData, String), ErrorCode> {
let Ok(pid) = name.parse() else {
return Err(ErrorCode::Core_InvalidArgument);
@ -84,8 +88,12 @@ impl Auth for AuthHandler {
let result = QResult::success(Core_Unknown);
let Ok(addr) = self.control_server.get_secure_proxy_url().await else {
return Err(ErrorCode::Core_Exception);
};
let connection_data = ConnectionData {
station_url: self.station_url.to_string(),
station_url: addr,
special_station_url: "".to_string(),
//date_time: KerberosDateTime::new(1,1,1,1,1,1),
date_time: KerberosDateTime::now(),
@ -126,11 +134,11 @@ impl Auth for AuthHandler {
Ok((result, ticket.into()))
}
async fn get_pid(&self, username: String) -> Result<u32, ErrorCode> {
async fn get_pid(&self, _username: String) -> Result<u32, ErrorCode> {
Err(ErrorCode::Core_Exception)
}
async fn get_name(&self, pid: u32) -> Result<String, ErrorCode> {
async fn get_name(&self, _pid: u32) -> Result<String, ErrorCode> {
Err(ErrorCode::Core_Exception)
}
}

View file

@ -2,7 +2,7 @@ use std::collections::HashMap;
use std::str::FromStr;
use std::sync::{Arc, Weak};
use std::sync::atomic::AtomicU32;
use std::sync::atomic::Ordering::{Relaxed, Release};
use std::sync::atomic::Ordering::Relaxed;
use std::time::Duration;
use log::info;
use rand::random;
@ -50,7 +50,7 @@ impl MatchmakeManager{
async fn garbage_collect(&self){
info!("running rnex garbage collector over all sessions and users");
let mut idx = 0;
let idx = 0;
let mut to_be_deleted_gids = Vec::new();
@ -64,7 +64,7 @@ impl MatchmakeManager{
session_pair
}{
let mut session = session.lock().await;
let session = session.lock().await;
if !session.is_reachable(){
to_be_deleted_gids.push(gid);

View file

@ -1,8 +1,6 @@
use macros::rmc_struct;
use crate::rmc::protocols::notifications::{Notification, NotificationEvent, RawNotification, RawNotificationInfo, RemoteNotification};
use crate::rmc::protocols::notifications::{Notification, RawNotification, RawNotificationInfo, RemoteNotification};
use crate::rmc::protocols::nat_traversal::{NatTraversalConsole, RemoteNatTraversalConsole, RawNatTraversalConsoleInfo, RawNatTraversalConsole};
use crate::define_rmc_proto;
use crate::nex::user::RemoteUserProtocol;
define_rmc_proto!(
proto Console{

View file

@ -1,14 +1,12 @@
use std::io::ErrorKind::HostUnreachable;
use crate::define_rmc_proto;
use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager};
use crate::nex::remote_console::RemoteConsole;
use crate::prudp::sockaddr::PRUDPSockAddr;
use crate::prudp::station_url::Type::{PRUDP, PRUDPS};
use crate::prudp::station_url::UrlOptions::{
Address, NatFiltering, NatMapping, NatType, Platform, Port, PrincipalID, RVConnectionID,
StreamID, PMP, UPNP,
Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID,
};
use crate::prudp::station_url::{nat_types, StationUrl, Type};
use crate::prudp::station_url::{StationUrl};
use crate::rmc::protocols::matchmake::{
Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake,
};
@ -24,15 +22,12 @@ use crate::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessi
use crate::rmc::structures::qresult::QResult;
use macros::rmc_struct;
use std::net::{Ipv4Addr, SocketAddrV4};
use std::sync::{Arc, Weak};
use log::{error, info};
use rocket::http::ext::IntoCollection;
use log::info;
use tokio::sync::{Mutex, RwLock};
use tonic::Code::InvalidArgument;
use crate::prudp::station_url::nat_types::PUBLIC;
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
use crate::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired, RendezVous_SessionVoid};
use crate::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired};
define_rmc_proto!(
proto UserProtocol{
@ -129,7 +124,7 @@ impl Secure for User {
public_station
};
let mut both = [&mut public_station, &mut private_station];
let both = [&mut public_station, &mut private_station];
for station in both {
station.options.retain(|v| {
@ -208,7 +203,7 @@ impl MatchmakeExtension for User {
Ok(())
}
async fn get_playing_session(&self, pids: Vec<u32>) -> Result<Vec<()>, ErrorCode> {
async fn get_playing_session(&self, _pids: Vec<u32>) -> Result<Vec<()>, ErrorCode> {
Ok(Vec::new())
}
@ -385,7 +380,7 @@ impl MatchmakeExtension for User {
}
impl Matchmake for User {
async fn unregister_gathering(&self, gid: u32) -> Result<bool, ErrorCode> {
async fn unregister_gathering(&self, _gid: u32) -> Result<bool, ErrorCode> {
Ok(true)
}
async fn get_session_urls(&self, gid: u32) -> Result<Vec<StationUrl>, ErrorCode> {
@ -460,7 +455,7 @@ impl Matchmake for User {
Ok(())
}
async fn migrate_gathering_ownership(&self, gid: u32, candidates: Vec<u32>, participants_only: bool) -> Result<(), ErrorCode> {
async fn migrate_gathering_ownership(&self, gid: u32, candidates: Vec<u32>, _participants_only: bool) -> Result<(), ErrorCode> {
let session = self.matchmake_manager.get_session(gid).await?;
let mut session = session.lock().await;
@ -522,11 +517,11 @@ impl NatTraversal for User {
Ok(())
}
async fn report_nat_traversal_result(&self, cid: u32, result: bool, rtt: u32) -> Result<(), ErrorCode> {
async fn report_nat_traversal_result(&self, _cid: u32, _result: bool, _rtt: u32) -> Result<(), ErrorCode> {
Ok(())
}
async fn request_probe_initiation(&self, station_to_probe: String) -> Result<(), ErrorCode> {
async fn request_probe_initiation(&self, _station_to_probe: String) -> Result<(), ErrorCode> {
info!("NO!");
Err(RendezVous_AccountExpired)
}

View file

@ -9,7 +9,7 @@ use std::io::{Cursor, Read, Seek, Write};
use std::net::SocketAddrV4;
use bytemuck::{Pod, Zeroable};
use hmac::{Hmac, Mac};
use log::{error, trace, warn};
use log::{error, warn};
use md5::{Md5, Digest};
use thiserror::Error;
use v_byte_macros::{SwapEndian};

View file

@ -5,11 +5,11 @@ use tokio::net::UdpSocket;
use std::net::{SocketAddr, SocketAddrV4};
use std::net::SocketAddr::V4;
use std::sync::{Arc, Weak};
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::atomic::{AtomicBool};
use std::time::Duration;
use tokio::task::JoinHandle;
use once_cell::sync::Lazy;
use log::{error, info, trace};
use log::{error, info};
use thiserror::Error;
use tokio::select;
use tokio::sync::RwLock;

View file

@ -10,7 +10,6 @@ use crate::kerberos::{derive_key, TicketInternalData};
use crate::nex::account::Account;
use crate::prudp::packet::PRUDPV1Packet;
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair};
use crate::prudp::unsecure::UnsecureInstance;
use crate::rmc::structures::RmcSerialize;
pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 32], u32, u32)>{
@ -103,7 +102,7 @@ pub fn generate_secure_encryption_pairs(mut session_key: [u8; 32], count: u8) ->
}
pub struct Secure(pub &'static str, pub &'static Account);
pub struct Secure(pub &'static str, pub Account);
pub struct SecureInstance {
@ -186,7 +185,7 @@ impl CryptoHandlerConnectionInstance for SecureInstance {
packet.calculate_and_assign_signature(self.access_key, Some(self.session_key), Some(self.self_signature));
}
fn verify_packet(&self, packet: &PRUDPV1Packet) -> bool {
fn verify_packet(&self, _packet: &PRUDPV1Packet) -> bool {
true
}
}

View file

@ -1,37 +1,24 @@
use crate::nex::account::Account;
use crate::prudp::packet::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE};
use crate::prudp::packet::types::{CONNECT, DATA, DISCONNECT, PING, SYN};
use crate::prudp::packet::PacketOption::{
ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions,
ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions,
};
use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, PacketOption, TypesFlags, VirtualPort};
use crate::prudp::router::{Error, Router};
use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags, VirtualPort};
use crate::prudp::sockaddr::PRUDPSockAddr;
use async_trait::async_trait;
use chrono::NaiveTime;
use hmac::digest::consts::U5;
use log::info;
use log::{error, trace, warn};
use once_cell::sync::Lazy;
use rand::random;
use rc4::{Key, KeyInit, Rc4, StreamCipher};
use rocket::http::hyper::body::HttpBody;
use std::collections::{BTreeMap, HashMap, VecDeque};
use std::fmt::{Debug, Formatter};
use std::future::Future;
use log::error;
use rc4::StreamCipher;
use std::collections::{BTreeMap, HashMap};
use std::marker::PhantomData;
use std::mem;
use std::net::SocketAddrV4;
use std::ops::Deref;
use std::pin::Pin;
use std::sync::{Arc, Weak};
use std::time::Duration;
use tokio::net::UdpSocket;
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::sync::{Mutex, RwLock};
use tokio::sync::Mutex;
use tokio::time::{sleep, Instant};
use tokio_stream::Stream;
// due to the way this is designed crashing the router thread causes deadlock, sorry ;-;
// (maybe i will fix that some day)
@ -479,7 +466,7 @@ impl<T: CryptoHandler> InternalSocket<T> {
self.send_packet_unbuffered(address, response).await;
}
async fn handle_data(&self, address: PRUDPSockAddr, mut packet: PRUDPV1Packet) {
async fn handle_data(&self, address: PRUDPSockAddr, packet: PRUDPV1Packet) {
info!("got data");
if packet.header.types_and_flags.get_flags() & (NEED_ACK | RELIABLE)
@ -533,7 +520,7 @@ impl<T: CryptoHandler> InternalSocket<T> {
let conn = conn.clone();
drop(connections);
let mut conn = conn.lock().await;
let conn = conn.lock().await;
let mut response = packet.base_acknowledgement_packet();
response.header.types_and_flags.set_flag(HAS_SIZE | ACK);
@ -553,7 +540,7 @@ impl<T: CryptoHandler> InternalSocket<T> {
let conn = conn.clone();
drop(connections);
let mut conn = conn.lock().await;
let conn = conn.lock().await;
let mut response = packet.base_acknowledgement_packet();
response.header.types_and_flags.set_flag(HAS_SIZE | ACK);

View file

@ -2,7 +2,6 @@ use std::net::Ipv4Addr;
use log::error;
use std::fmt::{Debug, Display, Formatter, Write};
use std::io::Read;
use rocket::delete;
use crate::prudp::station_url::Type::{PRUDP, PRUDPS, UDP};
use crate::prudp::station_url::UrlOptions::{Address, ConnectionID, NatFiltering, NatMapping, NatType, Platform, PMP, Port, PrincipalID, RVConnectionID, StreamID, StreamType, UPNP, PID};
use crate::rmc::structures::Error::StationUrlInvalid;

View file

@ -1,18 +1,26 @@
use std::{env, fs, io};
use std::io::{Error, ErrorKind};
use std::pin::Pin;
use std::sync::Arc;
use std::task::{Context, Poll};
use futures::{SinkExt, StreamExt};
use macros::{method_id, rmc_proto, rmc_struct};
use once_cell::sync::Lazy;
use rustls::{ClientConfig, RootCertStore, ServerConfig};
use rustls::client::WebPkiServerVerifier;
use rustls::server::WebPkiClientVerifier;
use rustls_pki_types::{CertificateDer, PrivateKeyDer, ServerName, TrustAnchor};
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio::net::TcpStream;
use thiserror::Error;
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt, ReadBuf};
use tokio::net::{TcpListener, TcpStream};
use tokio_rustls::{TlsAcceptor, TlsConnector};
use tokio_rustls::client::TlsStream;
use tokio_tungstenite::{connect_async, WebSocketStream};
use tokio_tungstenite::tungstenite::Message;
use webpki::anchor_from_trusted_cert;
use rust_nex::common::setup;
use crate::define_rmc_proto;
use crate::endianness::IS_BIG_ENDIAN;
use crate::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote, RmcCallable, RmcConnection};
use crate::rmc::response::ErrorCode;
use crate::rmc::structures::RmcSerialize;
@ -116,12 +124,12 @@ pub trait UnitPacketWrite: AsyncWrite + Unpin{
impl<T: AsyncWrite + Unpin> UnitPacketWrite for T{}
pub async fn establish_tls_connection_to(address: &str, server_name: &'static str) -> TlsStream<TcpStream>{
pub async fn establish_tls_connection_to(address: &str, server_name: &str) -> TlsStream<TcpStream>{
let connector = get_configured_tls_connector().await;
let stream = TcpStream::connect(address).await.unwrap();
let stream = connector.connect(ServerName::try_from(server_name).unwrap(), stream).await
let stream = connector.connect(ServerName::try_from(server_name.to_owned()).unwrap(), stream).await
.expect("unable to connect via tls");
stream
@ -147,3 +155,213 @@ impl RmcTestProto for TestStruct{
Ok("heya".into())
}
}
pub struct WebStreamSocket<T: AsyncRead + AsyncWrite + Unpin> {
socket: WebSocketStream<T>,
incoming_buffer: Vec<u8>,
finished_reading: bool,
}
impl<T: AsyncRead + AsyncWrite + Unpin> WebStreamSocket<T> {
pub fn new(socket: WebSocketStream<T>) -> Self{
Self{
incoming_buffer: Default::default(),
socket,
finished_reading: false,
}
}
}
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncWrite for WebStreamSocket<T> {
fn poll_write(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &[u8]) -> Poll<Result<usize, Error>> {
let this = &mut self.get_mut().socket;
let msg = Message::binary(buf.to_vec());
match this.poll_ready_unpin(cx) {
Poll::Pending => return Poll::Pending,
Poll::Ready(Err(e)) => return Poll::Ready(Err(Error::new(ErrorKind::Other, e))),
Poll::Ready(Ok(())) => {
// continue on
}
}
let Err(e) = this.start_send_unpin(msg) else {
return Poll::Ready(Ok(buf.len()));
};
Poll::Ready(Err(Error::new(ErrorKind::Other, e)))
}
fn poll_flush(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
let this = &mut self.get_mut().socket;
match this.poll_flush_unpin(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(Err(e)) => Poll::Ready(Err(Error::new(ErrorKind::Other, e))),
Poll::Ready(Ok(())) => Poll::Ready(Ok(()))
}
}
fn poll_shutdown(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Result<(), Error>> {
let this = &mut self.get_mut().socket;
match this.poll_close_unpin(cx) {
Poll::Pending => Poll::Pending,
Poll::Ready(Err(e)) => Poll::Ready(Err(Error::new(ErrorKind::Other, e))),
Poll::Ready(Ok(())) => Poll::Ready(Ok(()))
}
}
}
impl<T: AsyncRead + AsyncWrite + Unpin> AsyncRead for WebStreamSocket<T> {
fn poll_read(self: Pin<&mut Self>, cx: &mut Context<'_>, buf: &mut ReadBuf<'_>) -> Poll<io::Result<()>> {
let Self {
incoming_buffer,
socket,
finished_reading
} = &mut self.get_mut();
if !*finished_reading {
match socket.poll_next_unpin(cx) {
Poll::Ready(Some(Ok(msg))) => {
let Message::Binary(data) = msg else {
return Poll::Ready(Err(Error::new(ErrorKind::InvalidData, "got non binary data when trying to emulate stream")));
};
incoming_buffer.extend_from_slice(&data);
}
Poll::Ready(Some(Err(e))) if incoming_buffer.is_empty() => {
return Poll::Ready(Err(Error::new(ErrorKind::Other, e)));
}
Poll::Ready(None) if incoming_buffer.is_empty() => {
*finished_reading = true;
}
Poll::Pending if incoming_buffer.is_empty() => {
return Poll::Pending
}
_ => {}
}
}
if !incoming_buffer.is_empty(){
let read_ammount = buf.remaining();
let ammount_taken = read_ammount.min(incoming_buffer.len());
buf.put_slice(&incoming_buffer[0..ammount_taken]);
*incoming_buffer = (&incoming_buffer.get(ammount_taken..).unwrap_or(&[])).to_vec();
}
Poll::Ready(Ok(()))
/*if buf.remaining() == 0{
return Poll::Ready(Ok(()));
}
match socket.poll_next_unpin(cx) {
Poll::Ready(Some(Ok(msg))) => {
let Message::Binary(data) = msg else {
return Poll::Ready(Err(Error::new(ErrorKind::InvalidData, "got non binary data when trying to emulate stream")));
};
if data.len() <= buf.remaining() {
// if no data remains there is no reason to store anything
buf.put_slice(&data);
} else {
let read_ammount = buf.remaining();
let ammount_taken = read_ammount.min(data.len());
buf.put_slice(&data[..ammount_taken]);
*incoming_buffer = data[ammount_taken..].to_vec();
}
Poll::Ready(Ok(()))
}
Poll::Ready(Some(Err(e))) => Poll::Ready(Err(Error::new(ErrorKind::Other, e))),
// EOF
Poll::Ready(None) => Poll::Ready(Ok(())),
Poll::Pending => Poll::Pending
}*/
}
}
#[derive(Error, Debug)]
pub enum ConnectError{
#[error(transparent)]
Tungstenite(#[from] tungstenite::error::Error),
#[error(transparent)]
DataSendError(#[from] io::Error),
}
pub async fn rmc_connect_to<T: RmcCallable + Sync + Send + 'static, U: RmcSerialize, F>(url: &str, init_data: U, create_func: F) -> Result<Arc<T>, ConnectError>
where
F: FnOnce(RmcConnection) -> Arc<T>{
let (stream, _)= connect_async(format!("ws://{}/", url)).await?;
let webstreamsocket = WebStreamSocket::new(stream);
let connector = get_configured_tls_connector().await;
let mut connection = connector.connect(ServerName::try_from(url.to_string()).unwrap(), webstreamsocket).await.unwrap();
connection.send_buffer(&init_data.to_data()).await?;
let rmc = new_rmc_gateway_connection(connection.into(), create_func);
Ok(rmc)
}
#[tokio::test]
async fn test(){
setup();
let socket = connect_async("ws://192.168.178.120:12345/").await;
let (stream, resp) = socket.unwrap();
let mut webstreamsocket = WebStreamSocket::new(stream);
let connector = get_configured_tls_connector().await;
let connection = connector.connect(ServerName::try_from("agmp-tv.spfn.net").unwrap(), webstreamsocket).await.unwrap();
let rmc = new_rmc_gateway_connection(connection.into(), |r| {
Arc::new(OnlyRemote::<RemoteTestProto>::new(r))
});
println!("{:?}", rmc.test().await);
}
#[tokio::test]
async fn test_server(){
setup();
let socket = TcpListener::bind("192.168.178.120:12345").await.unwrap();
let acceptor = get_configured_tls_acceptor().await;
while let Ok((stream, _sock_addr)) = socket.accept().await{
let websocket = tokio_tungstenite::accept_async(stream).await.unwrap();
let webstreamsocket = WebStreamSocket::new(websocket);
let stream = acceptor.accept(webstreamsocket).await.unwrap();
new_rmc_gateway_connection(stream.into(), |_| {
Arc::new(
TestStruct
)
});
}
}

View file

@ -1,5 +1,4 @@
use macros::{method_id, rmc_proto};
use crate::prudp::station_url::StationUrl;
use crate::rmc::response::ErrorCode;
#[rmc_proto(50)]

View file

@ -10,28 +10,21 @@ pub mod matchmake_ext;
pub mod ranking;
use crate::util::{SendingBufferConnection, SplittableBufferConnection};
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 crate::rmc::structures::RmcSerialize;
use log::{error, info};
use macros::method_id;
use macros::{rmc_proto, rmc_struct};
use paste::paste;
use std::collections::HashMap;
use std::future::Future;
use std::io::Cursor;
use std::ops::{Add, Deref};
use std::sync::{Arc, Condvar};
use std::ops::Deref;
use std::sync::Arc;
use std::time::Duration;
use thiserror::Error;
use tokio::sync::{Mutex, Notify};
use tokio::time::{sleep_until, Instant};
use tokio::time::{sleep, sleep_until, Instant};
use crate::result::ResultExtension;
#[derive(Error, Debug)]
@ -74,6 +67,10 @@ impl RmcConnection {
Ok(())
}
pub async fn disconnect(&self){
self.0.disconnect().await;
}
}
impl RmcResponseReceiver {
@ -173,6 +170,9 @@ macro_rules! define_rmc_proto {
fn new(conn: rust_nex::rmc::protocols::RmcConnection) -> Self{
Self(conn)
}
async fn disconnect(&self){
self.0.disconnect().await;
}
}
impl rust_nex::rmc::protocols::HasRmcConnection for [<Remote $name>]{
@ -192,11 +192,11 @@ macro_rules! define_rmc_proto {
impl RmcCallable for () {
async fn rmc_call(
&self,
remote_response_connection: &SendingBufferConnection,
protocol_id: u16,
method_id: u32,
call_id: u32,
rest: Vec<u8>,
_remote_response_connection: &SendingBufferConnection,
_protocol_id: u16,
_method_id: u32,
_call_id: u32,
_rest: Vec<u8>,
) {
//todo: maybe reply with not implemented(?)
}
@ -204,6 +204,7 @@ impl RmcCallable for () {
pub trait RemoteInstantiatable{
fn new(conn: RmcConnection) -> Self;
async fn disconnect(&self);
}
pub struct OnlyRemote<T: RemoteInstantiatable>(T);
@ -220,10 +221,15 @@ impl<T: RemoteInstantiatable> OnlyRemote<T>{
pub fn new(conn: RmcConnection) -> Self{
Self(T::new(conn))
}
pub async fn disconnect(&self) {
self.0.disconnect().await;
}
}
impl<T: RemoteInstantiatable> RmcCallable for OnlyRemote<T>{
fn rmc_call(&self, responder: &SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>) -> impl std::future::Future<Output = ()> + Send {
fn rmc_call(&self, _responder: &SendingBufferConnection, _protocol_id: u16, _method_id: u32, _call_id: u32, _rest: Vec<u8>) -> impl Future<Output = ()> + Send {
// maybe respond with not implemented or something
async{}
}
}
@ -243,6 +249,12 @@ async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
return
};
// protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol
if *proto_id == 0{
println!("got keepalive");
continue;
}
if (proto_id & 0x80) == 0{
let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else {
error!("ending rmc gateway.");
@ -292,6 +304,8 @@ where
let rmc_conn = RmcConnection(sending_conn, response_recv);
let sending_conn = conn.duplicate_sender();
let exposed_object = (create_internal)(rmc_conn);
{
@ -304,7 +318,25 @@ where
incoming
).await;
});
tokio::spawn(async move {
while sending_conn.is_alive(){
sending_conn.send([0,0,0,0,0].to_vec()).await;
sleep(Duration::from_secs(10)).await;
}
});
}
exposed_object
}
impl<T: RmcCallable> RmcCallable for Arc<T>{
fn rmc_call(&self, responder: &SendingBufferConnection, protocol_id: u16, method_id: u32, call_id: u32, rest: Vec<u8>) -> impl Future<Output=()> + Send {
self.as_ref().rmc_call(responder, protocol_id, method_id, call_id, rest)
}
}
define_rmc_proto! {
proto NoProto{}
}

View file

@ -1,6 +1,5 @@
use macros::{method_id, rmc_proto};
use crate::rmc::response::ErrorCode;
use crate::rmc::structures::matchmake::{CreateMatchmakeSessionParam, MatchmakeSession};
#[rmc_proto(3)]
pub trait NatTraversal{

View file

@ -1,6 +1,4 @@
use macros::{method_id, rmc_proto, rmc_struct, RmcSerialize};
use crate::rmc::response::ErrorCode;
use crate::rmc::structures::qresult::QResult;
pub mod notification_types{
pub const OWNERSHIP_CHANGED: u32 = 4000;

View file

@ -1,4 +1,4 @@
use macros::{method_id, rmc_proto};
use macros::rmc_proto;
#[rmc_proto(112)]
pub trait Ranking{

View file

@ -1,8 +1,6 @@
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)]

View file

@ -1,3 +1,7 @@
// i seriously dont know why the compiler is complaining about unused parentheses in the repr
// attributes but this gets it to not complain anymore
#![allow(unused_parens)]
use std::io;
use std::io::{Read, Seek, Write};
use std::mem::transmute;
@ -5,14 +9,8 @@ use bytemuck::bytes_of;
use log::error;
use v_byte_macros::EnumTryInto;
use crate::endianness::{ReadExtensions, IS_BIG_ENDIAN};
use crate::prudp::packet::{PRUDPV1Packet};
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
use crate::prudp::packet::PacketOption::FragmentId;
use crate::prudp::packet::types::DATA;
use crate::prudp::socket::{ExternalConnection, SendingConnection};
use crate::rmc::response::ErrorCode::Core_Exception;
use crate::rmc::structures::qresult::ERROR_MASK;
use crate::rmc::structures::RmcSerialize;
use crate::util::SendingBufferConnection;
pub enum RMCResponseResult {
@ -72,7 +70,7 @@ impl RMCResponse {
error_code: {
match ErrorCode::try_from(error_code){
Ok(v) => v,
Err(e) => {
Err(()) => {
error!("invalid error code {:#010x}", error_code);
Core_Exception
}

View file

@ -18,7 +18,7 @@ impl<'a> RmcSerialize for &'a [u8]{
}
}
impl<'a> RmcSerialize for Box<[u8]>{
impl RmcSerialize for Box<[u8]>{
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
(&self[..]).serialize(writer)
}

View file

@ -1,8 +1,7 @@
use std::io::{Read, Write};
use bytemuck::bytes_of;
use macros::RmcSerialize;
use crate::kerberos::KerberosDateTime;
use crate::rmc::structures::{rmc_struct, RmcSerialize};
use crate::rmc::structures::RmcSerialize;
#[derive(Debug, RmcSerialize)]
#[rmc_struct(1)]

View file

@ -1,5 +1,8 @@
use std::array::from_fn;
use std::io::{Read, Write};
use std::mem::MaybeUninit;
use bytemuck::bytes_of;
use serde::Serialize;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use crate::rmc::structures::RmcSerialize;
@ -31,3 +34,27 @@ impl<T: RmcSerialize> RmcSerialize for Vec<T>{
Ok(vec)
}
}
impl<const LEN: usize, T: RmcSerialize> RmcSerialize for [T; LEN]{
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
for i in 0..LEN{
self[i].serialize(writer)?;
}
Ok(())
}
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
let mut arr = [const { MaybeUninit::<T>::uninit() }; LEN];
for i in 0..LEN{
arr[i] = MaybeUninit::new(T::deserialize(reader)?);
}
// all of the elements are now initialized so it is safe to assume they are initialized
let arr = arr.map(|v| unsafe{ v.assume_init() });
Ok(arr)
}
}

View file

@ -35,9 +35,9 @@ pub mod variant;
pub mod ranking;
mod networking;
pub trait RmcSerialize: Sized{
pub trait RmcSerialize{
fn serialize(&self, writer: &mut dyn Write) -> Result<()>;
fn deserialize(reader: &mut dyn Read) -> Result<Self>;
fn deserialize(reader: &mut dyn Read) -> Result<Self> where Self: Sized;
fn to_data(&self) -> Vec<u8>{
let mut data = Vec::new();

View file

@ -19,6 +19,7 @@ impl RmcSerialize for SocketAddrV4{
}
}
impl RmcSerialize for VirtualPort{
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
self.0.serialize(writer)?;

View file

@ -230,3 +230,12 @@ impl<T: RmcSerialize, U: RmcSerialize, V: RmcSerialize, W: RmcSerialize, X: RmcS
Ok((first, second, third, fourth, fifth, sixth, seventh))
}
}
impl<T: RmcSerialize> RmcSerialize for Box<T>{
fn serialize(&self, writer: &mut dyn Write) -> crate::rmc::structures::Result<()> {
self.as_ref().serialize(writer)
}
fn deserialize(reader: &mut dyn Read) -> crate::rmc::structures::Result<Self> {
T::deserialize(reader).map(Box::new)
}
}

View file

@ -2,7 +2,6 @@ use std::io::{Read, Write};
use bytemuck::bytes_of;
use crate::endianness::{IS_BIG_ENDIAN, ReadExtensions};
use crate::rmc::structures::{Result, RmcSerialize};
use crate::rmc::structures::qresult::QResult;
#[derive(Debug)]

View file

@ -1,5 +1,4 @@
use macros::RmcSerialize;
use crate::kerberos::KerberosDateTime;
use crate::prudp::sockaddr::PRUDPSockAddr;
#[derive(Debug, RmcSerialize)]

View file

@ -1,14 +1,14 @@
use std::cell::UnsafeCell;
use std::marker::PhantomData;
use std::ops::Deref;
use log::error;
use tokio::io::{AsyncRead, AsyncWrite};
use std::sync::Arc;
use log::{error, info};
use tokio::io::{AsyncRead, AsyncWrite, AsyncWriteExt};
use tokio::sync::mpsc::{channel, Receiver, Sender};
use tokio::sync::Notify;
use tokio::task;
use rust_nex::reggie::{UnitPacketRead, UnitPacketWrite};
#[derive(Clone)]
pub struct SendingBufferConnection(Sender<Vec<u8>>);
pub struct SendingBufferConnection(Sender<Vec<u8>>, Arc<Notify>);
pub struct SplittableBufferConnection(SendingBufferConnection, Receiver<Vec<u8>>);
@ -39,41 +39,53 @@ impl SplittableBufferConnection {
let (outside_send, inside_recv) = channel::<Vec<u8>>(10);
let (inside_send, outside_recv) = channel::<Vec<u8>>(10);
task::spawn(async move {
let sender = inside_send;
let mut recver = inside_recv;
let mut stream = stream;
loop {
tokio::select! {
data = recver.recv() => {
let Some(data) = data else {
break;
};
let notify = Arc::new(Notify::new());
if let Err(e) = stream.send_buffer(&data[..]).await{
error!("error sending data to backend: {}", e);
break;
}
},
data = stream.read_buffer() => {
let data = match data{
Ok(d) => d,
Err(e) => {
error!("error reveiving data from backend: {}", e);
{
let notify = notify.clone();
task::spawn(async move {
let sender = inside_send;
let mut recver = inside_recv;
let mut stream = stream;
loop {
tokio::select! {
data = recver.recv() => {
let Some(data) = data else {
break;
};
if let Err(e) = stream.send_buffer(&data[..]).await{
error!("error sending data to backend: {}", e);
break;
}
};
},
data = stream.read_buffer() => {
let data = match data{
Ok(d) => d,
Err(e) => {
error!("error reveiving data from backend: {}", e);
break;
}
};
if let Err(e) = sender.send(data).await{
error!("a send error occurred {}", e);
return;
if let Err(e) = sender.send(data).await{
error!("a send error occurred {}", e);
return;
}
},
_ = notify.notified() => {
info!("shutting down connection");
break;
}
},
}
}
}
});
stream.shutdown().await;
});
}
Self(SendingBufferConnection(outside_send), outside_recv)
Self(SendingBufferConnection(outside_send, notify), outside_recv)
}
}
@ -81,6 +93,15 @@ impl SendingBufferConnection{
pub async fn send(&self, buffer: Vec<u8>) -> Option<()>{
self.0.send(buffer).await.ok()
}
pub fn is_alive(&self) -> bool{
!self.0.is_closed()
}
pub async fn disconnect(&self) {
while !self.0.is_closed() {
self.1.notify_waiters();
tokio::task::yield_now().await;
}
}
}
impl SplittableBufferConnection{

View file

@ -1,6 +1,6 @@
use std::marker::PhantomData;
use std::ops::{BitAnd, BitOr};
use typenum::{Cmp, IsEqual, IsLess, IsLessOrEqual, Unsigned, U1, U2, U3};
use typenum::{Cmp, IsEqual, IsLess, IsLessOrEqual, Unsigned};
/// This trait represents a version at compile time
trait Version{

View file

@ -1,15 +1,10 @@
use std::net::SocketAddrV4;
use std::sync::Arc;
use async_trait::async_trait;
use once_cell::sync::Lazy;
use rocket::{get, routes, Request, Rocket, State};
use rocket::{get, routes, Request, State};
use rocket::request::{FromRequest, Outcome};
use rocket::serde::json::Json;
use tokio::task::JoinHandle;
use serde::Serialize;
use tokio::sync::Mutex;
use crate::nex::matchmake::MatchmakeManager;
use crate::rmc::protocols::HasRmcConnection;
use crate::rmc::protocols::notifications::NotificationEvent;
struct RnexApiAuth;