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};
1314use 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};
2122/// 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}
5152impl 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"))]
63pub fn bind(addr: SocketAddr) -> io::Result<TcpListener> {
64let socket = new_for_addr(addr)?;
65#[cfg(any(unix, target_os = "hermit"))]
66let listener = unsafe { TcpListener::from_raw_fd(socket) };
67#[cfg(windows)]
68let listener = unsafe { TcpListener::from_raw_socket(socket as _) };
6970// 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))]
78set_reuseaddr(&listener.inner, true)?;
7980 bind(&listener.inner, addr)?;
81 listen(&listener.inner, 1024)?;
82Ok(listener)
83 }
8485/// 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.
91pub fn from_std(listener: net::TcpListener) -> TcpListener {
92 TcpListener {
93 inner: IoSource::new(listener),
94 }
95 }
9697/// 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.
105pub fn accept(&self) -> io::Result<(TcpStream, SocketAddr)> {
106self.inner.do_io(|inner| {
107 sys::tcp::accept(inner).map(|(stream, addr)| (TcpStream::from_std(stream), addr))
108 })
109 }
110111/// Returns the local socket address of this listener.
112pub fn local_addr(&self) -> io::Result<SocketAddr> {
113self.inner.local_addr()
114 }
115116/// 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.
120pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
121self.inner.set_ttl(ttl)
122 }
123124/// 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
129pub fn ttl(&self) -> io::Result<u32> {
130self.inner.ttl()
131 }
132133/// 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.
138pub fn take_error(&self) -> io::Result<Option<io::Error>> {
139self.inner.take_error()
140 }
141}
142143impl event::Source for TcpListener {
144fn register(
145&mut self,
146 registry: &Registry,
147 token: Token,
148 interests: Interest,
149 ) -> io::Result<()> {
150self.inner.register(registry, token, interests)
151 }
152153fn reregister(
154&mut self,
155 registry: &Registry,
156 token: Token,
157 interests: Interest,
158 ) -> io::Result<()> {
159self.inner.reregister(registry, token, interests)
160 }
161162fn deregister(&mut self, registry: &Registry) -> io::Result<()> {
163self.inner.deregister(registry)
164 }
165}
166167impl fmt::Debug for TcpListener {
168fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
169self.inner.fmt(f)
170 }
171}
172173#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
174impl IntoRawFd for TcpListener {
175fn into_raw_fd(self) -> RawFd {
176self.inner.into_inner().into_raw_fd()
177 }
178}
179180#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
181impl AsRawFd for TcpListener {
182fn as_raw_fd(&self) -> RawFd {
183self.inner.as_raw_fd()
184 }
185}
186187#[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.
195unsafe fn from_raw_fd(fd: RawFd) -> TcpListener {
196 TcpListener::from_std(FromRawFd::from_raw_fd(fd))
197 }
198}
199200#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
201impl From<TcpListener> for OwnedFd {
202fn from(tcp_listener: TcpListener) -> Self {
203 tcp_listener.inner.into_inner().into()
204 }
205}
206207#[cfg(any(unix, target_os = "hermit", target_os = "wasi"))]
208impl AsFd for TcpListener {
209fn as_fd(&self) -> BorrowedFd<'_> {
210self.inner.as_fd()
211 }
212}
213214#[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.
222fn from(fd: OwnedFd) -> Self {
223 TcpListener::from_std(From::from(fd))
224 }
225}
226227#[cfg(windows)]
228impl IntoRawSocket for TcpListener {
229fn into_raw_socket(self) -> RawSocket {
230self.inner.into_inner().into_raw_socket()
231 }
232}
233234#[cfg(windows)]
235impl AsRawSocket for TcpListener {
236fn as_raw_socket(&self) -> RawSocket {
237self.inner.as_raw_socket()
238 }
239}
240241#[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.
249unsafe fn from_raw_socket(socket: RawSocket) -> TcpListener {
250 TcpListener::from_std(FromRawSocket::from_raw_socket(socket))
251 }
252}
253254#[cfg(windows)]
255impl From<TcpListener> for OwnedSocket {
256fn from(tcp_listener: TcpListener) -> Self {
257 tcp_listener.inner.into_inner().into()
258 }
259}
260261#[cfg(windows)]
262impl AsSocket for TcpListener {
263fn as_socket(&self) -> BorrowedSocket<'_> {
264self.inner.as_socket()
265 }
266}
267268#[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.
276fn from(socket: OwnedSocket) -> Self {
277 TcpListener::from_std(From::from(socket))
278 }
279}
280281impl From<TcpListener> for net::TcpListener {
282fn 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
286unsafe {
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}