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