Initial commit.

This commit is contained in:
TheLie0 2020-04-03 19:47:24 +02:00
commit 5fc381f7d6
9 changed files with 372 additions and 0 deletions

5
.gitignore vendored Normal file
View file

@ -0,0 +1,5 @@
internal.log
log
journal.md
test.log
rust/target/*

17
ErrorLog Normal file
View file

@ -0,0 +1,17 @@
sm exts load tf2p
>>> TF2P loaded! me = IExtension(0x19de8ae0), sys = IShareSys(0xe9d604c4), late = true
[SM] Loaded extension tf2p.ext.so successfully.
sm plugins unload tf2p-network-control
[SM] Plugin tf2p-network-control.smx unloaded successfully.
sm plugins load tf2p-network-control
Got ip "192.168.178.162" and Ports 27015
thread '<unnamed>' panicked at 'called `Option::unwrap()` on a `None` value', src/lib.rs:181:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace
L 04/03/2020 - 19:43:01: [SM] Exception reported: native panicked: called `Option::unwrap()` on a `None` value
L 04/03/2020 - 19:43:01: [SM] Blaming: tf2p-network-control.smx
L 04/03/2020 - 19:43:01: [SM] Call stack trace:
L 04/03/2020 - 19:43:01: [SM] [0] Rust_Start_Manager
L 04/03/2020 - 19:43:01: [SM] [1] Line 22, tf2p-network-control.sp::OnPluginStart
[SM] Plugin tf2p-network-control.smx failed to load: Error detected in plugin startup (see error logs).
thread '<unnamed>' panicked at 'Box<Any>', src/lib.rs:107:27
thread '<unnamed>' panicked at 'Box<Any>', src/socks.rs:12:23

93
rust/Cargo.lock generated Normal file
View file

@ -0,0 +1,93 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
[[package]]
name = "c_str_macro"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2e08268d37bbcbf98f70312c449a35763d3f85beafbedbb4e28b4c438e2b5bd"
[[package]]
name = "flume"
version = "0.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "aa697b56a44fc5e18d0892e8e01e0c5241ff8fd8bfd936d9af5aea2e113fbda0"
dependencies = [
"spin",
]
[[package]]
name = "libc"
version = "0.2.67"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "eb147597cdf94ed43ab7a9038716637d2d1bf2bc571da995d0028dec06bd3018"
[[package]]
name = "proc-macro2"
version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c09721c6781493a2a492a96b5a5bf19b65917fe6728884e7c44dd0c60ca3435"
dependencies = [
"unicode-xid",
]
[[package]]
name = "quote"
version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe"
dependencies = [
"proc-macro2",
]
[[package]]
name = "sm-ext"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bcdcd9d45b7f6d92ab1fa4dc1a9090d59ccdceab4f94aa51991c3ef0d73c8fda"
dependencies = [
"c_str_macro",
"libc",
"sm-ext-derive",
]
[[package]]
name = "sm-ext-derive"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "75e96380b9fa81d50460fa1240990754e7f5766a74ffa5791f0cf43f50e56fc2"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "spin"
version = "0.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d"
[[package]]
name = "syn"
version = "1.0.16"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "123bd9499cfb380418d509322d7a6d52e5315f064fe4b3ad18a53d6b92c07859"
dependencies = [
"proc-macro2",
"quote",
"unicode-xid",
]
[[package]]
name = "tf2p"
version = "0.1.0"
dependencies = [
"flume",
"sm-ext",
]
[[package]]
name = "unicode-xid"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c"

12
rust/Cargo.toml Normal file
View file

@ -0,0 +1,12 @@
[package]
name = "tf2p"
version = "0.1.0"
authors = ["TheLie0 <wf7za0XoHyYXVEkOeNu8>"]
edition = "2018"
[lib]
crate-type = ["cdylib"]
[dependencies]
sm-ext = "0.3.0"
flume = "0.5.1"

200
rust/src/lib.rs Normal file
View file

@ -0,0 +1,200 @@
use sm_ext::{cell_t, register_natives, IExtension, IExtensionInterface, IShareSys, SMExtension, TryIntoPlugin, HandleError, HandleId, HandleType};
use std::thread;
use std::net::{SocketAddr, UdpSocket};
use std::error::Error;
use std::collections::VecDeque;
use std::cell::RefCell;
// use std::rc::Rc; Using Rc like it's in the example threw an Error
pub mod test;
pub mod socks;
use sm_ext::{native, IPluginContext};
use std::ffi::CStr;
use flume;
/// The network plugin entrypoint.
#[native]
fn start_manager(_ctx: &IPluginContext, ip: &CStr, port1: i32) -> NMSender {
println!("Got ip {:?} and Ports {}", ip, port1);
let serv = format!("{}:{}", ip.to_str().unwrap(), port1).parse::<SocketAddr>().expect("Unable to parse socket address");
let mut sock = serv.clone();
sock.set_port(27419);
// bind sockets
let sock_r= UdpSocket::bind(sock).unwrap();
let sock_w = sock_r.try_clone().unwrap();
// Create flume channels
let (tx_s2m, rx_s2m) = flume::unbounded();
let (tx_m2s, rx_m2s) = flume::unbounded();
//create controller channel
let (tx_c, rx_c) = flume::unbounded();
// Spawn listen thread
thread::spawn(move || {
socks::usock_to_chan(sock_r, tx_s2m).unwrap();
});
// Spawn send thread
thread::spawn(move || {
socks::chan_to_usock(rx_m2s, sock_w).unwrap();
});
// Spawn manager thread
thread::spawn(move || {
manager(rx_c, rx_s2m, tx_m2s, serv).unwrap();
});
NMSender::new(tx_c)
}
/// The network manager function.
/// It handles the incoming requests and sends the corresponding answers
fn manager<'a> (controller: flume::Receiver<NMCommand>, input: flume::Receiver<(Vec<u8>, SocketAddr)>, output: flume::Sender<(Vec<u8>, SocketAddr)>, serv_addr: SocketAddr) -> Result<(), Box<dyn Error>> {
let mut cl_ip: Option<SocketAddr> = None;
let mut addr_queue = VecDeque::new();
let conns: [Option<SocketAddr>; 3];
// This is the String "Source Engine Query" in binary form
let cliet_query = vec!(0xff, 0xff, 0xff, 0xff, 0x54, 0x53, 0x6f, 0x75, 0x72, 0x63, 0x65, 0x20, 0x45, 0x6e, 0x67, 0x69, 0x6e, 0x65, 0x20, 0x51, 0x75, 0x65, 0x72, 0x79, 0x00);
'main: loop {
// Get game info for cache
output.send((cliet_query.clone(), serv_addr)).unwrap();
let game_info = match input.recv() {
Ok((buf, src)) => {
let search = serv_addr.port().to_le_bytes();
let replace = (27419 as u16).to_le_bytes();
if src == serv_addr {
let mut buf = buf;
for i in 0..buf.len()-1 {
if buf[i..i+2] == search {
buf[i] = replace[0];
buf[i+1] = replace[1];
}
}
buf
} else {
panic!("Expected query answer from server, got message from {:?}", src);
}
}
Err(e) => panic!(e),
};
// Send cached game info on query and pass any other request to server
'inner1: loop {
//check for controller input
//TODO: rewrite this so it doesn't block
match controller.recv() {
Ok(comm) => {
match comm {
NMCommand::Kill => break 'main,
_ => (),
}
}
Err(e) => panic!(e),
}
match input.recv() {
Ok((buf, source)) => {
if source == serv_addr {
match addr_queue.pop_front() {
Some(ip) => {
output.send((buf.clone(), ip)).unwrap();
}
None => println!("No clients in queue."),
}
}else {
if buf[0 .. cliet_query.len()] == cliet_query[..] {
output.send((game_info.clone(), source)).unwrap();
}else {
output.send((buf.clone(), serv_addr)).unwrap();
addr_queue.push_back(source);
}
}
}
Err(e) => panic!(e),
}
}
//TODO: Get game info again
//TODO: Actual p2p communication
}
Ok(())
}
enum NMCommand{
Connect(u8, SocketAddr),
Kill
}
struct NMSender(flume::Sender<NMCommand>);
impl<'ctx> TryIntoPlugin<'ctx> for NMSender {
type Error = HandleError;
fn try_into_plugin(self, ctx: &'ctx IPluginContext) -> Result<cell_t, Self::Error> {
let object = RefCell::new(self);
let handle = Tf2pNetworking::handle_type().create_handle(object, ctx.get_identity())?;
Ok(handle.into())
}
}
impl NMSender {
fn new(s: flume::Sender<NMCommand>) -> Self {
Self(s)
}
}
#[derive (Default, SMExtension)]
#[extension(name = "TF2P", description = "Decentralize all the things!")]
pub struct Tf2pNetworking{
handle_type: Option<HandleType<RefCell<NMSender>>>,
}
impl Tf2pNetworking {
fn get() -> &'static Self {
EXTENSION_GLOBAL.with(|ext| unsafe { &(*ext.borrow().unwrap()).delegate })
}
fn handle_type() -> &'static HandleType<RefCell<NMSender>> {
Self::get().handle_type.as_ref().unwrap() // This line panics
}
}
impl IExtensionInterface for Tf2pNetworking {
fn on_extension_load(&mut self, myself: IExtension, sys: IShareSys, late: bool) -> Result<(), Box<dyn std::error::Error>> {
println!(">>> TF2P loaded! me = {:?}, sys = {:?}, late = {:?}", myself, sys, late);
register_natives!(
&sys,
&myself,
[
("Rust_Start_Manager", start_manager),
]
);
Ok(())
}
}

34
rust/src/socks.rs Normal file
View file

@ -0,0 +1,34 @@
use std::net::{UdpSocket, SocketAddr};
use std::error::Error;
use flume;
/// Sends buffer messages from a mpsc channel to an udp socket.
pub fn chan_to_usock(input: flume::Receiver<(Vec<u8>, SocketAddr)>, output: UdpSocket) -> Result<(), Box<dyn Error>> {
loop {
match input.recv() {
Ok((buf, target)) => output.send_to(&buf, &target)?,
Err(e) => panic!(e),
};
};
}
/// Sends buffer messages from an udp socket to a mpsc channel.
pub fn usock_to_chan(input: UdpSocket, output: flume::Sender<(Vec<u8>, SocketAddr)>) -> Result<(), Box<dyn Error>> {
let mut buf = [0; 2048];
let mut tup;
loop {
{
tup = input.recv_from(&mut buf).unwrap();
}
match output.send((buf[0..tup.0 + 1].to_vec(), tup.1)) {
Ok(s) => s,
Err(e) => panic!(e)
}
}
}

9
rust/src/test.rs Normal file
View file

@ -0,0 +1,9 @@
use std::net::UdpSocket;
use std::error::Error;
/// Udp ping helper function
pub fn test_ping(ip: String) -> Result<(), Box<dyn Error>> {
let socket = UdpSocket::bind("127.0.0.1:6969")?;
socket.send_to("ping".as_bytes(), ip)?;
Ok(())
}

1
sourcepawn/include/tf2p.inc Symbolic link
View file

@ -0,0 +1 @@
/mnt/disk3/TF2DS/tf/addons/sourcemod/scripting/include//tf2p.inc

View file

@ -0,0 +1 @@
/mnt/disk3/TF2DS/tf/addons/sourcemod/scripting/tf2p-network-control.sp