| 1 | use std::net::{self, SocketAddr}; |
| 2 | #[cfg (any(unix, target_os = "wasi" ))] |
| 3 | use 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" )] |
| 7 | use std::os::hermit::io::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd}; |
| 8 | #[cfg (windows)] |
| 9 | use std::os::windows::io::{ |
| 10 | AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket, |
| 11 | }; |
| 12 | use std::{fmt, io}; |
| 13 | |
| 14 | use crate::io_source::IoSource; |
| 15 | use crate::net::TcpStream; |
| 16 | #[cfg (any(unix, target_os = "hermit" ))] |
| 17 | use crate::sys::tcp::set_reuseaddr; |
| 18 | #[cfg (not(target_os = "wasi" ))] |
| 19 | use crate::sys::tcp::{bind, listen, new_for_addr}; |
| 20 | use 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 | /// ``` |
| 48 | pub struct TcpListener { |
| 49 | inner: IoSource<net::TcpListener>, |
| 50 | } |
| 51 | |
| 52 | impl 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 | |
| 143 | impl 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 | |
| 167 | impl 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" ))] |
| 174 | impl 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" ))] |
| 181 | impl 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" ))] |
| 188 | impl 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" ))] |
| 201 | impl 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" ))] |
| 208 | impl 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" ))] |
| 215 | impl 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)] |
| 228 | impl IntoRawSocket for TcpListener { |
| 229 | fn into_raw_socket(self) -> RawSocket { |
| 230 | self.inner.into_inner().into_raw_socket() |
| 231 | } |
| 232 | } |
| 233 | |
| 234 | #[cfg (windows)] |
| 235 | impl AsRawSocket for TcpListener { |
| 236 | fn as_raw_socket(&self) -> RawSocket { |
| 237 | self.inner.as_raw_socket() |
| 238 | } |
| 239 | } |
| 240 | |
| 241 | #[cfg (windows)] |
| 242 | impl 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)] |
| 255 | impl From<TcpListener> for OwnedSocket { |
| 256 | fn from(tcp_listener: TcpListener) -> Self { |
| 257 | tcp_listener.inner.into_inner().into() |
| 258 | } |
| 259 | } |
| 260 | |
| 261 | #[cfg (windows)] |
| 262 | impl AsSocket for TcpListener { |
| 263 | fn as_socket(&self) -> BorrowedSocket<'_> { |
| 264 | self.inner.as_socket() |
| 265 | } |
| 266 | } |
| 267 | |
| 268 | #[cfg (windows)] |
| 269 | impl 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 | |
| 281 | impl 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 | |