extern crate libc;
use super::common::stream::{InputStream, OutputStream};
use std::borrow::ToOwned;
use std::clone::Clone;
use std::io::Result as IoResult;
use std::net::IpAddr;
use std::net::{TcpListener, TcpStream};
use std::ops::Deref;
use std::os::unix::io::{AsRawFd, FromRawFd};
use std::sync::Arc;
use std::thread;
pub mod commands;
extern "C" {
fn gethostname(name: *mut libc::c_char, size: libc::size_t) -> libc::c_int;
}
fn rust_gethostname() -> Result<String, ()> {
let len = 255;
let mut buf = Vec::<u8>::with_capacity(len);
let ptr = buf.as_mut_slice().as_mut_ptr();
let err = unsafe { gethostname(ptr as *mut libc::c_char, len as libc::size_t) } as isize;
match err {
0 => {
let mut real_len = len;
let mut i = 0;
loop {
if i >= len {
break;
}
let byte = unsafe { *(((ptr as u64) + (i as u64)) as *const u8) };
if byte == 0 {
real_len = i;
break;
}
i += 1;
}
unsafe { buf.set_len(real_len) }
Ok(String::from_utf8_lossy(buf.as_ref()).into_owned())
}
_ => Err(()),
}
}
pub struct NextMiddleware<CT, ST> {
callback: MiddlewareFn<CT, ST>,
next: Box<Option<NextMiddleware<CT, ST>>>,
}
impl<CT, ST> Clone for NextMiddleware<CT, ST> {
fn clone(&self) -> NextMiddleware<CT, ST> {
NextMiddleware {
callback: self.callback,
next: self.next.clone(),
}
}
}
impl<CT, ST> NextMiddleware<CT, ST> {
pub fn call(
&self,
config: &ServerConfig<CT>,
container: &mut CT,
i: &mut InputStream<ST>,
o: &mut OutputStream<ST>,
l: &str,
) {
match *self.next {
Some(ref next) => {
(self.callback)(config, container, i, o, l, Some(next.clone()));
}
None => {
(self.callback)(config, container, i, o, l, None);
}
}
}
}
pub type MiddlewareFn<CT, ST> = fn(
&ServerConfig<CT>,
&mut CT,
&mut InputStream<ST>,
&mut OutputStream<ST>,
&str,
Option<NextMiddleware<CT, ST>>,
) -> ();
pub struct Command<CT, ST> {
start: Option<String>,
front_middleware: Option<NextMiddleware<CT, ST>>,
}
impl<CT, ST> Clone for Command<CT, ST> {
fn clone(&self) -> Command<CT, ST> {
Command {
start: self.start.clone(),
front_middleware: self.front_middleware.clone(),
}
}
}
impl<CT, ST> Command<CT, ST> {
pub fn new() -> Command<CT, ST> {
Command {
start: None,
front_middleware: None,
}
}
pub fn starts_with(&mut self, start: &str) {
self.start = Some(start.to_owned());
}
fn last_middleware<'a>(prev: &'a mut NextMiddleware<CT, ST>) -> &'a mut NextMiddleware<CT, ST> {
match *prev.next {
None => prev,
Some(ref mut next) => Command::last_middleware(next),
}
}
pub fn middleware(&mut self, callback: MiddlewareFn<CT, ST>) {
let next = Some(NextMiddleware {
callback: callback,
next: Box::new(None),
});
match self.front_middleware {
None => {
self.front_middleware = next;
}
Some(_) => {
Command::last_middleware(self.front_middleware.as_mut().unwrap()).next =
Box::new(next);
}
}
}
fn ready(&self) -> bool {
true
}
}
pub struct ServerConfig<CT> {
hostname: String,
max_recipients: usize,
max_message_size: usize,
max_command_line_size: usize,
max_text_line_size: usize,
commands: Vec<Command<CT, TcpStream>>,
extensions: Vec<String>,
}
impl<CT> Clone for ServerConfig<CT> {
fn clone(&self) -> ServerConfig<CT> {
let mut cloned_commands = Vec::with_capacity(self.commands.len());
for c in self.commands.iter() {
cloned_commands.push(c.clone());
}
ServerConfig {
hostname: self.hostname.clone(),
max_recipients: self.max_recipients,
max_message_size: self.max_message_size,
max_command_line_size: self.max_command_line_size,
max_text_line_size: self.max_text_line_size,
commands: cloned_commands,
extensions: self.extensions.clone(),
}
}
}
pub struct Server<CT> {
config: ServerConfig<CT>,
container: CT,
}
#[derive(PartialEq, Eq, Clone, Debug, Copy)]
pub enum ServerError {
Hostname,
Bind,
Listen,
}
pub type ServerResult<T> = Result<T, ServerError>;
impl<CT: 'static + Send + Sync + Clone> Server<CT> {
pub fn new(container: CT) -> Server<CT> {
Server {
config: ServerConfig {
hostname: String::new(),
max_recipients: 100,
max_message_size: 65536,
max_command_line_size: 512,
max_text_line_size: 1000,
commands: Vec::with_capacity(16),
extensions: Vec::with_capacity(16),
},
container: container,
}
}
fn set_hostname(&mut self, hostname: &str) {
self.config.hostname = hostname.to_owned();
}
fn set_max_recipients(&mut self, max: usize) {
if max < 100 {
panic!("Maximum number of recipients must be >= 100.");
}
self.config.max_recipients = max;
}
fn set_max_message_size(&mut self, max: usize) {
if max < 65536 {
panic!("Maximum message size must be >= 65536.");
}
self.config.max_message_size = max;
}
pub fn add_command(&mut self, command: Command<CT, TcpStream>) {
self.config.commands.push(command);
}
fn increase_max_command_line_size(&mut self, bytes: usize) {
self.config.max_command_line_size += bytes;
}
fn increase_max_text_line_size(&mut self, bytes: usize) {
self.config.max_text_line_size += bytes;
}
pub fn add_extension(&mut self, extension: &str) {
self.config.extensions.push(extension.to_owned());
}
fn get_hostname_from_system(&mut self) -> ServerResult<String> {
match rust_gethostname() {
Ok(s) => Ok(s),
Err(_) => Err(ServerError::Hostname),
}
}
fn get_listener_for_address(&mut self, address: (IpAddr, u16)) -> ServerResult<TcpListener> {
match TcpListener::bind(address) {
Ok(listener) => Ok(listener),
Err(_) => Err(ServerError::Bind),
}
}
fn handle_commands(
config: &ServerConfig<CT>,
input: &mut InputStream<TcpStream>,
output: &mut OutputStream<TcpStream>,
container: &mut CT,
) {
'main: loop {
let line = match input.read_line() {
Ok(buffer) => {
String::from_utf8_lossy(buffer).into_owned()
}
Err(err) => {
panic!("Could not read command: {}", err);
}
};
for command in config.commands.iter() {
match command.start {
Some(ref start) => {
let ls = line.as_str();
if ls.starts_with(start.as_str()) {
match command.front_middleware {
Some(ref next) => {
next.call(config, container, input, output, &ls[start.len()..]);
}
None => {
panic!("Found a command with no middleware");
}
}
continue 'main;
}
}
None => {
panic!("Found a command with no start string");
}
}
}
output.write_line("500 Command unrecognized").unwrap();
}
}
fn handle_connection(&self, stream_res: IoResult<TcpStream>, config: &Arc<ServerConfig<CT>>) {
let config = config.clone();
let mut container = self.container.clone();
let thread_handle = thread::spawn(move || {
match stream_res {
Ok(stream) => {
let mut input = InputStream::new(
unsafe { TcpStream::from_raw_fd(stream.as_raw_fd()) },
1000,
false,
);
let mut output = OutputStream::new(stream, false);
Server::<CT>::handle_commands(
config.deref(),
&mut input,
&mut output,
&mut container,
);
}
Err(err) => {
panic!("Could not accept client: {}", err);
}
}
});
println!(
"Connection being handled in thread: {:?}",
thread_handle.thread().name()
);
}
pub fn listen(&mut self, ip: IpAddr, port: u16) -> ServerResult<()> {
if self.config.hostname.len() == 0 {
self.config.hostname = self.get_hostname_from_system()?;
}
let listener = self.get_listener_for_address((ip, port))?;
println!(
"Server '{}' listening on {}:{}...",
self.config.hostname, ip, port
);
let config = Arc::new(self.config.clone());
for conn in listener.incoming() {
self.handle_connection(conn, &config);
}
Ok(())
}
}