mio/net/tcp/
listener.rs

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