use mio::event::Event;
use mio::net::{TcpListener, TcpStream};
use mio::{Events, Interest, Poll, Registry, Token};
use std::collections::HashMap;
use std::io::{self, Read, Write};
use std::str::from_utf8;
const SERVER: Token = Token(0);
const DATA: &[u8] = b"Hello world!\n";
#[cfg(not(windows))]
fn get_first_listen_fd_listener() -> Option<std::net::TcpListener> {
#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
use std::os::fd::FromRawFd;
let stdlistener = unsafe { std::net::TcpListener::from_raw_fd(3) };
stdlistener.set_nonblocking(true).unwrap();
Some(stdlistener)
}
#[cfg(windows)]
fn get_first_listen_fd_listener() -> Option<std::net::TcpListener> {
None
}
fn main() -> io::Result<()> {
env_logger::init();
std::env::var("LISTEN_FDS").expect("LISTEN_FDS environment variable unset");
let mut poll = Poll::new()?;
let mut events = Events::with_capacity(128);
let mut server = {
let stdlistener = get_first_listen_fd_listener().unwrap();
println!("Using preopened socket FD 3");
println!("You can connect to the server using `nc`:");
match stdlistener.local_addr() {
Ok(a) => println!(" $ nc {} {}", a.ip(), a.port()),
Err(_) => println!(" $ nc <IP> <PORT>"),
}
println!("You'll see our welcome message and anything you type will be printed here.");
TcpListener::from_std(stdlistener)
};
poll.registry()
.register(&mut server, SERVER, Interest::READABLE)?;
let mut connections = HashMap::new();
let mut unique_token = Token(SERVER.0 + 1);
loop {
poll.poll(&mut events, None)?;
for event in events.iter() {
match event.token() {
SERVER => loop {
let (mut connection, address) = match server.accept() {
Ok((connection, address)) => (connection, address),
Err(ref e) if would_block(e) => {
break;
}
Err(e) => {
return Err(e);
}
};
println!("Accepted connection from: {}", address);
let token = next(&mut unique_token);
poll.registry()
.register(&mut connection, token, Interest::WRITABLE)?;
connections.insert(token, connection);
},
token => {
let done = if let Some(connection) = connections.get_mut(&token) {
handle_connection_event(poll.registry(), connection, event)?
} else {
false
};
if done {
if let Some(mut connection) = connections.remove(&token) {
poll.registry().deregister(&mut connection)?;
}
}
}
}
}
}
}
fn next(current: &mut Token) -> Token {
let next = current.0;
current.0 += 1;
Token(next)
}
fn handle_connection_event(
registry: &Registry,
connection: &mut TcpStream,
event: &Event,
) -> io::Result<bool> {
if event.is_writable() {
match connection.write(DATA) {
Ok(n) if n < DATA.len() => return Err(io::ErrorKind::WriteZero.into()),
Ok(_) => {
registry.reregister(connection, event.token(), Interest::READABLE)?
}
Err(ref err) if would_block(err) => {}
Err(ref err) if interrupted(err) => {
return handle_connection_event(registry, connection, event)
}
Err(err) => return Err(err),
}
}
if event.is_readable() {
let mut connection_closed = false;
let mut received_data = vec![0; 4096];
let mut bytes_read = 0;
loop {
match connection.read(&mut received_data[bytes_read..]) {
Ok(0) => {
connection_closed = true;
break;
}
Ok(n) => {
bytes_read += n;
if bytes_read == received_data.len() {
received_data.resize(received_data.len() + 1024, 0);
}
}
Err(ref err) if would_block(err) => break,
Err(ref err) if interrupted(err) => continue,
Err(err) => return Err(err),
}
}
if bytes_read != 0 {
let received_data = &received_data[..bytes_read];
if let Ok(str_buf) = from_utf8(received_data) {
println!("Received data: {}", str_buf.trim_end());
} else {
println!("Received (none UTF-8) data: {:?}", received_data);
}
}
if connection_closed {
println!("Connection closed");
return Ok(true);
}
}
Ok(false)
}
fn would_block(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::WouldBlock
}
fn interrupted(err: &io::Error) -> bool {
err.kind() == io::ErrorKind::Interrupted
}