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(listener: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(listener: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}
298