aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorbnewbold <bnewbold@robocracy.org>2016-05-29 20:31:09 -0400
committerbnewbold <bnewbold@robocracy.org>2016-05-29 20:31:09 -0400
commit557159a2e00508820cb7bad66822cc97c61b6de5 (patch)
treec66589f768cd8da0778b762e3d9c9ff1f17f5123
parent223da5cfea8608f7b11f32720203a2704dd02601 (diff)
downloaducp-557159a2e00508820cb7bad66822cc97c61b6de5.tar.gz
ucp-557159a2e00508820cb7bad66822cc97c61b6de5.zip
begin implementation of actual file transfer
-rw-r--r--src/client.rs7
-rw-r--r--src/common.rs110
-rw-r--r--src/main.rs2
-rw-r--r--src/server.rs7
4 files changed, 108 insertions, 18 deletions
diff --git a/src/client.rs b/src/client.rs
index a2ebf27..637a216 100644
--- a/src/client.rs
+++ b/src/client.rs
@@ -49,10 +49,11 @@ pub fn run_client(host: &str, local_file: &str, remote_file: &str, remote_is_dir
println!("\tsecret: {}", remote_secret);
let mut socket = UtpSocket::connect((remote_host, remote_port)).unwrap();;
+ let mut stream = socket.into();
if is_recv {
- common::receive_files(&mut socket, local_file, remote_is_dir);
+ common::sink_files(&mut stream, local_file, remote_is_dir);
} else {
- common::send_files(&mut socket, local_file, remote_is_dir);
+ common::source_files(&mut stream, local_file, remote_is_dir);
}
- socket.close().unwrap();
+ stream.close().unwrap();
}
diff --git a/src/common.rs b/src/common.rs
index 8183bbf..421f3a5 100644
--- a/src/common.rs
+++ b/src/common.rs
@@ -3,21 +3,109 @@ extern crate utp;
use std::str;
use std::env;
-use std::fs::File;
-use std::io::Read;
+use std::path::Path;
+use std::fs::{self, File};
+use std::os::unix::fs::PermissionsExt;
+use std::io;
+use std::io::{Read, Write, BufRead, BufReader};
use std::process::exit;
-use utp::{UtpSocket};
+use utp::{UtpStream};
-pub fn send_files(socket: &mut UtpSocket, file_path: &str, recursive: bool) {
- assert!(!recursive);
- let f = File::open(file_path).unwrap();
- unimplemented!();
+pub fn source_files(stream: &mut UtpStream, file_path: &str, recursive: bool) {
+ if recursive { unimplemented!(); }
+ let mut f = File::open(file_path).unwrap();
+ let metadata = f.metadata().unwrap();
+ assert!(metadata.is_file());
+ let fmode: u32 = metadata.permissions().mode();
+ 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);
+ stream.write_all(line.as_bytes()).unwrap();
+
+ let mut byte_buf = [0; 1];
+ stream.read_exact(&mut byte_buf).unwrap();
+ let reply = byte_buf[0];
+ match reply {
+ 0 => {}, // Success, pass
+ 1 | 2 => { // Warning
+ unimplemented!();
+ },
+ _ => { panic!("Unexpected status char!") },
+ };
+
+ let mut buf = [0; 4096];
+ let mut sent: usize = 0;
+ while sent < flen {
+ let rlen = f.read(&mut buf).unwrap();
+ assert!(rlen > 0);
+ let mut wbuf = &mut buf[..rlen];
+ stream.write_all(&wbuf).unwrap();
+ sent += rlen;
+ }
+ // f.close(); XXX:
+ stream.read_exact(&mut byte_buf).unwrap();
+ let reply = byte_buf[0];
+ match reply {
+ 0 => {}, // Success, pass
+ 1 | 2 => { // Warning
+ unimplemented!();
+ },
+ _ => { panic!("Unexpected status char!") },
+ };
+}
+
+fn raw_read_line(stream: &mut UtpStream) -> io::Result<String> {
+
+ let mut s = String::new();
+ let mut byte_buf = [0];
+ loop {
+ stream.read_exact(&mut byte_buf).unwrap();
+ if byte_buf[0] == '\n' as u8 {
+ return Ok(s);
+ }
+ s.push(byte_buf[0] as char);
+ }
}
-pub fn receive_files(socket: &mut UtpSocket, file_path: &str, recursive: bool) {
- assert!(!recursive);
- let f = File::create(file_path).unwrap();
+// TODO: it would be nice to be able to do BufReader/BufWriter on UtpStream. This would require
+// 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) {
+ if recursive { unimplemented!(); }
+ let mut f = File::create(file_path).unwrap();
+
+ let mut byte_buf = [0; 1];
+ let mut buf = [0; 4096];
+ stream.read_exact(&mut byte_buf).unwrap();
+ let msg_type = byte_buf[0];
+ match msg_type as char {
+ 'C' => {} // pass
+ 'D' => { unimplemented!(); },
+ 'E' => { unimplemented!(); },
+ 'T' => { unimplemented!(); },
+ _ => { panic!(format!("Unexpected message type: {}", msg_type)); },
+ };
+ let line = raw_read_line(stream).unwrap();
+ let line: Vec<&str> = line.split_whitespace().collect();
+ assert!(line.len() == 3);
+ let fmode: u32 = u32::from_str_radix(line[0], 8).unwrap();
+ let flen: usize = line[1].parse::<usize>().unwrap();
+ let fpath = Path::new(line[2]);
+
+ f.set_len(flen as u64).unwrap();
+ fs::set_permissions(file_path, PermissionsExt::from_mode(fmode)).unwrap();
- //f.set_len();
+ let mut received: usize = 0;
+ while received < flen {
+ let rlen = stream.read(&mut buf).unwrap();
+ assert!(rlen > 0);
+ let mut wbuf = &mut buf[..rlen];
+ f.write_all(&wbuf).unwrap();
+ received += rlen;
+ }
+ f.sync_all().unwrap();
+ // f.close(); XXX: closes automatically?
+ stream.write(&[0]).unwrap();
}
diff --git a/src/main.rs b/src/main.rs
index bf2ceba..f916958 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,6 +1,6 @@
// XXX: re-enable these warnings
-#![allow(unused_imports, unused_variables)]
+#![allow(unused_imports, unused_variables, unused_mut)]
extern crate getopts;
extern crate utp;
diff --git a/src/server.rs b/src/server.rs
index e60c054..4c590be 100644
--- a/src/server.rs
+++ b/src/server.rs
@@ -47,13 +47,14 @@ fn run_server(path: &str, is_recv: bool, recursive: bool) {
let (mut socket, _src) = listener.accept().unwrap();
println!("Got connection from {}", socket.peer_addr().unwrap());
+ let mut stream = socket.into();
if is_recv {
- common::receive_files(&mut socket, path, recursive);
+ common::sink_files(&mut stream, path, recursive);
} else {
- common::send_files(&mut socket, path, recursive);
+ common::source_files(&mut stream, path, recursive);
}
- socket.close().unwrap();
+ stream.close().unwrap();
}
fn usage_server(opts: Options) {