pub(crate) use std::net::{ SocketAddr as StdSocketAddr, TcpListener as StdTcpListener, ToSocketAddrs, }; pub(crate) use mio::net::{TcpListener as MioTcpListener, TcpSocket as MioTcpSocket}; #[cfg(unix)] pub(crate) use { mio::net::UnixListener as MioUnixListener, std::os::unix::net::UnixListener as StdUnixListener, }; use std::{fmt, io}; use actix_rt::net::TcpStream; use mio::net::TcpStream as MioTcpStream; use mio::{event::Source, Interest, Registry, Token}; use crate::accept::{AcceptContext, Acceptable}; /// impl Acceptable trait for [mio::net::TcpListener] so it can be managed by server and it's [mio::Poll] instance. impl Acceptable for MioTcpListener { type Connection = MioTcpStream; fn accept( &mut self, _: &mut AcceptContext<'_, Self::Connection>, ) -> io::Result> { Self::accept(self).map(|stream| Some(stream.0)) } fn register(&mut self, registry: &mio::Registry, token: mio::Token) -> io::Result<()> { Source::register(self, registry, token, Interest::READABLE) } fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()> { Source::deregister(self, registry) } } pub enum MioListener { Tcp(MioTcpListener), #[cfg(unix)] Uds(MioUnixListener), } impl From for MioListener { fn from(lst: StdTcpListener) -> Self { MioListener::Tcp(MioTcpListener::from_std(lst)) } } impl Acceptable for MioListener { type Connection = MioStream; fn accept( &mut self, _: &mut AcceptContext<'_, Self::Connection>, ) -> io::Result> { match *self { MioListener::Tcp(ref mut lst) => { MioTcpListener::accept(lst).map(|stream| Some(MioStream::Tcp(stream.0))) } #[cfg(unix)] MioListener::Uds(ref mut lst) => { MioUnixListener::accept(lst).map(|stream| Some(MioStream::Uds(stream.0))) } } } fn register(&mut self, registry: &Registry, token: Token) -> io::Result<()> { match *self { MioListener::Tcp(ref mut lst) => { Source::register(lst, registry, token, Interest::READABLE) } #[cfg(unix)] MioListener::Uds(ref mut lst) => { Source::register(lst, registry, token, Interest::READABLE) } } } fn deregister(&mut self, registry: &Registry) -> io::Result<()> { match *self { MioListener::Tcp(ref mut lst) => Source::deregister(lst, registry), #[cfg(unix)] MioListener::Uds(ref mut lst) => { let res = Source::deregister(lst, registry); // cleanup file path if let Ok(addr) = lst.local_addr() { if let Some(path) = addr.as_pathname() { let _ = std::fs::remove_file(path); } } res } } } } impl fmt::Debug for MioListener { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { MioListener::Tcp(ref lst) => write!(f, "{:?}", lst), #[cfg(all(unix))] MioListener::Uds(ref lst) => write!(f, "{:?}", lst), } } } #[derive(Debug)] pub enum MioStream { Tcp(MioTcpStream), #[cfg(unix)] Uds(mio::net::UnixStream), } /// helper trait for converting mio stream to tokio stream. pub trait FromConnection: Sized { fn from_conn(conn: C) -> io::Result; } #[cfg(windows)] mod win_impl { use super::*; use std::os::windows::io::{FromRawSocket, IntoRawSocket}; // FIXME: This is a workaround and we need an efficient way to convert between mio and tokio stream impl FromConnection for TcpStream { fn from_conn(conn: MioTcpStream) -> io::Result { let raw = IntoRawSocket::into_raw_socket(conn); // SAFETY: This is a in place conversion from mio stream to tokio stream. TcpStream::from_std(unsafe { FromRawSocket::from_raw_socket(raw) }) } } impl FromConnection for TcpStream { fn from_conn(stream: MioStream) -> io::Result { match stream { MioStream::Tcp(tcp) => FromConnection::from_conn(tcp), } } } } #[cfg(unix)] mod unix_impl { use super::*; use std::os::unix::io::{FromRawFd, IntoRawFd}; use actix_rt::net::UnixStream; use mio::net::UnixStream as MioUnixStream; impl From for MioListener { fn from(lst: StdUnixListener) -> Self { MioListener::Uds(MioUnixListener::from_std(lst)) } } /// impl Acceptable trait for [mio::net::UnixListener] so it can be managed by server and it's [mio::Poll] instance. impl Acceptable for MioUnixListener { type Connection = MioUnixStream; fn accept( &mut self, _: &mut AcceptContext<'_, Self::Connection>, ) -> io::Result> { Self::accept(self).map(|stream| Some(stream.0)) } fn register(&mut self, registry: &mio::Registry, token: mio::Token) -> io::Result<()> { Source::register(self, registry, token, Interest::READABLE) } fn deregister(&mut self, registry: &mio::Registry) -> io::Result<()> { Source::deregister(self, registry) } } // FIXME: This is a workaround and we need an efficient way to convert between mio and tokio stream impl FromConnection for TcpStream { fn from_conn(conn: MioTcpStream) -> io::Result { let raw = IntoRawFd::into_raw_fd(conn); // SAFETY: This is a in place conversion from mio stream to tokio stream. TcpStream::from_std(unsafe { FromRawFd::from_raw_fd(raw) }) } } // FIXME: This is a workaround and we need an efficient way to convert between mio and tokio stream impl FromConnection for UnixStream { fn from_conn(conn: MioUnixStream) -> io::Result { let raw = IntoRawFd::into_raw_fd(conn); // SAFETY: This is a in place conversion from mio stream to tokio stream. UnixStream::from_std(unsafe { FromRawFd::from_raw_fd(raw) }) } } impl FromConnection for TcpStream { fn from_conn(stream: MioStream) -> io::Result { match stream { MioStream::Tcp(tcp) => FromConnection::from_conn(tcp), MioStream::Uds(_) => unreachable!("UnixStream can not convert to TcpStream"), } } } impl FromConnection for UnixStream { fn from_conn(stream: MioStream) -> io::Result { match stream { MioStream::Tcp(_) => unreachable!("TcpStream can not convert to UnixStream"), MioStream::Uds(uds) => FromConnection::from_conn(uds), } } } }