diff --git a/PROTOCOL b/PROTOCOL index a9f034c..acfff4d 100644 --- a/PROTOCOL +++ b/PROTOCOL @@ -30,6 +30,8 @@ The next 1 byte - number that represents this packet's type (ID) where: 4: TEXT PACKET 5: FILEINFO PACKET 6: FILEDATA PACKET +7: FILE ACCEPT PACKET +8: FILE REJECT PACKET Then the internal structure varies from one packet type to the other, but the content-types are encoded as follows: diff --git a/src/main.rs b/src/main.rs index 0f98fdb..bd1fc61 100644 --- a/src/main.rs +++ b/src/main.rs @@ -23,6 +23,8 @@ mod nodes; use protocol::specs::RunMode; use args::parser::Args; use nodes::recv_node::RecvOptions; +use nodes::send_node::SendOptions; + const VERSION: &str = "v0.1.0"; const HELP_MESSAGE: &str = @@ -85,8 +87,8 @@ fn main() { RunMode::RECEIVE => { match nodes::recv_node::start( RecvOptions::new(format!("0.0.0.0:{}", DEFAULT_PORT), args.save_directory), args.verbose_output) { - None => {} - Some(error) => { + Ok(_) => {} + Err(error) => { println!("Error receiving: {}", error.text); return; } @@ -94,7 +96,20 @@ fn main() { } RunMode::SEND => { - // match nodes::send_node::start(options: SendOptions, verbose_output: bool); + match nodes::send_node::start( + SendOptions::new( + args.address_str, + args.send_type, + args.text_to_send, + args.send_path, + ), args.verbose_output) { + + Ok(_) => {} + Err(error) => { + println!("Error sending: {}", error.text); + return; + } + } } RunMode::DAEMON => { diff --git a/src/nodes/recv_node.rs b/src/nodes/recv_node.rs index bfe09b0..9378399 100644 --- a/src/nodes/recv_node.rs +++ b/src/nodes/recv_node.rs @@ -39,14 +39,14 @@ impl RecvOptions { } -pub fn start(options: RecvOptions, verbose_output: bool) -> Option { +pub fn start(options: RecvOptions, verbose_output: bool) -> Result<(), Error> { let listener: net::TcpListener; match net::TcpListener::bind(options.listen_address) { Ok(l) => { listener = l; } Err(error) => { - return Some(Error::new(format!("could not create TCP listener: {}", error).as_str())); + return Err(Error::new(format!("could not create TCP listener: {}", error).as_str())); } } @@ -63,7 +63,7 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { address = a; } Err(error) => { - return Some(Error::new(format!("error accepting a new incoming connection: {}", error).as_str())); + return Err(Error::new(format!("error accepting a new incoming connection: {}", error).as_str())); } } @@ -83,7 +83,7 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { if verbose_output { println!("{} did not provide valid handshake packet. Dropping connection...", address); } - connection.shutdown(net::Shutdown::Both); + packets::close_connection(&mut connection); continue; } } @@ -92,7 +92,9 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { PacketType::Handshake => { match handshake.from_bytes(incoming_packet.as_bytes()) { Some(error) => { - return Some( + packets::close_connection(&mut connection); + + return Err( Error::new( format!("error constructing handshake from {}: {}", address, error.text).as_str() )); @@ -108,7 +110,9 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { match send_packet(&mut connection, &packets::HandshakeAccept{}) { Ok(()) => {} Err(error) => { - return Some( + packets::close_connection(&mut connection); + + return Err( Error::new(format!("error accepting handshake from {}: {}", address, error.text).as_str()) ); } @@ -122,7 +126,7 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { if verbose_output { println!("{} didn't send a handshake packet, but {:?} packet instead. Dropping connection...", address, incoming_packet.get_type()); } - connection.shutdown(net::Shutdown::Both); + packets::close_connection(&mut connection); continue; } } @@ -140,7 +144,9 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { } Err(_) => { - return Some( + packets::close_connection(&mut connection); + + return Err( Error::new("could not clone connection") ); } @@ -177,7 +183,9 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { } Err(error) => { - return Some(Error::new( + packets::close_connection(&mut connection); + + return Err(Error::new( format!("error receiving a new packet from listener thread: {}", error).as_str() )); } @@ -188,7 +196,7 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { if verbose_output { println!("{} shuts down the connection", address); } - connection.shutdown(net::Shutdown::Both); + packets::close_connection(&mut connection); break; } @@ -203,10 +211,9 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { Some(error) => { // close connection and exit - send_packet(&mut connection, &packets::ConnectionShutdown{}); - connection.shutdown(net::Shutdown::Both); + packets::close_connection(&mut connection); - return Some( + return Err( Error::new(format!("could not get text packet: {}", error.text).as_str()) ); } @@ -217,5 +224,5 @@ pub fn start(options: RecvOptions, verbose_output: bool) -> Option { } } - return None; + return Ok(()); } diff --git a/src/nodes/send_node.rs b/src/nodes/send_node.rs index 5ac6cd7..cb03cc6 100644 --- a/src/nodes/send_node.rs +++ b/src/nodes/send_node.rs @@ -13,7 +13,17 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more details. */ +use crate::util::error::Error; use crate::args::parser::DataType; +use crate::crypt; +use crate::protocol::packets; +use crate::protocol::packets::{send_packet, read_next_packet}; +use crate::protocol::specs::PacketType; +use crate::protocol::specs; +use crate::protocol::specs::Packet; +use std::thread; +use std::sync::mpsc::{Sender, Receiver}; +use std::sync::mpsc; use std::net; use std::path; @@ -24,6 +34,139 @@ pub struct SendOptions { pub source_path: path::PathBuf, } -pub fn start(options: SendOptions, verbose_output: bool) { +impl SendOptions { + pub fn new(addr: String, send_t: DataType, txt_to_send: String, src_path: path::PathBuf) -> SendOptions { + return SendOptions{ + address: addr, + send_type: send_t, + text_to_send: txt_to_send, + source_path: src_path, + }; + } +} + +pub fn start(options: SendOptions, verbose_output: bool) -> Result<(), Error> { + let mut connection: net::TcpStream; + match net::TcpStream::connect(options.address) { + Ok(conn) => { + connection = conn; + } + + Err(error) => { + return Err( + Error::new(format!("connection error: {}", error).as_str()) + ); + } + } + + // send handshake + let handshake: packets::Handshake = packets::Handshake{ + protocol_version: specs::PROTOCOL_VERSION_1, + encryption_type: specs::ECRYPTION_XOR, + encryption_key: vec!(crypt::keys::Key8bit::new_random().k), + }; + + match send_packet(&mut connection, &handshake) { + Ok(_) => {} + + Err(error) => { + packets::close_connection(&mut connection); + + return Err( + Error::new(format!("could not send handshake: {}", error.text).as_str()) + ); + } + } + + // see if the handshake has been accepted + match read_next_packet(&mut connection) { + Ok(packet) => { + if packet.get_type() != PacketType::HandshakeAccept { + // not approved or entirely not according to the protocol + packets::close_connection(&mut connection); + return Err( + Error::new(format!("handshake hasn't been approved").as_str()) + ); + } + } + + Err(error) => { + packets::close_connection(&mut connection); + return Err( + Error::new(format!("could not receive potential handshake approval: {}", error.text).as_str()) + ); + } + } + + // launch a new packet reading thread + let (ch_send, ch_recv): (Sender>, Receiver>) = mpsc::channel(); + + let mut cloned_connection: net::TcpStream; + match connection.try_clone() { + Ok(cc) => { + cloned_connection = cc; + } + + Err(_) => { + packets::close_connection(&mut connection); + + return Err( + Error::new("could not clone connection") + ); + } + } + + thread::spawn(move || { + loop { + match read_next_packet(&mut cloned_connection) { + Ok(packet) => { + if let Err(_) = ch_send.send(packet) { + // the channel has been hung up + // return from this thread + return; + } + } + + Err(error) => { + if verbose_output { + println!("Could not read packet: {}", error.text); + } + continue; + } + } + } + }); + + + // handle incoming packets + loop { + let incoming_packet: Box; + 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(()); } diff --git a/src/protocol/packets.rs b/src/protocol/packets.rs index 3daff97..5196081 100644 --- a/src/protocol/packets.rs +++ b/src/protocol/packets.rs @@ -123,6 +123,10 @@ pub fn read_next_packet(conn: &mut net::TcpStream) -> Result