1 | use std::net::{self, SocketAddr}; |
2 | #[cfg (unix)] |
3 | use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; |
4 | #[cfg (target_os = "wasi" )] |
5 | use std::os::wasi::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; |
6 | #[cfg (windows)] |
7 | use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; |
8 | use std::{fmt, io}; |
9 | |
10 | use crate::io_source::IoSource; |
11 | use crate::net::TcpStream; |
12 | #[cfg (unix)] |
13 | use crate::sys::tcp::set_reuseaddr; |
14 | #[cfg (not(target_os = "wasi" ))] |
15 | use crate::sys::tcp::{bind, listen, new_for_addr}; |
16 | use 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 | /// ``` |
44 | pub struct TcpListener { |
45 | inner: IoSource<net::TcpListener>, |
46 | } |
47 | |
48 | impl 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 | |
139 | impl 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 | |
163 | impl 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)] |
170 | impl IntoRawFd for TcpListener { |
171 | fn into_raw_fd(self) -> RawFd { |
172 | self.inner.into_inner().into_raw_fd() |
173 | } |
174 | } |
175 | |
176 | #[cfg (unix)] |
177 | impl AsRawFd for TcpListener { |
178 | fn as_raw_fd(&self) -> RawFd { |
179 | self.inner.as_raw_fd() |
180 | } |
181 | } |
182 | |
183 | #[cfg (unix)] |
184 | impl 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(listener:FromRawFd::from_raw_fd(fd)) |
193 | } |
194 | } |
195 | |
196 | #[cfg (windows)] |
197 | impl IntoRawSocket for TcpListener { |
198 | fn into_raw_socket(self) -> RawSocket { |
199 | self.inner.into_inner().into_raw_socket() |
200 | } |
201 | } |
202 | |
203 | #[cfg (windows)] |
204 | impl AsRawSocket for TcpListener { |
205 | fn as_raw_socket(&self) -> RawSocket { |
206 | self.inner.as_raw_socket() |
207 | } |
208 | } |
209 | |
210 | #[cfg (windows)] |
211 | impl 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" )] |
224 | impl 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" )] |
231 | impl AsRawFd for TcpListener { |
232 | fn as_raw_fd(&self) -> RawFd { |
233 | self.inner.as_raw_fd() |
234 | } |
235 | } |
236 | |
237 | #[cfg (target_os = "wasi" )] |
238 | impl 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 | } |
249 | |