Browse Source

local ip addr; fixed parser with verbose flag; ddtu can send|receive text now !

master
Gitea 2 years ago
parent
commit
3436450963
  1. 178
      src/args/parser.rs
  2. 15
      src/main.rs
  3. 4
      src/nodes/recv_node.rs
  4. 80
      src/nodes/send_node.rs
  5. 45
      src/protocol/packets.rs
  6. 53
      src/util/local_ip.rs
  7. 3
      src/util/mod.rs

178
src/args/parser.rs

@ -65,93 +65,135 @@ pub fn parse(raw_args: &Vec<String>) -> Result<Args, Error> {
return Err(Error::new("no arguments")); return Err(Error::new("no arguments"));
} }
match raw_args[1].to_lowercase().as_str() {
"help" => { let mut arg_index: usize = 1;
parsed_args.help = true; loop {
} match raw_args[arg_index].to_lowercase().as_str() {
"help" => {
"version" => { parsed_args.help = true;
parsed_args.version = true; break;
}
"verbose" => {
parsed_args.verbose_output = true;
}
"send" => {
if arg_amount < 5 {
// not enough arguments !
return Err(Error::new("not enough arguments for send mode"));
} }
parsed_args.mode = RunMode::SEND; "version" => {
parsed_args.version = true;
// DataType break;
match raw_args[2].to_lowercase().as_str() { }
"text" => {
parsed_args.send_type = DataType::TEXT; "verbose" => {
parsed_args.text_to_send = String::from(&raw_args[3]); parsed_args.verbose_output = true;
arg_index += 1;
continue;
}
"send" => {
if arg_amount < 5 && !parsed_args.verbose_output {
// not enough arguments !
return Err(Error::new("not enough arguments for send mode"));
} else if arg_amount < 6 && parsed_args.verbose_output {
return Err(Error::new("not enough arguments for send mode"));
} }
"file" => { parsed_args.mode = RunMode::SEND;
parsed_args.send_type = DataType::FILE;
parsed_args.send_path = std::path::Path::new(&raw_args[3]).to_path_buf(); match parsed_args.verbose_output {
true => {
arg_index = 3;
}
false => {
arg_index = 2;
}
} }
"dir" => { // DataType
parsed_args.send_type = DataType::DIR; match raw_args[arg_index].to_lowercase().as_str() {
parsed_args.send_path = std::path::Path::new(&raw_args[3]).to_path_buf(); "text" => {
parsed_args.send_type = DataType::TEXT;
parsed_args.text_to_send = String::from(&raw_args[arg_index + 1]);
}
"file" => {
parsed_args.send_type = DataType::FILE;
parsed_args.send_path = std::path::Path::new(&raw_args[arg_index + 1]).to_path_buf();
}
"dir" => {
parsed_args.send_type = DataType::DIR;
parsed_args.send_path = std::path::Path::new(&raw_args[arg_index + 1]).to_path_buf();
}
_ => {
return Err(Error::new(format!("invalid DataType {}", raw_args[arg_index]).as_str()));
}
} }
// addr
arg_index += 1;
parsed_args.address_str = raw_args[arg_index + 1].to_string();
_ => { break;
return Err(Error::new(format!("invalid DataType {}", raw_args[2]).as_str()));
}
} }
// src "recv" => {
if parsed_args.send_type == DataType::FILE || parsed_args.send_type == DataType::DIR { parsed_args.mode = RunMode::RECEIVE;
// check if exists
match path::Path::new(raw_args[3].as_str()).exists() { let arg_index: usize;
match parsed_args.verbose_output {
true => { true => {
parsed_args.send_path = path::Path::new(raw_args[3].as_str()).to_path_buf(); arg_index = 3;
} }
false => { false => {
return Err(Error::new(format!("\"{}\" does not exist or unreachable", raw_args[3]).as_str())); arg_index = 2;
} }
} }
}
if arg_amount > 2 && !parsed_args.verbose_output {
parsed_args.save_directory = path::Path::new(raw_args[arg_index].as_str()).to_path_buf();
} else if arg_amount > 3 && parsed_args.verbose_output {
parsed_args.save_directory = path::Path::new(raw_args[arg_index].as_str()).to_path_buf();
}
// addr break;
parsed_args.address_str = raw_args[4].to_string(); }
}
"sync" => {
parsed_args.mode = RunMode::SYNC;
if arg_amount < 3 && !parsed_args.verbose_output {
return Err(Error::new("not enough arguments for syncing"));
} else if arg_amount < 4 && !parsed_args.verbose_output {
return Err(Error::new("not enough arguments for syncing"));
}
let arg_index: usize;
match parsed_args.verbose_output {
true => {
arg_index = 3;
}
false => {
arg_index = 2;
}
}
let sync_path: &path::Path = path::Path::new(raw_args[arg_index].as_str());
if !sync_path.exists() || !sync_path.is_dir() {
return Err(Error::new(format!("{} does not exist or is not a directory", sync_path.display()).as_str()));
}
"recv" => { break;
parsed_args.mode = RunMode::RECEIVE;
if arg_amount > 2 {
parsed_args.save_directory = path::Path::new(raw_args[2].as_str()).to_path_buf();
} }
}
"daemon" => {
"sync" => { parsed_args.mode = RunMode::DAEMON;
parsed_args.mode = RunMode::SYNC; break;
if arg_amount < 3 {
return Err(Error::new("not enough arguments for syncing"));
} }
let sync_path: &path::Path = path::Path::new(raw_args[2].as_str()); _ => {
if !sync_path.exists() || !sync_path.is_dir() { return Err(Error::new(format!("invalid argument {}", raw_args[arg_index]).as_str()));
return Err(Error::new(format!("{} does not exist or is not a directory", sync_path.display()).as_str()));
} }
} }
"daemon" => {
parsed_args.mode = RunMode::DAEMON;
}
_ => {
return Err(Error::new(format!("invalid argument {}", raw_args[1]).as_str()));
}
} }
return Ok(parsed_args); return Ok(parsed_args);

15
src/main.rs

@ -25,7 +25,6 @@ use args::parser::Args;
use nodes::recv_node::RecvOptions; use nodes::recv_node::RecvOptions;
use nodes::send_node::SendOptions; use nodes::send_node::SendOptions;
const VERSION: &str = "v0.1.0"; const VERSION: &str = "v0.1.0";
const HELP_MESSAGE: &str = const HELP_MESSAGE: &str =
"ddtu - digital data transferring tool v0.1.0 "ddtu - digital data transferring tool v0.1.0
@ -69,8 +68,6 @@ fn main() {
return; return;
} }
} }
println!("{:?}", args);
// handle them // handle them
if args.help { if args.help {
@ -84,7 +81,17 @@ fn main() {
} }
match args.mode { match args.mode {
RunMode::RECEIVE => { RunMode::RECEIVE => {
match util::local_ip::get_addr() {
Ok(local_ip_addr) => {
println!("Listening on {}:{}", local_ip_addr.to_string(), DEFAULT_PORT);
}
Err(_) => {
println!("Listening on port {}", DEFAULT_PORT);
}
}
match nodes::recv_node::start( match nodes::recv_node::start(
RecvOptions::new(format!("0.0.0.0:{}", DEFAULT_PORT), args.save_directory), args.verbose_output) { RecvOptions::new(format!("0.0.0.0:{}", DEFAULT_PORT), args.save_directory), args.verbose_output) {
Ok(_) => {} Ok(_) => {}

4
src/nodes/recv_node.rs

@ -78,10 +78,10 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Result<(), Error> {
incoming_packet = packet; incoming_packet = packet;
} }
Err(_) => { Err(error) => {
// not a valid packet; it's most probably not another instance // not a valid packet; it's most probably not another instance
if verbose_output { if verbose_output {
println!("{} did not provide valid handshake packet. Dropping connection...", address); println!("{} did not provide valid handshake packet: {}. Dropping connection...", address, error.text);
} }
packets::close_connection(&mut connection); packets::close_connection(&mut connection);
continue; continue;

80
src/nodes/send_node.rs

@ -47,7 +47,7 @@ impl SendOptions {
pub fn start(options: SendOptions, verbose_output: bool) -> Result<(), Error> { pub fn start(options: SendOptions, verbose_output: bool) -> Result<(), Error> {
let mut connection: net::TcpStream; let mut connection: net::TcpStream;
match net::TcpStream::connect(options.address) { match net::TcpStream::connect(&options.address) {
Ok(conn) => { Ok(conn) => {
connection = conn; connection = conn;
} }
@ -59,6 +59,10 @@ pub fn start(options: SendOptions, verbose_output: bool) -> Result<(), Error> {
} }
} }
if verbose_output {
println!("Connected to {}", &options.address);
}
// send handshake // send handshake
let handshake: packets::Handshake = packets::Handshake{ let handshake: packets::Handshake = packets::Handshake{
protocol_version: specs::PROTOCOL_VERSION_1, protocol_version: specs::PROTOCOL_VERSION_1,
@ -67,7 +71,11 @@ pub fn start(options: SendOptions, verbose_output: bool) -> Result<(), Error> {
}; };
match send_packet(&mut connection, &handshake) { match send_packet(&mut connection, &handshake) {
Ok(_) => {} Ok(_) => {
if verbose_output {
println!("Sent handshake");
}
}
Err(error) => { Err(error) => {
packets::close_connection(&mut connection); packets::close_connection(&mut connection);
@ -88,6 +96,10 @@ pub fn start(options: SendOptions, verbose_output: bool) -> Result<(), Error> {
Error::new(format!("handshake hasn't been approved").as_str()) Error::new(format!("handshake hasn't been approved").as_str())
); );
} }
if verbose_output {
println!("Handshake has been accepted");
}
} }
Err(error) => { Err(error) => {
@ -136,37 +148,55 @@ pub fn start(options: SendOptions, verbose_output: bool) -> Result<(), Error> {
} }
} }
}); });
// handle incoming packets
loop {
let incoming_packet: Box<dyn Packet>;
match ch_recv.recv() {
Ok(p) => {
incoming_packet = p;
}
Err(error) => {
match options.send_type {
DataType::TEXT => {
if let Err(error) = send_packet(&mut connection, &packets::Text::new(&options.text_to_send)) {
packets::close_connection(&mut connection); packets::close_connection(&mut connection);
return Err(Error::new( return Err(Error::new(format!("error sending text: {}", error.text).as_str()))
format!("error receiving a new packet from listener thread: {}", error).as_str()
));
} }
packets::close_connection(&mut connection);
} }
match incoming_packet.get_type() { DataType::FILE => {
PacketType::ConnectionShutdown => {
if verbose_output { }
println!("Connection has been shut down");
} DataType::DIR => {
packets::close_connection(&mut connection);
break;
}
_ => {}
} }
} }
// // handle incoming packets
// loop {
// let incoming_packet: Box<dyn Packet>;
// match ch_recv.recv() {
// Ok(p) => {
// incoming_packet = p;
// }
// Err(error) => {
// packets::close_connection(&mut connection);
// return Err(Error::new(
// format!("error receiving a new packet from listener thread: {}", error).as_str()
// ));
// }
// }
// match incoming_packet.get_type() {
// PacketType::ConnectionShutdown => {
// if verbose_output {
// println!("Connection has been shut down");
// }
// packets::close_connection(&mut connection);
// break;
// }
// _ => {}
// }
// }
return Ok(()); return Ok(());
} }

45
src/protocol/packets.rs

@ -23,7 +23,7 @@ use crate::protocol::specs::*;
use crate::fsys::file::ChunkedFile; use crate::fsys::file::ChunkedFile;
pub fn send_packet(conn: &mut net::TcpStream, packet: &dyn Packet) -> Result<(), Error> { pub fn send_packet<W>(conn: &mut W, packet: &dyn Packet) -> Result<(), Error> where W: Write {
let mut payload: Vec<u8> = Vec::<u8>::new(); let mut payload: Vec<u8> = Vec::<u8>::new();
let packet_bytes: Vec<u8> = packet.as_bytes(); let packet_bytes: Vec<u8> = packet.as_bytes();
@ -43,15 +43,29 @@ pub fn send_packet(conn: &mut net::TcpStream, packet: &dyn Packet) -> Result<(),
} }
} }
pub fn read_next_packet(conn: &mut net::TcpStream) -> Result<Box<dyn Packet + Send>, Error> { pub fn read_next_packet<R>(conn: &mut R) -> Result<Box<dyn Packet + Send>, Error> where R: Read {
let mut u128_buf: [u8; 16] = [0; 16]; let mut u128_buf: [u8; 16] = [0; 16];
loop {
match conn.read_exact(&mut u128_buf) {
Ok(()) => {
break;
}
Err(error) => {
// this is guaranteed to happen. It looks like networking in Rust is naive. Stream literally
// is being read ONCE and that's it, even if it is empty, which results in an error.
if error.kind() == std::io::ErrorKind::UnexpectedEof {
// try once again, maybe the packet has been delivered this time
continue;
}
match conn.read_exact(&mut u128_buf) { return Err(
Ok(()) => {} Error::new(format!("error reading initial length bytes: {}", error).as_str())
Err(error) => { );
return Err(Error::new(format!("error while reading initial length bytes: {}", error).as_str())); }
} }
} }
let packet_len: u128 = u128::from_be_bytes(u128_buf); let packet_len: u128 = u128::from_be_bytes(u128_buf);
let mut packet_bytes: Vec<u8> = vec!(0; packet_len as usize); let mut packet_bytes: Vec<u8> = vec!(0; packet_len as usize);
@ -71,6 +85,23 @@ pub fn read_next_packet(conn: &mut net::TcpStream) -> Result<Box<dyn Packet + Se
let packet_type_byte: u8 = u8::from_be_bytes([packet_bytes[0]]); let packet_type_byte: u8 = u8::from_be_bytes([packet_bytes[0]]);
match packet_type_byte { match packet_type_byte {
HANDSHAKE_PACKET_ID => {
let mut new_handshake_packet: Handshake = Handshake::empty();
match new_handshake_packet.from_bytes(packet_bytes) {
Some(error) => {
return Err(Error::new(format!("could not construct a new handshake packet: {}", error.text).as_str()));
}
None => {
return Ok(Box::new(new_handshake_packet));
}
}
}
HANDSHAKE_ACCEPT_PACKET_ID => {
return Ok(Box::new(HandshakeAccept{}));
}
CONNECTION_SHUTDOWN_PACKET_ID => { CONNECTION_SHUTDOWN_PACKET_ID => {
return Ok(Box::new(ConnectionShutdown{})); return Ok(Box::new(ConnectionShutdown{}));
} }
@ -118,7 +149,7 @@ pub fn read_next_packet(conn: &mut net::TcpStream) -> Result<Box<dyn Packet + Se
} }
_ => { _ => {
return Err(Error::new(format!("invalid packet type ID \"{}\"", packet_type_byte).as_str())); return Err(Error::new(format!("invalid or unimplemented packet type ID \"{}\"", packet_type_byte).as_str()));
} }
} }
} }

53
src/util/local_ip.rs

@ -0,0 +1,53 @@
/*
ddtu - digital data transferring utility
Copyright (C) 2022 Kasyanov Nikolay Alexeyevich (Unbewohnte)
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
*/
use std::net;
use crate::util::error::Error;
pub fn get_addr() -> Result<net::IpAddr, Error> {
let socket: net::UdpSocket;
match net::UdpSocket::bind("0.0.0.0:0") {
Ok(s) => {
socket = s;
}
Err(error) => {
return Err(
Error::new(format!("error binding UDP socket: {}", error).as_str())
);
}
}
match socket.connect("8.8.8.8:80") {
Ok(()) => {}
Err(error) => {
return Err(
Error::new(format!("could not connect to 8.8.8.8: {}", error).as_str())
);
}
}
match socket.local_addr() {
Ok(addr) => {
return Ok(addr.ip());
}
Err(error) => {
return Err(
Error::new(format!("could not get local IP address from socket: {}", error).as_str())
);
}
}
}

3
src/util/mod.rs

@ -1,2 +1,3 @@
pub mod error; pub mod error;
pub mod buf_read; pub mod buf_read;
pub mod local_ip;
Loading…
Cancel
Save