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