Multi machine follow-up (#2334)
* improved tree generator. possibility to dump state on exit. * warnings. * clippy * clippy * aaaaaa * aaaaaa * make nix mandatory for unix * stddddddd * stddddddd * stddddddd * aaa * clippy * doc * aaa * aaa * aaa * aaa * fix * aaaaaaaa * dump state * aaa * aaa * aaa * more minimal dump * aaa * aaa * aaa * simpler tc dump * pub * more pub * revert a bit * release by default * delete Makefile.toml * release * dump execs * merge * delete stuff * aa * ff * dig * FMT cargo stuf --------- Co-authored-by: Toka <tokazerkje@outlook.com>
This commit is contained in:
parent
1113879a34
commit
203d3d340a
@ -33,6 +33,7 @@ use static_alloc::Bump;
|
|||||||
#[global_allocator]
|
#[global_allocator]
|
||||||
static A: Bump<[u8; 512 * 1024 * 1024]> = Bump::uninit();
|
static A: Bump<[u8; 512 * 1024 * 1024]> = Bump::uninit();
|
||||||
|
|
||||||
|
#[cfg(not(test))]
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn panic(_info: &PanicInfo) -> ! {
|
fn panic(_info: &PanicInfo) -> ! {
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
|
@ -6,14 +6,14 @@ if [ ! -d "sqlite3" ]; then
|
|||||||
find ./sqlite3 -name "*.test" -exec cp {} corpus/ \;
|
find ./sqlite3 -name "*.test" -exec cp {} corpus/ \;
|
||||||
fi
|
fi
|
||||||
|
|
||||||
if [ "$1" = "release" ]; then
|
if [ "$1" = "d" ]; then
|
||||||
cargo build --release
|
|
||||||
else
|
|
||||||
cargo build
|
cargo build
|
||||||
|
else
|
||||||
|
cargo build --release
|
||||||
fi
|
fi
|
||||||
|
|
||||||
export CC=`pwd`/target/debug/libafl_cc
|
export CC=`pwd`/target/release/libafl_cc
|
||||||
export CXX=`pwd`/target/debug/libafl_cxx
|
export CXX=`pwd`/target/release/libafl_cxx
|
||||||
export CFLAGS='--libafl'
|
export CFLAGS='--libafl'
|
||||||
export CXXFLAGS='--libafl'
|
export CXXFLAGS='--libafl'
|
||||||
export CFLAGS="$CFLAGS -DSQLITE_MAX_LENGTH=128000000 \
|
export CFLAGS="$CFLAGS -DSQLITE_MAX_LENGTH=128000000 \
|
||||||
|
@ -1,3 +1,3 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
./ossfuzz --cores 4-7 --input ./corpus
|
./ossfuzz --cores 0-1 --input ./corpus
|
||||||
|
64
fuzzers/sqlite_centralized_multi_machine/Cargo.toml
Normal file
64
fuzzers/sqlite_centralized_multi_machine/Cargo.toml
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
[package]
|
||||||
|
name = "libfuzzer_libpng_launcher_centralized_multi_machine"
|
||||||
|
version = "0.12.0"
|
||||||
|
authors = [
|
||||||
|
"Romain Malmain <romain.malmain@pm.me>",
|
||||||
|
"Andrea Fioraldi <andreafioraldi@gmail.com>",
|
||||||
|
"Dominik Maier <domenukk@gmail.com>",
|
||||||
|
]
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[features]
|
||||||
|
default = ["std"]
|
||||||
|
std = []
|
||||||
|
|
||||||
|
[profile.release]
|
||||||
|
lto = true
|
||||||
|
codegen-units = 1
|
||||||
|
opt-level = 3
|
||||||
|
debug = true
|
||||||
|
|
||||||
|
[build-dependencies]
|
||||||
|
cc = { version = "1.0", features = ["parallel"] }
|
||||||
|
which = "6.0"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
# no llmp compression for now, better perfs.
|
||||||
|
libafl = { path = "../../libafl", default-features = false, features = [
|
||||||
|
"std",
|
||||||
|
"derive",
|
||||||
|
"llmp_small_maps",
|
||||||
|
"llmp_broker_timeouts",
|
||||||
|
"rand_trait",
|
||||||
|
"fork",
|
||||||
|
"prelude",
|
||||||
|
"gzip",
|
||||||
|
"regex",
|
||||||
|
"serdeany_autoreg",
|
||||||
|
"tui_monitor",
|
||||||
|
"std",
|
||||||
|
"derive",
|
||||||
|
"rand_trait",
|
||||||
|
"fork",
|
||||||
|
"prelude",
|
||||||
|
"gzip",
|
||||||
|
"regex",
|
||||||
|
"scalability_introspection",
|
||||||
|
"multi_machine",
|
||||||
|
"errors_backtrace",
|
||||||
|
"dump_state",
|
||||||
|
] }
|
||||||
|
libafl_bolts = { path = "../../libafl_bolts", features = ["xxh3"] }
|
||||||
|
libafl_targets = { path = "../../libafl_targets", features = [
|
||||||
|
"sancov_pcguard_hitcounts",
|
||||||
|
"libfuzzer",
|
||||||
|
] }
|
||||||
|
# TODO Include it only when building cc
|
||||||
|
libafl_cc = { path = "../../libafl_cc" }
|
||||||
|
clap = { version = "4.0", features = ["derive"] }
|
||||||
|
mimalloc = { version = "*", default-features = false }
|
||||||
|
env_logger = "0.11"
|
||||||
|
|
||||||
|
[lib]
|
||||||
|
name = "libfuzzer_libpng"
|
||||||
|
crate-type = ["staticlib"]
|
@ -102,6 +102,9 @@ tcp_compression = ["tcp_manager", "libafl_bolts/gzip"]
|
|||||||
## Enable multi-machine support
|
## Enable multi-machine support
|
||||||
multi_machine = ["tokio", "std", "enumflags2", "ahash/std"]
|
multi_machine = ["tokio", "std", "enumflags2", "ahash/std"]
|
||||||
|
|
||||||
|
## Dump state of each client on exit
|
||||||
|
dump_state = ["std"]
|
||||||
|
|
||||||
## Enables the `NaiveTokenizer` and `StacktraceObserver`
|
## Enables the `NaiveTokenizer` and `StacktraceObserver`
|
||||||
regex = ["std", "dep:regex"]
|
regex = ["std", "dep:regex"]
|
||||||
|
|
||||||
|
@ -177,7 +177,7 @@ where
|
|||||||
fn on_restart(&mut self, state: &mut S) -> Result<(), Error> {
|
fn on_restart(&mut self, state: &mut S) -> Result<(), Error> {
|
||||||
state.on_restart()?;
|
state.on_restart()?;
|
||||||
|
|
||||||
// First, reset the page to 0 so the next iteration can read read from the beginning of this page
|
// First, reset the page to 0 so the next iteration can read from the beginning of this page
|
||||||
self.staterestorer.reset();
|
self.staterestorer.reset();
|
||||||
self.staterestorer.save(&(
|
self.staterestorer.save(&(
|
||||||
if self.save_state.on_restart() {
|
if self.save_state.on_restart() {
|
||||||
@ -595,7 +595,7 @@ where
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// If this guy wants to fork, then ignore sigit
|
// If this guy wants to fork, then ignore sigint
|
||||||
#[cfg(any(windows, not(feature = "fork")))]
|
#[cfg(any(windows, not(feature = "fork")))]
|
||||||
unsafe {
|
unsafe {
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -614,7 +614,7 @@ where
|
|||||||
#[cfg(any(windows, not(feature = "fork")))]
|
#[cfg(any(windows, not(feature = "fork")))]
|
||||||
let child_status = child_status.code().unwrap_or_default();
|
let child_status = child_status.code().unwrap_or_default();
|
||||||
|
|
||||||
compiler_fence(Ordering::SeqCst);
|
compiler_fence(Ordering::SeqCst); // really useful?
|
||||||
|
|
||||||
if child_status == CTRL_C_EXIT || staterestorer.wants_to_exit() {
|
if child_status == CTRL_C_EXIT || staterestorer.wants_to_exit() {
|
||||||
// if ctrl-c is pressed, we end up in this branch
|
// if ctrl-c is pressed, we end up in this branch
|
||||||
|
@ -34,7 +34,9 @@ pub use broker_hooks::*;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use launcher::*;
|
pub use launcher::*;
|
||||||
#[cfg(all(unix, feature = "std"))]
|
#[cfg(all(unix, feature = "std"))]
|
||||||
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal, CTRL_C_EXIT};
|
use libafl_bolts::os::unix_signals::{siginfo_t, ucontext_t, Handler, Signal};
|
||||||
|
#[cfg(all(unix, feature = "std"))]
|
||||||
|
use libafl_bolts::os::CTRL_C_EXIT;
|
||||||
use libafl_bolts::{
|
use libafl_bolts::{
|
||||||
current_time,
|
current_time,
|
||||||
tuples::{Handle, MatchNameRef},
|
tuples::{Handle, MatchNameRef},
|
||||||
@ -86,10 +88,7 @@ impl Handler for ShutdownSignalData {
|
|||||||
_info: &mut siginfo_t,
|
_info: &mut siginfo_t,
|
||||||
_context: Option<&mut ucontext_t>,
|
_context: Option<&mut ucontext_t>,
|
||||||
) {
|
) {
|
||||||
// println!("in handler! {}", std::process::id());
|
|
||||||
unsafe {
|
unsafe {
|
||||||
// println!("Exiting from the handler....");
|
|
||||||
|
|
||||||
#[cfg(unix)]
|
#[cfg(unix)]
|
||||||
libc::_exit(CTRL_C_EXIT);
|
libc::_exit(CTRL_C_EXIT);
|
||||||
|
|
||||||
|
@ -225,7 +225,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// A testcase metadata holding a list of indexes of a map
|
/// A testcase metadata holding a list of indexes of a map
|
||||||
#[derive(Debug, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[cfg_attr(
|
#[cfg_attr(
|
||||||
any(not(feature = "serdeany_autoreg"), miri),
|
any(not(feature = "serdeany_autoreg"), miri),
|
||||||
allow(clippy::unsafe_derive_deserialize)
|
allow(clippy::unsafe_derive_deserialize)
|
||||||
|
@ -242,8 +242,8 @@ where
|
|||||||
) -> Result<(), Error> {
|
) -> Result<(), Error> {
|
||||||
let monitor_timeout = STATS_TIMEOUT_DEFAULT;
|
let monitor_timeout = STATS_TIMEOUT_DEFAULT;
|
||||||
loop {
|
loop {
|
||||||
// log::info!("Starting another fuzz_loop");
|
|
||||||
manager.maybe_report_progress(state, monitor_timeout)?;
|
manager.maybe_report_progress(state, monitor_timeout)?;
|
||||||
|
|
||||||
self.fuzz_one(stages, executor, state, manager)?;
|
self.fuzz_one(stages, executor, state, manager)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -82,8 +82,9 @@ pub use owned_map::*;
|
|||||||
/// # InMemoryCorpus::<BytesInput>::new(),
|
/// # InMemoryCorpus::<BytesInput>::new(),
|
||||||
/// # InMemoryCorpus::new(),
|
/// # InMemoryCorpus::new(),
|
||||||
/// # &mut feedback,
|
/// # &mut feedback,
|
||||||
/// # &mut ()
|
/// # &mut (),
|
||||||
/// # ).unwrap();
|
/// # ).unwrap();
|
||||||
|
///
|
||||||
/// # feedback.init_state(&mut state).unwrap();
|
/// # feedback.init_state(&mut state).unwrap();
|
||||||
///
|
///
|
||||||
/// let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
/// let scheduler = IndexesLenTimeMinimizerScheduler::new(&edges_observer, QueueScheduler::new());
|
||||||
|
@ -10,7 +10,6 @@ use core::{
|
|||||||
};
|
};
|
||||||
use std::os::raw::{c_long, c_void};
|
use std::os::raw::{c_long, c_void};
|
||||||
|
|
||||||
use log::info;
|
|
||||||
use num_enum::FromPrimitive;
|
use num_enum::FromPrimitive;
|
||||||
pub use windows::Win32::{
|
pub use windows::Win32::{
|
||||||
Foundation::{BOOL, NTSTATUS},
|
Foundation::{BOOL, NTSTATUS},
|
||||||
@ -462,7 +461,7 @@ unsafe fn internal_handle_exception(
|
|||||||
.unwrap();
|
.unwrap();
|
||||||
match &EXCEPTION_HANDLERS[index] {
|
match &EXCEPTION_HANDLERS[index] {
|
||||||
Some(handler_holder) => {
|
Some(handler_holder) => {
|
||||||
info!(
|
log::info!(
|
||||||
"{:?}: Handling exception {}",
|
"{:?}: Handling exception {}",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
exception_code
|
exception_code
|
||||||
@ -472,7 +471,7 @@ unsafe fn internal_handle_exception(
|
|||||||
EXCEPTION_CONTINUE_EXECUTION
|
EXCEPTION_CONTINUE_EXECUTION
|
||||||
}
|
}
|
||||||
None => {
|
None => {
|
||||||
info!(
|
log::info!(
|
||||||
"{:?}: No handler for exception {}",
|
"{:?}: No handler for exception {}",
|
||||||
std::process::id(),
|
std::process::id(),
|
||||||
exception_code
|
exception_code
|
||||||
@ -601,11 +600,11 @@ pub(crate) unsafe fn setup_ctrl_handler<T: 'static + CtrlHandler>(
|
|||||||
let result = SetConsoleCtrlHandler(Some(ctrl_handler), true);
|
let result = SetConsoleCtrlHandler(Some(ctrl_handler), true);
|
||||||
match result {
|
match result {
|
||||||
Ok(()) => {
|
Ok(()) => {
|
||||||
info!("SetConsoleCtrlHandler succeeded");
|
log::info!("SetConsoleCtrlHandler succeeded");
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
Err(err) => {
|
Err(err) => {
|
||||||
info!("SetConsoleCtrlHandler failed");
|
log::info!("SetConsoleCtrlHandler failed");
|
||||||
Err(Error::from(err))
|
Err(Error::from(err))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -615,7 +614,7 @@ unsafe extern "system" fn ctrl_handler(ctrl_type: u32) -> BOOL {
|
|||||||
let handler = ptr::read_volatile(addr_of!(CTRL_HANDLER));
|
let handler = ptr::read_volatile(addr_of!(CTRL_HANDLER));
|
||||||
match handler {
|
match handler {
|
||||||
Some(handler_holder) => {
|
Some(handler_holder) => {
|
||||||
info!("{:?}: Handling ctrl {}", std::process::id(), ctrl_type);
|
log::info!("{:?}: Handling ctrl {}", std::process::id(), ctrl_type);
|
||||||
let handler = &mut *handler_holder.handler.get();
|
let handler = &mut *handler_holder.handler.get();
|
||||||
if let Some(ctrl_handler) = handler.as_mut() {
|
if let Some(ctrl_handler) = handler.as_mut() {
|
||||||
(*ctrl_handler).handle(ctrl_type).into()
|
(*ctrl_handler).handle(ctrl_type).into()
|
||||||
|
2
utils/multi_machine_generator/.gitignore
vendored
Normal file
2
utils/multi_machine_generator/.gitignore
vendored
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
*.txt
|
||||||
|
*.dot
|
@ -9,3 +9,6 @@ edition = "2021"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
petgraph = "0.6"
|
petgraph = "0.6"
|
||||||
|
clap = { version = "4.5", features = ["derive"] }
|
||||||
|
serde = { version = "1.0", features = ["derive"] }
|
||||||
|
serde_json = "1.0"
|
||||||
|
@ -1,20 +1,48 @@
|
|||||||
use std::net::SocketAddr;
|
use std::{
|
||||||
|
fmt::{Display, Formatter},
|
||||||
|
mem,
|
||||||
|
};
|
||||||
|
|
||||||
use petgraph::{graph::NodeIndex, Direction, Graph};
|
use petgraph::{graph::NodeIndex, Direction, Graph};
|
||||||
|
use serde::Serialize;
|
||||||
|
|
||||||
/// A node of the network
|
/// A node of the network
|
||||||
#[derive(Debug, Clone, Default)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct MultiMachineNode {}
|
pub struct MultiMachineNode {
|
||||||
|
addr: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The final configuration of a node on the network
|
||||||
|
#[derive(Debug, Clone, Serialize)]
|
||||||
|
pub struct MultiMachineNodeConfig {
|
||||||
|
addr: String,
|
||||||
|
parent: Option<String>,
|
||||||
|
port: u16,
|
||||||
|
}
|
||||||
|
|
||||||
/// The tree
|
/// The tree
|
||||||
pub struct MultiMachineTree {
|
pub struct MultiMachineTree {
|
||||||
pub graph: Graph<MultiMachineNode, ()>,
|
pub graph: Graph<MultiMachineNode, MultiMachineEdge>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct MultiMachineEdge;
|
||||||
|
|
||||||
|
impl Display for MultiMachineEdge {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Display for MultiMachineNode {
|
||||||
|
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", self.addr)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MultiMachineNode {
|
impl MultiMachineNode {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn new() -> Self {
|
pub fn new(addr: String) -> Self {
|
||||||
Self {}
|
Self { addr }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,12 +53,13 @@ impl MultiMachineTree {
|
|||||||
/// - machines: machines to add.
|
/// - machines: machines to add.
|
||||||
/// - `max_children_per_parent`: each parent will have at most this amount of children
|
/// - `max_children_per_parent`: each parent will have at most this amount of children
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn generate(machines: &[SocketAddr], max_children_per_parent: u64) -> Self {
|
pub fn generate(machines: &[String], max_children_per_parent: u64) -> Self {
|
||||||
let mut graph = Graph::<MultiMachineNode, ()>::new();
|
let mut graph = Graph::<MultiMachineNode, MultiMachineEdge>::new();
|
||||||
let mut machines = Vec::from(machines);
|
let mut machines = Vec::from(machines);
|
||||||
|
machines.reverse();
|
||||||
|
|
||||||
let root = if let Some(_root) = machines.pop() {
|
let root = if let Some(root) = machines.pop() {
|
||||||
graph.add_node(MultiMachineNode::new())
|
graph.add_node(MultiMachineNode::new(root))
|
||||||
} else {
|
} else {
|
||||||
return Self { graph };
|
return Self { graph };
|
||||||
};
|
};
|
||||||
@ -43,17 +72,17 @@ impl MultiMachineTree {
|
|||||||
let mut nodes_to_populate_later: Vec<NodeIndex> = Vec::new();
|
let mut nodes_to_populate_later: Vec<NodeIndex> = Vec::new();
|
||||||
|
|
||||||
// place all the machines in the graph
|
// place all the machines in the graph
|
||||||
while let Some(_machine) = machines.pop() {
|
while let Some(machine) = machines.pop() {
|
||||||
if graph.nb_children(nodes_to_populate_now[populate_idx as usize])
|
if graph.nb_children(nodes_to_populate_now[populate_idx as usize])
|
||||||
== max_children_per_parent
|
== max_children_per_parent
|
||||||
{
|
{
|
||||||
nodes_to_populate_now = core::mem::take(&mut nodes_to_populate_later);
|
nodes_to_populate_now = mem::take(&mut nodes_to_populate_later);
|
||||||
populate_idx = 0; // should be useless
|
populate_idx = 0; // should be useless
|
||||||
}
|
}
|
||||||
|
|
||||||
let new_child = graph.add_child(
|
let new_child = graph.add_child(
|
||||||
nodes_to_populate_now[populate_idx as usize],
|
nodes_to_populate_now[populate_idx as usize],
|
||||||
MultiMachineNode::new(),
|
MultiMachineNode::new(machine),
|
||||||
);
|
);
|
||||||
nodes_to_populate_later.push(new_child);
|
nodes_to_populate_later.push(new_child);
|
||||||
|
|
||||||
@ -65,7 +94,7 @@ impl MultiMachineTree {
|
|||||||
|
|
||||||
fn add_child(&mut self, parent: NodeIndex, child: MultiMachineNode) -> NodeIndex {
|
fn add_child(&mut self, parent: NodeIndex, child: MultiMachineNode) -> NodeIndex {
|
||||||
let child_idx = self.graph.add_node(child);
|
let child_idx = self.graph.add_node(child);
|
||||||
self.graph.add_edge(child_idx, parent, ());
|
self.graph.add_edge(child_idx, parent, MultiMachineEdge);
|
||||||
child_idx
|
child_idx
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -74,4 +103,30 @@ impl MultiMachineTree {
|
|||||||
.neighbors_directed(node, Direction::Incoming)
|
.neighbors_directed(node, Direction::Incoming)
|
||||||
.count() as u64
|
.count() as u64
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn get_parent(&self, node: NodeIndex) -> Option<NodeIndex> {
|
||||||
|
self.graph
|
||||||
|
.neighbors_directed(node, Direction::Outgoing)
|
||||||
|
.next()
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn get_config(&self, default_port: u16) -> Vec<MultiMachineNodeConfig> {
|
||||||
|
let mut node_configs: Vec<MultiMachineNodeConfig> = Vec::new();
|
||||||
|
for node_idx in self.graph.node_indices() {
|
||||||
|
let node = &self.graph[node_idx];
|
||||||
|
|
||||||
|
let parent = self
|
||||||
|
.get_parent(node_idx)
|
||||||
|
.map(|parent_idx| self.graph[parent_idx].addr.clone());
|
||||||
|
|
||||||
|
node_configs.push(MultiMachineNodeConfig {
|
||||||
|
addr: node.addr.clone(),
|
||||||
|
parent,
|
||||||
|
port: default_port,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
node_configs
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,39 +6,49 @@
|
|||||||
//!
|
//!
|
||||||
//! We suppose everyone is on the same network and the machines have the fuzzer ready to run on each machine.
|
//! We suppose everyone is on the same network and the machines have the fuzzer ready to run on each machine.
|
||||||
|
|
||||||
use std::{fs, net::SocketAddr, str::FromStr};
|
use std::{fs, fs::File, io, io::BufRead, path::PathBuf};
|
||||||
|
|
||||||
|
use clap::Parser;
|
||||||
use petgraph::dot::Dot;
|
use petgraph::dot::Dot;
|
||||||
|
|
||||||
use crate::graph::MultiMachineTree;
|
use crate::graph::MultiMachineTree;
|
||||||
|
|
||||||
pub mod graph;
|
pub mod graph;
|
||||||
|
|
||||||
|
#[derive(Parser)]
|
||||||
|
struct Opt {
|
||||||
|
#[arg(short, long)]
|
||||||
|
machines_file: PathBuf,
|
||||||
|
#[arg(long)]
|
||||||
|
dot_output: Option<PathBuf>,
|
||||||
|
#[arg(short, long)]
|
||||||
|
json_output: Option<PathBuf>,
|
||||||
|
#[arg(short, long, default_value_t = 50000)]
|
||||||
|
default_port: u16,
|
||||||
|
// #[arg(short, long)]
|
||||||
|
// cmd_file: PathBuf,
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let machines = [
|
let opt = Opt::parse();
|
||||||
SocketAddr::from_str("0.0.0.1:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.2:50000").unwrap(),
|
let machine_file = File::open(opt.machines_file.as_path()).unwrap();
|
||||||
SocketAddr::from_str("0.0.0.3:50000").unwrap(),
|
let machines: Vec<String> = io::BufReader::new(machine_file)
|
||||||
SocketAddr::from_str("0.0.0.4:50000").unwrap(),
|
.lines()
|
||||||
SocketAddr::from_str("0.0.0.5:50000").unwrap(),
|
.map(|m| m.unwrap())
|
||||||
SocketAddr::from_str("0.0.0.6:50000").unwrap(),
|
.collect();
|
||||||
SocketAddr::from_str("0.0.0.7:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.8:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.9:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.10:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.11:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.12:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.13:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.14:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.15:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.16:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.17:50000").unwrap(),
|
|
||||||
SocketAddr::from_str("0.0.0.18:50000").unwrap(),
|
|
||||||
];
|
|
||||||
|
|
||||||
let multi_machine_graph = MultiMachineTree::generate(&machines, 3);
|
let multi_machine_graph = MultiMachineTree::generate(&machines, 3);
|
||||||
|
|
||||||
let dot = Dot::new(&multi_machine_graph.graph);
|
// final graph
|
||||||
|
if let Some(dot_path) = opt.dot_output {
|
||||||
|
let dot = Dot::new(&multi_machine_graph.graph);
|
||||||
|
fs::write(dot_path, format!("{dot}")).unwrap();
|
||||||
|
}
|
||||||
|
|
||||||
fs::write("multi_machine.dot", format!("{dot:?}")).unwrap();
|
if let Some(json_path) = opt.json_output {
|
||||||
|
let cfg = multi_machine_graph.get_config(opt.default_port);
|
||||||
|
let cfg_json = serde_json::to_string_pretty(&cfg).unwrap();
|
||||||
|
fs::write(json_path, cfg_json).unwrap();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user