forked from smoltcp-rs/smoltcp
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathutils.rs
157 lines (147 loc) · 4.4 KB
/
utils.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// TODO: this is literally a copy of examples/utils.rs, but without an allow dead code attribute.
// The include logic does not allow having attributes in included files.
use getopts::{Matches, Options};
use std::env;
use std::fs::File;
use std::io;
use std::io::Write;
use std::process;
use std::str::{self, FromStr};
use std::time::{SystemTime, UNIX_EPOCH};
use smoltcp::phy::{Device, FaultInjector, Tracer};
use smoltcp::phy::{PcapMode, PcapWriter};
use smoltcp::time::Duration;
pub fn create_options() -> (Options, Vec<&'static str>) {
let mut opts = Options::new();
opts.optflag("h", "help", "print this help menu");
(opts, Vec::new())
}
pub fn parse_options(options: &Options, free: Vec<&str>) -> Matches {
match options.parse(env::args().skip(1)) {
Err(err) => {
println!("{}", err);
process::exit(1)
}
Ok(matches) => {
if matches.opt_present("h") || matches.free.len() != free.len() {
let brief = format!(
"Usage: {} [OPTION]... {}",
env::args().nth(0).unwrap(),
free.join(" ")
);
print!("{}", options.usage(&brief));
process::exit(if matches.free.len() != free.len() {
1
} else {
0
})
}
matches
}
}
}
pub fn add_middleware_options(opts: &mut Options, _free: &mut Vec<&str>) {
opts.optopt("", "pcap", "Write a packet capture file", "FILE");
opts.optopt(
"",
"drop-chance",
"Chance of dropping a packet (%)",
"CHANCE",
);
opts.optopt(
"",
"corrupt-chance",
"Chance of corrupting a packet (%)",
"CHANCE",
);
opts.optopt(
"",
"size-limit",
"Drop packets larger than given size (octets)",
"SIZE",
);
opts.optopt(
"",
"tx-rate-limit",
"Drop packets after transmit rate exceeds given limit \
(packets per interval)",
"RATE",
);
opts.optopt(
"",
"rx-rate-limit",
"Drop packets after transmit rate exceeds given limit \
(packets per interval)",
"RATE",
);
opts.optopt(
"",
"shaping-interval",
"Sets the interval for rate limiting (ms)",
"RATE",
);
}
pub fn parse_middleware_options<D>(
matches: &mut Matches,
device: D,
loopback: bool,
) -> FaultInjector<Tracer<PcapWriter<D, Box<dyn Write>>>>
where
D: Device,
{
let drop_chance = matches
.opt_str("drop-chance")
.map(|s| u8::from_str(&s).unwrap())
.unwrap_or(0);
let corrupt_chance = matches
.opt_str("corrupt-chance")
.map(|s| u8::from_str(&s).unwrap())
.unwrap_or(0);
let size_limit = matches
.opt_str("size-limit")
.map(|s| usize::from_str(&s).unwrap())
.unwrap_or(0);
let tx_rate_limit = matches
.opt_str("tx-rate-limit")
.map(|s| u64::from_str(&s).unwrap())
.unwrap_or(0);
let rx_rate_limit = matches
.opt_str("rx-rate-limit")
.map(|s| u64::from_str(&s).unwrap())
.unwrap_or(0);
let shaping_interval = matches
.opt_str("shaping-interval")
.map(|s| u64::from_str(&s).unwrap())
.unwrap_or(0);
let pcap_writer: Box<dyn io::Write>;
if let Some(pcap_filename) = matches.opt_str("pcap") {
pcap_writer = Box::new(File::create(pcap_filename).expect("cannot open file"))
} else {
pcap_writer = Box::new(io::sink())
}
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.subsec_nanos();
let device = PcapWriter::new(
device,
pcap_writer,
if loopback {
PcapMode::TxOnly
} else {
PcapMode::Both
},
);
let device = Tracer::new(device, |_timestamp, _printer| {
#[cfg(feature = "log")]
trace!("{}", _printer);
});
let mut device = FaultInjector::new(device, seed);
device.set_drop_chance(drop_chance);
device.set_corrupt_chance(corrupt_chance);
device.set_max_packet_size(size_limit);
device.set_max_tx_rate(tx_rate_limit);
device.set_max_rx_rate(rx_rate_limit);
device.set_bucket_interval(Duration::from_millis(shaping_interval));
device
}