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