Initial commit
This commit is contained in:
commit
cf43bfebfb
4 changed files with 323 additions and 0 deletions
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
||||||
|
/target
|
7
Cargo.lock
generated
Normal file
7
Cargo.lock
generated
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# This file is automatically @generated by Cargo.
|
||||||
|
# It is not intended for manual editing.
|
||||||
|
version = 3
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "qft"
|
||||||
|
version = "0.1.0"
|
8
Cargo.toml
Normal file
8
Cargo.toml
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
[package]
|
||||||
|
name = "qft"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||||
|
|
||||||
|
[dependencies]
|
307
src/main.rs
Normal file
307
src/main.rs
Normal file
|
@ -0,0 +1,307 @@
|
||||||
|
use std::{
|
||||||
|
fs::File,
|
||||||
|
io::{Error, Read, Write},
|
||||||
|
net::*,
|
||||||
|
time::Duration,
|
||||||
|
};
|
||||||
|
|
||||||
|
trait Ordinal {
|
||||||
|
fn ordinal(&self) -> isize;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum SafeReadWritePacket {
|
||||||
|
WRITE,
|
||||||
|
ACK,
|
||||||
|
END,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ordinal for SafeReadWritePacket {
|
||||||
|
fn ordinal(&self) -> isize {
|
||||||
|
match self {
|
||||||
|
SafeReadWritePacket::WRITE => 0,
|
||||||
|
SafeReadWritePacket::ACK => 1,
|
||||||
|
SafeReadWritePacket::END => 2,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct SafeReadWrite {
|
||||||
|
socket: UdpSocket,
|
||||||
|
packet_count_out: u8,
|
||||||
|
packet_count_in: u8,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SafeReadWrite {
|
||||||
|
pub fn new(socket: UdpSocket) -> SafeReadWrite {
|
||||||
|
SafeReadWrite {
|
||||||
|
socket,
|
||||||
|
packet_count_in: 0,
|
||||||
|
packet_count_out: 0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn write_safe(&mut self, buf: &[u8]) -> Result<(), Error> {
|
||||||
|
if buf.len() > 0xfffd {
|
||||||
|
panic!(
|
||||||
|
"too large data packet sent over SafeReadWrite ({} > 0xfffd)",
|
||||||
|
buf.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let id = self.packet_count_out;
|
||||||
|
self.packet_count_out += 1;
|
||||||
|
|
||||||
|
let mut buf = Vec::from(buf);
|
||||||
|
buf.insert(0, SafeReadWritePacket::WRITE.ordinal() as u8);
|
||||||
|
buf.insert(0, id);
|
||||||
|
let buf = buf.as_slice();
|
||||||
|
|
||||||
|
self.socket
|
||||||
|
.set_read_timeout(Some(Duration::from_secs(1)))
|
||||||
|
.expect("cannot set_read_timeout");
|
||||||
|
|
||||||
|
let mut resend = true;
|
||||||
|
while resend {
|
||||||
|
match self.socket.send(buf) {
|
||||||
|
Ok(x) => {
|
||||||
|
if x != buf.len() {
|
||||||
|
panic!("bad buf length")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(x) => return Err(x),
|
||||||
|
}
|
||||||
|
let mut buf = [0, 0];
|
||||||
|
match self.socket.recv(&mut buf).ok() {
|
||||||
|
Some(x) => {
|
||||||
|
if x == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if buf[1] == SafeReadWritePacket::ACK.ordinal() as u8 && buf[0] == id {
|
||||||
|
resend = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Ok(());
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn read_safe(&mut self, buf: &[u8]) -> Result<(Vec<u8>, usize), Error> {
|
||||||
|
if buf.len() > 0xfffd {
|
||||||
|
panic!(
|
||||||
|
"attempted to receive too large data packet with SafeReadWrite ({} > 0xfffd)",
|
||||||
|
buf.len()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut mbuf = Vec::from(buf);
|
||||||
|
mbuf.insert(0, 0);
|
||||||
|
mbuf.insert(0, 0);
|
||||||
|
let buf: &mut [u8] = mbuf.as_mut();
|
||||||
|
|
||||||
|
let mut r = (vec![], 0);
|
||||||
|
|
||||||
|
let mut try_again = true;
|
||||||
|
while try_again {
|
||||||
|
match self.socket.recv(buf) {
|
||||||
|
Ok(x) => {
|
||||||
|
if x == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if buf[0] <= self.packet_count_in {
|
||||||
|
self.socket
|
||||||
|
.send(&[buf[0], SafeReadWritePacket::ACK.ordinal() as u8])
|
||||||
|
.expect("send error");
|
||||||
|
}
|
||||||
|
if buf[0] == self.packet_count_in {
|
||||||
|
try_again = false;
|
||||||
|
self.packet_count_in += 1;
|
||||||
|
r.1 = x - 2;
|
||||||
|
}
|
||||||
|
if buf[0] > self.packet_count_in {
|
||||||
|
panic!("illegal packet id {} > {}", buf[0], self.packet_count_in);
|
||||||
|
}
|
||||||
|
if buf[1] == SafeReadWritePacket::END.ordinal() as u8 {
|
||||||
|
return Ok((vec![], 0));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(x) => return Err(x),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
mbuf.remove(0);
|
||||||
|
mbuf.remove(0);
|
||||||
|
r.0 = mbuf;
|
||||||
|
return Ok(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn end(mut self) -> UdpSocket {
|
||||||
|
let id = self.packet_count_out;
|
||||||
|
self.packet_count_out += 1;
|
||||||
|
|
||||||
|
let mut buf = vec![];
|
||||||
|
buf.insert(0, SafeReadWritePacket::END.ordinal() as u8);
|
||||||
|
buf.insert(0, id);
|
||||||
|
let buf = buf.as_slice();
|
||||||
|
|
||||||
|
self.socket
|
||||||
|
.set_read_timeout(Some(Duration::from_secs(1)))
|
||||||
|
.expect("cannot set_read_timeout");
|
||||||
|
|
||||||
|
let mut resend = true;
|
||||||
|
while resend {
|
||||||
|
match self.socket.send(buf) {
|
||||||
|
Ok(x) => {
|
||||||
|
if x != buf.len() {
|
||||||
|
panic!("internet down")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(_) => return self.socket,
|
||||||
|
}
|
||||||
|
let mut buf = [0, 0];
|
||||||
|
match self.socket.recv(&mut buf).ok() {
|
||||||
|
Some(x) => {
|
||||||
|
if x == 0 {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if buf[1] == SafeReadWritePacket::ACK.ordinal() as u8 && buf[0] == id {
|
||||||
|
resend = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
None => {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
self.socket
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_socket(&self) -> &UdpSocket {
|
||||||
|
&self.socket
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn get_mut_socket(&mut self) -> &mut UdpSocket {
|
||||||
|
&mut self.socket
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let args: Vec<String> = std::env::args().collect();
|
||||||
|
if args.len() <= 1 {
|
||||||
|
print_args(&args);
|
||||||
|
}
|
||||||
|
match args
|
||||||
|
.get(1)
|
||||||
|
.expect("no args supplied, check if the first arg is truly the program name")
|
||||||
|
.as_str()
|
||||||
|
{
|
||||||
|
"helper" => helper(&args),
|
||||||
|
"sender" => sender(&args),
|
||||||
|
"receiver" => receiver(&args),
|
||||||
|
_ => print_args(&args),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn helper(args: &Vec<String>) {
|
||||||
|
let bind_addr = (
|
||||||
|
"127.0.0.1",
|
||||||
|
u16::from_str_radix(args[2].as_str(), 10).expect("invalid port: must be integer"),
|
||||||
|
);
|
||||||
|
let listener = UdpSocket::bind(&bind_addr).expect("unable to create socket");
|
||||||
|
let mut buf = [0 as u8];
|
||||||
|
loop {
|
||||||
|
let (_, addr) = listener.recv_from(&mut buf).expect("read error");
|
||||||
|
// we got a connection
|
||||||
|
if listener.send_to(&addr.port().to_be_bytes(), addr).is_ok() {
|
||||||
|
// success!
|
||||||
|
println!("Helped {}! :D", addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sender(args: &Vec<String>) {
|
||||||
|
let mut bind_addr = ("127.0.0.1", 0);
|
||||||
|
{
|
||||||
|
let holepunch = UdpSocket::bind(&bind_addr).expect("unable to create socket");
|
||||||
|
let mut buf = [0 as u8; 2];
|
||||||
|
holepunch
|
||||||
|
.connect(args.get(2).unwrap_or_else(|| {
|
||||||
|
print_args(args);
|
||||||
|
panic!("unreachable")
|
||||||
|
}))
|
||||||
|
.expect("unable to connect to helper");
|
||||||
|
holepunch.send(&[0]).expect("unable to talk to helper");
|
||||||
|
holepunch
|
||||||
|
.recv(&mut buf)
|
||||||
|
.expect("unable to receive from helper");
|
||||||
|
// buf should now contain our port.
|
||||||
|
bind_addr = ("127.0.0.1", u16::from_be_bytes(buf));
|
||||||
|
println!("Holepunch successful. Running on port {}.", bind_addr.1);
|
||||||
|
}
|
||||||
|
// we have the needed bind_addr and did the holepunch
|
||||||
|
{
|
||||||
|
let connection = UdpSocket::bind(&bind_addr).expect("unable to create send socket");
|
||||||
|
let mut buf = [0 as u8; 256];
|
||||||
|
let mut file = File::open(args.get(3).unwrap_or_else(|| {
|
||||||
|
print_args(args);
|
||||||
|
panic!("unreachable")
|
||||||
|
}))
|
||||||
|
.expect("file not readable");
|
||||||
|
connection
|
||||||
|
.connect(connection.recv_from(&mut buf).expect("connect error").1)
|
||||||
|
.expect("connect error");
|
||||||
|
|
||||||
|
let mut sc = SafeReadWrite::new(connection);
|
||||||
|
loop {
|
||||||
|
let read = file.read(&mut buf).expect("file read error");
|
||||||
|
if read == 0 {
|
||||||
|
println!("Transfer done. Thank you!");
|
||||||
|
sc.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
sc.write_safe(&buf[..read]).expect("send error");
|
||||||
|
println!("Sent {} bytes", read);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn receiver(args: &Vec<String>) {
|
||||||
|
let connection = UdpSocket::bind(("127.0.0.1", 0)).expect("unable to create receive socket");
|
||||||
|
let mut buf: &[u8] = &[0 as u8; 256];
|
||||||
|
let mut file = File::create(args.get(3).unwrap_or_else(|| {
|
||||||
|
print_args(args);
|
||||||
|
panic!("unreachable")
|
||||||
|
}))
|
||||||
|
.expect("file not writable");
|
||||||
|
connection
|
||||||
|
.connect(args.get(2).unwrap_or_else(|| {
|
||||||
|
print_args(args);
|
||||||
|
panic!("unreachable")
|
||||||
|
}))
|
||||||
|
.expect("unable to connect");
|
||||||
|
connection.send(&[0]).expect("connect write error");
|
||||||
|
|
||||||
|
let mut sc = SafeReadWrite::new(connection);
|
||||||
|
loop {
|
||||||
|
let (mbuf, len) = sc.read_safe(buf).expect("read error");
|
||||||
|
buf = &mbuf.leak()[..len];
|
||||||
|
if len == 0 {
|
||||||
|
println!("Transfer done. Thank you!");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
file.write(buf).expect("write error");
|
||||||
|
println!("Received {} bytes", len);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn print_args(args: &Vec<String>) {
|
||||||
|
let f = args.get(0).unwrap();
|
||||||
|
println!(
|
||||||
|
"No arguments. Needed: \n\
|
||||||
|
| {} helper <bind-port>\n\
|
||||||
|
| {} sender <helper-address>:<helper-port> <filename>\n\
|
||||||
|
| {} receiver <sender-address>:<sender-port> <filename>",
|
||||||
|
f, f, f
|
||||||
|
);
|
||||||
|
panic!("No arguments");
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue