ptth/crates/insecure_chat/src/main.rs

151 lines
3.3 KiB
Rust

use std::{
net::{
Ipv4Addr,
SocketAddrV4,
UdpSocket,
},
};
mod ip;
fn main () -> Result <(), Error>
{
let mut args = std::env::args ();
let mut bail_unknown = true;
let mut last_unknown = None;
let mut name = ptth_diceware::passphrase ("_", 3);
let mut subcommand_count = 0;
let mut subcommand = None;
args.next ();
while let Some (arg) = args.next () {
if arg == "--ignore-unknown" {
bail_unknown = false;
}
if arg == "--name" {
name = args.next ().unwrap ().to_string ();
}
else if arg == "sender" {
subcommand = Some (Subcommand::Sender);
subcommand_count += 1;
}
else if arg == "spy" {
subcommand = Some (Subcommand::Spy);
subcommand_count += 1;
}
else {
last_unknown = Some (arg);
}
}
if bail_unknown {
if let Some (last_unknown) = last_unknown {
eprintln! ("Unknown argument `{}`", last_unknown);
return Err (Error::Args);
}
}
if subcommand_count >= 2 {
eprintln! ("Detected {} subcommands in arguments", subcommand_count);
return Err (Error::Args)
}
let rt = tokio::runtime::Runtime::new ()?;
let params = Params::default ();
rt.block_on (async {
if let Some (cmd) = subcommand {
return match cmd {
Subcommand::Sender => sender (params).await,
Subcommand::Spy => spy (params),
};
}
println! ("Name is `{}`", name);
Ok::<_, Error> (())
})?;
Ok (())
}
enum Subcommand {
Sender,
Spy,
}
struct Params {
multicast_group: (Ipv4Addr, u16),
}
impl Default for Params {
fn default () -> Self {
let multicast_group = (Ipv4Addr::new (225, 100, 99, 98), 9041);
Self {
multicast_group,
}
}
}
async fn sender (params: Params) -> Result <(), Error>
{
let socket = tokio::net::UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, 0)).await?;
let (multicast_addr, multicast_port) = params.multicast_group;
socket.join_multicast_v4 (multicast_addr, Ipv4Addr::UNSPECIFIED)?;
eprintln! ("Multicast group is {:?}", params.multicast_group);
eprintln! ("Local addr is {}", socket.local_addr ()?);
socket.send_to (&[], params.multicast_group).await?;
Ok (())
}
fn spy (params: Params) -> Result <(), Error>
{
let (multicast_addr, multicast_port) = params.multicast_group;
let socket = match UdpSocket::bind (SocketAddrV4::new (Ipv4Addr::UNSPECIFIED, multicast_port)) {
Ok (x) => x,
Err (e) => if e.kind () == std::io::ErrorKind::AddrInUse {
eprintln! ("Address in use. You can only run 1 instance of Insecure Chat at a time, even in spy mode.");
return Err (Error::AddrInUse);
}
else {
return Err (e.into ());
}
};
for bind_addr in ip::get_ips ()? {
socket.join_multicast_v4 (&multicast_addr, &bind_addr)?;
// eprintln! ("Joined multicast with {}", bind_addr);
}
eprintln! ("Multicast addr is {}", multicast_addr);
eprintln! ("Local addr is {}", socket.local_addr ()?);
loop {
let mut buf = vec! [0u8; 2048];
eprintln! ("Listening for UDP packets...");
let (bytes_recved, remote_addr) = socket.recv_from (&mut buf)?;
buf.truncate (bytes_recved);
println! ("Received {} bytes from {}", bytes_recved, remote_addr);
}
}
#[derive (Debug, thiserror::Error)]
enum Error {
#[error ("Address in use")]
AddrInUse,
#[error ("CLI args")]
Args,
#[error (transparent)]
Io (#[from] std::io::Error),
#[error (transparent)]
Ip (#[from] ip::Error),
}