1 pub(crate) use std::net::{ 2 SocketAddr as StdSocketAddr, TcpListener as StdTcpListener, ToSocketAddrs, 3 }; 4 5 pub(crate) use mio::net::{TcpListener as MioTcpListener, TcpSocket as MioTcpSocket}; 6 #[cfg(unix)] 7 pub(crate) use { 8 mio::net::UnixListener as MioUnixListener, 9 std::os::unix::net::UnixListener as StdUnixListener, 10 }; 11 12 use std::{fmt, io}; 13 14 use actix_rt::net::TcpStream; 15 use mio::{event::Source, Interest, Registry, Token}; 16 17 pub(crate) enum MioListener { 18 Tcp(MioTcpListener), 19 #[cfg(unix)] 20 Uds(MioUnixListener), 21 } 22 23 impl MioListener { local_addr(&self) -> SocketAddr24 pub(crate) fn local_addr(&self) -> SocketAddr { 25 match *self { 26 MioListener::Tcp(ref lst) => SocketAddr::Tcp(lst.local_addr().unwrap()), 27 #[cfg(unix)] 28 MioListener::Uds(ref lst) => SocketAddr::Uds(lst.local_addr().unwrap()), 29 } 30 } 31 accept(&self) -> io::Result<MioStream>32 pub(crate) fn accept(&self) -> io::Result<MioStream> { 33 match *self { 34 MioListener::Tcp(ref lst) => lst.accept().map(|(stream, _)| MioStream::Tcp(stream)), 35 #[cfg(unix)] 36 MioListener::Uds(ref lst) => lst.accept().map(|(stream, _)| MioStream::Uds(stream)), 37 } 38 } 39 } 40 41 impl Source for MioListener { register( &mut self, registry: &Registry, token: Token, interests: Interest, ) -> io::Result<()>42 fn register( 43 &mut self, 44 registry: &Registry, 45 token: Token, 46 interests: Interest, 47 ) -> io::Result<()> { 48 match *self { 49 MioListener::Tcp(ref mut lst) => lst.register(registry, token, interests), 50 #[cfg(unix)] 51 MioListener::Uds(ref mut lst) => lst.register(registry, token, interests), 52 } 53 } 54 reregister( &mut self, registry: &Registry, token: Token, interests: Interest, ) -> io::Result<()>55 fn reregister( 56 &mut self, 57 registry: &Registry, 58 token: Token, 59 interests: Interest, 60 ) -> io::Result<()> { 61 match *self { 62 MioListener::Tcp(ref mut lst) => lst.reregister(registry, token, interests), 63 #[cfg(unix)] 64 MioListener::Uds(ref mut lst) => lst.reregister(registry, token, interests), 65 } 66 } 67 deregister(&mut self, registry: &Registry) -> io::Result<()>68 fn deregister(&mut self, registry: &Registry) -> io::Result<()> { 69 match *self { 70 MioListener::Tcp(ref mut lst) => lst.deregister(registry), 71 #[cfg(unix)] 72 MioListener::Uds(ref mut lst) => { 73 let res = lst.deregister(registry); 74 75 // cleanup file path 76 if let Ok(addr) = lst.local_addr() { 77 if let Some(path) = addr.as_pathname() { 78 let _ = std::fs::remove_file(path); 79 } 80 } 81 res 82 } 83 } 84 } 85 } 86 87 impl From<StdTcpListener> for MioListener { from(lst: StdTcpListener) -> Self88 fn from(lst: StdTcpListener) -> Self { 89 MioListener::Tcp(MioTcpListener::from_std(lst)) 90 } 91 } 92 93 #[cfg(unix)] 94 impl From<StdUnixListener> for MioListener { from(lst: StdUnixListener) -> Self95 fn from(lst: StdUnixListener) -> Self { 96 MioListener::Uds(MioUnixListener::from_std(lst)) 97 } 98 } 99 100 impl fmt::Debug for MioListener { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result101 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 102 match *self { 103 MioListener::Tcp(ref lst) => write!(f, "{:?}", lst), 104 #[cfg(all(unix))] 105 MioListener::Uds(ref lst) => write!(f, "{:?}", lst), 106 } 107 } 108 } 109 110 impl fmt::Display for MioListener { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result111 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 112 match *self { 113 MioListener::Tcp(ref lst) => write!(f, "{}", lst.local_addr().ok().unwrap()), 114 #[cfg(unix)] 115 MioListener::Uds(ref lst) => write!(f, "{:?}", lst.local_addr().ok().unwrap()), 116 } 117 } 118 } 119 120 pub(crate) enum SocketAddr { 121 Tcp(StdSocketAddr), 122 #[cfg(unix)] 123 Uds(mio::net::SocketAddr), 124 } 125 126 impl fmt::Display for SocketAddr { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result127 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 128 match *self { 129 SocketAddr::Tcp(ref addr) => write!(f, "{}", addr), 130 #[cfg(unix)] 131 SocketAddr::Uds(ref addr) => write!(f, "{:?}", addr), 132 } 133 } 134 } 135 136 impl fmt::Debug for SocketAddr { fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result137 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 138 match *self { 139 SocketAddr::Tcp(ref addr) => write!(f, "{:?}", addr), 140 #[cfg(unix)] 141 SocketAddr::Uds(ref addr) => write!(f, "{:?}", addr), 142 } 143 } 144 } 145 146 #[derive(Debug)] 147 pub enum MioStream { 148 Tcp(mio::net::TcpStream), 149 #[cfg(unix)] 150 Uds(mio::net::UnixStream), 151 } 152 153 /// helper trait for converting mio stream to tokio stream. 154 pub trait FromStream: Sized { from_mio(sock: MioStream) -> io::Result<Self>155 fn from_mio(sock: MioStream) -> io::Result<Self>; 156 } 157 158 #[cfg(windows)] 159 mod win_impl { 160 use super::*; 161 162 use std::os::windows::io::{FromRawSocket, IntoRawSocket}; 163 164 // FIXME: This is a workaround and we need an efficient way to convert between mio and tokio stream 165 impl FromStream for TcpStream { from_mio(sock: MioStream) -> io::Result<Self>166 fn from_mio(sock: MioStream) -> io::Result<Self> { 167 match sock { 168 MioStream::Tcp(mio) => { 169 let raw = IntoRawSocket::into_raw_socket(mio); 170 // SAFETY: This is a in place conversion from mio stream to tokio stream. 171 TcpStream::from_std(unsafe { FromRawSocket::from_raw_socket(raw) }) 172 } 173 } 174 } 175 } 176 } 177 178 #[cfg(unix)] 179 mod unix_impl { 180 use super::*; 181 182 use std::os::unix::io::{FromRawFd, IntoRawFd}; 183 184 use actix_rt::net::UnixStream; 185 186 // FIXME: This is a workaround and we need an efficient way to convert between mio and tokio stream 187 impl FromStream for TcpStream { from_mio(sock: MioStream) -> io::Result<Self>188 fn from_mio(sock: MioStream) -> io::Result<Self> { 189 match sock { 190 MioStream::Tcp(mio) => { 191 let raw = IntoRawFd::into_raw_fd(mio); 192 // SAFETY: This is a in place conversion from mio stream to tokio stream. 193 TcpStream::from_std(unsafe { FromRawFd::from_raw_fd(raw) }) 194 } 195 MioStream::Uds(_) => { 196 panic!("Should not happen, bug in server impl"); 197 } 198 } 199 } 200 } 201 202 // FIXME: This is a workaround and we need an efficient way to convert between mio and tokio stream 203 impl FromStream for UnixStream { from_mio(sock: MioStream) -> io::Result<Self>204 fn from_mio(sock: MioStream) -> io::Result<Self> { 205 match sock { 206 MioStream::Tcp(_) => panic!("Should not happen, bug in server impl"), 207 MioStream::Uds(mio) => { 208 let raw = IntoRawFd::into_raw_fd(mio); 209 // SAFETY: This is a in place conversion from mio stream to tokio stream. 210 UnixStream::from_std(unsafe { FromRawFd::from_raw_fd(raw) }) 211 } 212 } 213 } 214 } 215 } 216 217 #[cfg(test)] 218 mod tests { 219 use super::*; 220 221 #[test] socket_addr()222 fn socket_addr() { 223 let addr = SocketAddr::Tcp("127.0.0.1:8080".parse().unwrap()); 224 assert!(format!("{:?}", addr).contains("127.0.0.1:8080")); 225 assert_eq!(format!("{}", addr), "127.0.0.1:8080"); 226 227 let addr: StdSocketAddr = "127.0.0.1:0".parse().unwrap(); 228 let socket = MioTcpSocket::new_v4().unwrap(); 229 socket.set_reuseaddr(true).unwrap(); 230 socket.bind(addr).unwrap(); 231 let tcp = socket.listen(128).unwrap(); 232 let lst = MioListener::Tcp(tcp); 233 assert!(format!("{:?}", lst).contains("TcpListener")); 234 assert!(format!("{}", lst).contains("127.0.0.1")); 235 } 236 237 #[test] 238 #[cfg(unix)] uds()239 fn uds() { 240 let _ = std::fs::remove_file("/tmp/sock.xxxxx"); 241 if let Ok(socket) = MioUnixListener::bind("/tmp/sock.xxxxx") { 242 let addr = socket.local_addr().expect("Couldn't get local address"); 243 let a = SocketAddr::Uds(addr); 244 assert!(format!("{:?}", a).contains("/tmp/sock.xxxxx")); 245 assert!(format!("{}", a).contains("/tmp/sock.xxxxx")); 246 247 let lst = MioListener::Uds(socket); 248 assert!(format!("{:?}", lst).contains("/tmp/sock.xxxxx")); 249 assert!(format!("{}", lst).contains("/tmp/sock.xxxxx")); 250 } 251 } 252 } 253