mirror of
https://github.com/Astatin3/unshell.git
synced 2026-06-08 22:38:01 -06:00
Get dynamic component loading working
This commit is contained in:
@@ -9,24 +9,24 @@ edition = "2024"
|
||||
crate-type = ["cdylib"]
|
||||
|
||||
[features]
|
||||
default = ["client", "server"]
|
||||
default = ["client", "server", "log_debug"]
|
||||
|
||||
client = ["unshell-lib/client"]
|
||||
server = ["unshell-lib/server"]
|
||||
|
||||
log_debug = ["unshell-lib/log_debug"]
|
||||
obfuscate = ["unshell-lib/obfuscate"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
unshell-lib = {path = "../unshell-lib"}
|
||||
unshell-lib = {path = "../unshell-lib", default-featues = false}
|
||||
|
||||
|
||||
[profile.release]
|
||||
strip = true # Strip symbols from the binary
|
||||
# strip = "debuginfo"
|
||||
opt-level = "s" # Optimize for size
|
||||
lto = true
|
||||
codegen-units = 1
|
||||
panic = "abort"
|
||||
debug = false
|
||||
trim-paths = "all"
|
||||
|
||||
# crate-type = ["cdylib"]
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Behold! The world's most sophisticated shared library! (it has no code)
|
||||
|
||||
#![no_main]
|
||||
|
||||
pub use unshell_lib::get_components;
|
||||
|
||||
// Behold! The world's most sophisticated shared library!
|
||||
|
||||
+30
-24
@@ -5,31 +5,37 @@ use unshell_lib::Announcement;
|
||||
fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut serverruntime = unshell_lib::server::ListenerRuntime::new();
|
||||
|
||||
loop {
|
||||
print!("> ");
|
||||
stdout().flush().expect("Failed to flush stdout");
|
||||
let mut input = String::new();
|
||||
stdin().read_line(&mut input).expect("Failed to read line");
|
||||
// loop {
|
||||
// print!("> ");
|
||||
// stdout().flush().expect("Failed to flush stdout");
|
||||
// let mut input = String::new();
|
||||
// stdin().read_line(&mut input).expect("Failed to read line");
|
||||
|
||||
let args = input.trim().split(" ").collect::<Vec<&str>>();
|
||||
// let args = input.trim().split(" ").collect::<Vec<&str>>();
|
||||
|
||||
match args[0] {
|
||||
"" => {}
|
||||
"test" => {
|
||||
if let Some(arg) = args.get(1) {
|
||||
println!("Test with argument: {}", arg);
|
||||
serverruntime
|
||||
.send(&Announcement::TestAnnouncement(arg.to_string()))
|
||||
.unwrap();
|
||||
} else {
|
||||
println!("Test without argument");
|
||||
}
|
||||
}
|
||||
_ => {
|
||||
println!("Invalid Command: '{}'", args[0]);
|
||||
}
|
||||
}
|
||||
// match args[0] {
|
||||
// "" => {}
|
||||
// "test" => {
|
||||
// if let Some(arg) = args.get(1) {
|
||||
// println!("Test with argument: {}", arg);
|
||||
// serverruntime
|
||||
// .send(&Announcement::TestAnnouncement(arg.to_string()))
|
||||
// .unwrap();
|
||||
// } else {
|
||||
// println!("Test without argument");
|
||||
// }
|
||||
// }
|
||||
// _ => {
|
||||
// println!("Invalid Command: '{}'", args[0]);
|
||||
// }
|
||||
// }
|
||||
|
||||
// println!("{:?}", args);
|
||||
}
|
||||
// // println!("{:?}", args);
|
||||
// }
|
||||
|
||||
serverruntime.send(&Announcement::GetRuntimes)?;
|
||||
|
||||
// let response = serverruntime.
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,8 +1,16 @@
|
||||
use bincode::{Decode, Encode};
|
||||
|
||||
use crate::config::RuntimeConfig;
|
||||
|
||||
#[derive(Debug, Encode, Decode)]
|
||||
pub enum Announcement {
|
||||
TestAnnouncement(String),
|
||||
|
||||
GetRuntimes,
|
||||
GetRuntimesAck(usize),
|
||||
|
||||
StartRuntime(RuntimeConfig),
|
||||
StartRuntimeAck(bool),
|
||||
}
|
||||
|
||||
const BINCODE_CONFIG: bincode::config::Configuration = bincode::config::standard();
|
||||
|
||||
@@ -2,7 +2,7 @@ use std::{
|
||||
io::Read,
|
||||
net::TcpStream,
|
||||
sync::{
|
||||
Arc,
|
||||
Arc, Mutex,
|
||||
atomic::{AtomicBool, Ordering},
|
||||
},
|
||||
thread::{self, JoinHandle},
|
||||
@@ -43,16 +43,6 @@ impl ClientRuntime {
|
||||
}
|
||||
};
|
||||
info!("Connected");
|
||||
// let reader = BufReader::new(stream.try_clone().unwrap());
|
||||
// let mut writer = BufWriter::new(stream.try_clone().unwrap());
|
||||
|
||||
// let (a, b) = crossbeam_channel::unbounded();
|
||||
|
||||
// a.
|
||||
|
||||
// if join_receiver.len() == 0 {
|
||||
// join_receiver.recv().unwrap();
|
||||
// }
|
||||
|
||||
while !join_clone.load(Ordering::Relaxed) {
|
||||
let mut size_buf = [0u8; 4];
|
||||
@@ -69,12 +59,29 @@ impl ClientRuntime {
|
||||
Announcement::TestAnnouncement(s) => {
|
||||
println!("Received test announcement: {}", s)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
}),
|
||||
join_signal,
|
||||
})
|
||||
}
|
||||
|
||||
// pub fn send(&mut self, announcement: &Announcement) -> Result<(), ModuleError> {
|
||||
// let bytes = announcement.encode();
|
||||
|
||||
// let mut streams = self.stream.lock().unwrap();
|
||||
|
||||
// for stream in streams.iter_mut() {
|
||||
// stream.write_all(&u32::to_be_bytes(bytes.len() as u32))?;
|
||||
// stream.write_all(&bytes)?;
|
||||
// stream.flush()?;
|
||||
// }
|
||||
|
||||
// println!("Announcement {:?} sent", announcement);
|
||||
|
||||
// Ok(())
|
||||
// }
|
||||
}
|
||||
|
||||
impl ModuleRuntime for ClientRuntime {
|
||||
|
||||
@@ -4,20 +4,8 @@ use crate::config::NamedComponent;
|
||||
|
||||
#[obfuscated_symbol]
|
||||
pub fn get_components() -> Vec<NamedComponent> {
|
||||
// let mut components: HashMap<&'static str, Box<dyn Component>> = HashMap::new();
|
||||
|
||||
// let a = crate::client::get_interface;
|
||||
|
||||
return vec![
|
||||
#[cfg(feature = "client")]
|
||||
crate::client::get_named_component(),
|
||||
];
|
||||
|
||||
// components
|
||||
|
||||
// vec![
|
||||
// Feature::Client,
|
||||
// #[cfg(feature = "server")]
|
||||
// Feature::Server,
|
||||
// ]
|
||||
}
|
||||
|
||||
@@ -3,6 +3,8 @@ use std::collections::HashMap;
|
||||
// use bincode::{Decode, Encode};
|
||||
// use serde::{Deserialize, Serialize};
|
||||
|
||||
use bincode::{Decode, Encode};
|
||||
|
||||
use crate::{ModuleError, ModuleRuntime};
|
||||
|
||||
// /// Payload config that is instantiated
|
||||
@@ -19,11 +21,11 @@ pub struct PayloadConfig {
|
||||
pub runtime_config: Vec<RuntimeConfig>,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
#[derive(Debug, Clone, Encode, Decode)]
|
||||
pub struct RuntimeConfig {
|
||||
pub parent_component: &'static str,
|
||||
pub name: &'static str,
|
||||
pub config: HashMap<&'static str, String>,
|
||||
pub parent_component: String,
|
||||
pub name: String,
|
||||
pub config: HashMap<String, String>,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
|
||||
@@ -10,15 +10,10 @@ mod components;
|
||||
pub use components::get_components;
|
||||
|
||||
mod announcement;
|
||||
use std::{
|
||||
fmt,
|
||||
// sync::{Arc, Mutex},
|
||||
};
|
||||
use std::fmt;
|
||||
|
||||
pub use announcement::Announcement;
|
||||
|
||||
// use crate::module::{Interface, Manager};
|
||||
|
||||
///Generic error type for module-related operations.
|
||||
#[derive(Debug)]
|
||||
pub enum ModuleError {
|
||||
|
||||
@@ -19,18 +19,17 @@ pub struct Manager {
|
||||
pub modules: Vec<Module>,
|
||||
|
||||
active_runtimes: Vec<Box<dyn ModuleRuntime>>,
|
||||
// runtime_config: Vec<RuntimeConfig>,
|
||||
components: HashMap<String, NamedComponent>,
|
||||
}
|
||||
|
||||
// static mut MANAGER_RUNTIME: Option<Arc<Mutex<Manager>>> = None;
|
||||
|
||||
impl Manager {
|
||||
fn new(id: &'static str, config: Vec<NamedComponent>, modules: Vec<Module>) -> Self {
|
||||
fn new(id: &'static str, components: Vec<NamedComponent>, modules: Vec<Module>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
modules,
|
||||
components: config
|
||||
components: components
|
||||
.into_iter()
|
||||
.map(|c| (c.name.to_string(), c))
|
||||
.collect(),
|
||||
@@ -44,6 +43,9 @@ impl Manager {
|
||||
// Construct self
|
||||
let mut this = Self::new(&config.id, config.components.clone(), modules);
|
||||
|
||||
debug!("Imported {} base components", this.components.len());
|
||||
debug!("Imported {} base runtimes", &config.runtime_config.len());
|
||||
|
||||
// Load each of the pre-prepared modules
|
||||
this.load_components();
|
||||
|
||||
@@ -60,7 +62,7 @@ impl Manager {
|
||||
for module in &self.modules {
|
||||
// Load get_components function from shared object library
|
||||
let component_func = match module
|
||||
.get_symbol::<fn() -> Vec<NamedComponent>>(symbol!(b"get_components"))
|
||||
.get_symbol::<fn() -> Vec<NamedComponent>>(symbol!("get_components").as_bytes())
|
||||
{
|
||||
Ok(func) => func,
|
||||
Err(_) => {
|
||||
@@ -70,7 +72,7 @@ impl Manager {
|
||||
};
|
||||
|
||||
let components = component_func();
|
||||
let component_name = "TODO";
|
||||
let component_name = "TODO"; //TODO: Make this actually load component name
|
||||
|
||||
debug!("{} - Retrieved payload metadata", component_name);
|
||||
|
||||
@@ -88,11 +90,11 @@ impl Manager {
|
||||
for runtime in runtimes {
|
||||
let mut this_lock = this.lock().unwrap();
|
||||
|
||||
let component = match this_lock.components.get(runtime.parent_component) {
|
||||
let component = match this_lock.components.get(&runtime.parent_component) {
|
||||
Some(component) => component,
|
||||
None => {
|
||||
warn!(
|
||||
"Could not find component {} which is referenced by runtime {}",
|
||||
"Could not find component '{}' which is referenced by runtime: {}",
|
||||
runtime.parent_component, runtime.name
|
||||
);
|
||||
continue;
|
||||
@@ -119,12 +121,18 @@ impl Manager {
|
||||
let mut this_lock = this.lock().unwrap();
|
||||
|
||||
if this_lock.active_runtimes.len() <= 0 {
|
||||
debug!("There are no more runtimes! Exiting...");
|
||||
break;
|
||||
}
|
||||
|
||||
this_lock
|
||||
.active_runtimes
|
||||
.retain(|runtime| runtime.is_running());
|
||||
this_lock.active_runtimes.retain(|runtime| {
|
||||
if runtime.is_running() {
|
||||
true
|
||||
} else {
|
||||
debug!("Runtime exited!"); //TODO: Make this better
|
||||
false
|
||||
}
|
||||
});
|
||||
|
||||
drop(this_lock);
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
use std::{
|
||||
io::Write,
|
||||
io::{Read, Write},
|
||||
net::{TcpListener, TcpStream},
|
||||
sync::{Arc, Mutex},
|
||||
thread::{self, JoinHandle},
|
||||
@@ -52,6 +52,24 @@ impl ListenerRuntime {
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn recv(&mut self) -> Result<Announcement, ModuleError> {
|
||||
let stream = &mut self.streams.lock().unwrap()[0];
|
||||
|
||||
let mut size_buf = [0u8; 4];
|
||||
stream.read_exact(&mut size_buf).unwrap();
|
||||
let size = u32::from_be_bytes(size_buf);
|
||||
|
||||
let mut buf = vec![0u8; size as usize];
|
||||
|
||||
stream.read_exact(&mut buf).unwrap();
|
||||
|
||||
if let Some(announcement) = Announcement::decode(&buf) {
|
||||
Ok(announcement)
|
||||
} else {
|
||||
Err(ModuleError::Error("Failed to decode announcement".into()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl ModuleRuntime for ListenerRuntime {
|
||||
|
||||
@@ -7,7 +7,10 @@ edition = "2024"
|
||||
[features]
|
||||
obfuscate = ["unshell-obfuscate/obfuscate"]
|
||||
log_debug = ["unshell-lib/log_debug"]
|
||||
# default = ["obfuscate"]
|
||||
|
||||
client = ["unshell-lib/client"]
|
||||
server = ["unshell-lib/server"]
|
||||
|
||||
|
||||
[dependencies]
|
||||
env_logger = "0.11.8"
|
||||
@@ -15,7 +18,7 @@ lazy_static = "1.5.0"
|
||||
libloading = "0.8.9"
|
||||
proc-macro2 = "1.0.103"
|
||||
|
||||
unshell-lib = {path = "../unshell-lib"}
|
||||
unshell-lib = {path = "../unshell-lib", default-features = false}
|
||||
unshell-obfuscate = {path = "../unshell-obfuscate"}
|
||||
|
||||
[profile.release]
|
||||
@@ -26,4 +29,3 @@ codegen-units = 1
|
||||
panic = "abort"
|
||||
debug = false # Remove debug
|
||||
trim-paths="all"
|
||||
# panic=immediate-abort
|
||||
|
||||
Executable
+3
@@ -0,0 +1,3 @@
|
||||
OBFUSCATION_KEY=abc123abc \
|
||||
RUST_LOG=info \
|
||||
cargo run --no-default-features $@ --release # $(ls ../*/target/release/*.so)
|
||||
@@ -16,15 +16,15 @@ lazy_static! {
|
||||
id: symbol!("Test ID"),
|
||||
components: unshell_lib::get_components(),
|
||||
runtime_config: vec![RuntimeConfig {
|
||||
parent_component: symbol!("client"),
|
||||
name: symbol!("client runtime"),
|
||||
config: HashMap::from([(symbol!("host"), obs!("localhost:1234"))]),
|
||||
parent_component: symbol!("client").to_string(),
|
||||
name: symbol!("client runtime").to_string(),
|
||||
config: HashMap::from([(symbol!("host").to_string(), obs!("localhost:1234"))]),
|
||||
}],
|
||||
};
|
||||
}
|
||||
|
||||
fn main() {
|
||||
// #[cfg(not(feature = "obfuscate"))]
|
||||
#[cfg(not(feature = "obfuscate"))]
|
||||
unshell_lib::logger::PrettyLogger::init();
|
||||
|
||||
debug!("Initialized");
|
||||
|
||||
Reference in New Issue
Block a user