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(unix, target_os = "hermit"))]
17use crate::sys::tcp::set_reuseaddr;
18#[cfg(not(target_os = "wasi"))]
19use crate::sys::tcp::{bind, listen, new_for_addr};
20use 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/// ```
48pub struct TcpListener {
49    inner: IoSource<net::TcpListener>,
50}
51
52impl 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
143impl 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
167impl 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"))]
174impl 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"))]
181impl 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"))]
188impl 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(FromRawFd::from_raw_fd(fd))
197    }
198}
199
200#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
201impl 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"))]
208impl 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"))]
215impl 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(From::from(fd))
224    }
225}
226
227#[cfg(windows)]
228impl IntoRawSocket for TcpListener {
229    fn into_raw_socket(self) -> RawSocket {
230        self.inner.into_inner().into_raw_socket()
231    }
232}
233
234#[cfg(windows)]
235impl AsRawSocket for TcpListener {
236    fn as_raw_socket(&self) -> RawSocket {
237        self.inner.as_raw_socket()
238    }
239}
240
241#[cfg(windows)]
242impl 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)]
255impl From<TcpListener> for OwnedSocket {
256    fn from(tcp_listener: TcpListener) -> Self {
257        tcp_listener.inner.into_inner().into()
258    }
259}
260
261#[cfg(windows)]
262impl AsSocket for TcpListener {
263    fn as_socket(&self) -> BorrowedSocket<'_> {
264        self.inner.as_socket()
265    }
266}
267
268#[cfg(windows)]
269impl 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
281impl 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}