aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbnewbold <bnewbold@robocracy.org>2016-05-29 20:31:44 -0400
committerbnewbold <bnewbold@robocracy.org>2016-05-29 20:31:44 -0400
commitc5d696e079b7fbfa54b3460bebdaf185a56574de (patch)
tree375fd48bd7f145876bd47a25634968a54e45de10
parent557159a2e00508820cb7bad66822cc97c61b6de5 (diff)
downloaducp-c5d696e079b7fbfa54b3460bebdaf185a56574de.tar.gz
ucp-c5d696e079b7fbfa54b3460bebdaf185a56574de.zip
add client mode for testing/dev; misc progress
-rw-r--r--src/client.rs60
-rw-r--r--src/common.rs13
-rw-r--r--src/main.rs5
-rw-r--r--src/server.rs40
4 files changed, 97 insertions, 21 deletions
diff --git a/src/client.rs b/src/client.rs
index 637a216..ccdf07d 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -1,4 +1,5 @@
+extern crate getopts;
extern crate utp;
use super::common;
@@ -6,7 +7,9 @@ use super::common;
use std::string::String;
use std::env;
use std::process;
+use std::process::exit;
use std::process::Command;
+use getopts::Options;
use utp::{UtpSocket};
pub fn run_client(host: &str, local_file: &str, remote_file: &str, remote_is_dir: bool, is_recv: bool) {
@@ -36,7 +39,7 @@ pub fn run_client(host: &str, local_file: &str, remote_file: &str, remote_is_dir
let reply = String::from_utf8_lossy(&ssh_output.stdout);
println!("SSH reply: {}", reply);
let words: Vec<&str> = reply.split_whitespace().collect();
- if words.len() != 5 || words[0] != "UDP" || words[1] != "CONNECT" {
+ if words.len() != 5 || words[0] != "UCP" || words[1] != "CONNECT" {
panic!("Unexpected data via SSH pipe (TCP)");
}
let remote_host = words[2];
@@ -57,3 +60,58 @@ pub fn run_client(host: &str, local_file: &str, remote_file: &str, remote_is_dir
}
stream.close().unwrap();
}
+
+fn usage_client(opts: Options) {
+ let brief = "usage:\tucp client ..."; // XXX:
+ println!("");
+ println!("IMPORTANT: this is the client mode of ucp. Unless you are developing/debugging, you probably want the 'regular' one (from the 'client' from you command)");
+ print!("{}", opts.usage(&brief));
+}
+
+pub fn main_client() {
+
+ let args: Vec<String> = env::args().collect();
+
+ let mut opts = Options::new();
+ opts.optflag("h", "help", "print this help menu");
+ //opts.optflag("v", "verbose", "more debugging messages");
+ opts.optflag("d", "dir-mode", "read/write a dir instead of file (client side)");
+ opts.optopt("f", "from", "file or dir to read from (client side)", "FILE");
+ opts.optopt("t", "to", "file or dir to write to (client side)", "FILE");
+ opts.reqopt("", "host", "remote hostname to connect to", "HOSTNAME");
+ opts.reqopt("", "port", "remote port to connect to", "PORT");
+
+ assert!(args.len() >= 2 && args[1] == "client");
+ let matches = match opts.parse(&args[2..]) {
+ Ok(m) => { m }
+ Err(f) => { println!("Error parsing args!"); usage_client(opts); exit(-1); }
+ };
+
+ if matches.opt_present("h") {
+ usage_client(opts);
+ return;
+ }
+
+ //let verbose: bool = matches.opt_present("v");
+ let dir_mode: bool = matches.opt_present("d");
+
+ match (matches.opt_present("f"), matches.opt_present("t")) {
+ (true, true) | (false, false) => {
+ println!("Must be either 'from' or 'to', but not both");
+ exit(-1);
+ },
+ _ => {},
+ }
+
+ let port = matches.opt_str("port").unwrap().parse::<u16>().unwrap();
+ let mut socket = UtpSocket::connect((matches.opt_str("host").unwrap().as_str(), port)).unwrap();
+ let mut stream = socket.into();
+ println!("opened socket");
+ if matches.opt_present("f") {
+ common::source_files(&mut stream, &matches.opt_str("f").unwrap(), dir_mode);
+ }
+ if matches.opt_present("t") {
+ common::sink_files(&mut stream, &matches.opt_str("t").unwrap(), dir_mode);
+ }
+ stream.close().unwrap();
+}
diff --git a/src/common.rs b/src/common.rs
index 421f3a5..afdfe06 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -13,6 +13,7 @@ use utp::{UtpStream};
pub fn source_files(stream: &mut UtpStream, file_path: &str, recursive: bool) {
+ println!("SOURCE FILE: {}", file_path);
if recursive { unimplemented!(); }
let mut f = File::open(file_path).unwrap();
let metadata = f.metadata().unwrap();
@@ -21,8 +22,9 @@ pub fn source_files(stream: &mut UtpStream, file_path: &str, recursive: bool) {
let flen: usize = metadata.len() as usize;
// Format as 4 digits octal, left-padding with zero
- let line = format!("C{:0<4o} {} {}\n", fmode, flen, file_path);
+ let line = format!("C{:0>4o} {} {}\n", fmode, flen, file_path);
stream.write_all(line.as_bytes()).unwrap();
+ println!("{}", line);
let mut byte_buf = [0; 1];
stream.read_exact(&mut byte_buf).unwrap();
@@ -43,6 +45,7 @@ pub fn source_files(stream: &mut UtpStream, file_path: &str, recursive: bool) {
let mut wbuf = &mut buf[..rlen];
stream.write_all(&wbuf).unwrap();
sent += rlen;
+ //println!("sent: {}", sent);
}
// f.close(); XXX:
stream.read_exact(&mut byte_buf).unwrap();
@@ -73,6 +76,7 @@ fn raw_read_line(stream: &mut UtpStream) -> io::Result<String> {
// implementations of Read and Write on immutable references to UtpStream (a la TcpStream, File, et
// al)
pub fn sink_files(stream: &mut UtpStream, file_path: &str, recursive: bool) {
+ println!("SINK FILE: {}", file_path);
if recursive { unimplemented!(); }
let mut f = File::create(file_path).unwrap();
@@ -81,13 +85,17 @@ pub fn sink_files(stream: &mut UtpStream, file_path: &str, recursive: bool) {
stream.read_exact(&mut byte_buf).unwrap();
let msg_type = byte_buf[0];
match msg_type as char {
- 'C' => {} // pass
+ 'C' => {
+ println!("Going to create!");
+ },
'D' => { unimplemented!(); },
'E' => { unimplemented!(); },
'T' => { unimplemented!(); },
_ => { panic!(format!("Unexpected message type: {}", msg_type)); },
};
let line = raw_read_line(stream).unwrap();
+ println!("got msg: {}", line);
+ stream.write(&[0]).unwrap();
let line: Vec<&str> = line.split_whitespace().collect();
assert!(line.len() == 3);
let fmode: u32 = u32::from_str_radix(line[0], 8).unwrap();
@@ -100,6 +108,7 @@ pub fn sink_files(stream: &mut UtpStream, file_path: &str, recursive: bool) {
let mut received: usize = 0;
while received < flen {
let rlen = stream.read(&mut buf).unwrap();
+ //println!("recieved: {}", rlen);
assert!(rlen > 0);
let mut wbuf = &mut buf[..rlen];
f.write_all(&wbuf).unwrap();
diff --git a/src/main.rs b/src/main.rs
index f916958..dc328f3 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -24,10 +24,13 @@ fn main() {
let args: Vec<String> = env::args().collect();
- // First check for "hidden" server mode
+ // First check for "hidden" server and client modes
if args.len() > 1 && args[1] == "server" {
server::main_server();
return;
+ } else if args.len() > 1 && args[1] == "client" {
+ client::main_client();
+ return;
}
let mut opts = Options::new();
diff --git a/src/server.rs b/src/server.rs
index 4c590be..390093e 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -12,7 +12,7 @@ use std::process::exit;
use getopts::Options;
use utp::{UtpSocket, UtpListener};
-fn run_server(path: &str, is_recv: bool, recursive: bool) {
+fn run_server(path: &str, is_recv: bool, recursive: bool, daemonize: bool) {
// TODO: try to detect the address the SSH connection came in on via the SSH_CONNECTION env
// variable.
@@ -27,23 +27,27 @@ fn run_server(path: &str, is_recv: bool, recursive: bool) {
let listen_addr = listener.local_addr().unwrap().ip();
// Send back details so client can connect
- println!("UDP CONNECT {} {} {}", listen_addr, listen_port, "<SECRET>");
+ println!("UCP CONNECT {} {} {}", listen_addr, listen_port, "<SECRET>");
// TODO: maybe wait for an ACK of some sort here before daemonizing?
- // At this point we partially daemonize (fork and redirect terminal), so that SSH will drop us.
- // But, don't clobber working dir.
- let working_dir = match env::home_dir() {
- Some(path) => path,
- None => env::current_dir().unwrap(),
- };
- // XXX: should maybe use log/syslog from here on?
- let daemonizer = daemonize::Daemonize::new().working_directory(working_dir);
-
- match daemonizer.start() {
- Ok(_) => println!("Success, daemonized"),
- Err(e) => println!("{}", e),
- }
+ if daemonize {
+ // At this point we partially daemonize (fork and redirect terminal), so that SSH will drop us.
+ // But, don't clobber working dir.
+ let working_dir = match env::home_dir() {
+ Some(path) => path,
+ None => env::current_dir().unwrap(),
+ };
+ // XXX: should maybe use log/syslog from here on?
+ let daemonizer = daemonize::Daemonize::new().working_directory(working_dir);
+
+ match daemonizer.start() {
+ Ok(_) => println!("Success, daemonized"),
+ Err(e) => println!("{}", e),
+ }
+ } else {
+ println!("Not daemonizing (DEBUG MODE)");
+ }
let (mut socket, _src) = listener.accept().unwrap();
println!("Got connection from {}", socket.peer_addr().unwrap());
@@ -72,6 +76,7 @@ pub fn main_server() {
opts.optflag("h", "help", "print this help menu");
//opts.optflag("v", "verbose", "more debugging messages");
opts.optflag("d", "dir-mode", "read/write a dir instead of file (server side)");
+ opts.optflag("", "no-daemonize", "don't daemonize (for debuggign)");
opts.optopt("f", "from", "file or dir to read from (server side)", "FILE");
opts.optopt("t", "to", "file or dir to write to (server side)", "FILE");
@@ -88,6 +93,7 @@ pub fn main_server() {
//let verbose: bool = matches.opt_present("v");
let dir_mode: bool = matches.opt_present("d");
+ let daemonize: bool = !matches.opt_present("no-daemonize");
match (matches.opt_present("f"), matches.opt_present("t")) {
(true, true) | (false, false) => {
@@ -98,9 +104,9 @@ pub fn main_server() {
}
if matches.opt_present("f") {
- run_server(&matches.opt_str("f").unwrap(), false, dir_mode);
+ run_server(&matches.opt_str("f").unwrap(), false, dir_mode, daemonize);
}
if matches.opt_present("t") {
- run_server(&matches.opt_str("t").unwrap(), true, dir_mode);
+ run_server(&matches.opt_str("t").unwrap(), true, dir_mode, daemonize);
}
}