working on TLV-formatted messages

main
_ 2021-12-05 19:58:18 +00:00
parent 0914a972e4
commit eaca615510
3 changed files with 178 additions and 18 deletions

View File

@ -2,6 +2,7 @@ use std::{
env, env,
net::{ net::{
Ipv4Addr, Ipv4Addr,
SocketAddr,
SocketAddrV4, SocketAddrV4,
UdpSocket, UdpSocket,
}, },
@ -10,12 +11,26 @@ use std::{
use mac_address::get_mac_address; use mac_address::get_mac_address;
use thiserror::Error; use thiserror::Error;
mod message;
mod tlv; mod tlv;
use message::{
PACKET_SIZE,
Message,
};
#[derive (Debug, Error)] #[derive (Debug, Error)]
enum AppError { enum AppError {
#[error (transparent)] #[error (transparent)]
CliArgs (#[from] CliArgError), CliArgs (#[from] CliArgError),
#[error (transparent)]
Io (#[from] std::io::Error),
#[error (transparent)]
MacAddr (#[from] mac_address::MacAddressError),
#[error (transparent)]
Message (#[from] message::MessageError),
#[error (transparent)]
Tlv (#[from] tlv::TlvError),
} }
#[derive (Debug, Error)] #[derive (Debug, Error)]
@ -58,10 +73,10 @@ fn main () -> Result <(), AppError> {
} }
match args.next ().as_ref ().map (|s| &s[..]) { match args.next ().as_ref ().map (|s| &s[..]) {
None => Err (CliArgError::MissingSubcommand)?, None => return Err (CliArgError::MissingSubcommand.into ()),
Some ("client") => client ()?, Some ("client") => client ()?,
Some ("server") => server ()?, Some ("server") => server ()?,
Some (x) => Err (CliArgError::UnknownSubcommand (x.to_string ()))?, Some (x) => return Err (CliArgError::UnknownSubcommand (x.to_string ()).into ()),
} }
Ok (()) Ok (())
@ -73,30 +88,51 @@ fn client () -> Result <(), AppError> {
socket.join_multicast_v4 (&params.multicast_addr, &([0u8, 0, 0, 0].into ())).unwrap (); socket.join_multicast_v4 (&params.multicast_addr, &([0u8, 0, 0, 0].into ())).unwrap ();
socket.send_to ("hi there".as_bytes (), (params.multicast_addr, params.server_port)).unwrap (); let msg = Message::Request (None).to_vec ()?;
socket.send_to (&msg, (params.multicast_addr, params.server_port)).unwrap ();
let (resp, remote_addr) = recv_msg_from (&socket)?;
let mut buf = vec! [0u8; 4096];
let (bytes_recved, remote_addr) = socket.recv_from (&mut buf).unwrap ();
buf.truncate (bytes_recved);
let _buf = buf;
dbg! (remote_addr); dbg! (remote_addr);
Ok (()) Ok (())
} }
fn server () -> Result <(), AppError> { fn server () -> Result <(), AppError> {
let our_mac = get_mac_address ()?.map (|x| x.bytes ());
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");
}
let params = CommonParams::default (); let params = CommonParams::default ();
let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, params.server_port)).unwrap (); let socket = UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, params.server_port)).unwrap ();
socket.join_multicast_v4 (&params.multicast_addr, &([0u8, 0, 0, 0].into ())).unwrap (); socket.join_multicast_v4 (&params.multicast_addr, &([0u8, 0, 0, 0].into ())).unwrap ();
let mut buf = vec! [0u8; 4096]; let (req, remote_addr) = recv_msg_from (&socket)?;
let (bytes_recved, remote_addr) = socket.recv_from (&mut buf).unwrap ();
buf.truncate (bytes_recved);
let _buf = buf;
dbg! (remote_addr); dbg! (remote_addr);
socket.send_to ("hi there".as_bytes (), remote_addr).unwrap (); let resp = match req {
Message::Request (None) => {
Some (Message::Response (our_mac))
},
_ => None,
};
if let Some (resp) = resp {
socket.send_to (&resp.to_vec ()?, remote_addr).unwrap ();
}
Ok (()) Ok (())
} }
fn recv_msg_from (socket: &UdpSocket) -> Result <(Message, SocketAddr), AppError>
{
let mut buf = vec! [0u8; PACKET_SIZE];
let (bytes_recved, remote_addr) = socket.recv_from (&mut buf)?;
buf.truncate (bytes_recved);
let msg = Message::from_slice (&buf)?;
Ok ((msg, remote_addr))
}

106
src/message.rs Normal file
View File

@ -0,0 +1,106 @@
use std::{
io::Cursor,
};
use crate::tlv;
use thiserror::Error;
const MAGIC_NUMBER: [u8; 4] = [0x9a, 0x4a, 0x43, 0x81];
pub const PACKET_SIZE: usize = 1024;
pub enum Message {
Request (Option <[u8; 6]>),
Response (Option <[u8; 6]>),
}
#[derive (Debug, Error)]
pub enum MessageError {
#[error (transparent)]
Io (#[from] std::io::Error),
#[error (transparent)]
Tlv (#[from] tlv::TlvError),
#[error ("Unknown type")]
UnknownType,
}
impl Message {
pub fn write <W: std::io::Write> (&self, w: &mut W) -> Result <(), std::io::Error>
{
w.write_all (&MAGIC_NUMBER)?;
match self {
Self::Request (mac) => {
w.write_all (&[1])?;
Self::write_mac_opt (w, *mac)?;
},
Self::Response (mac) => {
w.write_all (&[2])?;
Self::write_mac_opt (w, *mac)?;
},
}
Ok (())
}
fn write_mac_opt <W: std::io::Write> (w: &mut W, mac: Option <[u8; 6]>) -> Result <(), std::io::Error>
{
match mac {
Some (mac) => {
w.write_all (&[1])?;
w.write_all (&mac[..])?;
},
None => w.write_all (&[0])?,
}
Ok (())
}
pub fn to_vec (&self) -> Result <Vec <u8>, tlv::TlvError> {
let mut cursor = Cursor::new (Vec::with_capacity (PACKET_SIZE));
self.write (&mut cursor)?;
Ok (cursor.into_inner ())
}
pub fn read <R: std::io::Read> (r: &mut R) -> Result <Self, MessageError> {
tlv::Reader::expect (r, &MAGIC_NUMBER)?;
let t = tlv::Reader::u8 (r)?;
Ok (match t {
1 => {
let mac = Self::read_mac_opt (r)?;
Self::Request (mac)
},
2 => {
let mac = Self::read_mac_opt (r)?;
Self::Response (mac)
},
_ => return Err (MessageError::UnknownType),
})
}
fn read_mac_opt <R: std::io::Read> (r: &mut R)
-> Result <Option <[u8; 6]>, std::io::Error>
{
Ok (if tlv::Reader::u8 (r)? == 1 {
let mut mac = [0u8; 6];
r.read_exact (&mut mac)?;
Some (mac)
}
else {
None
})
}
pub fn from_slice (buf: &[u8]) -> Result <Self, MessageError> {
let mut cursor = Cursor::new (buf);
Self::read (&mut cursor)
}
}
#[cfg (test)]
mod test {
#[test]
fn test_1 () {
}
}

View File

@ -10,11 +10,13 @@ pub enum TlvError {
CallerBufferTooSmall, CallerBufferTooSmall,
#[error (transparent)] #[error (transparent)]
Io (#[from] std::io::Error), Io (#[from] std::io::Error),
#[error ("Actual bytes didn't match expected bytes")]
NotExpected,
#[error (transparent)] #[error (transparent)]
TryFromInt (#[from] std::num::TryFromIntError), TryFromInt (#[from] std::num::TryFromIntError),
} }
struct Writer <W> { pub struct Writer <W> {
_x: std::marker::PhantomData <W>, _x: std::marker::PhantomData <W>,
} }
@ -24,9 +26,9 @@ impl <W: std::io::Write> Writer <W> {
Ok (()) Ok (())
} }
fn lv_bytes (w: &mut W, b: &[u8]) -> Result <()> { pub fn lv_bytes (w: &mut W, b: &[u8]) -> Result <()> {
if b.len () > 2_000_000_000 { if b.len () > 2_000_000_000 {
Err (TlvError::BufferTooBig)?; return Err (TlvError::BufferTooBig);
} }
let l = u32::try_from (b.len ())?; let l = u32::try_from (b.len ())?;
@ -38,11 +40,20 @@ impl <W: std::io::Write> Writer <W> {
} }
} }
struct Reader <R> { pub struct Reader <R> {
_x: std::marker::PhantomData <R>, _x: std::marker::PhantomData <R>,
} }
impl <R: std::io::Read> Reader <R> { impl <R: std::io::Read> Reader <R> {
pub fn expect (r: &mut R, expected: &[u8]) -> Result <()> {
let mut actual = vec! [0u8; expected.len ()];
r.read_exact (&mut actual)?;
if actual != expected {
return Err (TlvError::NotExpected);
}
Ok (())
}
fn length (r: &mut R) -> Result <u32> { fn length (r: &mut R) -> Result <u32> {
let mut buf = [0; 4]; let mut buf = [0; 4];
r.read_exact (&mut buf)?; r.read_exact (&mut buf)?;
@ -50,16 +61,23 @@ impl <R: std::io::Read> Reader <R> {
Ok (u32::from_le_bytes (buf)) Ok (u32::from_le_bytes (buf))
} }
fn lv_bytes (r: &mut R, buf: &mut [u8]) -> Result <u32> { pub fn lv_bytes (r: &mut R, buf: &mut [u8]) -> Result <u32> {
let l = Self::length (r)?; let l = Self::length (r)?;
if usize::try_from (l)? > buf.len () { if usize::try_from (l)? > buf.len () {
Err (TlvError::CallerBufferTooSmall)?; return Err (TlvError::CallerBufferTooSmall);
} }
r.read_exact (&mut buf [0..usize::try_from (l)?])?; r.read_exact (&mut buf [0..usize::try_from (l)?])?;
Ok (l) Ok (l)
} }
pub fn u8 (r: &mut R) -> std::io::Result <u8> {
let mut buf = [0];
r.read_exact (&mut buf)?;
Ok (buf [0])
}
} }
#[cfg (test)] #[cfg (test)]