1 | use std::net::{self, SocketAddr}; |
2 | #[cfg (any(unix, target_os = "wasi" ))] |
3 | use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; |
4 | // TODO: once <https://github.com/rust-lang/rust/issues/126198> is fixed this |
5 | // can use `std::os::fd` and be merged with the above. |
6 | #[cfg (target_os = "hermit" )] |
7 | use std::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; |
8 | #[cfg (windows)] |
9 | use std::os::windows::io::{ |
10 | AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, |
11 | }; |
12 | use std::{fmt, io}; |
13 | |
14 | use crate::io_source::IoSource; |
15 | use crate::net::TcpStream; |
16 | #[cfg (any(unix, target_os = "hermit" ))] |
17 | use crate::sys::tcp::set_reuseaddr; |
18 | #[cfg (not(target_os = "wasi" ))] |
19 | use crate::sys::tcp::{bind, listen, new_for_addr}; |
20 | use crate::{event, sys, Interest, Registry, Token}; |
21 | |
22 | /// A structure representing a socket server |
23 | /// |
24 | /// # Examples |
25 | /// |
26 | #[cfg_attr (feature = "os-poll" , doc = "```" )] |
27 | #[cfg_attr (not(feature = "os-poll" ), doc = "```ignore" )] |
28 | /// # use std::error::Error; |
29 | /// # fn main() -> Result<(), Box<dyn Error>> { |
30 | /// use mio::{Events, Interest, Poll, Token}; |
31 | /// use mio::net::TcpListener; |
32 | /// use std::time::Duration; |
33 | /// |
34 | /// let mut listener = TcpListener::bind("127.0.0.1:34255" .parse()?)?; |
35 | /// |
36 | /// let mut poll = Poll::new()?; |
37 | /// let mut events = Events::with_capacity(128); |
38 | /// |
39 | /// // Register the socket with `Poll` |
40 | /// poll.registry().register(&mut listener, Token(0), Interest::READABLE)?; |
41 | /// |
42 | /// poll.poll(&mut events, Some(Duration::from_millis(100)))?; |
43 | /// |
44 | /// // There may be a socket ready to be accepted |
45 | /// # Ok(()) |
46 | /// # } |
47 | /// ``` |
48 | pub struct TcpListener { |
49 | inner: IoSource<net::TcpListener>, |
50 | } |
51 | |
52 | impl TcpListener { |
53 | /// Convenience method to bind a new TCP listener to the specified address |
54 | /// to receive new connections. |
55 | /// |
56 | /// This function will take the following steps: |
57 | /// |
58 | /// 1. Create a new TCP socket. |
59 | /// 2. Set the `SO_REUSEADDR` option on the socket on Unix. |
60 | /// 3. Bind the socket to the specified address. |
61 | /// 4. Calls `listen` on the socket to prepare it to receive new connections. |
62 | #[cfg (not(target_os = "wasi" ))] |
63 | pub fn bind(addr: SocketAddr) -> io::Result<TcpListener> { |
64 | let socket = new_for_addr(addr)?; |
65 | #[cfg (any(unix, target_os = "hermit" ))] |
66 | let listener = unsafe { TcpListener::from_raw_fd(socket) }; |
67 | #[cfg (windows)] |
68 | let listener = unsafe { TcpListener::from_raw_socket(socket as _) }; |
69 | |
70 | // On platforms with Berkeley-derived sockets, this allows to quickly |
71 | // rebind a socket, without needing to wait for the OS to clean up the |
72 | // previous one. |
73 | // |
74 | // On Windows, this allows rebinding sockets which are actively in use, |
75 | // which allows “socket hijacking”, so we explicitly don't set it here. |
76 | // https://docs.microsoft.com/en-us/windows/win32/winsock/using-so-reuseaddr-and-so-exclusiveaddruse |
77 | #[cfg (not(windows))] |
78 | set_reuseaddr(&listener.inner, true)?; |
79 | |
80 | bind(&listener.inner, addr)?; |
81 | listen(&listener.inner, 1024)?; |
82 | Ok(listener) |
83 | } |
84 | |
85 | /// Creates a new `TcpListener` from a standard `net::TcpListener`. |
86 | /// |
87 | /// This function is intended to be used to wrap a TCP listener from the |
88 | /// standard library in the Mio equivalent. The conversion assumes nothing |
89 | /// about the underlying listener; ; it is left up to the user to set it |
90 | /// in non-blocking mode. |
91 | pub fn from_std(listener: net::TcpListener) -> TcpListener { |
92 | TcpListener { |
93 | inner: IoSource::new(listener), |
94 | } |
95 | } |
96 | |
97 | /// Accepts a new `TcpStream`. |
98 | /// |
99 | /// This may return an `Err(e)` where `e.kind()` is |
100 | /// `io::ErrorKind::WouldBlock`. This means a stream may be ready at a later |
101 | /// point and one should wait for an event before calling `accept` again. |
102 | /// |
103 | /// If an accepted stream is returned, the remote address of the peer is |
104 | /// returned along with it. |
105 | pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> { |
106 | self.inner.do_io(|inner| { |
107 | sys::tcp::accept(inner).map(|(stream, addr)| (TcpStream::from_std(stream), addr)) |
108 | }) |
109 | } |
110 | |
111 | /// Returns the local socket address of this listener. |
112 | pub fn local_addr(&self) -> io::Result<SocketAddr> { |
113 | self.inner.local_addr() |
114 | } |
115 | |
116 | /// Sets the value for the `IP_TTL` option on this socket. |
117 | /// |
118 | /// This value sets the time-to-live field that is used in every packet sent |
119 | /// from this socket. |
120 | pub fn set_ttl(&self, ttl: u32) -> io::Result<()> { |
121 | self.inner.set_ttl(ttl) |
122 | } |
123 | |
124 | /// Gets the value of the `IP_TTL` option for this socket. |
125 | /// |
126 | /// For more information about this option, see [`set_ttl`][link]. |
127 | /// |
128 | /// [link]: #method.set_ttl |
129 | pub fn ttl(&self) -> io::Result<u32> { |
130 | self.inner.ttl() |
131 | } |
132 | |
133 | /// Get the value of the `SO_ERROR` option on this socket. |
134 | /// |
135 | /// This will retrieve the stored error in the underlying socket, clearing |
136 | /// the field in the process. This can be useful for checking errors between |
137 | /// calls. |
138 | pub fn take_error(&self) -> io::Result<Option<io::Error>> { |
139 | self.inner.take_error() |
140 | } |
141 | } |
142 | |
143 | impl event::Source for TcpListener { |
144 | fn register( |
145 | &mut self, |
146 | registry: &Registry, |
147 | token: Token, |
148 | interests: Interest, |
149 | ) -> io::Result<()> { |
150 | self.inner.register(registry, token, interests) |
151 | } |
152 | |
153 | fn reregister( |
154 | &mut self, |
155 | registry: &Registry, |
156 | token: Token, |
157 | interests: Interest, |
158 | ) -> io::Result<()> { |
159 | self.inner.reregister(registry, token, interests) |
160 | } |
161 | |
162 | fn deregister(&mut self, registry: &Registry) -> io::Result<()> { |
163 | self.inner.deregister(registry) |
164 | } |
165 | } |
166 | |
167 | impl fmt::Debug for TcpListener { |
168 | fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { |
169 | self.inner.fmt(f) |
170 | } |
171 | } |
172 | |
173 | #[cfg (any(unix, target_os = "hermit" , target_os = "wasi" ))] |
174 | impl IntoRawFd for TcpListener { |
175 | fn into_raw_fd(self) -> RawFd { |
176 | self.inner.into_inner().into_raw_fd() |
177 | } |
178 | } |
179 | |
180 | #[cfg (any(unix, target_os = "hermit" , target_os = "wasi" ))] |
181 | impl AsRawFd for TcpListener { |
182 | fn as_raw_fd(&self) -> RawFd { |
183 | self.inner.as_raw_fd() |
184 | } |
185 | } |
186 | |
187 | #[cfg (any(unix, target_os = "hermit" , target_os = "wasi" ))] |
188 | impl FromRawFd for TcpListener { |
189 | /// Converts a `RawFd` to a `TcpListener`. |
190 | /// |
191 | /// # Notes |
192 | /// |
193 | /// The caller is responsible for ensuring that the socket is in |
194 | /// non-blocking mode. |
195 | unsafe fn from_raw_fd(fd: RawFd) -> TcpListener { |
196 | TcpListener::from_std(listener:FromRawFd::from_raw_fd(fd)) |
197 | } |
198 | } |
199 | |
200 | #[cfg (any(unix, target_os = "hermit" , target_os = "wasi" ))] |
201 | impl From<TcpListener> for OwnedFd { |
202 | fn from(tcp_listener: TcpListener) -> Self { |
203 | tcp_listener.inner.into_inner().into() |
204 | } |
205 | } |
206 | |
207 | #[cfg (any(unix, target_os = "hermit" , target_os = "wasi" ))] |
208 | impl AsFd for TcpListener { |
209 | fn as_fd(&self) -> BorrowedFd<'_> { |
210 | self.inner.as_fd() |
211 | } |
212 | } |
213 | |
214 | #[cfg (any(unix, target_os = "hermit" , target_os = "wasi" ))] |
215 | impl From<OwnedFd> for TcpListener { |
216 | /// Converts a `RawFd` to a `TcpListener`. |
217 | /// |
218 | /// # Notes |
219 | /// |
220 | /// The caller is responsible for ensuring that the socket is in |
221 | /// non-blocking mode. |
222 | fn from(fd: OwnedFd) -> Self { |
223 | TcpListener::from_std(listener:From::from(fd)) |
224 | } |
225 | } |
226 | |
227 | #[cfg (windows)] |
228 | impl IntoRawSocket for TcpListener { |
229 | fn into_raw_socket(self) -> RawSocket { |
230 | self.inner.into_inner().into_raw_socket() |
231 | } |
232 | } |
233 | |
234 | #[cfg (windows)] |
235 | impl AsRawSocket for TcpListener { |
236 | fn as_raw_socket(&self) -> RawSocket { |
237 | self.inner.as_raw_socket() |
238 | } |
239 | } |
240 | |
241 | #[cfg (windows)] |
242 | impl FromRawSocket for TcpListener { |
243 | /// Converts a `RawSocket` to a `TcpListener`. |
244 | /// |
245 | /// # Notes |
246 | /// |
247 | /// The caller is responsible for ensuring that the socket is in |
248 | /// non-blocking mode. |
249 | unsafe fn from_raw_socket(socket: RawSocket) -> TcpListener { |
250 | TcpListener::from_std(FromRawSocket::from_raw_socket(socket)) |
251 | } |
252 | } |
253 | |
254 | #[cfg (windows)] |
255 | impl From<TcpListener> for OwnedSocket { |
256 | fn from(tcp_listener: TcpListener) -> Self { |
257 | tcp_listener.inner.into_inner().into() |
258 | } |
259 | } |
260 | |
261 | #[cfg (windows)] |
262 | impl AsSocket for TcpListener { |
263 | fn as_socket(&self) -> BorrowedSocket<'_> { |
264 | self.inner.as_socket() |
265 | } |
266 | } |
267 | |
268 | #[cfg (windows)] |
269 | impl From<OwnedSocket> for TcpListener { |
270 | /// Converts a `RawSocket` to a `TcpListener`. |
271 | /// |
272 | /// # Notes |
273 | /// |
274 | /// The caller is responsible for ensuring that the socket is in |
275 | /// non-blocking mode. |
276 | fn from(socket: OwnedSocket) -> Self { |
277 | TcpListener::from_std(From::from(socket)) |
278 | } |
279 | } |
280 | |
281 | impl From<TcpListener> for net::TcpListener { |
282 | fn from(listener: TcpListener) -> Self { |
283 | // Safety: This is safe since we are extracting the raw fd from a well-constructed |
284 | // mio::net::TcpListener which ensures that we actually pass in a valid file |
285 | // descriptor/socket |
286 | unsafe { |
287 | #[cfg (any(unix, target_os = "hermit" , target_os = "wasi" ))] |
288 | { |
289 | net::TcpListener::from_raw_fd(listener.into_raw_fd()) |
290 | } |
291 | #[cfg (windows)] |
292 | { |
293 | net::TcpListener::from_raw_socket(listener.into_raw_socket()) |
294 | } |
295 | } |
296 | } |
297 | } |
298 | |