use std::io::{Error, ErrorKind};
use std::cell::UnsafeCell;
use std::sync::{Arc, Mutex};
use std::os::unix::io::{RawFd, AsRawFd};
use libc;
use simple_slab::Slab;
use super::{Stream, Handler};
pub type ConnectionSlab = Arc<MutSlab>;
pub type NewConnectionSlab = Arc<Mutex<Slab<Connection>>>;
pub type IoQueue = Arc<Mutex<Vec<IoPair>>>;
#[derive(Clone, PartialEq, Eq)]
pub enum IoEvent {
ReadAvailable,
WriteAvailable,
ReadWriteAvailable
}
#[derive(Clone)]
pub struct IoPair {
pub event: IoEvent,
pub arc_connection: Arc<Connection>
}
pub struct Connection {
pub fd: RawFd,
pub err_mutex: Mutex<Option<Error>>,
pub tx_mutex: Mutex<()>,
pub stream: Arc<UnsafeCell<Stream>>
}
unsafe impl Send for Connection {}
unsafe impl Sync for Connection {}
pub struct MutSlab {
pub inner: UnsafeCell<Slab<Arc<Connection>>>
}
unsafe impl Send for MutSlab {}
unsafe impl Sync for MutSlab {}
pub struct EventHandler(pub *mut Handler);
unsafe impl Send for EventHandler {}
unsafe impl Sync for EventHandler {}
impl Clone for EventHandler {
fn clone(&self) -> EventHandler {
let EventHandler(ptr) = *self;
unsafe {
let same_location = &mut *ptr;
EventHandler(same_location)
}
}
}
pub struct HydrogenSocket {
arc_connection: Arc<Connection>,
rearm_fn: unsafe fn(&Arc<Connection>, i32)
}
impl Clone for HydrogenSocket {
fn clone(&self) -> HydrogenSocket {
let fn_ptr = self.rearm_fn;
HydrogenSocket {
arc_connection: self.arc_connection.clone(),
rearm_fn: fn_ptr
}
}
}
impl HydrogenSocket {
pub fn new(arc_connection: Arc<Connection>,
rearm_fn: unsafe fn(&Arc<Connection>, i32))
-> HydrogenSocket
{
HydrogenSocket {
arc_connection: arc_connection,
rearm_fn: rearm_fn
}
}
pub fn send(&self, buf: &[u8]) {
let err;
{ let _ = match self.arc_connection.tx_mutex.lock() {
Ok(g) => g,
Err(p) => p.into_inner()
};
let stream_ptr = self.arc_connection.stream.get();
let write_result = unsafe {
(*stream_ptr).send(buf)
};
if write_result.is_ok() {
trace!("HydrogenSocket.send OK");
return;
}
err = write_result.unwrap_err();
}
match err.kind() {
ErrorKind::WouldBlock => {
trace!("HydrogenSocket.send received WouldBlock");
let execute = self.rearm_fn;
unsafe {
execute(&(self.arc_connection), libc::EPOLLOUT);
}
}
_ => {
trace!("HydrogenSocket.send received err");
{ let mut err_state = match self.arc_connection.err_mutex.lock() {
Ok(g) => g,
Err(p) => p.into_inner()
};
*err_state = Some(err);
} }
}
}
pub fn shutdown(&mut self) -> Result<(), Error> {
let stream_ptr = self.arc_connection.stream.get();
unsafe {
(*stream_ptr).shutdown()
}
}
}
impl AsRawFd for HydrogenSocket {
fn as_raw_fd(&self) -> RawFd {
self.arc_connection.fd
}
}