sunbeam/sunbeam.rs

91 lines
2.4 KiB
Rust

use std::io;
use std::io::prelude::*;
use std::net::{TcpListener,TcpStream,SocketAddr};
use std::process::exit;
use std::collections::VecDeque;
use std::thread::sleep;
use std::time::Duration;
static PORT:u16 = 55555;
static IDLE_THRESH:usize = 1024;
fn main() {
'recovery:loop {
let listener = match TcpListener::bind(&format!("[::]:{}",PORT)) {
Err(why) => {
eprintln!("failed to bind TCP listener: {}",why);
exit(1);
},
Ok(l) => l,
};
listener.set_nonblocking(true).expect("cannot set listener to nonblocking");
let mut connections:VecDeque<(TcpStream,SocketAddr)> = VecDeque::new();
let mut bottle:[u8;1] = [0x00];
let mut idlecycles:usize = 0;
'processor:loop {
idlecycles += 1;
match listener.accept() {
Err(why) => match why.kind() {
io::ErrorKind::WouldBlock => (),
_ => {
eprintln!("failed to accept new connection: {}",why);
break 'processor;
},
},
Ok((stream,address)) => {
println!("+ connection opened by {}",address);
stream.set_nonblocking(true).expect("cannot set stream to nonblocking");
stream.set_nodelay(true).expect("cannot set stream to nodelay");
connections.push_back((stream,address));
},
};
match connections.pop_front() {
None => sleep(Duration::from_millis(1)),
Some((mut stream,address)) => match stream.read(&mut bottle) {
Err(why) => match why.kind() {
io::ErrorKind::WouldBlock => connections.push_back((stream,address)),
_ => println!("- connection to {} failed: read error: {}",address,why),
},
Ok(n) => match n {
0 => {
println!("- connection to {} closed: read reached end of stream",address);
},
_ => {
for _ in 0..connections.len() {
if let Some((mut otherstream,otheraddress)) = connections.pop_front() {
match otherstream.write(&bottle) {
Err(why) => println!("- connection to {} failed: write error: {}",otheraddress,why),
Ok(n) => match n {
0 => {
println!("- connection to {} closed: write reached end of stream",otheraddress);
},
_ => {
connections.push_back((otherstream,otheraddress));
},
},
};
}
}
connections.push_back((stream,address));
idlecycles = 0;
},
},
},
};
if idlecycles > IDLE_THRESH {
sleep(Duration::from_millis(1));
}
}
} // 'recovery
}