#![feature(backtrace)] extern crate hptp; extern crate tokio; #[macro_use] extern crate thiserror; use hptp::log::Logger; use hptp::msg::Msg; use hptp::peer::Peer; use std::net::SocketAddr; use tokio::io::AsyncRead; // use tokio::net::UdpSocket; #[derive(Error, Debug)] enum Error { #[error("io error: {source}")] Io { #[from] source: tokio::io::Error, backtrace: std::backtrace::Backtrace, }, #[error("invalid command-line arguments")] InvalidArgs, #[error("did not find an available local port")] NoAvailPort, } fn main() { match entry() { Err(Error::InvalidArgs) => print_usage(), Err(e) => { use std::error::Error; println!("Error: {:?}", e); for bt in e.backtrace() { println!("{}", bt); } } Ok(()) => (), } } fn print_usage() { print!("Usage:\n./3700send :\n") } fn entry() -> Result<(), Error> { let mut rt = tokio::runtime::Runtime::new().unwrap(); let mut log = Logger::new(); rt.block_on(start(&mut log)) } async fn start(log: &mut Logger) -> Result<(), Error> { let targ_addr = parse_args(std::env::args())?; let sock = hptp::udp_retrying_bind(16, hptp::random_port) .await .map_err(|_| Error::NoAvailPort)?; log.debug_msg(format!("bound on {}", sock.local_addr()?)) .await; let mut out = tokio::io::stdin(); let mut peer = Peer::new(sock); peer.set_known_target(targ_addr); upload(log, &mut peer, &mut out).await } fn parse_args(mut args: impl Iterator) -> Result { args.nth(1) .ok_or(Error::InvalidArgs)? .parse() .map_err(|_| Error::InvalidArgs) } async fn read_some(inp: &mut IN) -> Result>, Error> where IN: AsyncRead + Unpin, { use tokio::io::AsyncReadExt; let mut buf = [0u8; 512]; let len = inp.read(&mut buf).await?; Ok(if len > 0 { Some(buf[..len].into()) } else { None }) } async fn upload(log: &mut Logger, peer: &mut Peer, inp: &mut IN) -> Result<(), Error> where IN: AsyncRead + Unpin, { let mut pos = 0; loop { match read_some(inp).await? { Some(data) => { let len = data.len(); peer.send(Msg::Data(data)).await?; log.send_data(pos, len).await; pos += len; } None => return Ok(()), } } }