#![cfg(feature = "server")]
use std::
{
thread,
process,
io::Read,
time::Duration,
sync::{ Arc, Mutex },
net::
{
TcpListener,
UdpSocket,
Shutdown,
},
};
use log::LevelFilter;
use simple_logger::SimpleLogger;
use why2_chat::
{
misc,
config,
options,
crypto::kex,
network::
{
file::server as file,
screen::server as screen,
voice::server as voice_server,
server::{ self, ConnectionType },
},
};
fn quit() {
log::info!("Exiting...");
server::disconnect_all(); }
fn main()
{
SimpleLogger::new()
.with_level(LevelFilter::Info)
.with_module_level("ureq", LevelFilter::Warn) .with_module_level("rustls", LevelFilter::Warn) .init()
.unwrap();
misc::check_version(); config::init_config(); kex::generate_server_keys();
if config::read_config("enable_voice_chat")
{
options::enable_voice_chat();
}
options::set_server_username(&config::read_config::<String>("server_username"));
let address = format!("{}:{}", config::read_config::<String>("server_ip"), config::read_config::<u16>("server_port"));
let listener = match TcpListener::bind(&address)
{
Ok(l) => l,
Err(_) =>
{
log::error!("Binding on {address} failed!");
process::exit(1);
}
};
let udp_socket = if options::voice_chat_enabled() {
Some(UdpSocket::bind(&address).expect("Binding UDP failed"))
} else { None };
log::info!("Listening on {address}");
thread::spawn(move ||
{
let mut n = 0;
loop
{
thread::sleep(Duration::from_secs(5));
server::disconnect_inactive();
server::PENDING_TOKENS.retain(|_, (_, _, created)| created.elapsed().as_secs() < 5);
n = (n + 1) % 6;
if n == 0
{
server::send_keepalive();
}
}
});
ctrlc::set_handler(move ||
{
quit();
process::exit(0);
}).expect("Setting Ctrl+C handler failed");
if options::voice_chat_enabled()
{
thread::spawn(move || voice_server::listen_client_voice(udp_socket.unwrap()));
}
for stream in listener.incoming()
{
match stream
{
Ok(mut stream) =>
{
let peer_addr = match stream.peer_addr()
{
Ok(p) => p,
Err(_) => continue
};
stream.set_read_timeout(Some(Duration::from_millis(2000))).expect("Failed to set read timeout");
stream.set_write_timeout(Some(Duration::from_millis(5000))).expect("Failed to set write timeout");
let mut token = [0u8; 32];
if let Ok(_) = stream.read_exact(&mut token)
{
stream.set_read_timeout(None).expect("Failed to set read timeout");
match stream.set_nodelay(true)
{
Ok(_) => {},
Err(_) => continue
}
if let Some((_, (id, conn_type, _))) = server::PENDING_TOKENS.remove(&token)
{
match conn_type
{
ConnectionType::FileUpload { uid } =>
{
stream.set_read_timeout(Some(Duration::from_millis(5000))).expect("Failed to set read timeout");
let write_stream = Arc::new(Mutex::new(stream.try_clone().expect("Failed cloning stream")));
thread::spawn(move || file::download(token, id, &mut (&mut stream, write_stream), uid));
continue;
},
ConnectionType::FileDownload { uid, file: file_data } =>
{
thread::spawn(move || file::upload(token, id, stream, file_data, uid));
continue;
},
ConnectionType::Screen =>
{
stream.set_read_timeout(Some(Duration::from_millis(5000))).expect("Failed to set read timeout");
let write_stream = Arc::new(Mutex::new(stream.try_clone().expect("Failed cloning stream")));
thread::spawn(move || screen::screen(token, id, &mut (&mut stream, write_stream)));
continue;
},
ConnectionType::Attach { id: sharer_id } =>
{
if let Some(mut conn) = server::CONNECTIONS.iter_mut().find(|c| c.id() == Some(&id))
{
conn.attach_screen(sharer_id, Arc::new(stream), token);
}
continue;
},
}
} else
{
let auth_clients = server::CONNECTIONS.iter().filter(|c| c.is_authenticated()).count();
let unauth_clients = server::CONNECTIONS.len() - auth_clients;
let ip_clients = server::CONNECTIONS.iter().filter(|c| c.peer_addr().ip() == peer_addr.ip()).count();
if auth_clients >= config::read_config::<usize>("max_clients") ||
unauth_clients >= config::read_config::<usize>("max_unauth_clients") ||
ip_clients >= config::read_config::<usize>("max_ip_clients")
{
log::error!("Connection rejected (limit): {peer_addr}");
stream.shutdown(Shutdown::Both).ok();
continue;
}
let write_stream = Arc::new(Mutex::new(stream.try_clone().expect("Failed cloning stream")));
thread::spawn(move || server::listen_client(&mut (&mut stream, write_stream), peer_addr, token));
continue;
}
}
log::error!("Connection rejected (header): {peer_addr}");
stream.shutdown(Shutdown::Both).ok();
},
Err(e) =>
{
log::error!("Connection failed: {}", e);
}
}
}
}