Skip to content

Commit da84c16

Browse files
committed
Use StructOpt to simplify clap. Because learning
1 parent 724554b commit da84c16

File tree

2 files changed

+46
-62
lines changed

2 files changed

+46
-62
lines changed

Cargo.toml

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
[package]
22
name = "net_hex"
3-
version = "0.1.0"
4-
authors = ["jack"]
3+
version = "0.3.0"
4+
authors = ["Jack Newman jacknewman12@gmail.com"]
55
edition = "2018"
66
license = "MIT"
77

@@ -10,7 +10,7 @@ license = "MIT"
1010
[dependencies]
1111
hexplay = "*"
1212
hex = "0.3.2"
13-
clap = "2.33.0"
13+
structopt = "0.2"
1414

1515
[dependencies.pnet]
1616
version = "0.22.0"

src/main.rs

Lines changed: 43 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
extern crate clap;
1+
extern crate hex;
22
extern crate hexplay;
33
extern crate pnet;
44

5-
use clap::{value_t, App, Arg};
6-
5+
use hex::FromHex;
76
use pnet::datalink::Channel::Ethernet;
87
use pnet::datalink::{self, Config, NetworkInterface};
8+
use structopt::StructOpt;
99

1010
use std::io;
1111
use std::time::{Duration, Instant};
@@ -21,82 +21,66 @@ fn print_interfaces() {
2121
}
2222
}
2323

24+
/// A small utility for reading / writing directly to a network interface
25+
#[derive(StructOpt, Debug)]
26+
#[structopt(
27+
name = "NetHex",
28+
raw(setting = "structopt::clap::AppSettings::ColoredHelp")
29+
)]
30+
struct Opt {
31+
/// Number of packet to receive before exiting
32+
#[structopt(short = "c", long = "count", default_value = "-1")]
33+
count: i64,
34+
35+
/// Number of packet to receive before exiting
36+
#[structopt(short = "t", long = "timeout")]
37+
timeout: Option<u64>,
38+
39+
/// The network interface to listen on
40+
#[structopt(name = "interface")]
41+
interface: Option<String>,
42+
43+
/// The hex bytes to send over the network
44+
#[structopt(name = "bytes")]
45+
bytes: Option<String>,
46+
}
47+
2448
// Invoke as echo <interface name>
2549
fn main() {
26-
let matches = App::new("NetHex")
27-
.version("0.1.0")
28-
.author("Jack Newman")
29-
.about("A small utility for reading / writing directly to a network interface")
30-
.arg(
31-
Arg::with_name("timeout")
32-
.short("t")
33-
.long("timeout")
34-
.takes_value(true)
35-
.help("Time before exiting the program"),
36-
)
37-
.arg(
38-
Arg::with_name("count")
39-
.short("c")
40-
.long("count")
41-
.takes_value(true)
42-
.help("Number of packet to receive before exiting")
43-
.default_value("-1"),
44-
)
45-
.arg(
46-
Arg::with_name("list")
47-
.short("l")
48-
.long("list")
49-
.help("List network interfaces"),
50-
)
51-
.arg(
52-
Arg::with_name("interface")
53-
.help("The network interface to send/read from")
54-
.required_unless("list"),
55-
)
56-
.arg(
57-
Arg::with_name("bytes")
58-
.help("A hex string of raw bytes to send to the interface e.g. 11EE22FF"),
59-
)
60-
.get_matches();
50+
let opt = Opt::from_args();
51+
// println!("{:?}", opt);
6152

62-
// println!("{:?}", matches);
63-
if matches.is_present("list") {
53+
// If the user did not specify any interface. List some to be helpful
54+
if let None = opt.interface {
6455
print_interfaces();
6556
std::process::exit(0);
6657
};
6758

68-
let rx_timeout = value_t!(matches, "timeout", u64)
69-
.ok()
70-
.map(|time| Duration::from_secs(time));
71-
let mut rx_countlimit = value_t!(matches, "count", i64).unwrap();
72-
73-
// Grab the input interface. No error checking as clap will exit if it does not exist
74-
let interface_name = matches.value_of("interface").unwrap();
59+
let rx_timeout = opt.timeout.map(|time| Duration::from_secs(time));
60+
let mut rx_countlimit = opt.count;
7561

7662
// Find the network interface with the provided name
77-
let interface_names_match = |iface: &NetworkInterface| iface.name == interface_name;
7863
let interfaces = datalink::interfaces();
7964
let interface = interfaces
8065
.into_iter()
81-
.filter(interface_names_match)
66+
// Safe to unwrap since print_interfaces will exit above
67+
.filter(|iface: &NetworkInterface| iface.name == *opt.interface.as_ref().unwrap())
8268
.next()
8369
.expect("Could not find the network interface");
8470

85-
// Create a new channel, dealing with layer 2 packets
86-
let mut datalink_config = Config::default();
8771
// Set the timeout of the socket read to 10ms
88-
datalink_config.read_timeout = Some(std::time::Duration::new(0, 1e7 as u32));
72+
let mut datalink_config = Config::default();
73+
datalink_config.read_timeout = Some(std::time::Duration::new(0, 1e7 as u32));
8974

75+
// Create a new channel, dealing with layer 2 packets
9076
let (mut tx, mut rx) = match datalink::channel(&interface, datalink_config) {
9177
Ok(Ethernet(tx, rx)) => (tx, rx),
9278
Ok(_) => panic!("Unhandled channel type"),
9379
Err(e) => panic!("Error while creating datalink channel: {:?}", e),
9480
};
9581

9682
// Decode the hex input if the user specified one
97-
if let Some(arg) = matches.value_of("bytes") {
98-
extern crate hex;
99-
use hex::FromHex;
83+
if let Some(arg) = opt.bytes {
10084
let bytes = match Vec::from_hex(arg) {
10185
Ok(bytes) => bytes,
10286
Err(e) => {
@@ -106,11 +90,11 @@ fn main() {
10690
};
10791
// Transmit those bytes
10892
println!("Sending bytes: {:X?}", bytes);
109-
let res = tx.send_to(&bytes, None).unwrap();
93+
let res = tx.send_to(&bytes, None).unwrap();
11094
if let Err(error) = res {
111-
println!("{:?}", error);
112-
std::process::exit(1);
113-
};
95+
println!("{:?}", error);
96+
std::process::exit(1);
97+
};
11498
}
11599

116100
// Now do the Rx part

0 commit comments

Comments
 (0)