use std::net::{SocketAddr, TcpListener, UdpSocket}; use std::sync::Arc; use std::sync::Mutex; use std::thread; use ansi_term::Color; use openssl::ssl::{SslAcceptor, SslFiletype, SslMethod}; use rusty_pool; use std::fmt::Formatter; use std::time::Duration; mod database; mod error; mod http; mod udp; mod usimp; mod websocket; enum SocketType { Http, Https, Udp, } impl std::fmt::Display for SocketType { fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { write!(f, "{}", match self { SocketType::Http => "http+ws", SocketType::Https => "https+wss", SocketType::Udp => "udp", }) } } struct SocketConfig { address: SocketAddr, socket_type: SocketType, } fn main() { println!("Locutus server"); let socket_configs: Vec = vec![ SocketConfig { address: "[::]:8080".parse().unwrap(), socket_type: SocketType::Http, }, SocketConfig { address: "[::]:8443".parse().unwrap(), socket_type: SocketType::Https, }, SocketConfig { address: "[::]:3126".parse().unwrap(), socket_type: SocketType::Udp, }, ]; // Note: rust's stdout is line buffered! eprint!("Initializing database connection pool..."); if let Err(error) = database::init() { eprintln!("\n{}", Color::Red.bold().paint(error.to_string())); std::process::exit(1); } eprintln!(" {}", Color::Green.paint("success")); let thread_pool = rusty_pool::Builder::new() .core_size(4) .max_size(1024) .keep_alive(Duration::from_secs(60 * 60)) .build(); let thread_pool_mutex = Arc::new(Mutex::new(thread_pool)); let mut threads = Vec::new(); for socket_config in socket_configs { let thread_pool_mutex = thread_pool_mutex.clone(); eprintln!( "Creating listening thread for {} ({})", ansi_term::Style::new().bold().paint(socket_config.address.to_string()), socket_config.socket_type ); threads.push(match socket_config.socket_type { SocketType::Http => thread::spawn(move || { let mut tcp_socket = TcpListener::bind(socket_config.address).unwrap(); for stream in tcp_socket.incoming() { thread_pool_mutex.lock().unwrap().execute(|| { let stream = stream.unwrap(); http::connection_handler(http::Stream::Tcp(stream)); }); } }), SocketType::Https => thread::spawn(move || { let mut ssl_socket = TcpListener::bind(socket_config.address).unwrap(); let mut acceptor = SslAcceptor::mozilla_intermediate(SslMethod::tls()).unwrap(); acceptor .set_certificate_chain_file("/home/lorenz/Certificates/chakotay.pem") .unwrap(); acceptor .set_private_key_file("/home/lorenz/Certificates/priv/chakotay.key",SslFiletype::PEM) .unwrap(); acceptor.check_private_key().unwrap(); let acceptor = Arc::new(acceptor.build()); for stream in ssl_socket.incoming() { let acceptor = acceptor.clone(); thread_pool_mutex.lock().unwrap().execute(move || { let stream = stream.unwrap(); let stream = acceptor.accept(stream).unwrap(); http::connection_handler(http::Stream::Ssl(stream)); }); } }), SocketType::Udp => thread::spawn(move || { let mut udp_socket = UdpSocket::bind(socket_config.address).unwrap(); let mut buf = [0; 65_536]; loop { let (size, addr) = udp_socket.recv_from(&mut buf).unwrap(); let req = udp::Request::new(&udp_socket, addr, size, &buf); thread_pool_mutex .lock() .unwrap() .execute(|| udp::handler(req)); } }), }); } println!("{}", Color::Green.paint("Ready")); for thread in threads { thread.join().unwrap(); } }