mio/net/tcp/
listener.rs

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