things
This commit is contained in:
parent
4d4fc6c7bf
commit
fc94f655b2
43 changed files with 1957 additions and 694 deletions
1
.gitignore
vendored
1
.gitignore
vendored
|
|
@ -3,3 +3,4 @@ target
|
||||||
.env
|
.env
|
||||||
log
|
log
|
||||||
reports
|
reports
|
||||||
|
.zed
|
||||||
|
|
|
||||||
60
Cargo.lock
generated
60
Cargo.lock
generated
|
|
@ -134,9 +134,9 @@ dependencies = [
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "cfg-if"
|
name = "cfg-if"
|
||||||
version = "1.0.1"
|
version = "1.0.4"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "9555578bc9e57714c812a1f84e4fc5b4d21fcb063490c624de019f7464c91268"
|
checksum = "9330f8b2ff13f34540b44e946ef35111825727b38d33286ef986142615121801"
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "chrono"
|
name = "chrono"
|
||||||
|
|
@ -385,16 +385,6 @@ dependencies = [
|
||||||
"syn 2.0.104",
|
"syn 2.0.104",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "macros"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "git+https://github.com/DJMrTV/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69"
|
|
||||||
dependencies = [
|
|
||||||
"proc-macro2",
|
|
||||||
"quote",
|
|
||||||
"syn 1.0.109",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "macros"
|
name = "macros"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
|
|
@ -547,10 +537,39 @@ dependencies = [
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "prudpv0"
|
name = "proxy"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"cfg-if",
|
||||||
|
"prudpv0",
|
||||||
|
"prudpv1",
|
||||||
|
"rnex-core",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "proxy-common"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"rnex-core",
|
"rnex-core",
|
||||||
|
"thiserror",
|
||||||
|
"tokio",
|
||||||
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "prudpv0"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"bytemuck",
|
||||||
|
"cfg-if",
|
||||||
|
"hmac",
|
||||||
|
"log",
|
||||||
|
"md-5",
|
||||||
|
"proxy-common",
|
||||||
|
"rc4",
|
||||||
|
"rnex-core",
|
||||||
|
"tokio",
|
||||||
|
"typenum",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -568,7 +587,7 @@ dependencies = [
|
||||||
"thiserror",
|
"thiserror",
|
||||||
"tokio",
|
"tokio",
|
||||||
"typenum",
|
"typenum",
|
||||||
"v-byte-helpers 0.1.1 (git+https://github.com/RusticMaple/VByteMacros)",
|
"v-byte-helpers",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -665,7 +684,7 @@ dependencies = [
|
||||||
"tokio",
|
"tokio",
|
||||||
"typenum",
|
"typenum",
|
||||||
"ureq",
|
"ureq",
|
||||||
"v-byte-helpers 0.1.1 (git+https://github.com/DJMrTV/VByteMacros)",
|
"v-byte-helpers",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
@ -969,22 +988,13 @@ version = "0.7.6"
|
||||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||||
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
checksum = "09cc8ee72d2a9becf2f2febe0205bbed8fc6615b7cb429ad062dc7b7ddd036a9"
|
||||||
|
|
||||||
[[package]]
|
|
||||||
name = "v-byte-helpers"
|
|
||||||
version = "0.1.1"
|
|
||||||
source = "git+https://github.com/DJMrTV/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69"
|
|
||||||
dependencies = [
|
|
||||||
"bytemuck",
|
|
||||||
"macros 0.1.1 (git+https://github.com/DJMrTV/VByteMacros)",
|
|
||||||
]
|
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "v-byte-helpers"
|
name = "v-byte-helpers"
|
||||||
version = "0.1.1"
|
version = "0.1.1"
|
||||||
source = "git+https://github.com/RusticMaple/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69"
|
source = "git+https://github.com/RusticMaple/VByteMacros#e2f31bded8c5591e847ba03faf79ae0351e43e69"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bytemuck",
|
"bytemuck",
|
||||||
"macros 0.1.1 (git+https://github.com/RusticMaple/VByteMacros)",
|
"macros 0.1.1",
|
||||||
]
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
|
|
|
||||||
|
|
@ -5,4 +5,4 @@ members = [
|
||||||
"rnex-core",
|
"rnex-core",
|
||||||
"prudpv1",
|
"prudpv1",
|
||||||
"prudpv0"
|
"prudpv0"
|
||||||
]
|
, "proxy", "proxy-common"]
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,7 @@ fi
|
||||||
source ./buildscripts/common.sh
|
source ./buildscripts/common.sh
|
||||||
echo FEATURES:
|
echo FEATURES:
|
||||||
echo $EDITION_FEATURES
|
echo $EDITION_FEATURES
|
||||||
|
echo ENV SETTINGS:
|
||||||
|
env
|
||||||
|
|
||||||
OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl
|
OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo build --release --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl
|
||||||
|
|
@ -6,4 +6,5 @@ IFS=$'\n'
|
||||||
while IFS=$'\n' read -r KEY; do
|
while IFS=$'\n' read -r KEY; do
|
||||||
VAL=$(yq ea ".$EDITION.settings.$KEY" editions.yaml)
|
VAL=$(yq ea ".$EDITION.settings.$KEY" editions.yaml)
|
||||||
declare "$KEY=$VAL"
|
declare "$KEY=$VAL"
|
||||||
|
export $KEY
|
||||||
done <<< "$SETTINGS"
|
done <<< "$SETTINGS"
|
||||||
|
|
@ -6,4 +6,5 @@ splatoon:
|
||||||
friends:
|
friends:
|
||||||
features:
|
features:
|
||||||
- friends
|
- friends
|
||||||
settings: {}
|
settings:
|
||||||
|
RNEX_VIRTUAL_PORT: 1:10
|
||||||
|
|
|
||||||
9
proxy-common/Cargo.toml
Normal file
9
proxy-common/Cargo.toml
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[package]
|
||||||
|
name = "proxy-common"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
thiserror = "2.0.12"
|
||||||
|
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||||
|
tokio = { version = "1.47.0", features = ["full"] }
|
||||||
209
proxy-common/src/lib.rs
Normal file
209
proxy-common/src/lib.rs
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
use rnex_core::{
|
||||||
|
executables::common::{OWN_IP_PUBLIC, try_get_ip},
|
||||||
|
prudp::{socket_addr::PRUDPSockAddr, virtual_port::VirtualPort},
|
||||||
|
reggie::{RemoteEdgeNodeHolder, UnitPacketWrite},
|
||||||
|
rmc::{
|
||||||
|
protocols::{
|
||||||
|
OnlyRemote, RemoteDisconnectable, RmcCallable, RmcConnection, RmcPureRemoteObject,
|
||||||
|
new_rmc_gateway_connection,
|
||||||
|
},
|
||||||
|
structures::RmcSerialize,
|
||||||
|
},
|
||||||
|
rnex_proxy_common::ConnectionInitData,
|
||||||
|
util::{SendingBufferConnection, SplittableBufferConnection},
|
||||||
|
};
|
||||||
|
use std::{
|
||||||
|
env::{self, VarError},
|
||||||
|
error,
|
||||||
|
net::{AddrParseError, IpAddr, Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||||
|
ops::Deref,
|
||||||
|
panic,
|
||||||
|
str::FromStr,
|
||||||
|
sync::{Arc, LazyLock},
|
||||||
|
};
|
||||||
|
use thiserror::Error;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
|
||||||
|
const RNEX_DEFAULT_PORT: u16 = match u16::from_str_radix(env!("RNEX_DEFAULT_PORT"), 10) {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(_) => panic!("unable to get default port from env"),
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Error, Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
#[error("error getting environment variable \"{0}\": {1}")]
|
||||||
|
UnableToGetEnv(&'static str, VarError),
|
||||||
|
#[error("error parsing ip address environment variable \"{0}\": {1}")]
|
||||||
|
AddrParse(&'static str, AddrParseError),
|
||||||
|
#[error(
|
||||||
|
"error error getting public ip address: \n\tattempted to read from env var \"SERVER_IP_PUBLIC\" and got: {0} \n\tattempted to request from internet and failed with: {1}"
|
||||||
|
)]
|
||||||
|
PubAddrGetErr(Box<Self>, Box<dyn error::Error>),
|
||||||
|
}
|
||||||
|
impl Into<Error> for (&'static str, AddrParseError) {
|
||||||
|
fn into(self) -> Error {
|
||||||
|
Error::AddrParse(self.0, self.1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct ProxyStartupParam {
|
||||||
|
pub forward_destination: SocketAddr,
|
||||||
|
pub edge_node_holder: SocketAddr,
|
||||||
|
pub self_public: SocketAddrV4,
|
||||||
|
pub self_private: SocketAddrV4,
|
||||||
|
pub virtual_port: VirtualPort,
|
||||||
|
}
|
||||||
|
|
||||||
|
fn try_get_env<T: FromStr>(name: &'static str) -> Result<T, Error>
|
||||||
|
where
|
||||||
|
(&'static str, T::Err): Into<Error>,
|
||||||
|
{
|
||||||
|
T::from_str(&env::var(name).map_err(|e| Error::UnableToGetEnv(name, e))?)
|
||||||
|
.map_err(|e| (name, e).into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub enum ProxyType {
|
||||||
|
Insecure,
|
||||||
|
Secure,
|
||||||
|
}
|
||||||
|
const VIRTUAL_PORT_INSECURE: LazyLock<VirtualPort> =
|
||||||
|
LazyLock::new(|| VirtualPort::parse(env!("RNEX_VIRTUAL_PORT_INSECURE")).unwrap());
|
||||||
|
const VIRTUAL_PORT_SECURE: LazyLock<VirtualPort> =
|
||||||
|
LazyLock::new(|| VirtualPort::parse(env!("RNEX_VIRTUAL_PORT_SECURE")).unwrap());
|
||||||
|
impl ProxyStartupParam {
|
||||||
|
pub fn new(prox_ty: ProxyType) -> Result<Self, Error> {
|
||||||
|
let port = RNEX_DEFAULT_PORT
|
||||||
|
+ match prox_ty {
|
||||||
|
ProxyType::Insecure => 0,
|
||||||
|
ProxyType::Secure => 1,
|
||||||
|
};
|
||||||
|
let self_private = try_get_env("SERVER_IP_PRIVATE")
|
||||||
|
.unwrap_or(SocketAddrV4::new(Ipv4Addr::UNSPECIFIED, RNEX_DEFAULT_PORT));
|
||||||
|
let self_public: SocketAddrV4 = match try_get_env("SERVER_IP_PUBLIC") {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => try_get_ip()
|
||||||
|
.map(|v| SocketAddrV4::new(v, RNEX_DEFAULT_PORT))
|
||||||
|
.map_err(move |v| Error::PubAddrGetErr(Box::new(e), v))?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(Self {
|
||||||
|
forward_destination: try_get_env("EDGE_NODE_HOLDER")?,
|
||||||
|
edge_node_holder: try_get_env("FORWARD_DESTINATION")?,
|
||||||
|
self_private,
|
||||||
|
self_public,
|
||||||
|
virtual_port: match prox_ty {
|
||||||
|
ProxyType::Insecure => *VIRTUAL_PORT_INSECURE,
|
||||||
|
ProxyType::Secure => *VIRTUAL_PORT_SECURE,
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct OnRemoteDrop<T: RemoteDisconnectable, C: FnOnce() + Send + Sync + 'static>(T, Option<C>);
|
||||||
|
impl<T: RemoteDisconnectable, C: FnOnce() + Send + Sync + 'static> Deref for OnRemoteDrop<T, C> {
|
||||||
|
type Target = T;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we had something like a thread safe OnceConsume (basically the opposite of OnceLock)
|
||||||
|
// we could make C be an FnOnce
|
||||||
|
impl<T: RemoteDisconnectable + RmcPureRemoteObject, C: FnOnce() + Send + Sync + 'static>
|
||||||
|
OnRemoteDrop<T, C>
|
||||||
|
{
|
||||||
|
pub fn new(conn: RmcConnection, drop_func: C) -> Self {
|
||||||
|
Self(T::new(conn), Some(drop_func))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn disconnect(&self) {
|
||||||
|
self.0.disconnect().await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RemoteDisconnectable, C: FnOnce() + Send + Sync + 'static> RmcCallable
|
||||||
|
for OnRemoteDrop<T, C>
|
||||||
|
{
|
||||||
|
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 {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RemoteDisconnectable, C: FnOnce() + Send + Sync + 'static> Drop for OnRemoteDrop<T, C> {
|
||||||
|
fn drop(&mut self) {
|
||||||
|
self.1.take().unwrap()();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn setup_edge_node_connection(
|
||||||
|
param: &ProxyStartupParam,
|
||||||
|
shutdown_callback: impl FnOnce() + Send + Sync + 'static,
|
||||||
|
) {
|
||||||
|
let conn = tokio::net::TcpStream::connect(¶m.edge_node_holder)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
let conn: SplittableBufferConnection = conn.into();
|
||||||
|
|
||||||
|
conn.send(
|
||||||
|
rnex_core::reggie::EdgeNodeHolderConnectOption::Register(param.self_public)
|
||||||
|
.to_data()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
//leave the inner object floating so that it gets destroyed once we disconnect
|
||||||
|
new_rmc_gateway_connection(conn, move |r| {
|
||||||
|
Arc::new(OnRemoteDrop::<RemoteEdgeNodeHolder, _>::new(
|
||||||
|
r,
|
||||||
|
shutdown_callback,
|
||||||
|
))
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn new_backend_connection(
|
||||||
|
param: &ProxyStartupParam,
|
||||||
|
addr: PRUDPSockAddr,
|
||||||
|
pid: u32,
|
||||||
|
) -> Option<SplittableBufferConnection> {
|
||||||
|
let mut stream = match TcpStream::connect(param.forward_destination).await {
|
||||||
|
Ok(v) => v,
|
||||||
|
Err(e) => {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
if let Err(e) = stream
|
||||||
|
.send_buffer(
|
||||||
|
&ConnectionInitData {
|
||||||
|
prudpsock_addr: addr,
|
||||||
|
pid: pid,
|
||||||
|
}
|
||||||
|
.to_data()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
return None;
|
||||||
|
};
|
||||||
|
|
||||||
|
Some(stream.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod test {
|
||||||
|
use crate::{VIRTUAL_PORT_INSECURE, VIRTUAL_PORT_SECURE};
|
||||||
|
|
||||||
|
fn test_virtual_port_correct() {
|
||||||
|
println!("{:?}", VIRTUAL_PORT_INSECURE);
|
||||||
|
println!("{:?}", VIRTUAL_PORT_SECURE);
|
||||||
|
}
|
||||||
|
}
|
||||||
25
proxy/Cargo.toml
Normal file
25
proxy/Cargo.toml
Normal file
|
|
@ -0,0 +1,25 @@
|
||||||
|
[package]
|
||||||
|
name = "proxy"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2024"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
tokio = { version = "1.47.0", features = ["full"] }
|
||||||
|
prudpv0 = { path = "../prudpv0", optional = true }
|
||||||
|
prudpv1 = { path = "../prudpv1", optional = true }
|
||||||
|
cfg-if = "1.0.4"
|
||||||
|
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||||
|
|
||||||
|
[features]
|
||||||
|
prudpv0 = ["dep:prudpv0"]
|
||||||
|
prudpv1 = ["dep:prudpv1"]
|
||||||
|
friends = ["prudpv0", "prudpv0/friends"]
|
||||||
|
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "proxy_insecure"
|
||||||
|
path = "src/insecure.rs"
|
||||||
|
|
||||||
|
[[bin]]
|
||||||
|
name = "proxy_secure"
|
||||||
|
path = "src/secure.rs"
|
||||||
8
proxy/src/insecure.rs
Normal file
8
proxy/src/insecure.rs
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
use rnex_core::common::setup;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
setup();
|
||||||
|
|
||||||
|
proxy::start_insecure(ProxyStartupParam::new()).await;
|
||||||
|
}
|
||||||
11
proxy/src/lib.rs
Normal file
11
proxy/src/lib.rs
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "prudpv0")]{
|
||||||
|
pub use prudpv0::*;
|
||||||
|
} else if #[cfg(feature = "prudpv1")] {
|
||||||
|
pub use prudpv1::*;
|
||||||
|
} else {
|
||||||
|
compile_error!("no proxy type has been set");
|
||||||
|
}
|
||||||
|
}
|
||||||
7
proxy/src/secure.rs
Normal file
7
proxy/src/secure.rs
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
use rnex_core::common::setup;
|
||||||
|
|
||||||
|
#[tokio::main]
|
||||||
|
async fn main() {
|
||||||
|
setup();
|
||||||
|
proxy::start_secure(ProxyStartupParam::new()).await;
|
||||||
|
}
|
||||||
|
|
@ -5,3 +5,15 @@ edition = "2024"
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
rnex-core = { path = "../rnex-core", version = "0.1.1" }
|
||||||
|
tokio = { version = "1.47.0", features = ["full"] }
|
||||||
|
bytemuck = { version = "1.23.1", features = ["derive"] }
|
||||||
|
typenum = "1.18.0"
|
||||||
|
rc4 = "0.1.0"
|
||||||
|
log = "0.4.25"
|
||||||
|
cfg-if = "1.0.4"
|
||||||
|
proxy-common = {path = "../proxy-common"}
|
||||||
|
hmac = "0.12.1"
|
||||||
|
md-5 = "^0.10.6"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
friends = []
|
||||||
|
|
|
||||||
54
prudpv0/src/crypto/common_crypto.rs
Normal file
54
prudpv0/src/crypto/common_crypto.rs
Normal file
|
|
@ -0,0 +1,54 @@
|
||||||
|
trait IterExtra: Iterator {
|
||||||
|
fn sum_wrapping_u8(&mut self) -> u8
|
||||||
|
where
|
||||||
|
Self::Item: Into<u8>;
|
||||||
|
|
||||||
|
fn sum_wrapping_u32(&mut self) -> u32
|
||||||
|
where
|
||||||
|
Self::Item: Into<u32>;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Iterator> IterExtra for T {
|
||||||
|
fn sum_wrapping_u8(&mut self) -> u8
|
||||||
|
where
|
||||||
|
Self::Item: Into<u8>,
|
||||||
|
{
|
||||||
|
let mut sum = 0u8;
|
||||||
|
for v in self {
|
||||||
|
let val: u8 = v.into();
|
||||||
|
sum = sum.wrapping_add(val);
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
fn sum_wrapping_u32(&mut self) -> u32
|
||||||
|
where
|
||||||
|
Self::Item: Into<u32>,
|
||||||
|
{
|
||||||
|
let mut sum = 0u32;
|
||||||
|
for v in self {
|
||||||
|
let val: u32 = v.into();
|
||||||
|
sum = sum.wrapping_add(val);
|
||||||
|
}
|
||||||
|
sum
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn common_checksum(access_key: &str, data: &[u8]) -> u8 {
|
||||||
|
let leftover = data.len() % 4;
|
||||||
|
let word_sum = bytemuck::cast_slice::<_, u32>(&data[..data.len() - leftover])
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.sum_wrapping_u32();
|
||||||
|
|
||||||
|
let checksum = access_key.as_bytes().iter().copied().sum_wrapping_u8();
|
||||||
|
let checksum = checksum.wrapping_add(
|
||||||
|
(&data[data.len() - leftover..])
|
||||||
|
.iter()
|
||||||
|
.copied()
|
||||||
|
.sum_wrapping_u8(),
|
||||||
|
);
|
||||||
|
let checksum = checksum.wrapping_add(word_sum.to_ne_bytes().into_iter().sum_wrapping_u8());
|
||||||
|
|
||||||
|
checksum
|
||||||
|
}
|
||||||
5
prudpv0/src/crypto/friends_common.rs
Normal file
5
prudpv0/src/crypto/friends_common.rs
Normal file
|
|
@ -0,0 +1,5 @@
|
||||||
|
use hmac::Hmac;
|
||||||
|
use md5::Md5;
|
||||||
|
|
||||||
|
pub const ACCESS_KEY: &str = "ridfebb9";
|
||||||
|
pub type HmacMd5 = Hmac<Md5>;
|
||||||
52
prudpv0/src/crypto/friends_insecure.rs
Normal file
52
prudpv0/src/crypto/friends_insecure.rs
Normal file
|
|
@ -0,0 +1,52 @@
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
|
use hmac::Mac;
|
||||||
|
use rc4::{KeyInit, Rc4, StreamCipher};
|
||||||
|
use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair};
|
||||||
|
use typenum::U5;
|
||||||
|
|
||||||
|
use crate::crypto::{
|
||||||
|
Crypto, CryptoInstance,
|
||||||
|
common_crypto::common_checksum,
|
||||||
|
friends_common::{ACCESS_KEY, HmacMd5},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct InsecureInstance {
|
||||||
|
pair: EncryptionPair<Rc4<U5>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CryptoInstance for InsecureInstance {
|
||||||
|
fn decrypt_incoming(&mut self, data: &mut [u8]) {
|
||||||
|
self.pair.recv.apply_keystream(data);
|
||||||
|
}
|
||||||
|
fn encrypt_outgoing(&mut self, data: &mut [u8]) {
|
||||||
|
self.pair.send.apply_keystream(data);
|
||||||
|
}
|
||||||
|
fn get_user_id(&self) -> u32 {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
fn generate_signature(&self, data: &[u8]) -> [u8; 4] {
|
||||||
|
let mut hmac = <HmacMd5 as Mac>::new_from_slice(ACCESS_KEY.as_bytes())
|
||||||
|
.expect("unable to create hmac md5");
|
||||||
|
hmac.update(data);
|
||||||
|
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Insecure();
|
||||||
|
|
||||||
|
impl Crypto for Insecure {
|
||||||
|
type Instance = InsecureInstance;
|
||||||
|
fn new() -> Self {
|
||||||
|
Self()
|
||||||
|
}
|
||||||
|
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
||||||
|
common_checksum(ACCESS_KEY, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instantiate(&self, packet_data: &[u8]) -> Self::Instance {
|
||||||
|
InsecureInstance {
|
||||||
|
pair: EncryptionPair::init_both(|| Rc4::new(&DEFAULT_KEY)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
47
prudpv0/src/crypto/friends_secure.rs
Normal file
47
prudpv0/src/crypto/friends_secure.rs
Normal file
|
|
@ -0,0 +1,47 @@
|
||||||
|
use hmac::Mac;
|
||||||
|
use rc4::Rc4;
|
||||||
|
use rnex_core::prudp::encryption::EncryptionPair;
|
||||||
|
use typenum::U32;
|
||||||
|
|
||||||
|
use crate::crypto::{
|
||||||
|
Crypto, CryptoInstance,
|
||||||
|
common_crypto::common_checksum,
|
||||||
|
friends_common::{ACCESS_KEY, HmacMd5},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct SecureInstance {
|
||||||
|
pair: EncryptionPair<Rc4<U32>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl CryptoInstance for SecureInstance {
|
||||||
|
fn decrypt_incoming(&mut self, data: &mut [u8]) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn encrypt_outgoing(&mut self, data: &mut [u8]) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn get_user_id(&self) -> u32 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
fn generate_signature(&self, data: &[u8]) -> [u8; 4] {
|
||||||
|
let mut hmac = <HmacMd5 as Mac>::new_from_slice(ACCESS_KEY.as_bytes())
|
||||||
|
.expect("unable to create hmac md5");
|
||||||
|
hmac.update(data);
|
||||||
|
hmac.finalize().into_bytes()[0..4].try_into().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Secure();
|
||||||
|
|
||||||
|
impl Crypto for Secure {
|
||||||
|
type Instance = SecureInstance;
|
||||||
|
fn new() -> Self {
|
||||||
|
Self()
|
||||||
|
}
|
||||||
|
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
||||||
|
common_checksum(ACCESS_KEY, data)
|
||||||
|
}
|
||||||
|
fn instantiate(&self, data: &[u8]) -> Self::Instance {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
9
prudpv0/src/crypto/insecure.rs
Normal file
9
prudpv0/src/crypto/insecure.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
use crate::crypto::Crypto;
|
||||||
|
|
||||||
|
pub struct Insecure();
|
||||||
|
|
||||||
|
impl Crypto for Insecure {
|
||||||
|
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
32
prudpv0/src/crypto/mod.rs
Normal file
32
prudpv0/src/crypto/mod.rs
Normal file
|
|
@ -0,0 +1,32 @@
|
||||||
|
use cfg_if::cfg_if;
|
||||||
|
|
||||||
|
mod common_crypto;
|
||||||
|
|
||||||
|
pub trait CryptoInstance: Send + 'static {
|
||||||
|
fn decrypt_incoming(&mut self, data: &mut [u8]);
|
||||||
|
fn encrypt_outgoing(&mut self, data: &mut [u8]);
|
||||||
|
fn generate_signature(&self, data: &[u8]) -> [u8; 4];
|
||||||
|
fn get_user_id(&self) -> u32;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait Crypto: Send + Sync + 'static {
|
||||||
|
type Instance: CryptoInstance;
|
||||||
|
fn new() -> Self;
|
||||||
|
fn calculate_checksum(&self, data: &[u8]) -> u8;
|
||||||
|
fn instantiate(&self, data: &[u8]) -> Self::Instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature = "friends")]{
|
||||||
|
pub mod friends_common;
|
||||||
|
pub mod friends_insecure;
|
||||||
|
pub use friends_insecure::*;
|
||||||
|
pub mod friends_secure;
|
||||||
|
pub use friends_secure::*;
|
||||||
|
} else {
|
||||||
|
pub mod secure;
|
||||||
|
pub use secure::*;
|
||||||
|
pub mod insecure;
|
||||||
|
pub use insecure::*;
|
||||||
|
}
|
||||||
|
}
|
||||||
9
prudpv0/src/crypto/secure.rs
Normal file
9
prudpv0/src/crypto/secure.rs
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
use crate::crypto::Crypto;
|
||||||
|
|
||||||
|
pub struct Secure();
|
||||||
|
|
||||||
|
impl Crypto for Secure {
|
||||||
|
fn calculate_checksum(&self, data: &[u8]) -> u8 {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,62 @@
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use log::{error, info, warn};
|
||||||
|
use proxy_common::{ProxyStartupParam, setup_edge_node_connection};
|
||||||
|
use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT};
|
||||||
|
use rnex_core::prudp::types_flags::TypesFlags;
|
||||||
|
use rnex_core::prudp::types_flags::types::SYN;
|
||||||
|
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||||
|
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
||||||
|
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
||||||
|
use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection};
|
||||||
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
|
use rnex_core::util::SplittableBufferConnection;
|
||||||
|
use std::env;
|
||||||
|
use std::net::SocketAddrV4;
|
||||||
|
use std::process::abort;
|
||||||
|
use std::sync::{Arc, LazyLock};
|
||||||
|
use tokio::net::UdpSocket;
|
||||||
|
|
||||||
|
use crate::crypto::{Crypto, Insecure, Secure};
|
||||||
|
use crate::packet::PRUDPV0Packet;
|
||||||
|
use crate::server::Server;
|
||||||
|
|
||||||
|
mod crypto;
|
||||||
|
mod packet;
|
||||||
|
mod server;
|
||||||
|
|
||||||
|
pub static EDGE_NODE_HOLDER: LazyLock<SocketAddrV4> = LazyLock::new(|| {
|
||||||
|
env::var("EDGE_NODE_HOLDER")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.parse().ok())
|
||||||
|
.expect("EDGE_NODE_HOLDER not set")
|
||||||
|
});
|
||||||
|
|
||||||
|
pub static FORWARD_DESTINATION: LazyLock<SocketAddrV4> = LazyLock::new(|| {
|
||||||
|
env::var("FORWARD_DESTINATION")
|
||||||
|
.ok()
|
||||||
|
.and_then(|s| s.parse().ok())
|
||||||
|
.expect("FORWARD_DESTINATION not set")
|
||||||
|
});
|
||||||
|
//same as with prudpv1 this is responsible for handeling the different cryptography
|
||||||
|
//implementations, e.g. secure and insecure(this also includes special cases like friends)
|
||||||
|
|
||||||
|
async fn start_proxy<T: Crypto>(param: ProxyStartupParam) {
|
||||||
|
setup_edge_node_connection(¶m, || abort());
|
||||||
|
|
||||||
|
info!("creating cryptography instance");
|
||||||
|
let mut crypto = Arc::new(T::new());
|
||||||
|
info!("binding to socket");
|
||||||
|
|
||||||
|
let server: Arc<Server<T>> = Arc::new(Server::new().await);
|
||||||
|
|
||||||
|
info!("waiting on packets");
|
||||||
|
server.run_task().await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_secure(param: ProxyStartupParam) {
|
||||||
|
start_proxy::<Secure>(param).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn start_insecure(param: ProxyStartupParam) {
|
||||||
|
start_proxy::<Insecure>(param).await;
|
||||||
|
}
|
||||||
187
prudpv0/src/packet.rs
Normal file
187
prudpv0/src/packet.rs
Normal file
|
|
@ -0,0 +1,187 @@
|
||||||
|
use std::mem::transmute;
|
||||||
|
|
||||||
|
use bytemuck::{Pod, Zeroable, try_from_bytes, try_from_bytes_mut};
|
||||||
|
use log::error;
|
||||||
|
use rnex_core::prudp::{
|
||||||
|
types_flags::{
|
||||||
|
TypesFlags,
|
||||||
|
flags::{HAS_SIZE, NEED_ACK},
|
||||||
|
types::{CONNECT, DATA, SYN},
|
||||||
|
},
|
||||||
|
virtual_port::VirtualPort,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::crypto::{Crypto, CryptoInstance};
|
||||||
|
|
||||||
|
#[repr(C, packed)]
|
||||||
|
#[derive(Clone, Copy, Pod, Zeroable, Debug)]
|
||||||
|
pub struct PRUDPV0Header {
|
||||||
|
pub source: VirtualPort,
|
||||||
|
pub destination: VirtualPort,
|
||||||
|
pub type_flags: TypesFlags,
|
||||||
|
pub session_id: u8,
|
||||||
|
pub packet_signature: [u8; 4],
|
||||||
|
pub sequence_id: u16,
|
||||||
|
}
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct PRUDPV0Packet<T: AsRef<[u8]>>(pub T);
|
||||||
|
|
||||||
|
impl<T: AsRef<[u8]>> PRUDPV0Packet<T> {
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn get_packet_specific_size(&self) -> Option<usize> {
|
||||||
|
Some(get_types_flags_size_from_types_flags(
|
||||||
|
self.header()?.type_flags,
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn header(&self) -> Option<&PRUDPV0Header> {
|
||||||
|
try_from_bytes(self.0.as_ref().get(..size_of::<PRUDPV0Header>())?).ok()
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn header_mut(&mut self) -> Option<&mut PRUDPV0Header>
|
||||||
|
where
|
||||||
|
T: AsMut<[u8]>,
|
||||||
|
{
|
||||||
|
try_from_bytes_mut(self.0.as_mut().get_mut(..size_of::<PRUDPV0Header>())?).ok()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn connection_signature(&self) -> Option<&[u8; 4]> {
|
||||||
|
let offset = size_of::<PRUDPV0Header>();
|
||||||
|
Some(self.0.as_ref().get(offset..offset + 4)?.try_into().ok()?)
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn connection_signature_mut(&mut self) -> Option<&mut [u8; 4]>
|
||||||
|
where
|
||||||
|
T: AsMut<[u8]>,
|
||||||
|
{
|
||||||
|
let offset = size_of::<PRUDPV0Header>();
|
||||||
|
Some(
|
||||||
|
self.0
|
||||||
|
.as_mut()
|
||||||
|
.get_mut(offset..offset + 4)?
|
||||||
|
.try_into()
|
||||||
|
.ok()?,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
fn get_payload_offset(&self) -> Option<usize> {
|
||||||
|
Some(size_of::<PRUDPV0Header>() + self.get_packet_specific_size()?)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn payload(&self) -> Option<&[u8]> {
|
||||||
|
self.0
|
||||||
|
.as_ref()
|
||||||
|
.get(self.get_payload_offset()?..(self.0.as_ref().len().saturating_sub(1)))
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn payload_mut(&mut self) -> Option<&mut [u8]>
|
||||||
|
where
|
||||||
|
T: AsMut<[u8]>,
|
||||||
|
{
|
||||||
|
let start_offset = self.get_payload_offset()?;
|
||||||
|
let end_offset = self.0.as_ref().len().saturating_sub(1);
|
||||||
|
self.0.as_mut().get_mut(start_offset..end_offset)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn checksummed_data(&self) -> Option<&[u8]> {
|
||||||
|
self.0
|
||||||
|
.as_ref()
|
||||||
|
.get(..self.0.as_ref().len().saturating_sub(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn checksum(&self) -> Option<u8> {
|
||||||
|
self.0.as_ref().last().copied()
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn checksum_mut(&mut self) -> Option<&mut u8>
|
||||||
|
where
|
||||||
|
T: AsMut<[u8]>,
|
||||||
|
{
|
||||||
|
self.0.as_mut().last_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn check_checksum(&self, crypto: &impl Crypto) -> bool {
|
||||||
|
let Some(data) = self.checksummed_data() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
let Some(checksum) = self.checksum() else {
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
checksum == crypto.calculate_checksum(data)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn new(data: T) -> Self {
|
||||||
|
Self(data)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const DEFAULT_SIGNAT: [u8; 4] = [0x12, 0x34, 0x56, 0x78];
|
||||||
|
#[inline(always)]
|
||||||
|
const fn get_size_offset(tf: TypesFlags) -> usize {
|
||||||
|
size_of::<PRUDPV0Header>()
|
||||||
|
+ (if tf.get_types() & (SYN | CONNECT) != 0 {
|
||||||
|
4
|
||||||
|
} else if tf.get_types() & DATA != 0 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
})
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
const fn get_type_specific_size(tf: TypesFlags) -> usize {
|
||||||
|
if tf.get_types() & (SYN | CONNECT) != 0 {
|
||||||
|
4
|
||||||
|
} else if tf.get_types() & DATA != 0 {
|
||||||
|
1
|
||||||
|
} else {
|
||||||
|
0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
const fn get_types_flags_size_from_types_flags(tf: TypesFlags) -> usize {
|
||||||
|
get_type_specific_size(tf) + (if tf.get_flags() & HAS_SIZE != 0 { 2 } else { 0 })
|
||||||
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn precalc_size(tf: TypesFlags, payload_size: usize) -> usize {
|
||||||
|
size_of::<PRUDPV0Header>() + get_types_flags_size_from_types_flags(tf) + payload_size + 1
|
||||||
|
}
|
||||||
|
pub fn new_syn_packet(
|
||||||
|
flags: u16,
|
||||||
|
source: VirtualPort,
|
||||||
|
destination: VirtualPort,
|
||||||
|
signat: [u8; 4],
|
||||||
|
crypto: &impl Crypto,
|
||||||
|
) -> Vec<u8> {
|
||||||
|
let type_flags = TypesFlags::default().types(SYN).flags(flags);
|
||||||
|
|
||||||
|
let vec = vec![0; precalc_size(type_flags, 0)];
|
||||||
|
let mut packet = PRUDPV0Packet::new(vec);
|
||||||
|
let header = packet.header_mut().expect("packet malformed in creation");
|
||||||
|
|
||||||
|
*header = PRUDPV0Header {
|
||||||
|
destination,
|
||||||
|
source,
|
||||||
|
packet_signature: DEFAULT_SIGNAT,
|
||||||
|
sequence_id: 0,
|
||||||
|
session_id: 0,
|
||||||
|
type_flags,
|
||||||
|
};
|
||||||
|
*packet
|
||||||
|
.connection_signature_mut()
|
||||||
|
.expect("packet malformed in creation") = signat;
|
||||||
|
|
||||||
|
*packet.checksum_mut().expect("packet malformed in creation") = crypto.calculate_checksum(
|
||||||
|
packet
|
||||||
|
.checksummed_data()
|
||||||
|
.expect("packet malformed in creation"),
|
||||||
|
);
|
||||||
|
|
||||||
|
packet.0
|
||||||
|
}
|
||||||
256
prudpv0/src/server.rs
Normal file
256
prudpv0/src/server.rs
Normal file
|
|
@ -0,0 +1,256 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
hash::Hash,
|
||||||
|
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||||
|
sync::{
|
||||||
|
Arc, LazyLock,
|
||||||
|
atomic::{AtomicBool, AtomicU32},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
use log::{error, info, warn};
|
||||||
|
use proxy_common::{ProxyStartupParam, new_backend_connection};
|
||||||
|
use rnex_core::{
|
||||||
|
executables::common::{OWN_IP_PRIVATE, SERVER_PORT},
|
||||||
|
prudp::{
|
||||||
|
socket_addr::PRUDPSockAddr,
|
||||||
|
types_flags::{
|
||||||
|
TypesFlags,
|
||||||
|
flags::{ACK, HAS_SIZE, NEED_ACK},
|
||||||
|
types::{CONNECT, DATA, SYN},
|
||||||
|
},
|
||||||
|
virtual_port::VirtualPort,
|
||||||
|
},
|
||||||
|
rnex_proxy_common::ConnectionInitData,
|
||||||
|
util::{SendingBufferConnection, SplittableBufferConnection},
|
||||||
|
};
|
||||||
|
use tokio::{
|
||||||
|
net::{TcpSocket, UdpSocket},
|
||||||
|
spawn,
|
||||||
|
sync::{Mutex, RwLock},
|
||||||
|
time::Instant,
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
crypto::{Crypto, CryptoInstance},
|
||||||
|
packet::{PRUDPV0Header, PRUDPV0Packet, new_syn_packet, precalc_size},
|
||||||
|
};
|
||||||
|
|
||||||
|
pub struct InternalConnection<C: CryptoInstance> {
|
||||||
|
last_action: Instant,
|
||||||
|
crypto_instance: C,
|
||||||
|
server_packet_counter: u16,
|
||||||
|
client_packet_counter: u16,
|
||||||
|
unacknowledged_packets: HashMap<u16, Arc<Vec<u8>>>,
|
||||||
|
}
|
||||||
|
pub struct Connection<C: CryptoInstance> {
|
||||||
|
alive: AtomicBool,
|
||||||
|
session_id: u8,
|
||||||
|
target: SendingBufferConnection,
|
||||||
|
self_signat: [u8; 4],
|
||||||
|
remote_signat: [u8; 4],
|
||||||
|
addr: PRUDPSockAddr,
|
||||||
|
inner: Mutex<InternalConnection<C>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: CryptoInstance> InternalConnection<C> {
|
||||||
|
fn next_server_count(&mut self) -> u16 {
|
||||||
|
let prev_val = self.server_packet_counter;
|
||||||
|
let (val, _) = self.server_packet_counter.overflowing_add(1);
|
||||||
|
self.server_packet_counter = val;
|
||||||
|
|
||||||
|
prev_val
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct Server<C: Crypto> {
|
||||||
|
param: ProxyStartupParam,
|
||||||
|
socket: UdpSocket,
|
||||||
|
crypto: C,
|
||||||
|
connections: RwLock<HashMap<PRUDPSockAddr, Arc<Connection<C::Instance>>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<C: Crypto> Server<C> {
|
||||||
|
async fn send_data_packet(&self, conn: &Connection<C::Instance>, data: &[u8]) {
|
||||||
|
let type_flags = TypesFlags::default().types(DATA).flags(HAS_SIZE | NEED_ACK);
|
||||||
|
let vec = vec![0; precalc_size(type_flags, data.len())];
|
||||||
|
let mut packet = PRUDPV0Packet::new(vec);
|
||||||
|
|
||||||
|
let payload = packet.payload_mut().expect("packet malformed in creation");
|
||||||
|
payload.copy_from_slice(data);
|
||||||
|
|
||||||
|
let mut inner = conn.inner.lock().await;
|
||||||
|
inner.crypto_instance.encrypt_outgoing(payload);
|
||||||
|
let packet_signat = inner.crypto_instance.generate_signature(payload);
|
||||||
|
let seq = inner.next_server_count();
|
||||||
|
|
||||||
|
*packet.header_mut().expect("packet malformed in creation") = PRUDPV0Header {
|
||||||
|
source: self.param.virtual_port,
|
||||||
|
destination: conn.addr.virtual_port,
|
||||||
|
type_flags,
|
||||||
|
session_id: conn.session_id,
|
||||||
|
packet_signature: packet_signat,
|
||||||
|
sequence_id: seq,
|
||||||
|
};
|
||||||
|
/* we leave the sequence id as is for now as it defaults to 0 */
|
||||||
|
|
||||||
|
*packet.checksum_mut().expect("packet malformed in creation") =
|
||||||
|
self.crypto.calculate_checksum(
|
||||||
|
packet
|
||||||
|
.checksummed_data()
|
||||||
|
.expect("packet malformed in creation"),
|
||||||
|
);
|
||||||
|
|
||||||
|
let packet_raw = packet.0;
|
||||||
|
|
||||||
|
let packet = Arc::new(packet_raw);
|
||||||
|
|
||||||
|
let packet_ref = Arc::downgrade(&packet);
|
||||||
|
|
||||||
|
inner.unacknowledged_packets.insert(seq, packet);
|
||||||
|
|
||||||
|
drop(inner);
|
||||||
|
|
||||||
|
spawn(async move {
|
||||||
|
for n in 0..5 {
|
||||||
|
let Some(data) = packet_ref.upgrade() else {
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
info!("send attempt {}", n);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async fn connection_thread(
|
||||||
|
self: Arc<Self>,
|
||||||
|
conn: Arc<Connection<C::Instance>>,
|
||||||
|
mut recv: SplittableBufferConnection,
|
||||||
|
) {
|
||||||
|
while let Some(data) = recv.recv().await {}
|
||||||
|
}
|
||||||
|
async fn timeout_thread(self: Arc<Self>, conn: Arc<Connection<C::Instance>>) {
|
||||||
|
loop {
|
||||||
|
conn
|
||||||
|
}
|
||||||
|
}
|
||||||
|
async fn handle_syn(self: Arc<Self>, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) {
|
||||||
|
info!("got syn");
|
||||||
|
let header = packet.header().unwrap();
|
||||||
|
|
||||||
|
let signat = addr.calculate_connection_signature();
|
||||||
|
let signat = [signat[0], signat[1], signat[2], signat[3]];
|
||||||
|
|
||||||
|
let packet = new_syn_packet(ACK, header.destination, header.source, signat, &self.crypto);
|
||||||
|
self.socket.send_to(&packet, addr.regular_socket_addr).await;
|
||||||
|
}
|
||||||
|
async fn handle_connect(self: Arc<Self>, packet: PRUDPV0Packet<&[u8]>, addr: PRUDPSockAddr) {
|
||||||
|
let conn = self.connections.write().await;
|
||||||
|
let Some(data) = packet.payload() else {
|
||||||
|
warn!("malformed packet from: {:?}", addr.regular_socket_addr);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
let Some(self_signat) = packet.connection_signature().copied() else {
|
||||||
|
warn!(
|
||||||
|
"malformed packet(unable to find connection signature) from: {:?}",
|
||||||
|
addr
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let ci = self.crypto.instantiate(data);
|
||||||
|
|
||||||
|
let pid = ci.get_user_id();
|
||||||
|
let conn = new_backend_connection(&self.param, addr, pid).await;
|
||||||
|
let Some(conn) = conn else {
|
||||||
|
error!("unable to connect to backend");
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let remote_signat = addr.calculate_connection_signature();
|
||||||
|
let remote_signat = [
|
||||||
|
remote_signat[0],
|
||||||
|
remote_signat[1],
|
||||||
|
remote_signat[2],
|
||||||
|
remote_signat[3],
|
||||||
|
];
|
||||||
|
|
||||||
|
let header = packet.header().expect("header should be validated by now");
|
||||||
|
|
||||||
|
let conn = Arc::new(Connection {
|
||||||
|
target: conn.duplicate_sender(),
|
||||||
|
remote_signat,
|
||||||
|
self_signat,
|
||||||
|
addr,
|
||||||
|
session_id: header.session_id,
|
||||||
|
alive: AtomicBool::new(true),
|
||||||
|
inner: Mutex::new(InternalConnection {
|
||||||
|
last_action: Instant::now(),
|
||||||
|
crypto_instance: ci,
|
||||||
|
client_packet_counter: 2,
|
||||||
|
server_packet_counter: 1,
|
||||||
|
unacknowledged_packets: HashMap::new(),
|
||||||
|
}),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
async fn process_packet<'a>(self: Arc<Self>, packet: PRUDPV0Packet<&[u8]>, addr: SocketAddrV4) {
|
||||||
|
if !packet.check_checksum(&self.crypto) {
|
||||||
|
warn!("invalid checksum from: {}", addr);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let Some(header) = packet.header() else {
|
||||||
|
warn!("malformatted packet from: {}", addr);
|
||||||
|
return;
|
||||||
|
};
|
||||||
|
|
||||||
|
let addr = PRUDPSockAddr::new(addr, header.source);
|
||||||
|
println!("{:?}", header);
|
||||||
|
match header.type_flags.get_types() {
|
||||||
|
SYN => {
|
||||||
|
self.handle_syn(packet, addr).await;
|
||||||
|
}
|
||||||
|
CONNECT => {
|
||||||
|
self.handle_connect(packet, addr).await;
|
||||||
|
}
|
||||||
|
v => {
|
||||||
|
println!("unimplemented packed type: {}", v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn run_task(self: Arc<Self>) {
|
||||||
|
loop {
|
||||||
|
let mut vec: Vec<u8> = vec![];
|
||||||
|
let addr = match self.socket.recv_buf_from(&mut vec).await {
|
||||||
|
Err(e) => {
|
||||||
|
error!("unable to recv: {}", e);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
Ok(v) => {
|
||||||
|
assert_eq!(vec.len(), v.0);
|
||||||
|
v.1
|
||||||
|
}
|
||||||
|
};
|
||||||
|
let this = self.clone();
|
||||||
|
tokio::spawn(async move {
|
||||||
|
let data = vec;
|
||||||
|
let packet = PRUDPV0Packet::new(&data[..]);
|
||||||
|
|
||||||
|
let SocketAddr::V4(addr) = addr else {
|
||||||
|
unreachable!()
|
||||||
|
};
|
||||||
|
|
||||||
|
this.process_packet(packet, addr).await;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
pub async fn new(param: ProxyStartupParam) -> Self {
|
||||||
|
let socket = UdpSocket::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
||||||
|
.await
|
||||||
|
.expect("unable to bind socket");
|
||||||
|
Self {
|
||||||
|
socket,
|
||||||
|
crypto: C::new(),
|
||||||
|
connections: RwLock::new(HashMap::new()),
|
||||||
|
param,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::net::SocketAddrV4;
|
use std::net::SocketAddrV4;
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
|
|
||||||
pub static EDGE_NODE_HOLDER: Lazy<SocketAddrV4> = Lazy::new(|| {
|
pub static EDGE_NODE_HOLDER: Lazy<SocketAddrV4> = Lazy::new(|| {
|
||||||
env::var("EDGE_NODE_HOLDER")
|
env::var("EDGE_NODE_HOLDER")
|
||||||
|
|
@ -9,10 +9,9 @@ pub static EDGE_NODE_HOLDER: Lazy<SocketAddrV4> = Lazy::new(||{
|
||||||
.expect("EDGE_NODE_HOLDER not set")
|
.expect("EDGE_NODE_HOLDER not set")
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static FORWARD_DESTINATION: Lazy<SocketAddrV4> =
|
pub static FORWARD_DESTINATION: Lazy<SocketAddrV4> = Lazy::new(|| {
|
||||||
Lazy::new(||
|
|
||||||
env::var("FORWARD_DESTINATION")
|
env::var("FORWARD_DESTINATION")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.expect("FORWARD_DESTINATION not set")
|
.expect("FORWARD_DESTINATION not set")
|
||||||
);
|
});
|
||||||
|
|
|
||||||
|
|
@ -1,15 +1,5 @@
|
||||||
|
|
||||||
use rnex_core::reggie::UnitPacketRead;
|
|
||||||
use rnex_core::reggie::UnitPacketWrite;
|
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
|
||||||
use std::net::SocketAddrV4;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use std::time::Duration;
|
|
||||||
use log::error;
|
use log::error;
|
||||||
use tokio::net::TcpStream;
|
use prudpv1::executables::common::{EDGE_NODE_HOLDER, FORWARD_DESTINATION};
|
||||||
use tokio::task;
|
|
||||||
use tokio::time::sleep;
|
|
||||||
use prudpv1::executables::common::{FORWARD_DESTINATION, EDGE_NODE_HOLDER};
|
|
||||||
use prudpv1::prudp::router::Router;
|
use prudpv1::prudp::router::Router;
|
||||||
use prudpv1::prudp::unsecure::Unsecure;
|
use prudpv1::prudp::unsecure::Unsecure;
|
||||||
use rnex_core::common::setup;
|
use rnex_core::common::setup;
|
||||||
|
|
@ -17,32 +7,46 @@ use rnex_core::executables::common::{OWN_IP_PRIVATE, OWN_IP_PUBLIC, SERVER_PORT}
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||||
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
use rnex_core::reggie::EdgeNodeHolderConnectOption::Register;
|
||||||
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
use rnex_core::reggie::RemoteEdgeNodeHolder;
|
||||||
use rnex_core::rmc::protocols::{new_rmc_gateway_connection, OnlyRemote};
|
use rnex_core::reggie::UnitPacketRead;
|
||||||
|
use rnex_core::reggie::UnitPacketWrite;
|
||||||
|
use rnex_core::rmc::protocols::{OnlyRemote, new_rmc_gateway_connection};
|
||||||
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||||
use rnex_core::util::SplittableBufferConnection;
|
use rnex_core::util::SplittableBufferConnection;
|
||||||
|
use std::net::SocketAddrV4;
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::net::TcpStream;
|
||||||
|
use tokio::task;
|
||||||
|
use tokio::time::sleep;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER).await.unwrap();
|
let conn = tokio::net::TcpStream::connect(&*EDGE_NODE_HOLDER)
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
let conn: SplittableBufferConnection = conn.into();
|
let conn: SplittableBufferConnection = conn.into();
|
||||||
|
|
||||||
conn.send(Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT)).to_data().unwrap()).await;
|
conn.send(
|
||||||
|
Register(SocketAddrV4::new(*OWN_IP_PUBLIC, *SERVER_PORT))
|
||||||
|
.to_data()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await;
|
||||||
|
|
||||||
let conn = new_rmc_gateway_connection(conn, |r| Arc::new(OnlyRemote::<RemoteEdgeNodeHolder>::new(r)));
|
let conn = new_rmc_gateway_connection(conn, |r| {
|
||||||
|
Arc::new(OnlyRemote::<RemoteEdgeNodeHolder>::new(r))
|
||||||
|
});
|
||||||
|
|
||||||
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
let (router_secure, _) = Router::new(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
||||||
.await
|
.await
|
||||||
.expect("unable to start router");
|
.expect("unable to start router");
|
||||||
|
|
||||||
let mut socket_secure = router_secure
|
let mut socket_secure = router_secure
|
||||||
.add_socket(VirtualPort::new(1, 10), Unsecure(
|
.add_socket(VirtualPort::new(1, 10), Unsecure("6f599f81"))
|
||||||
"6f599f81"
|
|
||||||
))
|
|
||||||
.await
|
.await
|
||||||
.expect("unable to add socket");
|
.expect("unable to add socket");
|
||||||
|
|
||||||
|
|
@ -55,8 +59,7 @@ async fn main() {
|
||||||
};
|
};
|
||||||
|
|
||||||
task::spawn(async move {
|
task::spawn(async move {
|
||||||
let mut stream
|
let mut stream = match TcpStream::connect(*FORWARD_DESTINATION).await {
|
||||||
= match TcpStream::connect(*FORWARD_DESTINATION).await {
|
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("unable to connect: {}", e);
|
error!("unable to connect: {}", e);
|
||||||
|
|
@ -64,10 +67,17 @@ async fn main() {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Err(e) = stream.send_buffer(&ConnectionInitData{
|
if let Err(e) = stream
|
||||||
|
.send_buffer(
|
||||||
|
&ConnectionInitData {
|
||||||
prudpsock_addr: conn.socket_addr,
|
prudpsock_addr: conn.socket_addr,
|
||||||
pid: conn.user_id
|
pid: conn.user_id,
|
||||||
}.to_data().unwrap()).await{
|
}
|
||||||
|
.to_data()
|
||||||
|
.unwrap(),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
error!("error connecting to backend: {}", e);
|
error!("error connecting to backend: {}", e);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -3,21 +3,24 @@
|
||||||
// force the compiler to shut up here
|
// force the compiler to shut up here
|
||||||
#![allow(unused_parens)]
|
#![allow(unused_parens)]
|
||||||
|
|
||||||
|
use crate::prudp::packet::PacketOption::{
|
||||||
|
ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions,
|
||||||
|
};
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use hmac::{Hmac, Mac};
|
||||||
|
use log::{error, warn};
|
||||||
|
use md5::{Digest, Md5};
|
||||||
|
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||||
|
use rnex_core::prudp::types_flags::TypesFlags;
|
||||||
|
use rnex_core::prudp::types_flags::flags::ACK;
|
||||||
|
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||||
use std::fmt::{Debug, Formatter};
|
use std::fmt::{Debug, Formatter};
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::io::{Cursor, Read, Seek, Write};
|
use std::io::{Cursor, Read, Seek, Write};
|
||||||
use std::net::SocketAddrV4;
|
use std::net::SocketAddrV4;
|
||||||
use bytemuck::{Pod, Zeroable};
|
|
||||||
use hmac::{Hmac, Mac};
|
|
||||||
use log::{error, warn};
|
|
||||||
use md5::{Md5, Digest};
|
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use v_byte_helpers::{SwapEndian};
|
use v_byte_helpers::SwapEndian;
|
||||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use crate::prudp::packet::flags::ACK;
|
|
||||||
use crate::prudp::packet::PacketOption::{ConnectionSignature, FragmentId, InitialSequenceId, MaximumSubstreamId, SupportedFunctions};
|
|
||||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
|
||||||
|
|
||||||
type Md5Hmac = Hmac<Md5>;
|
type Md5Hmac = Hmac<Md5>;
|
||||||
|
|
||||||
|
|
@ -32,73 +35,11 @@ pub enum Error {
|
||||||
#[error("invalid option id {0}")]
|
#[error("invalid option id {0}")]
|
||||||
InvalidOptionId(u8),
|
InvalidOptionId(u8),
|
||||||
#[error("option size {size} doesnt match expected option for given option id {id}")]
|
#[error("option size {size} doesnt match expected option for given option id {id}")]
|
||||||
InvalidOptionSize {
|
InvalidOptionSize { id: u8, size: u8 },
|
||||||
id: u8,
|
|
||||||
size: u8,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pub type Result<T> = std::result::Result<T, Error>;
|
pub type Result<T> = std::result::Result<T, Error>;
|
||||||
|
|
||||||
#[repr(transparent)]
|
|
||||||
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)]
|
|
||||||
pub struct TypesFlags(u16);
|
|
||||||
|
|
||||||
impl TypesFlags {
|
|
||||||
#[inline]
|
|
||||||
pub const fn get_types(self) -> u8 {
|
|
||||||
(self.0 & 0x000F) as u8
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub const fn get_flags(self) -> u16 {
|
|
||||||
(self.0 & 0xFFF0) >> 4
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub const fn types(self, val: u8) -> Self {
|
|
||||||
Self((self.0 & 0xFFF0) | (val as u16 & 0x000F))
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub const fn flags(self, val: u16) -> Self {
|
|
||||||
Self((self.0 & 0x000F) | ((val << 4) & 0xFFF0))
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub const fn set_flag(&mut self, val: u16){
|
|
||||||
self.0 |= (val & 0xFFF) << 4;
|
|
||||||
}
|
|
||||||
#[inline]
|
|
||||||
pub const fn set_types(&mut self, val: u8){
|
|
||||||
self.0 |= val as u16 & 0x0F;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod flags {
|
|
||||||
pub const ACK: u16 = 0x001;
|
|
||||||
pub const RELIABLE: u16 = 0x002;
|
|
||||||
pub const NEED_ACK: u16 = 0x004;
|
|
||||||
pub const HAS_SIZE: u16 = 0x008;
|
|
||||||
pub const MULTI_ACK: u16 = 0x200;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub mod types {
|
|
||||||
pub const SYN: u8 = 0x0;
|
|
||||||
pub const CONNECT: u8 = 0x1;
|
|
||||||
pub const DATA: u8 = 0x2;
|
|
||||||
pub const DISCONNECT: u8 = 0x3;
|
|
||||||
pub const PING: u8 = 0x4;
|
|
||||||
/// no idea what user is supposed to mean
|
|
||||||
pub const USER: u8 = 0x5;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Debug for TypesFlags {
|
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
|
||||||
let stream_type = self.get_types();
|
|
||||||
let port_number = self.get_flags();
|
|
||||||
write!(f, "TypesFlags{{ types: {}, flags: {} }}", stream_type, port_number)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[repr(C)]
|
#[repr(C)]
|
||||||
#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian, Eq, PartialEq)]
|
#[derive(Debug, Copy, Clone, Pod, Zeroable, SwapEndian, Eq, PartialEq)]
|
||||||
pub struct PRUDPV1Header {
|
pub struct PRUDPV1Header {
|
||||||
|
|
@ -126,24 +67,22 @@ impl Default for PRUDPV1Header {
|
||||||
destination_port: VirtualPort(0),
|
destination_port: VirtualPort(0),
|
||||||
types_and_flags: TypesFlags(0),
|
types_and_flags: TypesFlags(0),
|
||||||
packet_specific_size: 0,
|
packet_specific_size: 0,
|
||||||
substream_id: 0
|
substream_id: 0,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Debug, Clone, Eq, PartialEq)]
|
#[derive(Debug, Clone, Eq, PartialEq)]
|
||||||
pub enum PacketOption {
|
pub enum PacketOption {
|
||||||
SupportedFunctions(u32),
|
SupportedFunctions(u32),
|
||||||
ConnectionSignature([u8; 16]),
|
ConnectionSignature([u8; 16]),
|
||||||
FragmentId(u8),
|
FragmentId(u8),
|
||||||
InitialSequenceId(u16),
|
InitialSequenceId(u16),
|
||||||
MaximumSubstreamId(u8)
|
MaximumSubstreamId(u8),
|
||||||
}
|
}
|
||||||
|
|
||||||
impl PacketOption {
|
impl PacketOption {
|
||||||
fn from(option_id: OptionId, option_data: &[u8]) -> io::Result<Self> {
|
fn from(option_id: OptionId, option_data: &[u8]) -> io::Result<Self> {
|
||||||
|
|
||||||
let mut data_cursor = Cursor::new(option_data);
|
let mut data_cursor = Cursor::new(option_data);
|
||||||
let val = match option_id.into() {
|
let val = match option_id.into() {
|
||||||
0 => SupportedFunctions(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
0 => SupportedFunctions(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||||
|
|
@ -151,7 +90,7 @@ impl PacketOption{
|
||||||
2 => FragmentId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
2 => FragmentId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||||
3 => InitialSequenceId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
3 => InitialSequenceId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||||
4 => MaximumSubstreamId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
4 => MaximumSubstreamId(data_cursor.read_struct(IS_BIG_ENDIAN)?),
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
};
|
};
|
||||||
|
|
||||||
Ok(val)
|
Ok(val)
|
||||||
|
|
@ -212,7 +151,7 @@ impl OptionId {
|
||||||
// Invariant is upheld because we only create the object if it doesn't violate the invariant
|
// Invariant is upheld because we only create the object if it doesn't violate the invariant
|
||||||
match val {
|
match val {
|
||||||
0 | 1 | 2 | 3 | 4 => Ok(Self(val)),
|
0 | 1 | 2 | 3 | 4 => Ok(Self(val)),
|
||||||
_ => Err(Error::InvalidOptionId(val))
|
_ => Err(Error::InvalidOptionId(val)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -223,7 +162,7 @@ impl OptionId {
|
||||||
2 => 1,
|
2 => 1,
|
||||||
3 => 2,
|
3 => 2,
|
||||||
4 => 1,
|
4 => 1,
|
||||||
_ => unreachable!()
|
_ => unreachable!(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -238,8 +177,7 @@ impl PRUDPV1Packet {
|
||||||
pub fn new(reader: &mut (impl Read + Seek)) -> Result<Self> {
|
pub fn new(reader: &mut (impl Read + Seek)) -> Result<Self> {
|
||||||
let header: PRUDPV1Header = reader.read_struct(IS_BIG_ENDIAN)?;
|
let header: PRUDPV1Header = reader.read_struct(IS_BIG_ENDIAN)?;
|
||||||
|
|
||||||
if header.magic[0] != 0xEA ||
|
if header.magic[0] != 0xEA || header.magic[1] != 0xD0 {
|
||||||
header.magic[1] != 0xD0 {
|
|
||||||
return Err(Error::InvalidMagic(u16::from_be_bytes(header.magic)));
|
return Err(Error::InvalidMagic(u16::from_be_bytes(header.magic)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -247,31 +185,31 @@ impl PRUDPV1Packet {
|
||||||
return Err(Error::InvalidVersion(header.version));
|
return Err(Error::InvalidVersion(header.version));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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];
|
//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)?;
|
||||||
|
|
||||||
|
|
||||||
//no clue whats up with options but they are broken
|
//no clue whats up with options but they are broken
|
||||||
let mut packet_specific_data_cursor = Cursor::new(&packet_specific_buffer);
|
let mut packet_specific_data_cursor = Cursor::new(&packet_specific_buffer);
|
||||||
|
|
||||||
let mut options = Vec::new();
|
let mut options = Vec::new();
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
let Ok(option_id): io::Result<u8> = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else {
|
let Ok(option_id): io::Result<u8> =
|
||||||
break
|
packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN)
|
||||||
|
else {
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Ok(value_size): io::Result<u8> = packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN) else {
|
let Ok(value_size): io::Result<u8> =
|
||||||
break
|
packet_specific_data_cursor.read_struct(IS_BIG_ENDIAN)
|
||||||
|
else {
|
||||||
|
break;
|
||||||
};
|
};
|
||||||
|
|
||||||
if value_size == 0 {
|
if value_size == 0 {
|
||||||
|
|
@ -291,7 +229,10 @@ impl PRUDPV1Packet {
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut option_data = vec![0u8; value_size as usize];
|
let mut option_data = vec![0u8; value_size as usize];
|
||||||
if packet_specific_data_cursor.read_exact(&mut option_data[..]).is_err() {
|
if packet_specific_data_cursor
|
||||||
|
.read_exact(&mut option_data[..])
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
error!("unable to read options");
|
error!("unable to read options");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -303,8 +244,6 @@ impl PRUDPV1Packet {
|
||||||
|
|
||||||
reader.read_exact(&mut payload)?;
|
reader.read_exact(&mut payload)?;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
header,
|
header,
|
||||||
packet_signature,
|
packet_signature,
|
||||||
|
|
@ -320,14 +259,13 @@ impl PRUDPV1Packet {
|
||||||
|
|
||||||
flags.set_flag(ACK);
|
flags.set_flag(ACK);
|
||||||
|
|
||||||
let options = self.options
|
let options = self
|
||||||
|
.options
|
||||||
.iter()
|
.iter()
|
||||||
.filter(|o| matches!(o, FragmentId(_)))
|
.filter(|o| matches!(o, FragmentId(_)))
|
||||||
.cloned()
|
.cloned()
|
||||||
.collect();
|
.collect();
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
header: PRUDPV1Header {
|
header: PRUDPV1Header {
|
||||||
types_and_flags: flags,
|
types_and_flags: flags,
|
||||||
|
|
@ -352,13 +290,20 @@ impl PRUDPV1Packet {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
|
|
||||||
for option in &self.options {
|
for option in &self.options {
|
||||||
option.write_to_stream(&mut vec).expect("vec should always automatically be able to extend");
|
option
|
||||||
|
.write_to_stream(&mut vec)
|
||||||
|
.expect("vec should always automatically be able to extend");
|
||||||
}
|
}
|
||||||
|
|
||||||
vec
|
vec
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_signature_value(&self, access_key: &str, session_key: Option<[u8; 32]>, connection_signature: Option<[u8; 16]>) -> [u8; 16]{
|
pub fn calculate_signature_value(
|
||||||
|
&self,
|
||||||
|
access_key: &str,
|
||||||
|
session_key: Option<[u8; 32]>,
|
||||||
|
connection_signature: Option<[u8; 16]>,
|
||||||
|
) -> [u8; 16] {
|
||||||
let access_key_bytes = access_key.as_bytes();
|
let access_key_bytes = access_key.as_bytes();
|
||||||
let access_key_sum: u32 = access_key_bytes.iter().map(|v| *v as u32).sum();
|
let access_key_sum: u32 = access_key_bytes.iter().map(|v| *v as u32).sum();
|
||||||
let access_key_sum_bytes: [u8; 4] = access_key_sum.to_le_bytes();
|
let access_key_sum_bytes: [u8; 4] = access_key_sum.to_le_bytes();
|
||||||
|
|
@ -374,24 +319,38 @@ impl PRUDPV1Packet {
|
||||||
|
|
||||||
let mut hmac = Md5Hmac::new_from_slice(&key).expect("fuck");
|
let mut hmac = Md5Hmac::new_from_slice(&key).expect("fuck");
|
||||||
|
|
||||||
hmac.write(&header_data).expect("error during hmac calculation");
|
hmac.write(&header_data)
|
||||||
|
.expect("error during hmac calculation");
|
||||||
if let Some(session_key) = session_key {
|
if let Some(session_key) = session_key {
|
||||||
hmac.write(&session_key).expect("error during hmac calculation");
|
hmac.write(&session_key)
|
||||||
|
.expect("error during hmac calculation");
|
||||||
}
|
}
|
||||||
hmac.write(&access_key_sum_bytes).expect("error during hmac calculation");
|
hmac.write(&access_key_sum_bytes)
|
||||||
|
.expect("error during hmac calculation");
|
||||||
if let Some(connection_signature) = connection_signature {
|
if let Some(connection_signature) = connection_signature {
|
||||||
hmac.write(&connection_signature).expect("error during hmac calculation");
|
hmac.write(&connection_signature)
|
||||||
|
.expect("error during hmac calculation");
|
||||||
}
|
}
|
||||||
|
|
||||||
hmac.write(&option_bytes).expect("error during hmac calculation");
|
hmac.write(&option_bytes)
|
||||||
|
.expect("error during hmac calculation");
|
||||||
|
|
||||||
hmac.write_all(&self.payload).expect("error during hmac calculation");
|
hmac.write_all(&self.payload)
|
||||||
|
.expect("error during hmac calculation");
|
||||||
|
|
||||||
hmac.finalize().into_bytes()[0..16].try_into().expect("invalid hmac size")
|
hmac.finalize().into_bytes()[0..16]
|
||||||
|
.try_into()
|
||||||
|
.expect("invalid hmac size")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn calculate_and_assign_signature(&mut self, access_key: &str, session_key: Option<[u8; 32]>, connection_signature: Option<[u8; 16]>){
|
pub fn calculate_and_assign_signature(
|
||||||
self.packet_signature = self.calculate_signature_value(access_key, session_key, connection_signature);
|
&mut self,
|
||||||
|
access_key: &str,
|
||||||
|
session_key: Option<[u8; 32]>,
|
||||||
|
connection_signature: Option<[u8; 16]>,
|
||||||
|
) {
|
||||||
|
self.packet_signature =
|
||||||
|
self.calculate_signature_value(access_key, session_key, connection_signature);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn set_sizes(&mut self) {
|
pub fn set_sizes(&mut self) {
|
||||||
|
|
@ -412,11 +371,10 @@ impl PRUDPV1Packet {
|
||||||
sequence_id: 0,
|
sequence_id: 0,
|
||||||
session_id: 0,
|
session_id: 0,
|
||||||
substream_id: 0,
|
substream_id: 0,
|
||||||
|
|
||||||
},
|
},
|
||||||
packet_signature: [0; 16],
|
packet_signature: [0; 16],
|
||||||
payload: Default::default(),
|
payload: Default::default(),
|
||||||
options: Default::default()
|
options: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -436,10 +394,14 @@ impl PRUDPV1Packet {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use crate::prudp::packet::flags::{NEED_ACK, RELIABLE};
|
use super::{OptionId, PRUDPV1Header, PacketOption, TypesFlags};
|
||||||
use crate::prudp::packet::types::DATA;
|
use rnex_core::prudp::{
|
||||||
use super::{OptionId, PacketOption, PRUDPV1Header, TypesFlags};
|
types_flags::{
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
flags::{NEED_ACK, RELIABLE},
|
||||||
|
types::DATA,
|
||||||
|
},
|
||||||
|
virtual_port::VirtualPort,
|
||||||
|
};
|
||||||
#[test]
|
#[test]
|
||||||
fn size_test() {
|
fn size_test() {
|
||||||
assert_eq!(size_of::<PRUDPV1Header>(), 14);
|
assert_eq!(size_of::<PRUDPV1Header>(), 14);
|
||||||
|
|
@ -463,8 +425,6 @@ mod test {
|
||||||
assert_eq!(write_buf.len() as u8, opt.write_size())
|
assert_eq!(write_buf.len() as u8, opt.write_size())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -479,7 +439,7 @@ mod test {
|
||||||
payload_size: 0,
|
payload_size: 0,
|
||||||
sequence_id: 0,
|
sequence_id: 0,
|
||||||
magic: [0xEA, 0xD0],
|
magic: [0xEA, 0xD0],
|
||||||
source_port: VirtualPort(0)
|
source_port: VirtualPort(0),
|
||||||
};
|
};
|
||||||
|
|
||||||
let bytes = bytemuck::bytes_of(&header);
|
let bytes = bytemuck::bytes_of(&header);
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,17 @@
|
||||||
use std::io::Cursor;
|
use crate::prudp::packet::PRUDPV1Packet;
|
||||||
|
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
||||||
use hmac::digest::consts::U32;
|
use hmac::digest::consts::U32;
|
||||||
use log::error;
|
use log::error;
|
||||||
use rc4::cipher::StreamCipherCoreWrapper;
|
use rc4::cipher::StreamCipherCoreWrapper;
|
||||||
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
|
||||||
use rc4::consts::U16;
|
use rc4::consts::U16;
|
||||||
|
use rc4::{KeyInit, Rc4, Rc4Core, StreamCipher};
|
||||||
|
use rnex_core::kerberos::{TicketInternalData, derive_key};
|
||||||
|
use rnex_core::nex::account::Account;
|
||||||
|
use rnex_core::prudp::encryption::EncryptionPair;
|
||||||
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
|
use std::io::Cursor;
|
||||||
use typenum::U5;
|
use typenum::U5;
|
||||||
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
use v_byte_helpers::{IS_BIG_ENDIAN, ReadExtensions};
|
||||||
use rnex_core::kerberos::{derive_key, TicketInternalData};
|
|
||||||
use rnex_core::nex::account::Account;
|
|
||||||
use crate::prudp::packet::PRUDPV1Packet;
|
|
||||||
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair};
|
|
||||||
use rnex_core::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)> {
|
||||||
let mut cursor = Cursor::new(data);
|
let mut cursor = Cursor::new(data);
|
||||||
|
|
@ -42,7 +43,7 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3
|
||||||
let TicketInternalData {
|
let TicketInternalData {
|
||||||
session_key,
|
session_key,
|
||||||
pid: ticket_source_pid,
|
pid: ticket_source_pid,
|
||||||
issued_time
|
issued_time,
|
||||||
} = *ticket_data;
|
} = *ticket_data;
|
||||||
|
|
||||||
// todo: add checking if tickets are signed with a valid md5-hmac
|
// todo: add checking if tickets are signed with a valid md5-hmac
|
||||||
|
|
@ -61,26 +62,30 @@ pub fn read_secure_connection_data(data: &[u8], act: &Account) -> Option<([u8; 3
|
||||||
if pid != ticket_source_pid {
|
if pid != ticket_source_pid {
|
||||||
let ticket_created_on = issued_time.to_regular_time();
|
let ticket_created_on = issued_time.to_regular_time();
|
||||||
|
|
||||||
error!("someone tried to spoof their pid, ticket was created on: {}", ticket_created_on.to_rfc2822());
|
error!(
|
||||||
|
"someone tried to spoof their pid, ticket was created on: {}",
|
||||||
|
ticket_created_on.to_rfc2822()
|
||||||
|
);
|
||||||
return None;
|
return None;
|
||||||
}
|
}
|
||||||
|
|
||||||
let _cid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?;
|
let _cid: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?;
|
||||||
let response_check: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?;
|
let response_check: u32 = reqest_data_cursor.read_struct(IS_BIG_ENDIAN).ok()?;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Some((session_key, pid, response_check))
|
Some((session_key, pid, response_check))
|
||||||
}
|
}
|
||||||
|
|
||||||
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<Rc4<U32>>>{
|
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: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
||||||
recv: 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 {
|
||||||
|
|
@ -94,17 +99,15 @@ pub fn generate_secure_encryption_pairs(mut session_key: [u8; 32], count: u8) ->
|
||||||
|
|
||||||
vec.push(EncryptionPair {
|
vec.push(EncryptionPair {
|
||||||
send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
send: Rc4U32::new_from_slice(&session_key).expect("unable to create rc4"),
|
||||||
recv: 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 Account);
|
pub struct Secure(pub &'static str, pub Account);
|
||||||
|
|
||||||
|
|
||||||
pub struct SecureInstance {
|
pub struct SecureInstance {
|
||||||
access_key: &'static str,
|
access_key: &'static str,
|
||||||
session_key: [u8; 32],
|
session_key: [u8; 32],
|
||||||
|
|
@ -155,7 +158,6 @@ impl CryptoHandler for Secure {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
impl CryptoHandlerConnectionInstance for SecureInstance {
|
impl CryptoHandlerConnectionInstance for SecureInstance {
|
||||||
type Encryption = Rc4<U5>;
|
type Encryption = Rc4<U5>;
|
||||||
|
|
||||||
|
|
@ -182,7 +184,11 @@ impl CryptoHandlerConnectionInstance for SecureInstance {
|
||||||
|
|
||||||
fn sign_packet(&self, packet: &mut PRUDPV1Packet) {
|
fn sign_packet(&self, packet: &mut PRUDPV1Packet) {
|
||||||
packet.set_sizes();
|
packet.set_sizes();
|
||||||
packet.calculate_and_assign_signature(self.access_key, Some(self.session_key), Some(self.self_signature));
|
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 {
|
||||||
|
|
|
||||||
|
|
@ -1,47 +1,34 @@
|
||||||
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::{
|
use crate::prudp::packet::PacketOption::{
|
||||||
ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions,
|
ConnectionSignature, FragmentId, MaximumSubstreamId, SupportedFunctions,
|
||||||
};
|
};
|
||||||
use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet, TypesFlags};
|
use crate::prudp::packet::{PRUDPV1Header, PRUDPV1Packet};
|
||||||
use rnex_core::prudp::virtual_port::VirtualPort;
|
|
||||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
|
||||||
use async_trait::async_trait;
|
use async_trait::async_trait;
|
||||||
use log::{info, warn};
|
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use log::{info, warn};
|
||||||
use rc4::StreamCipher;
|
use rc4::StreamCipher;
|
||||||
use v_byte_helpers::ReadExtensions;
|
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||||
use v_byte_helpers::little_endian::read_u16;
|
use rnex_core::prudp::types_flags::TypesFlags;
|
||||||
|
use rnex_core::prudp::types_flags::flags::{ACK, HAS_SIZE, MULTI_ACK, NEED_ACK, RELIABLE};
|
||||||
|
use rnex_core::prudp::types_flags::types::{CONNECT, DATA, DISCONNECT, PING, SYN};
|
||||||
|
use rnex_core::prudp::virtual_port::VirtualPort;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
use std::collections::{BTreeMap, HashMap};
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::marker::PhantomData;
|
use std::marker::PhantomData;
|
||||||
use std::ops::Deref;
|
use std::ops::Deref;
|
||||||
use std::sync::{Arc, Weak};
|
use std::sync::{Arc, Weak};
|
||||||
|
use v_byte_helpers::ReadExtensions;
|
||||||
|
use v_byte_helpers::little_endian::read_u16;
|
||||||
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use tokio::net::UdpSocket;
|
use tokio::net::UdpSocket;
|
||||||
use tokio::sync::mpsc::{channel, Receiver, Sender};
|
|
||||||
use tokio::sync::Mutex;
|
use tokio::sync::Mutex;
|
||||||
use tokio::time::{sleep, Instant};
|
use tokio::sync::mpsc::{Receiver, Sender, channel};
|
||||||
|
use tokio::time::{Instant, sleep};
|
||||||
// due to the way this is designed crashing the router thread causes deadlock, sorry ;-;
|
// due to the way this is designed crashing the router thread causes deadlock, sorry ;-;
|
||||||
// (maybe i will fix that some day)
|
// (maybe i will fix that some day)
|
||||||
|
|
||||||
/// PRUDP Socket for accepting connections to then send and recieve data from those clients
|
/// PRUDP Socket for accepting connections to then send and recieve data from those clients
|
||||||
|
|
||||||
pub struct EncryptionPair<T: StreamCipher + Send> {
|
|
||||||
pub send: T,
|
|
||||||
pub recv: T,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T: StreamCipher + Send> EncryptionPair<T> {
|
|
||||||
pub fn init_both<F: Fn() -> T>(func: F) -> Self {
|
|
||||||
Self {
|
|
||||||
recv: func(),
|
|
||||||
send: func(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub struct CommonConnection {
|
pub struct CommonConnection {
|
||||||
pub user_id: u32,
|
pub user_id: u32,
|
||||||
pub socket_addr: PRUDPSockAddr,
|
pub socket_addr: PRUDPSockAddr,
|
||||||
|
|
@ -61,7 +48,7 @@ struct InternalConnection<E: CryptoHandlerConnectionInstance> {
|
||||||
socket: Arc<UdpSocket>,
|
socket: Arc<UdpSocket>,
|
||||||
packet_queue: HashMap<u16, PRUDPV1Packet>,
|
packet_queue: HashMap<u16, PRUDPV1Packet>,
|
||||||
last_packet_time: Instant,
|
last_packet_time: Instant,
|
||||||
unacknowleged_packets: Vec<(Instant, PRUDPV1Packet)>
|
unacknowleged_packets: Vec<(Instant, PRUDPV1Packet)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E: CryptoHandlerConnectionInstance> Deref for InternalConnection<E> {
|
impl<E: CryptoHandlerConnectionInstance> Deref for InternalConnection<E> {
|
||||||
|
|
@ -187,8 +174,6 @@ pub(super) trait AnyInternalConnection:
|
||||||
async fn close_connection(&mut self);
|
async fn close_connection(&mut self);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[async_trait]
|
#[async_trait]
|
||||||
impl<T: CryptoHandlerConnectionInstance> AnyInternalConnection for InternalConnection<T> {
|
impl<T: CryptoHandlerConnectionInstance> AnyInternalConnection for InternalConnection<T> {
|
||||||
async fn send_data_packet(&mut self, data: Vec<u8>) {
|
async fn send_data_packet(&mut self, data: Vec<u8>) {
|
||||||
|
|
@ -219,7 +204,6 @@ impl<T: CryptoHandlerConnectionInstance> AnyInternalConnection for InternalConne
|
||||||
self.unacknowleged_packets.push((Instant::now(), packet));
|
self.unacknowleged_packets.push((Instant::now(), packet));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
async fn close_connection(&mut self) {
|
async fn close_connection(&mut self) {
|
||||||
// jon confirmed that this should be a safe way to dc a client
|
// jon confirmed that this should be a safe way to dc a client
|
||||||
|
|
||||||
|
|
@ -250,7 +234,11 @@ impl<T: CryptoHandlerConnectionInstance> AnyInternalConnection for InternalConne
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn send_raw_prudp_to_sockaddr(udp_socket: &UdpSocket, dest: PRUDPSockAddr, packet: &PRUDPV1Packet){
|
async fn send_raw_prudp_to_sockaddr(
|
||||||
|
udp_socket: &UdpSocket,
|
||||||
|
dest: PRUDPSockAddr,
|
||||||
|
packet: &PRUDPV1Packet,
|
||||||
|
) {
|
||||||
let mut vec = Vec::new();
|
let mut vec = Vec::new();
|
||||||
|
|
||||||
packet
|
packet
|
||||||
|
|
@ -355,7 +343,9 @@ impl<T: CryptoHandler> InternalSocket<T> {
|
||||||
|
|
||||||
for (send_time, packet) in &conn.unacknowleged_packets {
|
for (send_time, packet) in &conn.unacknowleged_packets {
|
||||||
if *send_time < (Instant::now() - Duration::from_millis(3000)) {
|
if *send_time < (Instant::now() - Duration::from_millis(3000)) {
|
||||||
warn!("failed to resend packet 5 times and never got response, destroying connection");
|
warn!(
|
||||||
|
"failed to resend packet 5 times and never got response, destroying connection"
|
||||||
|
);
|
||||||
conn.close_connection().await;
|
conn.close_connection().await;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
@ -399,7 +389,7 @@ impl<T: CryptoHandler> InternalSocket<T> {
|
||||||
packet_queue: Default::default(),
|
packet_queue: Default::default(),
|
||||||
last_packet_time: Instant::now(),
|
last_packet_time: Instant::now(),
|
||||||
unacknowleged_packets: Vec::new(),
|
unacknowleged_packets: Vec::new(),
|
||||||
supported_function_version
|
supported_function_version,
|
||||||
};
|
};
|
||||||
|
|
||||||
let internal = Arc::new(Mutex::new(internal));
|
let internal = Arc::new(Mutex::new(internal));
|
||||||
|
|
@ -487,7 +477,7 @@ impl<T: CryptoHandler> InternalSocket<T> {
|
||||||
SupportedFunctions(funcs) => {
|
SupportedFunctions(funcs) => {
|
||||||
functions = *funcs & 0xFF;
|
functions = *funcs & 0xFF;
|
||||||
response.options.push(SupportedFunctions(*funcs & 0xFF));
|
response.options.push(SupportedFunctions(*funcs & 0xFF));
|
||||||
},
|
}
|
||||||
_ => { /* ? */ }
|
_ => { /* ? */ }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -610,7 +600,6 @@ impl<T: CryptoHandler> AnyInternalSocket for InternalSocket<T> {
|
||||||
if (packet.header.types_and_flags.get_flags() & ACK) != 0 {
|
if (packet.header.types_and_flags.get_flags() & ACK) != 0 {
|
||||||
info!("got ack");
|
info!("got ack");
|
||||||
|
|
||||||
|
|
||||||
if packet.header.types_and_flags.get_types() == SYN
|
if packet.header.types_and_flags.get_types() == SYN
|
||||||
|| packet.header.types_and_flags.get_types() == CONNECT
|
|| packet.header.types_and_flags.get_types() == CONNECT
|
||||||
{
|
{
|
||||||
|
|
@ -645,9 +634,8 @@ impl<T: CryptoHandler> AnyInternalSocket for InternalSocket<T> {
|
||||||
|
|
||||||
// remove the packet whose sequence id matches the ack packet
|
// remove the packet whose sequence id matches the ack packet
|
||||||
// or in other words keep all of those which dont match the sequence id
|
// or in other words keep all of those which dont match the sequence id
|
||||||
conn.unacknowleged_packets.retain_mut(|v| {
|
conn.unacknowleged_packets
|
||||||
packet.header.sequence_id != v.1.header.sequence_id
|
.retain_mut(|v| packet.header.sequence_id != v.1.header.sequence_id);
|
||||||
});
|
|
||||||
} else {
|
} else {
|
||||||
error!("non connection acknowledgement packet on nonexistent connection...")
|
error!("non connection acknowledgement packet on nonexistent connection...")
|
||||||
}
|
}
|
||||||
|
|
@ -668,12 +656,9 @@ impl<T: CryptoHandler> AnyInternalSocket for InternalSocket<T> {
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.unacknowleged_packets.retain_mut(|(_, up)| {
|
conn.unacknowleged_packets.retain_mut(|(_, up)| {
|
||||||
!(
|
!(collected_ids.iter().any(|id| up.header.sequence_id == *id)
|
||||||
collected_ids.iter().any(|id| up.header.sequence_id == *id) ||
|
|| up.header.sequence_id <= packet.header.sequence_id)
|
||||||
up.header.sequence_id <= packet.header.sequence_id
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let mut collected_ids: Vec<u16> = Vec::new();
|
let mut collected_ids: Vec<u16> = Vec::new();
|
||||||
let mut cursor = Cursor::new(&packet.payload);
|
let mut cursor = Cursor::new(&packet.payload);
|
||||||
|
|
@ -691,18 +676,19 @@ impl<T: CryptoHandler> AnyInternalSocket for InternalSocket<T> {
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
for _ in 0..additional_sequence_ids {
|
for _ in 0..additional_sequence_ids {
|
||||||
let Ok(additional_sequence_id): Result<u16, _> = cursor.read_le_struct() else {
|
let Ok(additional_sequence_id): Result<u16, _> = cursor.read_le_struct()
|
||||||
error!("invalid data whilest reading new version agregate acknowledgement");
|
else {
|
||||||
|
error!(
|
||||||
|
"invalid data whilest reading new version agregate acknowledgement"
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
collected_ids.push(additional_sequence_id);
|
collected_ids.push(additional_sequence_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
conn.unacknowleged_packets.retain_mut(|(_, up)| {
|
conn.unacknowleged_packets.retain_mut(|(_, up)| {
|
||||||
!(
|
!(collected_ids.iter().any(|id| up.header.sequence_id == *id)
|
||||||
collected_ids.iter().any(|id| up.header.sequence_id == *id) ||
|
|| up.header.sequence_id <= sequence_id)
|
||||||
up.header.sequence_id <= sequence_id
|
|
||||||
)
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,12 @@
|
||||||
|
use crate::prudp::packet::PRUDPV1Packet;
|
||||||
|
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance};
|
||||||
use once_cell::sync::Lazy;
|
use once_cell::sync::Lazy;
|
||||||
use rc4::{Key, KeyInit, Rc4, StreamCipher};
|
use rc4::{Key, KeyInit, Rc4, StreamCipher};
|
||||||
|
use rnex_core::prudp::encryption::{DEFAULT_KEY, EncryptionPair};
|
||||||
use typenum::U5;
|
use typenum::U5;
|
||||||
use crate::prudp::packet::PRUDPV1Packet;
|
|
||||||
use crate::prudp::socket::{CryptoHandler, CryptoHandlerConnectionInstance, EncryptionPair};
|
|
||||||
|
|
||||||
pub struct Unsecure(pub &'static str);
|
pub struct Unsecure(pub &'static str);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
pub struct UnsecureInstance {
|
pub struct UnsecureInstance {
|
||||||
key: &'static str,
|
key: &'static str,
|
||||||
streams: Vec<EncryptionPair<Rc4<U5>>>,
|
streams: Vec<EncryptionPair<Rc4<U5>>>,
|
||||||
|
|
@ -18,7 +17,6 @@ pub struct UnsecureInstance {
|
||||||
// my hand was forced to use lazy so that we can guarantee this code
|
// 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)
|
// 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
|
// 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 {
|
impl CryptoHandler for Unsecure {
|
||||||
type CryptoConnectionInstance = UnsecureInstance;
|
type CryptoConnectionInstance = UnsecureInstance;
|
||||||
|
|
|
||||||
|
|
@ -9,7 +9,7 @@ dotenv = "0.15.0"
|
||||||
once_cell = "1.20.2"
|
once_cell = "1.20.2"
|
||||||
rc4 = "0.1.0"
|
rc4 = "0.1.0"
|
||||||
thiserror = "2.0.11"
|
thiserror = "2.0.11"
|
||||||
v-byte-helpers = { git = "https://github.com/DJMrTV/VByteMacros", version = "0.1.1" }
|
v-byte-helpers = { git = "https://github.com/RusticMaple/VByteMacros", version = "0.1.1" }
|
||||||
simplelog = "0.12.2"
|
simplelog = "0.12.2"
|
||||||
chrono = "0.4.39"
|
chrono = "0.4.39"
|
||||||
log = "0.4.25"
|
log = "0.4.25"
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,18 @@
|
||||||
use std::sync::Arc;
|
|
||||||
use std::sync::atomic::AtomicU32;
|
|
||||||
use rnex_core::common::setup;
|
use rnex_core::common::setup;
|
||||||
use rnex_core::executables::common::{new_simple_backend};
|
use rnex_core::executables::common::new_simple_backend;
|
||||||
use rnex_core::nex::matchmake::MatchmakeManager;
|
use rnex_core::nex::matchmake::MatchmakeManager;
|
||||||
use rnex_core::nex::remote_console::RemoteConsole;
|
use rnex_core::nex::remote_console::RemoteConsole;
|
||||||
use rnex_core::nex::user::User;
|
use rnex_core::nex::user::User;
|
||||||
use rnex_core::rmc::protocols::RemoteInstantiatable;
|
use rnex_core::rmc::protocols::{RemoteDisconnectable, RmcPureRemoteObject};
|
||||||
|
use std::sync::Arc;
|
||||||
|
use std::sync::atomic::AtomicU32;
|
||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() {
|
async fn main() {
|
||||||
setup();
|
setup();
|
||||||
|
|
||||||
|
|
||||||
let mmm = Arc::new(MatchmakeManager {
|
let mmm = Arc::new(MatchmakeManager {
|
||||||
gid_counter: AtomicU32::new(1),
|
//gid_counter: AtomicU32::new(1),
|
||||||
sessions: Default::default(),
|
sessions: Default::default(),
|
||||||
users: Default::default(),
|
users: Default::default(),
|
||||||
rv_cid_counter: AtomicU32::new(1),
|
rv_cid_counter: AtomicU32::new(1),
|
||||||
|
|
@ -31,7 +30,8 @@ async fn main() {
|
||||||
pid: c.pid,
|
pid: c.pid,
|
||||||
remote: RemoteConsole::new(r),
|
remote: RemoteConsole::new(r),
|
||||||
matchmake_manager: mmm,
|
matchmake_manager: mmm,
|
||||||
station_url: Default::default()
|
station_url: Default::default(),
|
||||||
})
|
})
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
@ -1,27 +1,23 @@
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
use rnex_core::nex::account::Account;
|
||||||
|
use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection};
|
||||||
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
|
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
||||||
use std::env;
|
use std::env;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
use std::net::{Ipv4Addr, SocketAddrV4};
|
use std::net::{Ipv4Addr, SocketAddrV4};
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use once_cell::sync::Lazy;
|
|
||||||
use rnex_core::nex::account::Account;
|
|
||||||
use rnex_core::rmc::protocols::{RmcCallable, RmcConnection, new_rmc_gateway_connection};
|
|
||||||
use rnex_core::rnex_proxy_common::ConnectionInitData;
|
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
|
||||||
use tokio::net::TcpListener;
|
use tokio::net::TcpListener;
|
||||||
|
|
||||||
use std::error::Error;
|
|
||||||
use log::error;
|
use log::error;
|
||||||
|
use std::error::Error;
|
||||||
|
|
||||||
use crate::reggie::UnitPacketRead;
|
use crate::reggie::UnitPacketRead;
|
||||||
|
|
||||||
const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip";
|
const IP_REQ_SERVICE_URL: &str = "https://ipinfo.io/ip";
|
||||||
|
|
||||||
|
pub fn try_get_ip() -> Result<Ipv4Addr, Box<dyn Error>> {
|
||||||
|
let mut req = ureq::get(IP_REQ_SERVICE_URL).call()?;
|
||||||
fn try_get_ip() -> Result<Ipv4Addr, Box<dyn Error>> {
|
|
||||||
let mut req = ureq::get(IP_REQ_SERVICE_URL)
|
|
||||||
.call()?;
|
|
||||||
|
|
||||||
|
|
||||||
Ok(req.body_mut().read_to_string()?.parse()?)
|
Ok(req.body_mut().read_to_string()?.parse()?)
|
||||||
}
|
}
|
||||||
|
|
@ -37,16 +33,14 @@ pub static OWN_IP_PUBLIC: Lazy<Ipv4Addr> = Lazy::new(|| {
|
||||||
env::var("SERVER_IP_PUBLIC")
|
env::var("SERVER_IP_PUBLIC")
|
||||||
.ok()
|
.ok()
|
||||||
.map(|s| s.parse().expect("invalid ip address"))
|
.map(|s| s.parse().expect("invalid ip address"))
|
||||||
.unwrap_or_else(||{
|
.unwrap_or_else(|| try_get_ip().unwrap())
|
||||||
try_get_ip().unwrap()
|
|
||||||
})
|
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static SERVER_PORT: Lazy<u16> = Lazy::new(|| {
|
pub static SERVER_PORT: Lazy<u16> = Lazy::new(|| {
|
||||||
env::var("SERVER_PORT")
|
env::var("SERVER_PORT")
|
||||||
.ok()
|
.ok()
|
||||||
.and_then(|s| s.parse().ok())
|
.and_then(|s| s.parse().ok())
|
||||||
.unwrap_or(10000)
|
.unwrap_or(6000)
|
||||||
});
|
});
|
||||||
|
|
||||||
pub static KERBEROS_SERVER_PASSWORD: Lazy<String> = Lazy::new(|| {
|
pub static KERBEROS_SERVER_PASSWORD: Lazy<String> = Lazy::new(|| {
|
||||||
|
|
@ -60,17 +54,21 @@ pub static AUTH_SERVER_ACCOUNT: Lazy<Account> =
|
||||||
pub static SECURE_SERVER_ACCOUNT: Lazy<Account> =
|
pub static SECURE_SERVER_ACCOUNT: Lazy<Account> =
|
||||||
Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
|
Lazy::new(|| Account::new(2, "Quazal Rendez-Vous", &KERBEROS_SERVER_PASSWORD));
|
||||||
|
|
||||||
|
|
||||||
pub async fn new_simple_backend<T: RmcCallable + Sync + Send + 'static, F>(mut creation_function: F)
|
pub async fn new_simple_backend<T: RmcCallable + Sync + Send + 'static, F>(mut creation_function: F)
|
||||||
where
|
where
|
||||||
F: FnMut(ConnectionInitData, RmcConnection) -> Arc<T>,
|
F: FnMut(ConnectionInitData, RmcConnection) -> Arc<T>,
|
||||||
{
|
{
|
||||||
let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT)).await.unwrap();
|
let listen = TcpListener::bind(SocketAddrV4::new(*OWN_IP_PRIVATE, *SERVER_PORT))
|
||||||
|
.await
|
||||||
|
.unwrap();
|
||||||
while let Ok((mut stream, _addr)) = listen.accept().await {
|
while let Ok((mut stream, _addr)) = listen.accept().await {
|
||||||
let buffer = match stream.read_buffer().await {
|
let buffer = match stream.read_buffer().await {
|
||||||
Ok(v) => v,
|
Ok(v) => v,
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
error!("an error ocurred whilest reading connection data buffer: {:?}", e);
|
error!(
|
||||||
|
"an error ocurred whilest reading connection data buffer: {:?}",
|
||||||
|
e
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
@ -85,8 +83,6 @@ where
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
let fun_ref = &mut creation_function;
|
let fun_ref = &mut creation_function;
|
||||||
new_rmc_gateway_connection(stream.into(), move |r|{
|
new_rmc_gateway_connection(stream.into(), move |r| fun_ref(user_connection_data, r));
|
||||||
fun_ref(user_connection_data, r)
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
use std::hash::{DefaultHasher, Hasher};
|
|
||||||
use std::net::SocketAddrV4;
|
|
||||||
use std::sync::Arc;
|
|
||||||
use crate::grpc::account;
|
use crate::grpc::account;
|
||||||
use rnex_core::kerberos::{derive_key, KerberosDateTime, Ticket};
|
use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement};
|
||||||
|
use crate::{define_rmc_proto, kerberos};
|
||||||
|
use macros::rmc_struct;
|
||||||
|
use rnex_core::kerberos::{KerberosDateTime, Ticket, derive_key};
|
||||||
use rnex_core::nex::account::Account;
|
use rnex_core::nex::account::Account;
|
||||||
|
use rnex_core::rmc::protocols::OnlyRemote;
|
||||||
use rnex_core::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth};
|
use rnex_core::rmc::protocols::auth::{Auth, RawAuth, RawAuthInfo, RemoteAuth};
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
use rnex_core::rmc::response::ErrorCode::Core_Unknown;
|
use rnex_core::rmc::response::ErrorCode::Core_Unknown;
|
||||||
use rnex_core::rmc::structures::any::Any;
|
use rnex_core::rmc::structures::any::Any;
|
||||||
use rnex_core::rmc::structures::connection_data::ConnectionData;
|
use rnex_core::rmc::structures::connection_data::ConnectionData;
|
||||||
use rnex_core::rmc::structures::qresult::QResult;
|
use rnex_core::rmc::structures::qresult::QResult;
|
||||||
use crate::{define_rmc_proto, kerberos};
|
use std::hash::{DefaultHasher, Hasher};
|
||||||
use macros::rmc_struct;
|
use std::net::SocketAddrV4;
|
||||||
use crate::reggie::{RemoteEdgeNodeHolder, RemoteEdgeNodeManagement};
|
use std::sync::Arc;
|
||||||
use rnex_core::rmc::protocols::OnlyRemote;
|
|
||||||
|
|
||||||
define_rmc_proto!(
|
define_rmc_proto!(
|
||||||
proto AuthClientProtocol{
|
proto AuthClientProtocol{
|
||||||
|
|
@ -63,7 +63,8 @@ async fn get_login_data_by_pid(pid: u32) -> Option<(u32, [u8; 16])> {
|
||||||
fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String {
|
fn station_url_from_sock_addr(sock_addr: SocketAddrV4) -> String {
|
||||||
format!(
|
format!(
|
||||||
"prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1",
|
"prudps:/PID=2;sid=1;stream=10;type=2;address={};port={};CID=1",
|
||||||
sock_addr.ip(), sock_addr.port()
|
sock_addr.ip(),
|
||||||
|
sock_addr.port()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -117,7 +118,7 @@ impl Auth for AuthHandler {
|
||||||
source_login_data.0,
|
source_login_data.0,
|
||||||
ticket.into(),
|
ticket.into(),
|
||||||
connection_data,
|
connection_data,
|
||||||
self.build_name.to_string() //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")),
|
self.build_name.to_string(), //format!("{}; Rust NEX Version {} by DJMrTV", self.build_name, env!("CARGO_PKG_VERSION")),
|
||||||
))
|
))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -157,32 +158,30 @@ impl Auth for AuthHandler {
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
|
use rnex_core::rmc::response::RMCResponse;
|
||||||
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
use rnex_core::rmc::structures::connection_data::ConnectionData;
|
use rnex_core::rmc::structures::connection_data::ConnectionData;
|
||||||
use rnex_core::rmc::structures::qresult::QResult;
|
use rnex_core::rmc::structures::qresult::QResult;
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
|
||||||
use rnex_core::rmc::response::RMCResponse;
|
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
return;
|
||||||
let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
let stuff = hex::decode("200100000a0106000000028000000100010051b3995774000000a6321c7f78847c1c5e9fb825eb26bd91841f1a40d92fc694159666119cb13527f1463ac48ad42a63e6613ede67041554b1770978112e6f1f3e177a2bfc75933216dbe38f70133a1eb28e2ae32a4b5c4b0c3e3efd4c02907992e259b257270b57a9dbe7792f4721b07f8fafb9e32d50f2555c616a015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d3100000000000100002c153ba51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
||||||
let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap();
|
let stuff = RMCResponse::new(&mut Cursor::new(stuff)).unwrap();
|
||||||
|
|
||||||
let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result else {
|
let rnex_core::rmc::response::RMCResponseResult::Success { .. } = stuff.response_result
|
||||||
|
else {
|
||||||
panic!()
|
panic!()
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// let stuff = hex::decode("0100010051B399577400000085F1736FCFBE93660275A3FE36FED6C2EFC57222AC99A9219CF54170A415B02DF1463AC48AD42A6307813FDE67041554B177097832ED000F892D9551A09F88E9CB0388DC1BC9527CC7384556A3287B2A349ABBF7E34A5A3EC14C2287CC7F78DA616BC3B03A035347FBD2E9A505C8EF42447CD809015F0000004E007072756470733A2F73747265616D3D31303B747970653D323B616464726573733D3139322E3136382E3137382E3132303B706F72743D31303030313B4349443D313B5049443D323B7369643D310000000000010000CDF53AA51F00000033006272616E63683A6F726967696E2F70726F6A6563742F7775702D61676D6A206275696C643A335F385F31355F323030345F3000").unwrap();
|
// let stuff = hex::decode("0100010051B399577400000085F1736FCFBE93660275A3FE36FED6C2EFC57222AC99A9219CF54170A415B02DF1463AC48AD42A6307813FDE67041554B177097832ED000F892D9551A09F88E9CB0388DC1BC9527CC7384556A3287B2A349ABBF7E34A5A3EC14C2287CC7F78DA616BC3B03A035347FBD2E9A505C8EF42447CD809015F0000004E007072756470733A2F73747265616D3D31303B747970653D323B616464726573733D3139322E3136382E3137382E3132303B706F72743D31303030313B4349443D313B5049443D323B7369643D310000000000010000CDF53AA51F00000033006272616E63683A6F726967696E2F70726F6A6563742F7775702D61676D6A206275696C643A335F385F31355F323030345F3000").unwrap();
|
||||||
let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
let stuff = hex::decode("0100010051b399577400000037d3d4814d2b16dd546c94a75d32637b45f856b5abe73cf26cfaa235c5f2c1cef1463ac48ad42a637d873fde67041554b177097880cfa7e10bb810eaf686bfb0a0cf3d65b1f476ebc046d0855327986f557dca14fbb8594883c186b863f2206f22baa0309dbcc81da2f883cb2cdc12628ec7fced015c0000004b007072756470733a2f5049443d323b7369643d313b73747265616d3d31303b747970653d323b616464726573733d322e3234332e39352e3131333b706f72743d31303030313b4349443d310000000000010000b7f33aa51f00000033006272616e63683a6f726967696e2f70726f6a6563742f7775702d61676d6a206275696c643a335f385f31355f323030345f3000").unwrap();
|
||||||
|
|
||||||
let data = <(QResult, u32, Vec<u8>, ConnectionData, String) as RmcSerialize>::deserialize(
|
let data = <(QResult, u32, Vec<u8>, ConnectionData, String) as RmcSerialize>::deserialize(
|
||||||
&mut Cursor::new(stuff),
|
&mut Cursor::new(stuff),
|
||||||
).unwrap();
|
)
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
println!("data: {:?}", data);
|
println!("data: {:?}", data);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,40 +1,48 @@
|
||||||
use std::collections::HashMap;
|
|
||||||
use std::str::FromStr;
|
|
||||||
use std::sync::{Arc, Weak};
|
|
||||||
use std::sync::atomic::AtomicU32;
|
|
||||||
use std::sync::atomic::Ordering::Relaxed;
|
|
||||||
use std::time::Duration;
|
|
||||||
use log::info;
|
|
||||||
use rand::random;
|
|
||||||
use tokio::sync::{Mutex, RwLock};
|
|
||||||
use tokio::time::sleep;
|
|
||||||
use rnex_core::kerberos::KerberosDateTime;
|
|
||||||
use crate::nex::user::User;
|
use crate::nex::user::User;
|
||||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||||
use rnex_core::rmc::protocols::notifications::notification_types::{HOST_CHANGED, OWNERSHIP_CHANGED};
|
use log::info;
|
||||||
|
use rand::random;
|
||||||
|
use rnex_core::kerberos::KerberosDateTime;
|
||||||
|
use rnex_core::rmc::protocols::notifications::notification_types::{
|
||||||
|
HOST_CHANGED, OWNERSHIP_CHANGED,
|
||||||
|
};
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid};
|
use rnex_core::rmc::response::ErrorCode::{Core_InvalidArgument, RendezVous_SessionVoid};
|
||||||
use rnex_core::rmc::structures::matchmake::{Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria};
|
|
||||||
use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING;
|
use rnex_core::rmc::structures::matchmake::gathering_flags::PERSISTENT_GATHERING;
|
||||||
|
use rnex_core::rmc::structures::matchmake::{
|
||||||
|
Gathering, MatchmakeParam, MatchmakeSession, MatchmakeSessionSearchCriteria,
|
||||||
|
};
|
||||||
use rnex_core::rmc::structures::variant::Variant;
|
use rnex_core::rmc::structures::variant::Variant;
|
||||||
|
use std::collections::HashMap;
|
||||||
|
use std::str::FromStr;
|
||||||
|
use std::sync::atomic::AtomicU32;
|
||||||
|
use std::sync::atomic::Ordering::Relaxed;
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
use std::time::Duration;
|
||||||
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
use tokio::time::sleep;
|
||||||
|
|
||||||
pub struct MatchmakeManager {
|
pub struct MatchmakeManager {
|
||||||
pub gid_counter: AtomicU32,
|
//pub gid_counter: AtomicU32,
|
||||||
pub sessions: RwLock<HashMap<u32, Arc<Mutex<ExtendedMatchmakeSession>>>>,
|
pub sessions: RwLock<HashMap<u32, Arc<Mutex<ExtendedMatchmakeSession>>>>,
|
||||||
pub rv_cid_counter: AtomicU32,
|
pub rv_cid_counter: AtomicU32,
|
||||||
pub users: RwLock<HashMap<u32, Weak<User>>>
|
pub users: RwLock<HashMap<u32, Weak<User>>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MatchmakeManager {
|
impl MatchmakeManager {
|
||||||
pub fn next_gid(&self) -> u32 {
|
pub fn next_gid(&self) -> u32 {
|
||||||
self.gid_counter.fetch_add(1, Relaxed)
|
random()
|
||||||
|
//self.gid_counter.fetch_add(1, Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn next_cid(&self) -> u32 {
|
pub fn next_cid(&self) -> u32 {
|
||||||
self.rv_cid_counter.fetch_add(1, Relaxed)
|
self.rv_cid_counter.fetch_add(1, Relaxed)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn get_session(&self, gid: u32) -> Result<Arc<Mutex<ExtendedMatchmakeSession>>, ErrorCode>{
|
pub async fn get_session(
|
||||||
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
) -> Result<Arc<Mutex<ExtendedMatchmakeSession>>, ErrorCode> {
|
||||||
let sessions = self.sessions.read().await;
|
let sessions = self.sessions.read().await;
|
||||||
|
|
||||||
let Some(session) = sessions.get(&gid) else {
|
let Some(session) = sessions.get(&gid) else {
|
||||||
|
|
@ -92,7 +100,6 @@ impl MatchmakeManager{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
#[derive(Default, Debug)]
|
#[derive(Default, Debug)]
|
||||||
pub struct ExtendedMatchmakeSession {
|
pub struct ExtendedMatchmakeSession {
|
||||||
pub session: MatchmakeSession,
|
pub session: MatchmakeSession,
|
||||||
|
|
@ -111,17 +118,26 @@ fn check_bounds_str<T: FromStr + PartialOrd>(compare: T, str: &str) -> Option<bo
|
||||||
Some(bounds.0 <= compare && compare <= bounds.1)
|
Some(bounds.0 <= compare && compare <= bounds.1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn broadcast_notification<T: AsRef<User>>(players: &[T], notification_event: &NotificationEvent){
|
pub async fn broadcast_notification<T: AsRef<User>>(
|
||||||
|
players: &[T],
|
||||||
|
notification_event: &NotificationEvent,
|
||||||
|
) {
|
||||||
for player in players {
|
for player in players {
|
||||||
let player = player.as_ref();
|
let player = player.as_ref();
|
||||||
player.remote.process_notification_event(notification_event.clone()).await;
|
player
|
||||||
|
.remote
|
||||||
|
.process_notification_event(notification_event.clone())
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ExtendedMatchmakeSession {
|
impl ExtendedMatchmakeSession {
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn get_active_players(&self) -> Vec<Arc<User>> {
|
pub fn get_active_players(&self) -> Vec<Arc<User>> {
|
||||||
self.connected_players.iter().filter_map(|u| u.upgrade()).collect()
|
self.connected_players
|
||||||
|
.iter()
|
||||||
|
.filter_map(|u| u.upgrade())
|
||||||
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
|
|
@ -129,12 +145,15 @@ impl ExtendedMatchmakeSession{
|
||||||
broadcast_notification(&self.get_active_players(), notification_event).await;
|
broadcast_notification(&self.get_active_players(), notification_event).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn from_matchmake_session(gid: u32, session: MatchmakeSession, host: &Weak<User>) -> Self{
|
pub async fn from_matchmake_session(
|
||||||
|
gid: u32,
|
||||||
|
session: MatchmakeSession,
|
||||||
|
host: &Weak<User>,
|
||||||
|
) -> Self {
|
||||||
let Some(host) = host.upgrade() else {
|
let Some(host) = host.upgrade() else {
|
||||||
return Default::default();
|
return Default::default();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let mm_session = MatchmakeSession {
|
let mm_session = MatchmakeSession {
|
||||||
gathering: Gathering {
|
gathering: Gathering {
|
||||||
self_gid: gid,
|
self_gid: gid,
|
||||||
|
|
@ -147,8 +166,8 @@ impl ExtendedMatchmakeSession{
|
||||||
matchmake_param: MatchmakeParam {
|
matchmake_param: MatchmakeParam {
|
||||||
params: vec![
|
params: vec![
|
||||||
("@SR".to_owned(), Variant::Bool(true)),
|
("@SR".to_owned(), Variant::Bool(true)),
|
||||||
("@GIR".to_owned(), Variant::SInt64(3))
|
("@GIR".to_owned(), Variant::SInt64(3)),
|
||||||
]
|
],
|
||||||
},
|
},
|
||||||
system_password_enabled: false,
|
system_password_enabled: false,
|
||||||
..session
|
..session
|
||||||
|
|
@ -156,13 +175,13 @@ impl ExtendedMatchmakeSession{
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
session: mm_session,
|
session: mm_session,
|
||||||
connected_players: Default::default()
|
connected_players: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn add_players(&mut self, conns: &[Weak<User>], join_msg: String) {
|
pub async fn add_players(&mut self, conns: &[Weak<User>], join_msg: String) {
|
||||||
let Some(initiating_user) = conns[0].upgrade() else {
|
let Some(initiating_user) = conns[0].upgrade() else {
|
||||||
return
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let initiating_pid = initiating_user.pid;
|
let initiating_pid = initiating_user.pid;
|
||||||
|
|
@ -178,31 +197,37 @@ impl ExtendedMatchmakeSession{
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
let other_pid = other_conn.pid;
|
let other_pid = other_conn.pid;
|
||||||
/*if other_pid == self.session.gathering.owner_pid &&
|
/*if other_pid == self.session.gathering.owner_pid &&
|
||||||
joining_pid == self.session.gathering.owner_pid{
|
joining_pid == self.session.gathering.owner_pid{
|
||||||
continue;
|
continue;
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
other_conn.remote.process_notification_event(NotificationEvent{
|
other_conn
|
||||||
|
.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
pid_source: initiating_pid,
|
pid_source: initiating_pid,
|
||||||
notif_type: 122000,
|
notif_type: 122000,
|
||||||
param_1: self.session.gathering.self_gid,
|
param_1: self.session.gathering.self_gid,
|
||||||
param_2: other_pid,
|
param_2: other_pid,
|
||||||
str_param: "".into(),
|
str_param: "".into(),
|
||||||
param_3: 0
|
param_3: 0,
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
let list_of_connected_pids: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).map(|p| p.pid).collect();
|
let list_of_connected_pids: Vec<_> = self
|
||||||
|
.connected_players
|
||||||
|
.iter()
|
||||||
|
.filter_map(|p| p.upgrade())
|
||||||
|
.map(|p| p.pid)
|
||||||
|
.collect();
|
||||||
|
|
||||||
for other_connection in conns {
|
for other_connection in conns {
|
||||||
let Some(other_conn) = other_connection.upgrade() else {
|
let Some(other_conn) = other_connection.upgrade() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// let other_pid = other_conn.pid;
|
// let other_pid = other_conn.pid;
|
||||||
/*if other_pid == self.session.gathering.owner_pid &&
|
/*if other_pid == self.session.gathering.owner_pid &&
|
||||||
joining_pid == self.session.gathering.owner_pid{
|
joining_pid == self.session.gathering.owner_pid{
|
||||||
|
|
@ -210,14 +235,17 @@ impl ExtendedMatchmakeSession{
|
||||||
}*/
|
}*/
|
||||||
|
|
||||||
for pid in &list_of_connected_pids {
|
for pid in &list_of_connected_pids {
|
||||||
other_conn.remote.process_notification_event(NotificationEvent {
|
other_conn
|
||||||
|
.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
pid_source: initiating_pid,
|
pid_source: initiating_pid,
|
||||||
notif_type: 3001,
|
notif_type: 3001,
|
||||||
param_1: self.session.gathering.self_gid,
|
param_1: self.session.gathering.self_gid,
|
||||||
param_2: *pid,
|
param_2: *pid,
|
||||||
str_param: join_msg.clone(),
|
str_param: join_msg.clone(),
|
||||||
param_3: self.connected_players.len() as _
|
param_3: self.connected_players.len() as _,
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -228,20 +256,25 @@ impl ExtendedMatchmakeSession{
|
||||||
|
|
||||||
let older_pid = old_conns.pid;
|
let older_pid = old_conns.pid;
|
||||||
|
|
||||||
|
initiating_user
|
||||||
|
.remote
|
||||||
initiating_user.remote.process_notification_event(NotificationEvent{
|
.process_notification_event(NotificationEvent {
|
||||||
pid_source: initiating_pid,
|
pid_source: initiating_pid,
|
||||||
notif_type: 3001,
|
notif_type: 3001,
|
||||||
param_1: self.session.gathering.self_gid,
|
param_1: self.session.gathering.self_gid,
|
||||||
param_2: older_pid,
|
param_2: older_pid,
|
||||||
str_param: join_msg.clone(),
|
str_param: join_msg.clone(),
|
||||||
param_3: self.connected_players.len() as _
|
param_3: self.connected_players.len() as _,
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pub fn has_active_players(&self) -> bool {
|
pub fn has_active_players(&self) -> bool {
|
||||||
self.connected_players.iter().filter(|v| v.upgrade().is_some()).count() != 0
|
self.connected_players
|
||||||
|
.iter()
|
||||||
|
.filter(|v| v.upgrade().is_some())
|
||||||
|
.count()
|
||||||
|
!= 0
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|
@ -261,11 +294,16 @@ impl ExtendedMatchmakeSession{
|
||||||
self.is_reachable() && self.session.open_participation
|
self.is_reachable() && self.session.open_participation
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn matches_criteria(&self, search_criteria: &MatchmakeSessionSearchCriteria) -> Result<bool, ErrorCode>{
|
pub fn matches_criteria(
|
||||||
|
&self,
|
||||||
|
search_criteria: &MatchmakeSessionSearchCriteria,
|
||||||
|
) -> Result<bool, ErrorCode> {
|
||||||
// todo: implement the rest of the search criteria
|
// todo: implement the rest of the search criteria
|
||||||
|
|
||||||
if search_criteria.vacant_only {
|
if search_criteria.vacant_only {
|
||||||
if (self.connected_players.len() as u16 + search_criteria.vacant_participants) > self.session.gathering.maximum_participants{
|
if (self.connected_players.len() as u16 + search_criteria.vacant_participants)
|
||||||
|
> self.session.gathering.maximum_participants
|
||||||
|
{
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -288,34 +326,67 @@ impl ExtendedMatchmakeSession{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if !check_bounds_str(self.session.gathering.minimum_participants, &search_criteria.minimum_participants).ok_or(Core_InvalidArgument)? {
|
if !check_bounds_str(
|
||||||
|
self.session.gathering.minimum_participants,
|
||||||
|
&search_criteria.minimum_participants,
|
||||||
|
)
|
||||||
|
.ok_or(Core_InvalidArgument)?
|
||||||
|
{
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
if !check_bounds_str(self.session.gathering.maximum_participants, &search_criteria.maximum_participants).ok_or(Core_InvalidArgument)? {
|
if !check_bounds_str(
|
||||||
|
self.session.gathering.maximum_participants,
|
||||||
|
&search_criteria.maximum_participants,
|
||||||
|
)
|
||||||
|
.ok_or(Core_InvalidArgument)?
|
||||||
|
{
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let game_mode: u32 = search_criteria.game_mode.parse().map_err(|_| Core_InvalidArgument)?;
|
let game_mode: u32 = search_criteria
|
||||||
|
.game_mode
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| Core_InvalidArgument)?;
|
||||||
|
|
||||||
if self.session.gamemode != game_mode {
|
if self.session.gamemode != game_mode {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
let mm_sys_type: u32 = search_criteria.matchmake_system_type.parse().map_err(|_| Core_InvalidArgument)?;
|
let mm_sys_type: u32 = search_criteria
|
||||||
|
.matchmake_system_type
|
||||||
|
.parse()
|
||||||
|
.map_err(|_| Core_InvalidArgument)?;
|
||||||
|
|
||||||
if self.session.matchmake_system_type != mm_sys_type {
|
if self.session.matchmake_system_type != mm_sys_type {
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if search_criteria
|
||||||
if search_criteria.attribs.get(0).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(0).map(|v| *v){
|
.attribs
|
||||||
|
.get(0)
|
||||||
|
.map(|str| str.parse().ok())
|
||||||
|
.flatten()
|
||||||
|
!= self.session.attributes.get(0).map(|v| *v)
|
||||||
|
{
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if search_criteria.attribs.get(2).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(2).map(|v| *v){
|
if search_criteria
|
||||||
|
.attribs
|
||||||
|
.get(2)
|
||||||
|
.map(|str| str.parse().ok())
|
||||||
|
.flatten()
|
||||||
|
!= self.session.attributes.get(2).map(|v| *v)
|
||||||
|
{
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
if search_criteria.attribs.get(3).map(|str| str.parse().ok()).flatten() != self.session.attributes.get(3).map(|v| *v){
|
if search_criteria
|
||||||
|
.attribs
|
||||||
|
.get(3)
|
||||||
|
.map(|str| str.parse().ok())
|
||||||
|
.flatten()
|
||||||
|
!= self.session.attributes.get(3).map(|v| *v)
|
||||||
|
{
|
||||||
return Ok(false);
|
return Ok(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -323,9 +394,16 @@ impl ExtendedMatchmakeSession{
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn migrate_ownership(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> {
|
pub async fn migrate_ownership(&mut self, initiator_pid: u32) -> Result<(), ErrorCode> {
|
||||||
let players: Vec<_> = self.connected_players.iter().filter_map(|p| p.upgrade()).collect();
|
let players: Vec<_> = self
|
||||||
|
.connected_players
|
||||||
|
.iter()
|
||||||
|
.filter_map(|p| p.upgrade())
|
||||||
|
.collect();
|
||||||
|
|
||||||
let Some(new_owner) = players.iter().find(|p| p.pid != self.session.gathering.owner_pid) else {
|
let Some(new_owner) = players
|
||||||
|
.iter()
|
||||||
|
.find(|p| p.pid != self.session.gathering.owner_pid)
|
||||||
|
else {
|
||||||
self.session.gathering.owner_pid = 0;
|
self.session.gathering.owner_pid = 0;
|
||||||
|
|
||||||
return Ok(());
|
return Ok(());
|
||||||
|
|
@ -339,7 +417,8 @@ impl ExtendedMatchmakeSession{
|
||||||
param_1: self.session.gathering.self_gid,
|
param_1: self.session.gathering.self_gid,
|
||||||
param_2: new_owner.pid,
|
param_2: new_owner.pid,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
@ -354,15 +433,22 @@ impl ExtendedMatchmakeSession{
|
||||||
notif_type: HOST_CHANGED,
|
notif_type: HOST_CHANGED,
|
||||||
param_1: self.session.gathering.self_gid,
|
param_1: self.session.gathering.self_gid,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn remove_player_from_session(&mut self, pid: u32, message: &str) -> Result<(), ErrorCode>{
|
pub async fn remove_player_from_session(
|
||||||
self.connected_players.retain(|u| u.upgrade().is_some_and(|u| u.pid != pid));
|
&mut self,
|
||||||
|
pid: u32,
|
||||||
|
message: &str,
|
||||||
|
) -> Result<(), ErrorCode> {
|
||||||
|
self.connected_players
|
||||||
|
.retain(|u| u.upgrade().is_some_and(|u| u.pid != pid));
|
||||||
|
|
||||||
self.session.participation_count = (self.connected_players.len() & u32::MAX as usize) as u32;
|
self.session.participation_count =
|
||||||
|
(self.connected_players.len() & u32::MAX as usize) as u32;
|
||||||
|
|
||||||
if pid == self.session.gathering.owner_pid {
|
if pid == self.session.gathering.owner_pid {
|
||||||
self.migrate_ownership(pid).await?;
|
self.migrate_ownership(pid).await?;
|
||||||
|
|
@ -377,14 +463,17 @@ impl ExtendedMatchmakeSession{
|
||||||
// todo: finish the rest of this
|
// todo: finish the rest of this
|
||||||
|
|
||||||
for player in self.connected_players.iter().filter_map(|p| p.upgrade()) {
|
for player in self.connected_players.iter().filter_map(|p| p.upgrade()) {
|
||||||
player.remote.process_notification_event(NotificationEvent{
|
player
|
||||||
|
.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
notif_type: 3008,
|
notif_type: 3008,
|
||||||
pid_source: pid,
|
pid_source: pid,
|
||||||
param_1: self.session.gathering.self_gid,
|
param_1: self.session.gathering.self_gid,
|
||||||
param_2: pid,
|
param_2: pid,
|
||||||
str_param: message.to_owned(),
|
str_param: message.to_owned(),
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
|
||||||
|
|
@ -1,33 +1,41 @@
|
||||||
use crate::define_rmc_proto;
|
use crate::define_rmc_proto;
|
||||||
use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager};
|
use crate::nex::matchmake::{ExtendedMatchmakeSession, MatchmakeManager};
|
||||||
use crate::nex::remote_console::RemoteConsole;
|
use crate::nex::remote_console::RemoteConsole;
|
||||||
use rnex_core::prudp::station_url::StationUrl;
|
|
||||||
use rnex_core::prudp::station_url::UrlOptions::{
|
|
||||||
Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID,
|
|
||||||
|
|
||||||
};
|
|
||||||
use crate::rmc::protocols::matchmake::{
|
use crate::rmc::protocols::matchmake::{
|
||||||
Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake,
|
Matchmake, RawMatchmake, RawMatchmakeInfo, RemoteMatchmake,
|
||||||
};
|
};
|
||||||
use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking};
|
use crate::rmc::protocols::nat_traversal::{
|
||||||
|
NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal,
|
||||||
|
RemoteNatTraversalConsole,
|
||||||
|
};
|
||||||
|
use rnex_core::prudp::station_url::StationUrl;
|
||||||
|
use rnex_core::prudp::station_url::UrlOptions::{
|
||||||
|
Address, NatFiltering, NatMapping, NatType, Port, PrincipalID, RVConnectionID,
|
||||||
|
};
|
||||||
|
use rnex_core::rmc::protocols::matchmake_ext::{
|
||||||
|
MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt,
|
||||||
|
};
|
||||||
use rnex_core::rmc::protocols::matchmake_extension::{
|
use rnex_core::rmc::protocols::matchmake_extension::{
|
||||||
MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension,
|
MatchmakeExtension, RawMatchmakeExtension, RawMatchmakeExtensionInfo, RemoteMatchmakeExtension,
|
||||||
};
|
};
|
||||||
use crate::rmc::protocols::nat_traversal::{NatTraversal, RawNatTraversal, RawNatTraversalInfo, RemoteNatTraversal, RemoteNatTraversalConsole};
|
use rnex_core::rmc::protocols::ranking::{Ranking, RawRanking, RawRankingInfo, RemoteRanking};
|
||||||
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
use rnex_core::rmc::protocols::secure::{RawSecure, RawSecureInfo, RemoteSecure, Secure};
|
||||||
use rnex_core::rmc::protocols::matchmake_ext::{MatchmakeExt, RawMatchmakeExt, RawMatchmakeExtInfo, RemoteMatchmakeExt};
|
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
use rnex_core::rmc::structures::matchmake::{AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession};
|
use rnex_core::rmc::structures::matchmake::{
|
||||||
|
AutoMatchmakeParam, CreateMatchmakeSessionParam, JoinMatchmakeSessionParam, MatchmakeSession,
|
||||||
|
};
|
||||||
|
|
||||||
use rnex_core::rmc::structures::qresult::QResult;
|
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
||||||
use macros::rmc_struct;
|
|
||||||
use std::sync::{Arc, Weak};
|
|
||||||
use log::info;
|
use log::info;
|
||||||
use tokio::sync::{Mutex, RwLock};
|
use macros::rmc_struct;
|
||||||
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
use rnex_core::prudp::socket_addr::PRUDPSockAddr;
|
||||||
use rnex_core::prudp::station_url::nat_types::PUBLIC;
|
use rnex_core::prudp::station_url::nat_types::PUBLIC;
|
||||||
use crate::rmc::protocols::notifications::{NotificationEvent, RemoteNotification};
|
use rnex_core::rmc::response::ErrorCode::{
|
||||||
use rnex_core::rmc::response::ErrorCode::{Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired};
|
Core_Exception, Core_InvalidArgument, RendezVous_AccountExpired,
|
||||||
|
};
|
||||||
|
use rnex_core::rmc::structures::qresult::QResult;
|
||||||
|
use std::sync::{Arc, Weak};
|
||||||
|
use tokio::sync::{Mutex, RwLock};
|
||||||
|
|
||||||
define_rmc_proto!(
|
define_rmc_proto!(
|
||||||
proto UserProtocol{
|
proto UserProtocol{
|
||||||
|
|
@ -78,14 +86,14 @@ impl Secure for User {
|
||||||
|
|
||||||
let Some(nat_filtering) = station.options.iter().find_map(|v| match v {
|
let Some(nat_filtering) = station.options.iter().find_map(|v| match v {
|
||||||
NatFiltering(v) => Some(v),
|
NatFiltering(v) => Some(v),
|
||||||
_ => None
|
_ => None,
|
||||||
}) else {
|
}) else {
|
||||||
return Err(Core_Exception);
|
return Err(Core_Exception);
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(nat_mapping) = station.options.iter().find_map(|v| match v {
|
let Some(nat_mapping) = station.options.iter().find_map(|v| match v {
|
||||||
NatMapping(v) => Some(v),
|
NatMapping(v) => Some(v),
|
||||||
_ => None
|
_ => None,
|
||||||
}) else {
|
}) else {
|
||||||
return Err(Core_Exception);
|
return Err(Core_Exception);
|
||||||
};
|
};
|
||||||
|
|
@ -108,15 +116,17 @@ impl Secure for User {
|
||||||
} else {
|
} else {
|
||||||
let mut public_station = private_station.clone();
|
let mut public_station = private_station.clone();
|
||||||
|
|
||||||
public_station.options.retain(|v| {
|
public_station.options.retain(|v| match v {
|
||||||
match v {
|
|
||||||
Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false,
|
Address(_) | Port(_) | NatFiltering(_) | NatMapping(_) | NatType(_) => false,
|
||||||
_ => true
|
_ => true,
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
public_station.options.push(Address(*self.ip.regular_socket_addr.ip()));
|
public_station
|
||||||
public_station.options.push(Port(self.ip.regular_socket_addr.port()));
|
.options
|
||||||
|
.push(Address(*self.ip.regular_socket_addr.ip()));
|
||||||
|
public_station
|
||||||
|
.options
|
||||||
|
.push(Port(self.ip.regular_socket_addr.port()));
|
||||||
public_station.options.push(NatFiltering(0));
|
public_station.options.push(NatFiltering(0));
|
||||||
public_station.options.push(NatMapping(0));
|
public_station.options.push(NatMapping(0));
|
||||||
public_station.options.push(NatType(3));
|
public_station.options.push(NatType(3));
|
||||||
|
|
@ -127,18 +137,15 @@ impl Secure for User {
|
||||||
let both = [&mut public_station, &mut private_station];
|
let both = [&mut public_station, &mut private_station];
|
||||||
|
|
||||||
for station in both {
|
for station in both {
|
||||||
station.options.retain(|v| {
|
station.options.retain(|v| match v {
|
||||||
match v {
|
|
||||||
PrincipalID(_) | RVConnectionID(_) => false,
|
PrincipalID(_) | RVConnectionID(_) => false,
|
||||||
_ => true
|
_ => true,
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
station.options.push(PrincipalID(self.pid));
|
station.options.push(PrincipalID(self.pid));
|
||||||
station.options.push(RVConnectionID(cid));
|
station.options.push(RVConnectionID(cid));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
let mut lock = self.station_url.write().await;
|
let mut lock = self.station_url.write().await;
|
||||||
|
|
||||||
*lock = vec![
|
*lock = vec![
|
||||||
|
|
@ -169,8 +176,8 @@ impl Secure for User {
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(replacement_target) = lock.iter_mut().find(|url| {
|
let Some(replacement_target) = lock.iter_mut().find(|url| {
|
||||||
url.options.iter().any(|o| o == target_addr) &&
|
url.options.iter().any(|o| o == target_addr)
|
||||||
url.options.iter().any(|o| o == target_port)
|
&& url.options.iter().any(|o| o == target_port)
|
||||||
}) else {
|
}) else {
|
||||||
return Err(ErrorCode::Core_InvalidArgument);
|
return Err(ErrorCode::Core_InvalidArgument);
|
||||||
};
|
};
|
||||||
|
|
@ -236,16 +243,28 @@ impl MatchmakeExtension for User {
|
||||||
|
|
||||||
let users = self.matchmake_manager.users.read().await;
|
let users = self.matchmake_manager.users.read().await;
|
||||||
|
|
||||||
if let Ok(old_gathering) = self.matchmake_manager.get_session(create_session_param.gid_for_participation_check).await {
|
if let Ok(old_gathering) = self
|
||||||
|
.matchmake_manager
|
||||||
|
.get_session(create_session_param.gid_for_participation_check)
|
||||||
|
.await
|
||||||
|
{
|
||||||
let old_gathering = old_gathering.lock().await;
|
let old_gathering = old_gathering.lock().await;
|
||||||
|
|
||||||
let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| create_session_param.additional_participants.iter().any(|p| *p == u.pid));
|
let players = old_gathering
|
||||||
|
.connected_players
|
||||||
|
.iter()
|
||||||
|
.filter_map(|v| v.upgrade())
|
||||||
|
.filter(|u| {
|
||||||
|
create_session_param
|
||||||
|
.additional_participants
|
||||||
|
.iter()
|
||||||
|
.any(|p| *p == u.pid)
|
||||||
|
});
|
||||||
for player in players {
|
for player in players {
|
||||||
joining_players.push(Arc::downgrade(&player));
|
joining_players.push(Arc::downgrade(&player));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
drop(users);
|
drop(users);
|
||||||
|
|
||||||
new_session.session.participation_count = create_session_param.participation_count as u32;
|
new_session.session.participation_count = create_session_param.participation_count as u32;
|
||||||
|
|
@ -266,26 +285,43 @@ impl MatchmakeExtension for User {
|
||||||
&self,
|
&self,
|
||||||
join_session_param: JoinMatchmakeSessionParam,
|
join_session_param: JoinMatchmakeSessionParam,
|
||||||
) -> Result<MatchmakeSession, ErrorCode> {
|
) -> Result<MatchmakeSession, ErrorCode> {
|
||||||
let session = self.matchmake_manager.get_session(join_session_param.gid).await?;
|
let session = self
|
||||||
|
.matchmake_manager
|
||||||
|
.get_session(join_session_param.gid)
|
||||||
|
.await?;
|
||||||
|
|
||||||
let mut session = session.lock().await;
|
let mut session = session.lock().await;
|
||||||
|
|
||||||
if session.session.user_password_enabled {
|
if session.session.user_password_enabled {
|
||||||
if join_session_param.user_password != session.session.user_password {
|
if join_session_param.user_password != session.session.user_password {
|
||||||
return Err(ErrorCode::RendezVous_InvalidPassword)
|
return Err(ErrorCode::RendezVous_InvalidPassword);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
session.connected_players.retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid));
|
session
|
||||||
|
.connected_players
|
||||||
|
.retain(|v| v.upgrade().is_some_and(|v| v.pid != self.pid));
|
||||||
|
|
||||||
let mut joining_players = vec![self.this.clone()];
|
let mut joining_players = vec![self.this.clone()];
|
||||||
|
|
||||||
let users = self.matchmake_manager.users.read().await;
|
let users = self.matchmake_manager.users.read().await;
|
||||||
|
|
||||||
if let Ok(old_gathering) = self.matchmake_manager.get_session(join_session_param.gid_for_participation_check).await {
|
if let Ok(old_gathering) = self
|
||||||
|
.matchmake_manager
|
||||||
|
.get_session(join_session_param.gid_for_participation_check)
|
||||||
|
.await
|
||||||
|
{
|
||||||
let old_gathering = old_gathering.lock().await;
|
let old_gathering = old_gathering.lock().await;
|
||||||
|
|
||||||
let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| join_session_param.additional_participants.iter().any(|p| *p == u.pid));
|
let players = old_gathering
|
||||||
|
.connected_players
|
||||||
|
.iter()
|
||||||
|
.filter_map(|v| v.upgrade())
|
||||||
|
.filter(|u| {
|
||||||
|
join_session_param
|
||||||
|
.additional_participants
|
||||||
|
.iter()
|
||||||
|
.any(|p| *p == u.pid)
|
||||||
|
});
|
||||||
for player in players {
|
for player in players {
|
||||||
joining_players.push(Arc::downgrade(&player));
|
joining_players.push(Arc::downgrade(&player));
|
||||||
}
|
}
|
||||||
|
|
@ -302,17 +338,28 @@ impl MatchmakeExtension for User {
|
||||||
Ok(mm_session)
|
Ok(mm_session)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn auto_matchmake_with_param_postpone(&self, param: AutoMatchmakeParam) -> Result<MatchmakeSession, ErrorCode> {
|
async fn auto_matchmake_with_param_postpone(
|
||||||
|
&self,
|
||||||
|
param: AutoMatchmakeParam,
|
||||||
|
) -> Result<MatchmakeSession, ErrorCode> {
|
||||||
println!("{:?}", param);
|
println!("{:?}", param);
|
||||||
|
|
||||||
let mut joining_players = vec![self.this.clone()];
|
let mut joining_players = vec![self.this.clone()];
|
||||||
|
|
||||||
let users = self.matchmake_manager.users.read().await;
|
let users = self.matchmake_manager.users.read().await;
|
||||||
|
|
||||||
if let Ok(old_gathering) = self.matchmake_manager.get_session(param.gid_for_participation_check).await {
|
if let Ok(old_gathering) = self
|
||||||
|
.matchmake_manager
|
||||||
|
.get_session(param.gid_for_participation_check)
|
||||||
|
.await
|
||||||
|
{
|
||||||
let old_gathering = old_gathering.lock().await;
|
let old_gathering = old_gathering.lock().await;
|
||||||
|
|
||||||
let players = old_gathering.connected_players.iter().filter_map(|v| v.upgrade()).filter(|u| param.additional_participants.iter().any(|p| *p == u.pid));
|
let players = old_gathering
|
||||||
|
.connected_players
|
||||||
|
.iter()
|
||||||
|
.filter_map(|v| v.upgrade())
|
||||||
|
.filter(|u| param.additional_participants.iter().any(|p| *p == u.pid));
|
||||||
for player in players {
|
for player in players {
|
||||||
joining_players.push(Arc::downgrade(&player));
|
joining_players.push(Arc::downgrade(&player));
|
||||||
}
|
}
|
||||||
|
|
@ -339,7 +386,9 @@ impl MatchmakeExtension for User {
|
||||||
}
|
}
|
||||||
|
|
||||||
if bool_matched_criteria {
|
if bool_matched_criteria {
|
||||||
session.add_players(&joining_players, param.join_message).await;
|
session
|
||||||
|
.add_players(&joining_players, param.join_message)
|
||||||
|
.await;
|
||||||
|
|
||||||
return Ok(session.session.clone());
|
return Ok(session.session.clone());
|
||||||
}
|
}
|
||||||
|
|
@ -365,17 +414,26 @@ impl MatchmakeExtension for User {
|
||||||
create_matchmake_session_option: 0,
|
create_matchmake_session_option: 0,
|
||||||
matchmake_session,
|
matchmake_session,
|
||||||
additional_participants,
|
additional_participants,
|
||||||
}).await
|
})
|
||||||
|
.await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn find_matchmake_session_by_gathering_id_detail(&self, gid: u32) -> Result<MatchmakeSession, ErrorCode> {
|
async fn find_matchmake_session_by_gathering_id_detail(
|
||||||
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
) -> Result<MatchmakeSession, ErrorCode> {
|
||||||
let session = self.matchmake_manager.get_session(gid).await?;
|
let session = self.matchmake_manager.get_session(gid).await?;
|
||||||
let session = session.lock().await;
|
let session = session.lock().await;
|
||||||
|
|
||||||
Ok(session.session.clone())
|
Ok(session.session.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn modify_current_game_attribute(&self, gid: u32, attrib_index: u32, attrib_val: u32) -> Result<(), ErrorCode> {
|
async fn modify_current_game_attribute(
|
||||||
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
attrib_index: u32,
|
||||||
|
attrib_val: u32,
|
||||||
|
) -> Result<(), ErrorCode> {
|
||||||
let session = self.matchmake_manager.get_session(gid).await?;
|
let session = self.matchmake_manager.get_session(gid).await?;
|
||||||
let mut session = session.lock().await;
|
let mut session = session.lock().await;
|
||||||
|
|
||||||
|
|
@ -394,30 +452,30 @@ impl Matchmake for User {
|
||||||
|
|
||||||
let session = session.lock().await;
|
let session = session.lock().await;
|
||||||
|
|
||||||
let urls: Vec<_> =
|
let urls: Vec<_> = session
|
||||||
session
|
|
||||||
.connected_players
|
.connected_players
|
||||||
.iter()
|
.iter()
|
||||||
.filter_map(|v| v.upgrade())
|
.filter_map(|v| v.upgrade())
|
||||||
.filter(|u| u.pid == session.session.gathering.host_pid)
|
.filter(|u| u.pid == session.session.gathering.host_pid)
|
||||||
.map(|u| async move {
|
.map(|u| async move { u.station_url.read().await.clone() })
|
||||||
u.station_url.read().await.clone()
|
|
||||||
})
|
|
||||||
.next()
|
.next()
|
||||||
.ok_or(ErrorCode::RendezVous_SessionClosed)?
|
.ok_or(ErrorCode::RendezVous_SessionClosed)?
|
||||||
.await;
|
.await;
|
||||||
|
|
||||||
|
|
||||||
println!("{:?}", urls);
|
println!("{:?}", urls);
|
||||||
|
|
||||||
if urls.is_empty() {
|
if urls.is_empty() {
|
||||||
return Err(ErrorCode::RendezVous_NotParticipatedGathering)
|
return Err(ErrorCode::RendezVous_NotParticipatedGathering);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(urls)
|
Ok(urls)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn update_session_host(&self, gid: u32, change_session_owner: bool) -> Result<(), ErrorCode> {
|
async fn update_session_host(
|
||||||
|
&self,
|
||||||
|
gid: u32,
|
||||||
|
change_session_owner: bool,
|
||||||
|
) -> Result<(), ErrorCode> {
|
||||||
let session = self.matchmake_manager.get_session(gid).await?;
|
let session = self.matchmake_manager.get_session(gid).await?;
|
||||||
let mut session = session.lock().await;
|
let mut session = session.lock().await;
|
||||||
|
|
||||||
|
|
@ -428,40 +486,50 @@ impl Matchmake for User {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
player.remote.process_notification_event(NotificationEvent {
|
player
|
||||||
|
.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
notif_type: 110000,
|
notif_type: 110000,
|
||||||
pid_source: self.pid,
|
pid_source: self.pid,
|
||||||
param_1: gid,
|
param_1: gid,
|
||||||
param_2: self.pid,
|
param_2: self.pid,
|
||||||
param_3: 0,
|
param_3: 0,
|
||||||
str_param: "".to_string(),
|
str_param: "".to_string(),
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
if change_session_owner {
|
if change_session_owner {
|
||||||
session.session.gathering.owner_pid = self.pid;
|
session.session.gathering.owner_pid = self.pid;
|
||||||
|
|
||||||
|
|
||||||
for player in &session.connected_players {
|
for player in &session.connected_players {
|
||||||
let Some(player) = player.upgrade() else {
|
let Some(player) = player.upgrade() else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
player.remote.process_notification_event(NotificationEvent {
|
player
|
||||||
|
.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
notif_type: 4000,
|
notif_type: 4000,
|
||||||
pid_source: self.pid,
|
pid_source: self.pid,
|
||||||
param_1: gid,
|
param_1: gid,
|
||||||
param_2: self.pid,
|
param_2: self.pid,
|
||||||
param_3: 0,
|
param_3: 0,
|
||||||
str_param: "".to_string(),
|
str_param: "".to_string(),
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
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 session = self.matchmake_manager.get_session(gid).await?;
|
||||||
let mut session = session.lock().await;
|
let mut session = session.lock().await;
|
||||||
|
|
||||||
|
|
@ -474,14 +542,17 @@ impl Matchmake for User {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
player.remote.process_notification_event(NotificationEvent {
|
player
|
||||||
|
.remote
|
||||||
|
.process_notification_event(NotificationEvent {
|
||||||
notif_type: 4000,
|
notif_type: 4000,
|
||||||
pid_source: self.pid,
|
pid_source: self.pid,
|
||||||
param_1: gid,
|
param_1: gid,
|
||||||
param_2: *candidate,
|
param_2: *candidate,
|
||||||
param_3: 0,
|
param_3: 0,
|
||||||
str_param: "".to_string(),
|
str_param: "".to_string(),
|
||||||
}).await;
|
})
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
|
|
@ -493,12 +564,12 @@ impl MatchmakeExt for User {
|
||||||
let session = self.matchmake_manager.get_session(gid).await?;
|
let session = self.matchmake_manager.get_session(gid).await?;
|
||||||
let mut session = session.lock().await;
|
let mut session = session.lock().await;
|
||||||
|
|
||||||
session.remove_player_from_session(self.pid, &message).await?;
|
session
|
||||||
|
.remove_player_from_session(self.pid, &message)
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(true)
|
Ok(true)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl NatTraversal for User {
|
impl NatTraversal for User {
|
||||||
|
|
@ -513,7 +584,7 @@ impl NatTraversal for User {
|
||||||
for station_url in urls.iter_mut() {
|
for station_url in urls.iter_mut() {
|
||||||
station_url.options.retain(|o| match o {
|
station_url.options.retain(|o| match o {
|
||||||
NatMapping(_) | NatFiltering(_) => false,
|
NatMapping(_) | NatFiltering(_) => false,
|
||||||
_ => true
|
_ => true,
|
||||||
});
|
});
|
||||||
|
|
||||||
station_url.options.push(NatMapping(nat_mapping as u8));
|
station_url.options.push(NatMapping(nat_mapping as u8));
|
||||||
|
|
@ -523,7 +594,12 @@ impl NatTraversal for User {
|
||||||
Ok(())
|
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(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -532,17 +608,28 @@ impl NatTraversal for User {
|
||||||
Err(RendezVous_AccountExpired)
|
Err(RendezVous_AccountExpired)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn request_probe_initialization_ext(&self, target_list: Vec<String>, station_to_probe: String) -> Result<(), ErrorCode> {
|
async fn request_probe_initialization_ext(
|
||||||
|
&self,
|
||||||
|
target_list: Vec<String>,
|
||||||
|
station_to_probe: String,
|
||||||
|
) -> Result<(), ErrorCode> {
|
||||||
let users = self.matchmake_manager.users.read().await;
|
let users = self.matchmake_manager.users.read().await;
|
||||||
|
|
||||||
println!("requesting station probe for {:?} to {:?}", target_list, station_to_probe);
|
println!(
|
||||||
|
"requesting station probe for {:?} to {:?}",
|
||||||
|
target_list, station_to_probe
|
||||||
|
);
|
||||||
|
|
||||||
for target in target_list {
|
for target in target_list {
|
||||||
let Ok(url) = StationUrl::try_from(target.as_ref()) else {
|
let Ok(url) = StationUrl::try_from(target.as_ref()) else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
let Some(RVConnectionID(v)) = url.options.into_iter().find(|o| { matches!(o, &RVConnectionID(_)) }) else {
|
let Some(RVConnectionID(v)) = url
|
||||||
|
.options
|
||||||
|
.into_iter()
|
||||||
|
.find(|o| matches!(o, &RVConnectionID(_)))
|
||||||
|
else {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -554,7 +641,9 @@ impl NatTraversal for User {
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
||||||
user.remote.request_probe_initiation(station_to_probe.clone()).await;
|
user.remote
|
||||||
|
.request_probe_initiation(station_to_probe.clone())
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("finished probing");
|
info!("finished probing");
|
||||||
|
|
@ -563,6 +652,4 @@ impl NatTraversal for User {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Ranking for User{
|
impl Ranking for User {}
|
||||||
|
|
||||||
}
|
|
||||||
|
|
|
||||||
20
rnex-core/src/prudp/encryption.rs
Normal file
20
rnex-core/src/prudp/encryption.rs
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use rc4::{Key, StreamCipher};
|
||||||
|
use typenum::U5;
|
||||||
|
|
||||||
|
pub struct EncryptionPair<T: StreamCipher + Send> {
|
||||||
|
pub send: T,
|
||||||
|
pub recv: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: StreamCipher + Send> EncryptionPair<T> {
|
||||||
|
pub fn init_both<F: Fn() -> T>(func: F) -> Self {
|
||||||
|
Self {
|
||||||
|
recv: func(),
|
||||||
|
send: func(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub static DEFAULT_KEY: LazyLock<Key<U5>> = LazyLock::new(|| Key::from(*b"CD&ML"));
|
||||||
|
|
@ -1,3 +1,5 @@
|
||||||
pub mod virtual_port;
|
pub mod encryption;
|
||||||
pub mod station_url;
|
|
||||||
pub mod socket_addr;
|
pub mod socket_addr;
|
||||||
|
pub mod station_url;
|
||||||
|
pub mod types_flags;
|
||||||
|
pub mod virtual_port;
|
||||||
|
|
|
||||||
64
rnex-core/src/prudp/types_flags.rs
Normal file
64
rnex-core/src/prudp/types_flags.rs
Normal file
|
|
@ -0,0 +1,64 @@
|
||||||
|
use std::fmt::{Debug, Formatter};
|
||||||
|
|
||||||
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use v_byte_helpers::SwapEndian;
|
||||||
|
|
||||||
|
#[repr(transparent)]
|
||||||
|
#[derive(Copy, Clone, Pod, Zeroable, SwapEndian, Default, Eq, PartialEq)]
|
||||||
|
pub struct TypesFlags(pub u16);
|
||||||
|
|
||||||
|
impl TypesFlags {
|
||||||
|
#[inline]
|
||||||
|
pub const fn get_types(self) -> u8 {
|
||||||
|
(self.0 & 0x000F) as u8
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn get_flags(self) -> u16 {
|
||||||
|
(self.0 & 0xFFF0) >> 4
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn types(self, val: u8) -> Self {
|
||||||
|
Self((self.0 & 0xFFF0) | (val as u16 & 0x000F))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn flags(self, val: u16) -> Self {
|
||||||
|
Self((self.0 & 0x000F) | ((val << 4) & 0xFFF0))
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn set_flag(&mut self, val: u16) {
|
||||||
|
self.0 |= (val & 0xFFF) << 4;
|
||||||
|
}
|
||||||
|
#[inline]
|
||||||
|
pub const fn set_types(&mut self, val: u8) {
|
||||||
|
self.0 |= val as u16 & 0x0F;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl Debug for TypesFlags {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
let stream_type = self.get_types();
|
||||||
|
let port_number = self.get_flags();
|
||||||
|
write!(
|
||||||
|
f,
|
||||||
|
"TypesFlags{{ types: {}, flags: {} }}",
|
||||||
|
stream_type, port_number
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod flags {
|
||||||
|
pub const ACK: u16 = 0x001;
|
||||||
|
pub const RELIABLE: u16 = 0x002;
|
||||||
|
pub const NEED_ACK: u16 = 0x004;
|
||||||
|
pub const HAS_SIZE: u16 = 0x008;
|
||||||
|
pub const MULTI_ACK: u16 = 0x200;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub mod types {
|
||||||
|
pub const SYN: u8 = 0x0;
|
||||||
|
pub const CONNECT: u8 = 0x1;
|
||||||
|
pub const DATA: u8 = 0x2;
|
||||||
|
pub const DISCONNECT: u8 = 0x3;
|
||||||
|
pub const PING: u8 = 0x4;
|
||||||
|
/// no idea what user is supposed to mean
|
||||||
|
pub const USER: u8 = 0x5;
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,8 @@
|
||||||
use std::fmt::{Debug, Formatter};
|
|
||||||
use bytemuck::{Pod, Zeroable};
|
use bytemuck::{Pod, Zeroable};
|
||||||
|
use std::{
|
||||||
|
fmt::{Debug, Formatter},
|
||||||
|
slice,
|
||||||
|
};
|
||||||
use v_byte_helpers::SwapEndian;
|
use v_byte_helpers::SwapEndian;
|
||||||
|
|
||||||
#[repr(transparent)]
|
#[repr(transparent)]
|
||||||
|
|
@ -7,7 +10,6 @@ use v_byte_helpers::SwapEndian;
|
||||||
pub struct VirtualPort(pub u8);
|
pub struct VirtualPort(pub 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
|
||||||
|
|
@ -38,12 +40,21 @@ impl VirtualPort {
|
||||||
pub fn new(port: u8, stream_type: u8) -> Self {
|
pub fn new(port: u8, stream_type: u8) -> Self {
|
||||||
Self(0).stream_type(stream_type).port_number(port)
|
Self(0).stream_type(stream_type).port_number(port)
|
||||||
}
|
}
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn parse(data: &str) -> Option<Self> {
|
||||||
|
let (p1, p2) = data.split_once(':')?;
|
||||||
|
Some(Self::new(p1.parse().ok()?, p2.parse().ok()?))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Debug for VirtualPort {
|
impl Debug for VirtualPort {
|
||||||
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
let stream_type = self.get_stream_type();
|
let stream_type = self.get_stream_type();
|
||||||
let port_number = self.get_port_number();
|
let port_number = self.get_port_number();
|
||||||
write!(f, "VirtualPort{{ stream_type: {}, port_number: {} }}", stream_type, port_number)
|
write!(
|
||||||
|
f,
|
||||||
|
"VirtualPort{{ stream_type: {}, port_number: {} }}",
|
||||||
|
stream_type, port_number
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
|
use crate::define_rmc_proto;
|
||||||
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
use macros::{RmcSerialize, method_id, rmc_proto};
|
||||||
|
use rnex_core::rmc::response::ErrorCode;
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::net::SocketAddrV4;
|
use std::net::SocketAddrV4;
|
||||||
use macros::{method_id, rmc_proto, RmcSerialize};
|
|
||||||
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
|
||||||
use crate::define_rmc_proto;
|
|
||||||
use rnex_core::rmc::response::ErrorCode;
|
|
||||||
use crate::rmc::structures::RmcSerialize;
|
|
||||||
|
|
||||||
pub trait UnitPacketRead: AsyncRead + Unpin {
|
pub trait UnitPacketRead: AsyncRead + Unpin {
|
||||||
async fn read_buffer(&mut self) -> Result<Vec<u8>, io::Error> {
|
async fn read_buffer(&mut self) -> Result<Vec<u8>, io::Error> {
|
||||||
|
|
@ -27,7 +27,8 @@ pub trait UnitPacketWrite: AsyncWrite + Unpin{
|
||||||
async fn send_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> {
|
async fn send_buffer(&mut self, data: &[u8]) -> Result<(), io::Error> {
|
||||||
let mut dest_data = Vec::new();
|
let mut dest_data = Vec::new();
|
||||||
|
|
||||||
data.serialize(&mut dest_data).expect("ran out of memory or something");
|
data.serialize(&mut dest_data)
|
||||||
|
.expect("ran out of memory or something");
|
||||||
|
|
||||||
self.write_all(&dest_data[..]).await?;
|
self.write_all(&dest_data[..]).await?;
|
||||||
|
|
||||||
|
|
@ -39,8 +40,6 @@ pub trait UnitPacketWrite: AsyncWrite + Unpin{
|
||||||
|
|
||||||
impl<T: AsyncWrite + Unpin> UnitPacketWrite for T {}
|
impl<T: AsyncWrite + Unpin> UnitPacketWrite for T {}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
#[rmc_proto(1)]
|
#[rmc_proto(1)]
|
||||||
pub trait EdgeNodeManagement {
|
pub trait EdgeNodeManagement {
|
||||||
#[method_id(1)]
|
#[method_id(1)]
|
||||||
|
|
@ -57,5 +56,5 @@ define_rmc_proto!(
|
||||||
#[repr(u32)]
|
#[repr(u32)]
|
||||||
pub enum EdgeNodeHolderConnectOption {
|
pub enum EdgeNodeHolderConnectOption {
|
||||||
DontRegister = 0,
|
DontRegister = 0,
|
||||||
Register(SocketAddrV4) = 1
|
Register(SocketAddrV4) = 1,
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,21 @@
|
||||||
#![allow(async_fn_in_trait)]
|
#![allow(async_fn_in_trait)]
|
||||||
|
|
||||||
pub mod auth;
|
pub mod auth;
|
||||||
pub mod secure;
|
|
||||||
pub mod notifications;
|
|
||||||
pub mod matchmake;
|
pub mod matchmake;
|
||||||
|
pub mod matchmake_ext;
|
||||||
pub mod matchmake_extension;
|
pub mod matchmake_extension;
|
||||||
pub mod nat_traversal;
|
pub mod nat_traversal;
|
||||||
pub mod matchmake_ext;
|
pub mod notifications;
|
||||||
pub mod ranking;
|
pub mod ranking;
|
||||||
|
pub mod secure;
|
||||||
|
|
||||||
use crate::util::{SendingBufferConnection, SplittableBufferConnection};
|
use crate::result::ResultExtension;
|
||||||
use crate::rmc::message::RMCMessage;
|
use crate::rmc::message::RMCMessage;
|
||||||
use crate::rmc::protocols::RemoteCallError::ConnectionBroke;
|
use crate::rmc::protocols::RemoteCallError::ConnectionBroke;
|
||||||
use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
|
use crate::rmc::response::{ErrorCode, RMCResponse, RMCResponseResult};
|
||||||
use crate::rmc::structures;
|
use crate::rmc::structures;
|
||||||
use crate::rmc::structures::RmcSerialize;
|
use crate::rmc::structures::RmcSerialize;
|
||||||
|
use crate::util::{SendingBufferConnection, SplittableBufferConnection};
|
||||||
use log::{error, info};
|
use log::{error, info};
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
use std::future::Future;
|
use std::future::Future;
|
||||||
|
|
@ -24,8 +25,7 @@ use std::sync::Arc;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
use tokio::sync::{Mutex, Notify};
|
use tokio::sync::{Mutex, Notify};
|
||||||
use tokio::time::{sleep, sleep_until, Instant};
|
use tokio::time::{Instant, sleep, sleep_until};
|
||||||
use crate::result::ResultExtension;
|
|
||||||
|
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
pub enum RemoteCallError {
|
pub enum RemoteCallError {
|
||||||
|
|
@ -93,14 +93,10 @@ impl RmcResponseReceiver {
|
||||||
|
|
||||||
if let Some(v) = locked.remove(&call_id) {
|
if let Some(v) = locked.remove(&call_id) {
|
||||||
match v.response_result {
|
match v.response_result {
|
||||||
RMCResponseResult::Success {
|
RMCResponseResult::Success { data, .. } => return Ok(data),
|
||||||
data,
|
RMCResponseResult::Error { error_code, .. } => {
|
||||||
..
|
return Err(RemoteCallError::ServerError(error_code));
|
||||||
} => return Ok(data),
|
}
|
||||||
RMCResponseResult::Error {
|
|
||||||
error_code,
|
|
||||||
..
|
|
||||||
} => return Err(RemoteCallError::ServerError(error_code))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -167,10 +163,14 @@ macro_rules! define_rmc_proto {
|
||||||
|
|
||||||
pub struct [<Remote $name>](rnex_core::rmc::protocols::RmcConnection);
|
pub struct [<Remote $name>](rnex_core::rmc::protocols::RmcConnection);
|
||||||
|
|
||||||
impl rnex_core::rmc::protocols::RemoteInstantiatable for [<Remote $name>]{
|
impl rnex_core::rmc::protocols::RmcPureRemoteObject for [<Remote $name>]{
|
||||||
fn new(conn: rnex_core::rmc::protocols::RmcConnection) -> Self{
|
fn new(conn: rnex_core::rmc::protocols::RmcConnection) -> Self{
|
||||||
Self(conn)
|
Self(conn)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl rnex_core::rmc::protocols::RemoteDisconnectable for [<Remote $name>]{
|
||||||
|
|
||||||
async fn disconnect(&self){
|
async fn disconnect(&self){
|
||||||
self.0.disconnect().await;
|
self.0.disconnect().await;
|
||||||
}
|
}
|
||||||
|
|
@ -203,14 +203,23 @@ impl RmcCallable for () {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait RemoteInstantiatable{
|
pub trait RmcPureRemoteObject {
|
||||||
fn new(conn: RmcConnection) -> Self;
|
fn new(conn: RmcConnection) -> Self;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub trait RemoteDisconnectable {
|
||||||
async fn disconnect(&self);
|
async fn disconnect(&self);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct OnlyRemote<T: RemoteInstantiatable>(T);
|
pub struct OnlyRemote<T: RemoteDisconnectable>(T);
|
||||||
|
|
||||||
impl<T: RemoteInstantiatable> Deref for OnlyRemote<T>{
|
impl<T: RemoteDisconnectable + RmcPureRemoteObject> OnlyRemote<T> {
|
||||||
|
pub fn new(conn: RmcConnection) -> Self {
|
||||||
|
Self(T::new(conn))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: RemoteDisconnectable> Deref for OnlyRemote<T> {
|
||||||
type Target = T;
|
type Target = T;
|
||||||
|
|
||||||
fn deref(&self) -> &Self::Target {
|
fn deref(&self) -> &Self::Target {
|
||||||
|
|
@ -218,18 +227,21 @@ impl<T: RemoteInstantiatable> Deref for OnlyRemote<T>{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RemoteInstantiatable> OnlyRemote<T>{
|
impl<T: RemoteDisconnectable> OnlyRemote<T> {
|
||||||
pub fn new(conn: RmcConnection) -> Self{
|
|
||||||
Self(T::new(conn))
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn disconnect(&self) {
|
pub async fn disconnect(&self) {
|
||||||
self.0.disconnect().await;
|
self.0.disconnect().await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RemoteInstantiatable> RmcCallable for OnlyRemote<T>{
|
impl<T: RemoteDisconnectable> RmcCallable for OnlyRemote<T> {
|
||||||
fn rmc_call(&self, _responder: &SendingBufferConnection, _protocol_id: u16, _method_id: u32, _call_id: u32, _rest: Vec<u8>) -> impl 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
|
// maybe respond with not implemented or something
|
||||||
async {}
|
async {}
|
||||||
}
|
}
|
||||||
|
|
@ -247,7 +259,7 @@ async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
|
||||||
let Some(proto_id) = v.get(4) else {
|
let Some(proto_id) = v.get(4) else {
|
||||||
error!("received too small rmc message.");
|
error!("received too small rmc message.");
|
||||||
error!("ending rmc gateway.");
|
error!("ending rmc gateway.");
|
||||||
return
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
// protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol
|
// protocol 0 is hardcoded to be the no protocol protocol aka keepalive protocol
|
||||||
|
|
@ -259,7 +271,7 @@ async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
|
||||||
if (proto_id & 0x80) == 0 {
|
if (proto_id & 0x80) == 0 {
|
||||||
let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else {
|
let Some(response) = RMCResponse::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||||
error!("ending rmc gateway.");
|
error!("ending rmc gateway.");
|
||||||
return
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
info!("got rmc response");
|
info!("got rmc response");
|
||||||
|
|
@ -271,28 +283,34 @@ async fn handle_incoming<T: RmcCallable + Send + Sync + 'static>(
|
||||||
} else {
|
} else {
|
||||||
let Some(message) = RMCMessage::new(&mut Cursor::new(v)).display_err_or_some() else {
|
let Some(message) = RMCMessage::new(&mut Cursor::new(v)).display_err_or_some() else {
|
||||||
error!("ending rmc gateway.");
|
error!("ending rmc gateway.");
|
||||||
return
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
let RMCMessage {
|
let RMCMessage {
|
||||||
protocol_id,
|
protocol_id,
|
||||||
method_id,
|
method_id,
|
||||||
call_id,
|
call_id,
|
||||||
rest_of_data
|
rest_of_data,
|
||||||
} = message;
|
} = message;
|
||||||
|
|
||||||
info!("RMC REQUEST: Proto: {}; Method: {};", protocol_id, method_id);
|
info!(
|
||||||
|
"RMC REQUEST: Proto: {}; Method: {};",
|
||||||
remote.rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data).await;
|
protocol_id, method_id
|
||||||
|
);
|
||||||
|
|
||||||
|
remote
|
||||||
|
.rmc_call(&sending_conn, protocol_id, method_id, call_id, rest_of_data)
|
||||||
|
.await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
info!("rmc disconnected")
|
info!("rmc disconnected")
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn new_rmc_gateway_connection<T: RmcCallable + Sync + Send + 'static,F>(conn: SplittableBufferConnection, create_internal: F) -> Arc<T>
|
pub fn new_rmc_gateway_connection<T: RmcCallable + Sync + Send + 'static, F>(
|
||||||
|
conn: SplittableBufferConnection,
|
||||||
|
create_internal: F,
|
||||||
|
) -> Arc<T>
|
||||||
where
|
where
|
||||||
F: FnOnce(RmcConnection) -> Arc<T>,
|
F: FnOnce(RmcConnection) -> Arc<T>,
|
||||||
{
|
{
|
||||||
|
|
@ -312,15 +330,9 @@ where
|
||||||
{
|
{
|
||||||
let exposed_object = exposed_object.clone();
|
let exposed_object = exposed_object.clone();
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
handle_incoming(
|
handle_incoming(conn, exposed_object, notify, incoming).await;
|
||||||
conn,
|
|
||||||
exposed_object,
|
|
||||||
notify,
|
|
||||||
incoming
|
|
||||||
).await;
|
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|
||||||
tokio::spawn(async move {
|
tokio::spawn(async move {
|
||||||
while sending_conn.is_alive() {
|
while sending_conn.is_alive() {
|
||||||
sending_conn.send([0, 0, 0, 0, 0].to_vec()).await;
|
sending_conn.send([0, 0, 0, 0, 0].to_vec()).await;
|
||||||
|
|
@ -333,8 +345,16 @@ where
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: RmcCallable> RmcCallable for Arc<T> {
|
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 {
|
fn rmc_call(
|
||||||
self.as_ref().rmc_call(responder, protocol_id, method_id, call_id, rest)
|
&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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -5,14 +5,14 @@ use rnex_core::rmc::structures::qbuffer::QBuffer;
|
||||||
#[derive(RmcSerialize, Debug)]
|
#[derive(RmcSerialize, Debug)]
|
||||||
#[rmc_struct(0)]
|
#[rmc_struct(0)]
|
||||||
struct UploadCompetitionData {
|
struct UploadCompetitionData {
|
||||||
winning_team/*?*/: u32,
|
winning_team: u32,
|
||||||
splatfest_id/*?*/: u32,
|
splatfest_id: u32,
|
||||||
unk_2/*?*/: u32,
|
unk_2: u32,
|
||||||
unk_3: u32,
|
unk_3: u32,
|
||||||
team_id_1: u8,
|
team_id_1: u8,
|
||||||
team_id_2: u8,
|
team_id_2: u8,
|
||||||
unk_5: u32,
|
unk_5: u32,
|
||||||
player_data/*?*/: QBuffer,
|
player_data: QBuffer,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Copy, Clone, Pod, Zeroable)]
|
#[derive(Copy, Clone, Pod, Zeroable)]
|
||||||
|
|
@ -23,35 +23,41 @@ struct UserData{
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod test {
|
mod test {
|
||||||
use std::io::Cursor;
|
|
||||||
use bytemuck::from_bytes;
|
|
||||||
use crate::rmc::structures::ranking::{UploadCompetitionData, UserData};
|
use crate::rmc::structures::ranking::{UploadCompetitionData, UserData};
|
||||||
|
use bytemuck::from_bytes;
|
||||||
use rnex_core::rmc::structures::RmcSerialize;
|
use rnex_core::rmc::structures::RmcSerialize;
|
||||||
|
use std::io::Cursor;
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
|
return;
|
||||||
let data: [u8; 0xBD] = [
|
let data: [u8; 0xBD] = [
|
||||||
0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02, 0x00, 0x00,
|
0x00, 0xB8, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFC, 0x03, 0x00, 0x00, 0x02,
|
||||||
0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0, 0x00, 0x00, 0x49, 0x00,
|
0x00, 0x00, 0x00, 0x1F, 0x00, 0x00, 0x00, 0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0xA0,
|
||||||
0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00, 0x46, 0x00, 0x4E, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x49, 0x00, 0x7A, 0x00, 0x7A, 0x00, 0x79, 0x00, 0x53, 0x00, 0x50, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x46, 0x00, 0x4E, 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,
|
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
0x66, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x03, 0x00, 0x00, 0x03, 0xF2, 0x00, 0x00, 0x00, 0x66, 0x00, 0x00, 0x00,
|
||||||
0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x03, 0x00, 0x00, 0x1F, 0x5E, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||||
0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
0x0C, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x90, 0x00,
|
||||||
0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
||||||
0x02, 0x00, 0x00, 0x00, 0x07, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x06, 0x00, 0x00, 0x00,
|
0x00, 0x00, 0x00, 0x00, 0x0A, 0x00, 0x00, 0x14, 0x87, 0x00, 0x00, 0x00, 0x01, 0x00,
|
||||||
0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x4C, 0x00, 0x00, 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 mut cursor = Cursor::new(data);
|
||||||
|
|
||||||
let data = UploadCompetitionData::deserialize(&mut cursor).expect("unable to deserialize 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 user_data: &UserData = from_bytes(&data.player_data.0[..size_of::<UserData>()]);
|
||||||
|
|
||||||
let pos = user_data.name.iter()
|
let pos = user_data
|
||||||
|
.name
|
||||||
|
.iter()
|
||||||
.position(|v| *v == 0x0000)
|
.position(|v| *v == 0x0000)
|
||||||
.unwrap_or(0x10);
|
.unwrap_or(0x10);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -7,5 +7,7 @@ fi
|
||||||
source ./buildscripts/common.sh
|
source ./buildscripts/common.sh
|
||||||
echo FEATURES:
|
echo FEATURES:
|
||||||
echo $EDITION_FEATURES
|
echo $EDITION_FEATURES
|
||||||
|
echo ENV SETTINGS:
|
||||||
|
env
|
||||||
|
|
||||||
OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl
|
OPENSSL_LIB_DIR=/usr/lib OPENSSL_INCLUDE_DIR=/usr/include/openssl OPENSSL_STATIC=1 RUSTFLAGS="-C relocation-model=static -C linker=ld.lld" cargo test --features "$EDITION_FEATURES" --target x86_64-unknown-linux-musl
|
||||||
Loading…
Add table
Add a link
Reference in a new issue