cargo fmt
parent
dc39531dc6
commit
319d8e6d29
|
@ -44,8 +44,7 @@ pub enum CliArgError {
|
||||||
UnrecognizedArgument(String),
|
UnrecognizedArgument(String),
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn recv_msg_from (socket: &UdpSocket) -> Result <(Vec <Message>, SocketAddr), AppError>
|
pub async fn recv_msg_from(socket: &UdpSocket) -> Result<(Vec<Message>, SocketAddr), AppError> {
|
||||||
{
|
|
||||||
let mut buf = vec![0u8; PACKET_SIZE];
|
let mut buf = vec![0u8; PACKET_SIZE];
|
||||||
let (bytes_recved, remote_addr) = socket.recv_from(&mut buf).await?;
|
let (bytes_recved, remote_addr) = socket.recv_from(&mut buf).await?;
|
||||||
buf.truncate(bytes_recved);
|
buf.truncate(bytes_recved);
|
||||||
|
|
|
@ -18,23 +18,9 @@ pub fn debug () {
|
||||||
// numbers differ.
|
// numbers differ.
|
||||||
|
|
||||||
fn mix(i: Mac) -> Mac {
|
fn mix(i: Mac) -> Mac {
|
||||||
[
|
[i[0] ^ i[5], i[1] ^ i[4], i[2] ^ i[3], i[3], i[4], i[5]]
|
||||||
i [0] ^ i [5],
|
|
||||||
i [1] ^ i [4],
|
|
||||||
i [2] ^ i [3],
|
|
||||||
i [3],
|
|
||||||
i [4],
|
|
||||||
i [5],
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn unmix(i: Mac) -> Mac {
|
fn unmix(i: Mac) -> Mac {
|
||||||
[
|
[i[0] ^ i[5], i[1] ^ i[4], i[2] ^ i[3], i[3], i[4], i[5]]
|
||||||
i [0] ^ i [5],
|
|
||||||
i [1] ^ i [4],
|
|
||||||
i [2] ^ i [3],
|
|
||||||
i [3],
|
|
||||||
i [4],
|
|
||||||
i [5],
|
|
||||||
]
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,12 @@ pub async fn client <I: Iterator <Item=String>> (args: I) -> Result <(), AppErro
|
||||||
|
|
||||||
let mut peers = HashMap::with_capacity(10);
|
let mut peers = HashMap::with_capacity(10);
|
||||||
|
|
||||||
timeout (Duration::from_millis (params.timeout_ms), listen_for_responses (&socket, params.nicknames, &mut peers)).await.ok ();
|
timeout(
|
||||||
|
Duration::from_millis(params.timeout_ms),
|
||||||
|
listen_for_responses(&socket, params.nicknames, &mut peers),
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
.ok();
|
||||||
|
|
||||||
let mut peers: Vec<_> = peers.into_iter().collect();
|
let mut peers: Vec<_> = peers.into_iter().collect();
|
||||||
peers.sort_by_key(|(_, v)| v.mac);
|
peers.sort_by_key(|(_, v)| v.mac);
|
||||||
|
@ -43,7 +48,7 @@ pub async fn client <I: Iterator <Item=String>> (args: I) -> Result <(), AppErro
|
||||||
None => {
|
None => {
|
||||||
println!("<Unknown> = {}", ip);
|
println!("<Unknown> = {}", ip);
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -51,7 +56,7 @@ pub async fn client <I: Iterator <Item=String>> (args: I) -> Result <(), AppErro
|
||||||
None => {
|
None => {
|
||||||
println!("{} = {}", MacAddress::new(mac), ip.ip());
|
println!("{} = {}", MacAddress::new(mac), ip.ip());
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
Some(x) => x,
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -61,13 +66,10 @@ pub async fn client <I: Iterator <Item=String>> (args: I) -> Result <(), AppErro
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn find_nick <I: Iterator <Item=String>> (mut args: I) -> Result <(), AppError>
|
pub async fn find_nick<I: Iterator<Item = String>>(mut args: I) -> Result<(), AppError> {
|
||||||
{
|
|
||||||
let mut nick = None;
|
let mut nick = None;
|
||||||
let mut timeout_ms = 500;
|
let mut timeout_ms = 500;
|
||||||
let ConfigFile {
|
let ConfigFile { nicknames } = load_config_file();
|
||||||
nicknames,
|
|
||||||
} = load_config_file ();
|
|
||||||
|
|
||||||
while let Some(arg) = args.next() {
|
while let Some(arg) = args.next() {
|
||||||
match arg.as_str() {
|
match arg.as_str() {
|
||||||
|
@ -76,12 +78,13 @@ pub async fn find_nick <I: Iterator <Item=String>> (mut args: I) -> Result <(),
|
||||||
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
||||||
Some(x) => u64::from_str(&x)?,
|
Some(x) => u64::from_str(&x)?,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
_ => nick = Some(arg),
|
_ => nick = Some(arg),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let needle_nick = nick.ok_or_else (|| CliArgError::MissingRequiredArg ("nickname".to_string ()))?;
|
let needle_nick =
|
||||||
|
nick.ok_or_else(|| CliArgError::MissingRequiredArg("nickname".to_string()))?;
|
||||||
let needle_nick = Some(needle_nick);
|
let needle_nick = Some(needle_nick);
|
||||||
|
|
||||||
let common_params = Default::default();
|
let common_params = Default::default();
|
||||||
|
@ -90,7 +93,8 @@ pub async fn find_nick <I: Iterator <Item=String>> (mut args: I) -> Result <(),
|
||||||
let msg = Message::new_request1().to_vec()?;
|
let msg = Message::new_request1().to_vec()?;
|
||||||
tokio::spawn(send_requests(Arc::clone(&socket), common_params, msg));
|
tokio::spawn(send_requests(Arc::clone(&socket), common_params, msg));
|
||||||
|
|
||||||
timeout (Duration::from_millis (timeout_ms), async move { loop {
|
timeout(Duration::from_millis(timeout_ms), async move {
|
||||||
|
loop {
|
||||||
let (msgs, remote_addr) = match recv_msg_from(&socket).await {
|
let (msgs, remote_addr) = match recv_msg_from(&socket).await {
|
||||||
Err(_) => continue,
|
Err(_) => continue,
|
||||||
Ok(x) => x,
|
Ok(x) => x,
|
||||||
|
@ -115,20 +119,18 @@ pub async fn find_nick <I: Iterator <Item=String>> (mut args: I) -> Result <(),
|
||||||
println!("{}", remote_addr.ip());
|
println!("{}", remote_addr.ip());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}}).await?;
|
}
|
||||||
|
})
|
||||||
|
.await?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure_client <I: Iterator <Item=String>> (mut args: I)
|
fn configure_client<I: Iterator<Item = String>>(mut args: I) -> Result<ClientParams, AppError> {
|
||||||
-> Result <ClientParams, AppError>
|
|
||||||
{
|
|
||||||
let mut bind_addrs = vec![];
|
let mut bind_addrs = vec![];
|
||||||
let mut timeout_ms = 500;
|
let mut timeout_ms = 500;
|
||||||
|
|
||||||
let ConfigFile {
|
let ConfigFile { nicknames } = load_config_file();
|
||||||
nicknames,
|
|
||||||
} = load_config_file ();
|
|
||||||
|
|
||||||
while let Some(arg) = args.next() {
|
while let Some(arg) = args.next() {
|
||||||
match arg.as_str() {
|
match arg.as_str() {
|
||||||
|
@ -137,13 +139,13 @@ fn configure_client <I: Iterator <Item=String>> (mut args: I)
|
||||||
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
||||||
Some(x) => Ipv4Addr::from_str(&x)?,
|
Some(x) => Ipv4Addr::from_str(&x)?,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
"--timeout-ms" => {
|
"--timeout-ms" => {
|
||||||
timeout_ms = match args.next() {
|
timeout_ms = match args.next() {
|
||||||
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
||||||
Some(x) => u64::from_str(&x)?,
|
Some(x) => u64::from_str(&x)?,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
_ => return Err(CliArgError::UnrecognizedArgument(arg).into()),
|
_ => return Err(CliArgError::UnrecognizedArgument(arg).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -179,9 +181,7 @@ fn load_config_file () -> ConfigFile {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ConfigFile {
|
ConfigFile { nicknames }
|
||||||
nicknames,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn make_socket(
|
async fn make_socket(
|
||||||
|
@ -192,7 +192,10 @@ async fn make_socket (
|
||||||
|
|
||||||
for bind_addr in &bind_addrs {
|
for bind_addr in &bind_addrs {
|
||||||
if let Err(e) = socket.join_multicast_v4(common_params.multicast_addr, *bind_addr) {
|
if let Err(e) = socket.join_multicast_v4(common_params.multicast_addr, *bind_addr) {
|
||||||
println! ("Error joining multicast group with iface {}: {:?}", bind_addr, e);
|
println!(
|
||||||
|
"Error joining multicast group with iface {}: {:?}",
|
||||||
|
bind_addr, e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -203,11 +206,11 @@ async fn send_requests (
|
||||||
socket: Arc<UdpSocket>,
|
socket: Arc<UdpSocket>,
|
||||||
params: app_common::Params,
|
params: app_common::Params,
|
||||||
msg: Vec<u8>,
|
msg: Vec<u8>,
|
||||||
)
|
) -> Result<(), AppError> {
|
||||||
-> Result <(), AppError>
|
|
||||||
{
|
|
||||||
for _ in 0..10 {
|
for _ in 0..10 {
|
||||||
socket.send_to (&msg, (params.multicast_addr, params.server_port)).await?;
|
socket
|
||||||
|
.send_to(&msg, (params.multicast_addr, params.server_port))
|
||||||
|
.await?;
|
||||||
sleep(Duration::from_millis(100)).await;
|
sleep(Duration::from_millis(100)).await;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -217,7 +220,7 @@ async fn send_requests (
|
||||||
async fn listen_for_responses(
|
async fn listen_for_responses(
|
||||||
socket: &UdpSocket,
|
socket: &UdpSocket,
|
||||||
nicknames: HashMap<String, String>,
|
nicknames: HashMap<String, String>,
|
||||||
peers: &mut HashMap <SocketAddr, ServerResponse>
|
peers: &mut HashMap<SocketAddr, ServerResponse>,
|
||||||
) {
|
) {
|
||||||
loop {
|
loop {
|
||||||
let (msgs, remote_addr) = match recv_msg_from(socket).await {
|
let (msgs, remote_addr) = match recv_msg_from(socket).await {
|
||||||
|
@ -247,9 +250,8 @@ async fn listen_for_responses (
|
||||||
fn get_peer_nickname(
|
fn get_peer_nickname(
|
||||||
nicknames: &HashMap<String, String>,
|
nicknames: &HashMap<String, String>,
|
||||||
mac: Option<[u8; 6]>,
|
mac: Option<[u8; 6]>,
|
||||||
peer_nickname: Option <String>
|
peer_nickname: Option<String>,
|
||||||
) -> Option <String>
|
) -> Option<String> {
|
||||||
{
|
|
||||||
match peer_nickname.as_deref() {
|
match peer_nickname.as_deref() {
|
||||||
None => (),
|
None => (),
|
||||||
Some("") => (),
|
Some("") => (),
|
||||||
|
@ -257,7 +259,9 @@ fn get_peer_nickname (
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Some(mac) = &mac {
|
if let Some(mac) = &mac {
|
||||||
return nicknames.get (&format! ("{}", MacAddress::new (*mac))).cloned ()
|
return nicknames
|
||||||
|
.get(&format!("{}", MacAddress::new(*mac)))
|
||||||
|
.cloned();
|
||||||
}
|
}
|
||||||
|
|
||||||
None
|
None
|
||||||
|
@ -271,9 +275,7 @@ mod test {
|
||||||
fn test_nicknames() {
|
fn test_nicknames() {
|
||||||
let mut nicks = HashMap::new();
|
let mut nicks = HashMap::new();
|
||||||
|
|
||||||
for (k, v) in [
|
for (k, v) in [("01:01:01:01:01:01", "phoenix")] {
|
||||||
("01:01:01:01:01:01", "phoenix")
|
|
||||||
] {
|
|
||||||
nicks.insert(k.to_string(), v.to_string());
|
nicks.insert(k.to_string(), v.to_string());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -286,8 +288,16 @@ mod test {
|
||||||
(3, (Some([1, 1, 1, 1, 1, 2]), None), None),
|
(3, (Some([1, 1, 1, 1, 1, 2]), None), None),
|
||||||
// If the server tells us its nickname, that always takes priority
|
// If the server tells us its nickname, that always takes priority
|
||||||
(4, (None, Some("snowflake")), Some("snowflake")),
|
(4, (None, Some("snowflake")), Some("snowflake")),
|
||||||
( 5, (Some ([1, 1, 1, 1, 1, 1]), Some ("snowflake")), Some ("snowflake")),
|
(
|
||||||
( 6, (Some ([1, 1, 1, 1, 1, 2]), Some ("snowflake")), Some ("snowflake")),
|
5,
|
||||||
|
(Some([1, 1, 1, 1, 1, 1]), Some("snowflake")),
|
||||||
|
Some("snowflake"),
|
||||||
|
),
|
||||||
|
(
|
||||||
|
6,
|
||||||
|
(Some([1, 1, 1, 1, 1, 2]), Some("snowflake")),
|
||||||
|
Some("snowflake"),
|
||||||
|
),
|
||||||
// But blank nicknames are treated like None
|
// But blank nicknames are treated like None
|
||||||
(7, (None, Some("")), None),
|
(7, (None, Some("")), None),
|
||||||
(8, (Some([1, 1, 1, 1, 1, 1]), Some("")), Some("phoenix")),
|
(8, (Some([1, 1, 1, 1, 1, 1]), Some("")), Some("phoenix")),
|
||||||
|
|
26
src/ip.rs
26
src/ip.rs
|
@ -1,8 +1,4 @@
|
||||||
use std::{
|
use std::{net::Ipv4Addr, process::Command, str::FromStr};
|
||||||
net::Ipv4Addr,
|
|
||||||
process::Command,
|
|
||||||
str::FromStr,
|
|
||||||
};
|
|
||||||
|
|
||||||
#[derive(Debug, thiserror::Error)]
|
#[derive(Debug, thiserror::Error)]
|
||||||
pub enum IpError {
|
pub enum IpError {
|
||||||
|
@ -38,9 +34,7 @@ pub mod linux {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn get_ip_addr_output() -> Result<String, IpError> {
|
pub fn get_ip_addr_output() -> Result<String, IpError> {
|
||||||
let output = Command::new ("ip")
|
let output = Command::new("ip").arg("addr").output()?;
|
||||||
.arg ("addr")
|
|
||||||
.output ()?;
|
|
||||||
let output = output.stdout.as_slice();
|
let output = output.stdout.as_slice();
|
||||||
let output = String::from_utf8(output.to_vec())?;
|
let output = String::from_utf8(output.to_vec())?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
|
@ -49,7 +43,8 @@ pub mod linux {
|
||||||
pub fn parse_ip_addr_output(output: &str) -> Vec<Ipv4Addr> {
|
pub fn parse_ip_addr_output(output: &str) -> Vec<Ipv4Addr> {
|
||||||
// I wrote this in FP style because I was bored.
|
// I wrote this in FP style because I was bored.
|
||||||
|
|
||||||
output.lines ()
|
output
|
||||||
|
.lines()
|
||||||
.map(|l| l.trim_start())
|
.map(|l| l.trim_start())
|
||||||
.filter_map(|l| l.strip_prefix("inet "))
|
.filter_map(|l| l.strip_prefix("inet "))
|
||||||
.filter_map(|l| l.find('/').map(|x| &l[0..x]))
|
.filter_map(|l| l.find('/').map(|x| &l[0..x]))
|
||||||
|
@ -64,8 +59,7 @@ pub mod windows {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
pub fn get_ip_config_output() -> Result<String, IpError> {
|
pub fn get_ip_config_output() -> Result<String, IpError> {
|
||||||
let output = Command::new ("ipconfig")
|
let output = Command::new("ipconfig").output()?;
|
||||||
.output ()?;
|
|
||||||
let output = output.stdout.as_slice();
|
let output = output.stdout.as_slice();
|
||||||
let output = String::from_utf8(output.to_vec())?;
|
let output = String::from_utf8(output.to_vec())?;
|
||||||
Ok(output)
|
Ok(output)
|
||||||
|
@ -104,16 +98,12 @@ pub mod windows {
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test() {
|
fn test() {
|
||||||
for (input, expected) in [
|
for (input, expected) in [(
|
||||||
(
|
|
||||||
r"
|
r"
|
||||||
IPv4 Address . . .. . . . : 192.168.1.1
|
IPv4 Address . . .. . . . : 192.168.1.1
|
||||||
",
|
",
|
||||||
vec! [
|
vec![Ipv4Addr::new(192, 168, 1, 1)],
|
||||||
Ipv4Addr::new (192, 168, 1, 1),
|
)] {
|
||||||
]
|
|
||||||
),
|
|
||||||
] {
|
|
||||||
let actual = parse_ip_config_output(input);
|
let actual = parse_ip_config_output(input);
|
||||||
assert_eq!(actual, expected);
|
assert_eq!(actual, expected);
|
||||||
}
|
}
|
||||||
|
|
|
@ -45,15 +45,13 @@ async fn async_main () -> Result <(), AppError> {
|
||||||
fn config() {
|
fn config() {
|
||||||
if let Some(proj_dirs) = ProjectDirs::from("", "ReactorScram", "LookAround") {
|
if let Some(proj_dirs) = ProjectDirs::from("", "ReactorScram", "LookAround") {
|
||||||
println!("Using config dir {:?}", proj_dirs.config_local_dir());
|
println!("Using config dir {:?}", proj_dirs.config_local_dir());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
println!("Can't detect config dir.");
|
println!("Can't detect config dir.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn my_ips() -> Result<(), AppError> {
|
fn my_ips() -> Result<(), AppError> {
|
||||||
for addr in ip::get_ips ()?
|
for addr in ip::get_ips()? {
|
||||||
{
|
|
||||||
println!("{:?}", addr);
|
println!("{:?}", addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
147
src/message.rs
147
src/message.rs
|
@ -8,10 +8,7 @@ type Mac = [u8; 6];
|
||||||
#[derive(Debug, PartialEq)]
|
#[derive(Debug, PartialEq)]
|
||||||
pub enum Message {
|
pub enum Message {
|
||||||
// 1
|
// 1
|
||||||
Request1 {
|
Request1 { idem_id: [u8; 8], mac: Option<Mac> },
|
||||||
idem_id: [u8; 8],
|
|
||||||
mac: Option <Mac>
|
|
||||||
},
|
|
||||||
// 2
|
// 2
|
||||||
Response1(Option<Mac>),
|
Response1(Option<Mac>),
|
||||||
// 3
|
// 3
|
||||||
|
@ -23,10 +20,7 @@ impl Message {
|
||||||
let mut idem_id = [0u8; 8];
|
let mut idem_id = [0u8; 8];
|
||||||
rand::thread_rng().fill_bytes(&mut idem_id);
|
rand::thread_rng().fill_bytes(&mut idem_id);
|
||||||
|
|
||||||
Message::Request1 {
|
Message::Request1 { idem_id, mac: None }
|
||||||
idem_id,
|
|
||||||
mac: None,
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,21 +64,19 @@ impl Write for DummyWriter {
|
||||||
|
|
||||||
impl Message {
|
impl Message {
|
||||||
pub fn write<T>(&self, w: &mut Cursor<T>) -> Result<(), MessageError>
|
pub fn write<T>(&self, w: &mut Cursor<T>) -> Result<(), MessageError>
|
||||||
where Cursor <T>: Write
|
where
|
||||||
|
Cursor<T>: Write,
|
||||||
{
|
{
|
||||||
match self {
|
match self {
|
||||||
Self::Request1 {
|
Self::Request1 { idem_id, mac } => {
|
||||||
idem_id,
|
|
||||||
mac,
|
|
||||||
}=> {
|
|
||||||
w.write_all(&[1])?;
|
w.write_all(&[1])?;
|
||||||
w.write_all(&idem_id[..])?;
|
w.write_all(&idem_id[..])?;
|
||||||
Self::write_mac_opt(w, *mac)?;
|
Self::write_mac_opt(w, *mac)?;
|
||||||
},
|
}
|
||||||
Self::Response1(mac) => {
|
Self::Response1(mac) => {
|
||||||
w.write_all(&[2])?;
|
w.write_all(&[2])?;
|
||||||
Self::write_mac_opt(w, *mac)?;
|
Self::write_mac_opt(w, *mac)?;
|
||||||
},
|
}
|
||||||
Self::Response2(x) => {
|
Self::Response2(x) => {
|
||||||
w.write_all(&[3])?;
|
w.write_all(&[3])?;
|
||||||
// Measure length with dummy writes
|
// Measure length with dummy writes
|
||||||
|
@ -98,28 +90,25 @@ impl Message {
|
||||||
let len = u32::try_from(dummy_writer.position)?;
|
let len = u32::try_from(dummy_writer.position)?;
|
||||||
w.write_all(&len.to_le_bytes())?;
|
w.write_all(&len.to_le_bytes())?;
|
||||||
Self::write_response_2(w, x)?;
|
Self::write_response_2(w, x)?;
|
||||||
},
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_response_2 <W: Write> (w: &mut W, params: &Response2)
|
fn write_response_2<W: Write>(w: &mut W, params: &Response2) -> Result<(), MessageError> {
|
||||||
-> Result <(), MessageError>
|
|
||||||
{
|
|
||||||
w.write_all(¶ms.idem_id)?;
|
w.write_all(¶ms.idem_id)?;
|
||||||
let nickname = params.nickname.as_bytes();
|
let nickname = params.nickname.as_bytes();
|
||||||
tlv::Writer::<_>::lv_bytes(w, nickname)?;
|
tlv::Writer::<_>::lv_bytes(w, nickname)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn write_mac_opt <W: Write> (w: &mut W, mac: Option <[u8; 6]>) -> Result <(), std::io::Error>
|
fn write_mac_opt<W: Write>(w: &mut W, mac: Option<[u8; 6]>) -> Result<(), std::io::Error> {
|
||||||
{
|
|
||||||
match mac {
|
match mac {
|
||||||
Some(mac) => {
|
Some(mac) => {
|
||||||
w.write_all(&[1])?;
|
w.write_all(&[1])?;
|
||||||
w.write_all(&mac[..])?;
|
w.write_all(&mac[..])?;
|
||||||
},
|
}
|
||||||
None => w.write_all(&[0])?,
|
None => w.write_all(&[0])?,
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
|
@ -150,15 +139,12 @@ impl Message {
|
||||||
r.read_exact(&mut idem_id)?;
|
r.read_exact(&mut idem_id)?;
|
||||||
|
|
||||||
let mac = Self::read_mac_opt(r)?;
|
let mac = Self::read_mac_opt(r)?;
|
||||||
Self::Request1 {
|
Self::Request1 { idem_id, mac }
|
||||||
idem_id,
|
|
||||||
mac,
|
|
||||||
}
|
}
|
||||||
},
|
|
||||||
2 => {
|
2 => {
|
||||||
let mac = Self::read_mac_opt(r)?;
|
let mac = Self::read_mac_opt(r)?;
|
||||||
Self::Response1(mac)
|
Self::Response1(mac)
|
||||||
},
|
}
|
||||||
3 => {
|
3 => {
|
||||||
tlv::Reader::<_>::length(r)?;
|
tlv::Reader::<_>::length(r)?;
|
||||||
|
|
||||||
|
@ -168,24 +154,18 @@ impl Message {
|
||||||
let nickname = tlv::Reader::<_>::lv_bytes_to_vec(r, 64)?;
|
let nickname = tlv::Reader::<_>::lv_bytes_to_vec(r, 64)?;
|
||||||
let nickname = String::from_utf8(nickname)?;
|
let nickname = String::from_utf8(nickname)?;
|
||||||
|
|
||||||
Self::Response2 (Response2 {
|
Self::Response2(Response2 { idem_id, nickname })
|
||||||
idem_id,
|
}
|
||||||
nickname,
|
|
||||||
})
|
|
||||||
},
|
|
||||||
_ => return Err(MessageError::UnknownType),
|
_ => return Err(MessageError::UnknownType),
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn read_mac_opt <R: std::io::Read> (r: &mut R)
|
fn read_mac_opt<R: std::io::Read>(r: &mut R) -> Result<Option<[u8; 6]>, std::io::Error> {
|
||||||
-> Result <Option <[u8; 6]>, std::io::Error>
|
|
||||||
{
|
|
||||||
Ok(if tlv::Reader::u8(r)? == 1 {
|
Ok(if tlv::Reader::u8(r)? == 1 {
|
||||||
let mut mac = [0u8; 6];
|
let mut mac = [0u8; 6];
|
||||||
r.read_exact(&mut mac)?;
|
r.read_exact(&mut mac)?;
|
||||||
Some(mac)
|
Some(mac)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
None
|
None
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -212,19 +192,14 @@ mod test {
|
||||||
fn test_write_2() -> Result<(), MessageError> {
|
fn test_write_2() -> Result<(), MessageError> {
|
||||||
for (input, expected) in [
|
for (input, expected) in [
|
||||||
(
|
(
|
||||||
vec! [
|
vec![Message::Request1 {
|
||||||
Message::Request1 {
|
idem_id: [1, 2, 3, 4, 5, 6, 7, 8],
|
||||||
idem_id: [1, 2, 3, 4, 5, 6, 7, 8,],
|
|
||||||
mac: None,
|
mac: None,
|
||||||
},
|
}],
|
||||||
],
|
|
||||||
vec![
|
vec![
|
||||||
154, 74, 67, 129,
|
154, 74, 67, 129, // Request tag
|
||||||
// Request tag
|
1, // Idem ID
|
||||||
1,
|
1, 2, 3, 4, 5, 6, 7, 8, // MAC is None
|
||||||
// Idem ID
|
|
||||||
1, 2, 3, 4, 5, 6, 7, 8,
|
|
||||||
// MAC is None
|
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -232,28 +207,20 @@ mod test {
|
||||||
vec![
|
vec![
|
||||||
Message::Response1(Some([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])),
|
Message::Response1(Some([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])),
|
||||||
Message::Response2(Response2 {
|
Message::Response2(Response2 {
|
||||||
idem_id: [1, 2, 3, 4, 5, 6, 7, 8,],
|
idem_id: [1, 2, 3, 4, 5, 6, 7, 8],
|
||||||
nickname: ":V".to_string(),
|
nickname: ":V".to_string(),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
vec![
|
vec![
|
||||||
// Magic number for LookAround packets
|
// Magic number for LookAround packets
|
||||||
154, 74, 67, 129,
|
154, 74, 67, 129, // Response1 tag
|
||||||
// Response1 tag
|
2, // MAC is Some
|
||||||
2,
|
1, // MAC
|
||||||
// MAC is Some
|
17, 34, 51, 68, 85, 102, // Response2 tag
|
||||||
1,
|
3, // Length prefix
|
||||||
// MAC
|
14, 0, 0, 0, // Idem ID
|
||||||
17, 34, 51, 68, 85, 102,
|
1, 2, 3, 4, 5, 6, 7, 8, // Length-prefixed string
|
||||||
// Response2 tag
|
2, 0, 0, 0, 58, 86,
|
||||||
3,
|
|
||||||
// Length prefix
|
|
||||||
14, 0, 0, 0,
|
|
||||||
// Idem ID
|
|
||||||
1, 2, 3, 4, 5, 6, 7, 8,
|
|
||||||
// Length-prefixed string
|
|
||||||
2, 0, 0, 0,
|
|
||||||
58, 86,
|
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
] {
|
] {
|
||||||
|
@ -273,12 +240,9 @@ mod test {
|
||||||
mac: None,
|
mac: None,
|
||||||
},
|
},
|
||||||
vec![
|
vec![
|
||||||
154, 74, 67, 129,
|
154, 74, 67, 129, // Request tag
|
||||||
// Request tag
|
1, // Idem ID
|
||||||
1,
|
1, 2, 3, 4, 5, 6, 7, 8, // MAC is None
|
||||||
// Idem ID
|
|
||||||
1, 2, 3, 4, 5, 6, 7, 8,
|
|
||||||
// MAC is None
|
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -286,12 +250,9 @@ mod test {
|
||||||
Message::Response1(Some([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])),
|
Message::Response1(Some([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])),
|
||||||
vec![
|
vec![
|
||||||
// Magic number for LookAround packets
|
// Magic number for LookAround packets
|
||||||
154, 74, 67, 129,
|
154, 74, 67, 129, // Response tag
|
||||||
// Response tag
|
2, // MAC is Some
|
||||||
2,
|
1, // MAC
|
||||||
// MAC is Some
|
|
||||||
1,
|
|
||||||
// MAC
|
|
||||||
17, 34, 51, 68, 85, 102,
|
17, 34, 51, 68, 85, 102,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
|
@ -299,14 +260,14 @@ mod test {
|
||||||
Message::Response1(None),
|
Message::Response1(None),
|
||||||
vec![
|
vec![
|
||||||
// Magic number for LookAround packets
|
// Magic number for LookAround packets
|
||||||
154, 74, 67, 129,
|
154, 74, 67, 129, // Response tag
|
||||||
// Response tag
|
2, // MAC is None
|
||||||
2,
|
|
||||||
// MAC is None
|
|
||||||
0,
|
0,
|
||||||
],
|
],
|
||||||
),
|
),
|
||||||
].into_iter () {
|
]
|
||||||
|
.into_iter()
|
||||||
|
{
|
||||||
let actual = input.to_vec()?;
|
let actual = input.to_vec()?;
|
||||||
assert_eq!(actual, expected, "{:?}", input);
|
assert_eq!(actual, expected, "{:?}", input);
|
||||||
}
|
}
|
||||||
|
@ -317,26 +278,24 @@ mod test {
|
||||||
#[test]
|
#[test]
|
||||||
fn test_read_2() -> Result<(), MessageError> {
|
fn test_read_2() -> Result<(), MessageError> {
|
||||||
for input in [
|
for input in [
|
||||||
vec! [
|
vec![Message::Request1 {
|
||||||
Message::Request1 {
|
|
||||||
idem_id: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
|
idem_id: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08],
|
||||||
mac: None,
|
mac: None,
|
||||||
},
|
}],
|
||||||
],
|
vec![Message::Response1(Some([
|
||||||
vec! [
|
0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
|
||||||
Message::Response1 (Some ([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])),
|
]))],
|
||||||
],
|
vec![Message::Response1(None)],
|
||||||
vec! [
|
|
||||||
Message::Response1 (None),
|
|
||||||
],
|
|
||||||
vec![
|
vec![
|
||||||
Message::Response1(Some([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])),
|
Message::Response1(Some([0x11, 0x22, 0x33, 0x44, 0x55, 0x66])),
|
||||||
Message::Response2(Response2 {
|
Message::Response2(Response2 {
|
||||||
idem_id: [1, 2, 3, 4, 5, 6, 7, 8,],
|
idem_id: [1, 2, 3, 4, 5, 6, 7, 8],
|
||||||
nickname: ":V".to_string(),
|
nickname: ":V".to_string(),
|
||||||
}),
|
}),
|
||||||
],
|
],
|
||||||
].into_iter () {
|
]
|
||||||
|
.into_iter()
|
||||||
|
{
|
||||||
let encoded = Message::many_to_vec(&input)?;
|
let encoded = Message::many_to_vec(&input)?;
|
||||||
let decoded = Message::from_slice2(&encoded)?;
|
let decoded = Message::from_slice2(&encoded)?;
|
||||||
assert_eq!(input, decoded);
|
assert_eq!(input, decoded);
|
||||||
|
|
|
@ -1,51 +1,27 @@
|
||||||
pub use std::{
|
pub use std::{
|
||||||
collections::HashMap,
|
collections::HashMap,
|
||||||
env,
|
env,
|
||||||
io::{
|
io::{Cursor, Write},
|
||||||
Cursor,
|
net::{Ipv4Addr, SocketAddr, SocketAddrV4},
|
||||||
Write,
|
|
||||||
},
|
|
||||||
net::{
|
|
||||||
Ipv4Addr,
|
|
||||||
SocketAddr,
|
|
||||||
SocketAddrV4,
|
|
||||||
},
|
|
||||||
str::FromStr,
|
str::FromStr,
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
time::{
|
time::Duration,
|
||||||
Duration,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use configparser::ini::Ini;
|
pub use configparser::ini::Ini;
|
||||||
pub use directories::ProjectDirs;
|
pub use directories::ProjectDirs;
|
||||||
pub use mac_address::{
|
pub use mac_address::{MacAddress, get_mac_address};
|
||||||
MacAddress,
|
|
||||||
get_mac_address,
|
|
||||||
};
|
|
||||||
pub use rand::RngCore;
|
pub use rand::RngCore;
|
||||||
pub use tokio::{
|
pub use tokio::{
|
||||||
net::UdpSocket,
|
net::UdpSocket,
|
||||||
time::{
|
time::{sleep, timeout},
|
||||||
sleep,
|
|
||||||
timeout,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
app_common::{
|
app_common::{
|
||||||
self,
|
self, AppError, CliArgError, LOOKAROUND_VERSION, find_project_dirs, recv_msg_from,
|
||||||
LOOKAROUND_VERSION,
|
|
||||||
AppError,
|
|
||||||
CliArgError,
|
|
||||||
find_project_dirs,
|
|
||||||
recv_msg_from,
|
|
||||||
},
|
},
|
||||||
ip::get_ips,
|
ip::get_ips,
|
||||||
message::{
|
message::{self, Message, PACKET_SIZE},
|
||||||
self,
|
|
||||||
PACKET_SIZE,
|
|
||||||
Message,
|
|
||||||
},
|
|
||||||
tlv,
|
tlv,
|
||||||
};
|
};
|
||||||
|
|
|
@ -8,8 +8,7 @@ struct Params {
|
||||||
our_mac: Option<[u8; 6]>,
|
our_mac: Option<[u8; 6]>,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn server <I: Iterator <Item=String>> (args: I) -> Result <(), AppError>
|
pub async fn server<I: Iterator<Item = String>>(args: I) -> Result<(), AppError> {
|
||||||
{
|
|
||||||
match get_mac_address() {
|
match get_mac_address() {
|
||||||
Ok(Some(ma)) => {
|
Ok(Some(ma)) => {
|
||||||
println!("Our MAC addr = {}", ma);
|
println!("Our MAC addr = {}", ma);
|
||||||
|
@ -20,11 +19,18 @@ pub async fn server <I: Iterator <Item=String>> (args: I) -> Result <(), AppErro
|
||||||
|
|
||||||
let params = configure(args)?;
|
let params = configure(args)?;
|
||||||
|
|
||||||
let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, params.common.server_port)).await?;
|
let socket = UdpSocket::bind(SocketAddrV4::new(
|
||||||
|
Ipv4Addr::UNSPECIFIED,
|
||||||
|
params.common.server_port,
|
||||||
|
))
|
||||||
|
.await?;
|
||||||
|
|
||||||
for bind_addr in ¶ms.bind_addrs {
|
for bind_addr in ¶ms.bind_addrs {
|
||||||
if let Err(e) = socket.join_multicast_v4(params.common.multicast_addr, *bind_addr) {
|
if let Err(e) = socket.join_multicast_v4(params.common.multicast_addr, *bind_addr) {
|
||||||
println! ("Error joining multicast group with iface {}: {:?}", bind_addr, e);
|
println!(
|
||||||
|
"Error joining multicast group with iface {}: {:?}",
|
||||||
|
bind_addr, e
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -33,8 +39,7 @@ pub async fn server <I: Iterator <Item=String>> (args: I) -> Result <(), AppErro
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn configure <I: Iterator <Item=String>> (mut args: I) -> Result <Params, AppError>
|
fn configure<I: Iterator<Item = String>>(mut args: I) -> Result<Params, AppError> {
|
||||||
{
|
|
||||||
let common = app_common::Params::default();
|
let common = app_common::Params::default();
|
||||||
let mut bind_addrs = vec![];
|
let mut bind_addrs = vec![];
|
||||||
let mut nickname = String::new();
|
let mut nickname = String::new();
|
||||||
|
@ -47,12 +52,13 @@ fn configure <I: Iterator <Item=String>> (mut args: I) -> Result <Params, AppErr
|
||||||
nickname = x;
|
nickname = x;
|
||||||
eprintln!("Loaded nickname {:?}", nickname);
|
eprintln!("Loaded nickname {:?}", nickname);
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
eprintln!(
|
||||||
|
"Can't load ini from {:?}, didn't load default configs",
|
||||||
|
path
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else {
|
} else {
|
||||||
eprintln! ("Can't load ini from {:?}, didn't load default configs", path);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
eprintln!("Can't find config dir, didn't load default configs");
|
eprintln!("Can't find config dir, didn't load default configs");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -63,20 +69,22 @@ fn configure <I: Iterator <Item=String>> (mut args: I) -> Result <Params, AppErr
|
||||||
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
||||||
Some(x) => Ipv4Addr::from_str(&x)?,
|
Some(x) => Ipv4Addr::from_str(&x)?,
|
||||||
});
|
});
|
||||||
},
|
}
|
||||||
"--nickname" => {
|
"--nickname" => {
|
||||||
nickname = match args.next() {
|
nickname = match args.next() {
|
||||||
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
None => return Err(CliArgError::MissingArgumentValue(arg).into()),
|
||||||
Some (x) => x
|
Some(x) => x,
|
||||||
};
|
};
|
||||||
},
|
}
|
||||||
_ => return Err(CliArgError::UnrecognizedArgument(arg).into()),
|
_ => return Err(CliArgError::UnrecognizedArgument(arg).into()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
let our_mac = get_mac_address()?.map(|x| x.bytes());
|
let our_mac = get_mac_address()?.map(|x| x.bytes());
|
||||||
if our_mac.is_none() {
|
if our_mac.is_none() {
|
||||||
println! ("Warning: Can't find our own MAC address. We won't be able to respond to MAC-specific lookaround requests");
|
println!(
|
||||||
|
"Warning: Can't find our own MAC address. We won't be able to respond to MAC-specific lookaround requests"
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if bind_addrs.is_empty() {
|
if bind_addrs.is_empty() {
|
||||||
|
@ -92,12 +100,7 @@ fn configure <I: Iterator <Item=String>> (mut args: I) -> Result <Params, AppErr
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn serve_interface (
|
async fn serve_interface(params: Params, socket: UdpSocket) -> Result<(), AppError> {
|
||||||
params: Params,
|
|
||||||
socket: UdpSocket,
|
|
||||||
)
|
|
||||||
-> Result <(), AppError>
|
|
||||||
{
|
|
||||||
let mut recent_idem_ids = Vec::with_capacity(32);
|
let mut recent_idem_ids = Vec::with_capacity(32);
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
|
@ -107,7 +110,7 @@ async fn serve_interface (
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
println!("Error while receiving message: {:?}", e);
|
println!("Error while receiving message: {:?}", e);
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let req = match req_msgs.into_iter().next() {
|
let req = match req_msgs.into_iter().next() {
|
||||||
|
@ -115,18 +118,14 @@ async fn serve_interface (
|
||||||
_ => {
|
_ => {
|
||||||
println!("Don't know how to handle this message, ignoring");
|
println!("Don't know how to handle this message, ignoring");
|
||||||
continue;
|
continue;
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
let resp = match req {
|
let resp = match req {
|
||||||
Message::Request1 {
|
Message::Request1 { mac: None, idem_id } => {
|
||||||
mac: None,
|
|
||||||
idem_id,
|
|
||||||
} => {
|
|
||||||
if recent_idem_ids.contains(&idem_id) {
|
if recent_idem_ids.contains(&idem_id) {
|
||||||
None
|
None
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
recent_idem_ids.insert(0, idem_id);
|
recent_idem_ids.insert(0, idem_id);
|
||||||
recent_idem_ids.truncate(30);
|
recent_idem_ids.truncate(30);
|
||||||
Some(vec![
|
Some(vec![
|
||||||
|
@ -137,12 +136,14 @@ async fn serve_interface (
|
||||||
}),
|
}),
|
||||||
])
|
])
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
_ => continue,
|
_ => continue,
|
||||||
};
|
};
|
||||||
|
|
||||||
if let Some(resp) = resp {
|
if let Some(resp) = resp {
|
||||||
socket.send_to (&Message::many_to_vec (&resp)?, remote_addr).await?;
|
socket
|
||||||
|
.send_to(&Message::many_to_vec(&resp)?, remote_addr)
|
||||||
|
.await?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,6 @@ pub enum TlvError {
|
||||||
// To live is to suffer,
|
// To live is to suffer,
|
||||||
// The data is too big,
|
// The data is too big,
|
||||||
// For the gosh-darn buffer.
|
// For the gosh-darn buffer.
|
||||||
|
|
||||||
#[error("Data too big")]
|
#[error("Data too big")]
|
||||||
DataTooBig,
|
DataTooBig,
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
@ -104,11 +103,7 @@ mod test {
|
||||||
|
|
||||||
let v = w.into_inner();
|
let v = w.into_inner();
|
||||||
|
|
||||||
assert_eq! (v, vec! [
|
assert_eq!(v, vec![8, 0, 0, 0, 104, 105, 32, 116, 104, 101, 114, 101,]);
|
||||||
8, 0, 0, 0,
|
|
||||||
104, 105, 32,
|
|
||||||
116, 104, 101, 114, 101,
|
|
||||||
]);
|
|
||||||
|
|
||||||
let mut r = Cursor::new(v);
|
let mut r = Cursor::new(v);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue