Initial commit.
This commit is contained in:
commit
5fc381f7d6
9 changed files with 372 additions and 0 deletions
5
.gitignore
vendored
Normal file
5
.gitignore
vendored
Normal file
|
@ -0,0 +1,5 @@
|
|||
internal.log
|
||||
log
|
||||
journal.md
|
||||
test.log
|
||||
rust/target/*
|
17
ErrorLog
Normal file
17
ErrorLog
Normal 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
93
rust/Cargo.lock
generated
Normal 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
12
rust/Cargo.toml
Normal 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
200
rust/src/lib.rs
Normal 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
34
rust/src/socks.rs
Normal 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
9
rust/src/test.rs
Normal 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
1
sourcepawn/include/tf2p.inc
Symbolic link
|
@ -0,0 +1 @@
|
|||
/mnt/disk3/TF2DS/tf/addons/sourcemod/scripting/include//tf2p.inc
|
1
sourcepawn/tf2p-network-control.sp
Symbolic link
1
sourcepawn/tf2p-network-control.sp
Symbolic link
|
@ -0,0 +1 @@
|
|||
/mnt/disk3/TF2DS/tf/addons/sourcemod/scripting/tf2p-network-control.sp
|
Loading…
Reference in a new issue