1 use std::io; 2 use std::mem; 3 use std::net::SocketAddr; 4 #[cfg(unix)] 5 use std::os::unix::io::{AsRawFd, FromRawFd, IntoRawFd, RawFd}; 6 #[cfg(windows)] 7 use std::os::windows::io::{AsRawSocket, FromRawSocket, IntoRawSocket, RawSocket}; 8 use std::time::Duration; 9 10 use crate::net::{TcpListener, TcpStream}; 11 use crate::sys; 12 13 /// A non-blocking TCP socket used to configure a stream or listener. 14 /// 15 /// The `TcpSocket` type wraps the operating-system's socket handle. This type 16 /// is used to configure the socket before establishing a connection or start 17 /// listening for inbound connections. 18 /// 19 /// The socket will be closed when the value is dropped. 20 #[derive(Debug)] 21 pub struct TcpSocket { 22 sys: sys::tcp::TcpSocket, 23 } 24 25 /// Configures a socket's TCP keepalive parameters. 26 #[derive(Debug, Default, Clone)] 27 pub struct TcpKeepalive { 28 pub(crate) time: Option<Duration>, 29 #[cfg(any( 30 target_os = "linux", 31 target_os = "macos", 32 target_os = "ios", 33 target_os = "freebsd", 34 target_os = "netbsd", 35 target_os = "windows", 36 ))] 37 pub(crate) interval: Option<Duration>, 38 #[cfg(any( 39 target_os = "linux", 40 target_os = "macos", 41 target_os = "ios", 42 target_os = "freebsd", 43 target_os = "netbsd", 44 ))] 45 pub(crate) retries: Option<u32>, 46 } 47 48 impl TcpSocket { 49 /// Create a new IPv4 TCP socket. 50 /// 51 /// This calls `socket(2)`. new_v4() -> io::Result<TcpSocket>52 pub fn new_v4() -> io::Result<TcpSocket> { 53 sys::tcp::new_v4_socket().map(|sys| TcpSocket { sys }) 54 } 55 56 /// Create a new IPv6 TCP socket. 57 /// 58 /// This calls `socket(2)`. new_v6() -> io::Result<TcpSocket>59 pub fn new_v6() -> io::Result<TcpSocket> { 60 sys::tcp::new_v6_socket().map(|sys| TcpSocket { sys }) 61 } 62 new_for_addr(addr: SocketAddr) -> io::Result<TcpSocket>63 pub(crate) fn new_for_addr(addr: SocketAddr) -> io::Result<TcpSocket> { 64 if addr.is_ipv4() { 65 TcpSocket::new_v4() 66 } else { 67 TcpSocket::new_v6() 68 } 69 } 70 71 /// Bind `addr` to the TCP socket. bind(&self, addr: SocketAddr) -> io::Result<()>72 pub fn bind(&self, addr: SocketAddr) -> io::Result<()> { 73 sys::tcp::bind(self.sys, addr) 74 } 75 76 /// Connect the socket to `addr`. 77 /// 78 /// This consumes the socket and performs the connect operation. Once the 79 /// connection completes, the socket is now a non-blocking `TcpStream` and 80 /// can be used as such. connect(self, addr: SocketAddr) -> io::Result<TcpStream>81 pub fn connect(self, addr: SocketAddr) -> io::Result<TcpStream> { 82 let stream = sys::tcp::connect(self.sys, addr)?; 83 84 // Don't close the socket 85 mem::forget(self); 86 Ok(TcpStream::from_std(stream)) 87 } 88 89 /// Listen for inbound connections, converting the socket to a 90 /// `TcpListener`. listen(self, backlog: u32) -> io::Result<TcpListener>91 pub fn listen(self, backlog: u32) -> io::Result<TcpListener> { 92 let listener = sys::tcp::listen(self.sys, backlog)?; 93 94 // Don't close the socket 95 mem::forget(self); 96 Ok(TcpListener::from_std(listener)) 97 } 98 99 /// Sets the value of `SO_REUSEADDR` on this socket. set_reuseaddr(&self, reuseaddr: bool) -> io::Result<()>100 pub fn set_reuseaddr(&self, reuseaddr: bool) -> io::Result<()> { 101 sys::tcp::set_reuseaddr(self.sys, reuseaddr) 102 } 103 104 /// Get the value of `SO_REUSEADDR` set on this socket. get_reuseaddr(&self) -> io::Result<bool>105 pub fn get_reuseaddr(&self) -> io::Result<bool> { 106 sys::tcp::get_reuseaddr(self.sys) 107 } 108 109 /// Sets the value of `SO_REUSEPORT` on this socket. 110 /// Only supported available in unix 111 #[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))] set_reuseport(&self, reuseport: bool) -> io::Result<()>112 pub fn set_reuseport(&self, reuseport: bool) -> io::Result<()> { 113 sys::tcp::set_reuseport(self.sys, reuseport) 114 } 115 116 /// Get the value of `SO_REUSEPORT` set on this socket. 117 /// Only supported available in unix 118 #[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))] get_reuseport(&self) -> io::Result<bool>119 pub fn get_reuseport(&self) -> io::Result<bool> { 120 sys::tcp::get_reuseport(self.sys) 121 } 122 123 /// Sets the value of `SO_LINGER` on this socket. set_linger(&self, dur: Option<Duration>) -> io::Result<()>124 pub fn set_linger(&self, dur: Option<Duration>) -> io::Result<()> { 125 sys::tcp::set_linger(self.sys, dur) 126 } 127 128 /// Gets the value of `SO_LINGER` on this socket get_linger(&self) -> io::Result<Option<Duration>>129 pub fn get_linger(&self) -> io::Result<Option<Duration>> { 130 sys::tcp::get_linger(self.sys) 131 } 132 133 /// Sets the value of `SO_RCVBUF` on this socket. set_recv_buffer_size(&self, size: u32) -> io::Result<()>134 pub fn set_recv_buffer_size(&self, size: u32) -> io::Result<()> { 135 sys::tcp::set_recv_buffer_size(self.sys, size) 136 } 137 138 /// Get the value of `SO_RCVBUF` set on this socket. 139 /// 140 /// Note that if [`set_recv_buffer_size`] has been called on this socket 141 /// previously, the value returned by this function may not be the same as 142 /// the argument provided to `set_recv_buffer_size`. This is for the 143 /// following reasons: 144 /// 145 /// * Most operating systems have minimum and maximum allowed sizes for the 146 /// receive buffer, and will clamp the provided value if it is below the 147 /// minimum or above the maximum. The minimum and maximum buffer sizes are 148 /// OS-dependent. 149 /// * Linux will double the buffer size to account for internal bookkeeping 150 /// data, and returns the doubled value from `getsockopt(2)`. As per `man 151 /// 7 socket`: 152 /// > Sets or gets the maximum socket receive buffer in bytes. The 153 /// > kernel doubles this value (to allow space for bookkeeping 154 /// > overhead) when it is set using `setsockopt(2)`, and this doubled 155 /// > value is returned by `getsockopt(2)`. 156 /// 157 /// [`set_recv_buffer_size`]: #method.set_recv_buffer_size get_recv_buffer_size(&self) -> io::Result<u32>158 pub fn get_recv_buffer_size(&self) -> io::Result<u32> { 159 sys::tcp::get_recv_buffer_size(self.sys) 160 } 161 162 /// Sets the value of `SO_SNDBUF` on this socket. set_send_buffer_size(&self, size: u32) -> io::Result<()>163 pub fn set_send_buffer_size(&self, size: u32) -> io::Result<()> { 164 sys::tcp::set_send_buffer_size(self.sys, size) 165 } 166 167 /// Get the value of `SO_SNDBUF` set on this socket. 168 /// 169 /// Note that if [`set_send_buffer_size`] has been called on this socket 170 /// previously, the value returned by this function may not be the same as 171 /// the argument provided to `set_send_buffer_size`. This is for the 172 /// following reasons: 173 /// 174 /// * Most operating systems have minimum and maximum allowed sizes for the 175 /// receive buffer, and will clamp the provided value if it is below the 176 /// minimum or above the maximum. The minimum and maximum buffer sizes are 177 /// OS-dependent. 178 /// * Linux will double the buffer size to account for internal bookkeeping 179 /// data, and returns the doubled value from `getsockopt(2)`. As per `man 180 /// 7 socket`: 181 /// > Sets or gets the maximum socket send buffer in bytes. The 182 /// > kernel doubles this value (to allow space for bookkeeping 183 /// > overhead) when it is set using `setsockopt(2)`, and this doubled 184 /// > value is returned by `getsockopt(2)`. 185 /// 186 /// [`set_send_buffer_size`]: #method.set_send_buffer_size get_send_buffer_size(&self) -> io::Result<u32>187 pub fn get_send_buffer_size(&self) -> io::Result<u32> { 188 sys::tcp::get_send_buffer_size(self.sys) 189 } 190 191 /// Sets whether keepalive messages are enabled to be sent on this socket. 192 /// 193 /// This will set the `SO_KEEPALIVE` option on this socket. set_keepalive(&self, keepalive: bool) -> io::Result<()>194 pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> { 195 sys::tcp::set_keepalive(self.sys, keepalive) 196 } 197 198 /// Returns whether or not TCP keepalive probes will be sent by this socket. get_keepalive(&self) -> io::Result<bool>199 pub fn get_keepalive(&self) -> io::Result<bool> { 200 sys::tcp::get_keepalive(self.sys) 201 } 202 203 /// Sets parameters configuring TCP keepalive probes for this socket. 204 /// 205 /// The supported parameters depend on the operating system, and are 206 /// configured using the [`TcpKeepalive`] struct. At a minimum, all systems 207 /// support configuring the [keepalive time]: the time after which the OS 208 /// will start sending keepalive messages on an idle connection. 209 /// 210 /// # Notes 211 /// 212 /// * This will enable TCP keepalive on this socket, if it is not already 213 /// enabled. 214 /// * On some platforms, such as Windows, any keepalive parameters *not* 215 /// configured by the `TcpKeepalive` struct passed to this function may be 216 /// overwritten with their default values. Therefore, this function should 217 /// either only be called once per socket, or the same parameters should 218 /// be passed every time it is called. 219 /// 220 /// # Examples 221 #[cfg_attr(feature = "os-poll", doc = "```")] 222 #[cfg_attr(not(feature = "os-poll"), doc = "```ignore")] 223 /// use mio::net::{TcpSocket, TcpKeepalive}; 224 /// use std::time::Duration; 225 /// 226 /// # fn main() -> Result<(), std::io::Error> { 227 /// let socket = TcpSocket::new_v6()?; 228 /// let keepalive = TcpKeepalive::default() 229 /// .with_time(Duration::from_secs(4)); 230 /// // Depending on the target operating system, we may also be able to 231 /// // configure the keepalive probe interval and/or the number of retries 232 /// // here as well. 233 /// 234 /// socket.set_keepalive_params(keepalive)?; 235 /// # Ok(()) } 236 /// ``` 237 /// 238 /// [`TcpKeepalive`]: ../struct.TcpKeepalive.html 239 /// [keepalive time]: ../struct.TcpKeepalive.html#method.with_time set_keepalive_params(&self, keepalive: TcpKeepalive) -> io::Result<()>240 pub fn set_keepalive_params(&self, keepalive: TcpKeepalive) -> io::Result<()> { 241 self.set_keepalive(true)?; 242 sys::tcp::set_keepalive_params(self.sys, keepalive) 243 } 244 245 /// Returns the amount of time after which TCP keepalive probes will be sent 246 /// on idle connections. 247 /// 248 /// If `None`, then keepalive messages are disabled. 249 /// 250 /// This returns the value of `SO_KEEPALIVE` + `IPPROTO_TCP` on OpenBSD, 251 /// NetBSD, and Haiku, `TCP_KEEPALIVE` on macOS and iOS, and `TCP_KEEPIDLE` 252 /// on all other Unix operating systems. On Windows, it is not possible to 253 /// access the value of TCP keepalive parameters after they have been set. 254 /// 255 /// Some platforms specify this value in seconds, so sub-second 256 /// specifications may be omitted. 257 #[cfg_attr(docsrs, doc(cfg(not(target_os = "windows"))))] 258 #[cfg(not(target_os = "windows"))] get_keepalive_time(&self) -> io::Result<Option<Duration>>259 pub fn get_keepalive_time(&self) -> io::Result<Option<Duration>> { 260 sys::tcp::get_keepalive_time(self.sys) 261 } 262 263 /// Returns the time interval between TCP keepalive probes, if TCP keepalive is 264 /// enabled on this socket. 265 /// 266 /// If `None`, then keepalive messages are disabled. 267 /// 268 /// This returns the value of `TCP_KEEPINTVL` on supported Unix operating 269 /// systems. On Windows, it is not possible to access the value of TCP 270 /// keepalive parameters after they have been set.. 271 /// 272 /// Some platforms specify this value in seconds, so sub-second 273 /// specifications may be omitted. 274 #[cfg_attr( 275 docsrs, 276 doc(cfg(any( 277 target_os = "linux", 278 target_os = "macos", 279 target_os = "ios", 280 target_os = "freebsd", 281 target_os = "netbsd", 282 ))) 283 )] 284 #[cfg(any( 285 target_os = "linux", 286 target_os = "macos", 287 target_os = "ios", 288 target_os = "freebsd", 289 target_os = "netbsd", 290 ))] get_keepalive_interval(&self) -> io::Result<Option<Duration>>291 pub fn get_keepalive_interval(&self) -> io::Result<Option<Duration>> { 292 sys::tcp::get_keepalive_interval(self.sys) 293 } 294 295 /// Returns the maximum number of TCP keepalive probes that will be sent before 296 /// dropping a connection, if TCP keepalive is enabled on this socket. 297 /// 298 /// If `None`, then keepalive messages are disabled. 299 /// 300 /// This returns the value of `TCP_KEEPCNT` on Unix operating systems that 301 /// support this option. On Windows, it is not possible to access the value 302 /// of TCP keepalive parameters after they have been set. 303 #[cfg_attr( 304 docsrs, 305 doc(cfg(any( 306 target_os = "linux", 307 target_os = "macos", 308 target_os = "ios", 309 target_os = "freebsd", 310 target_os = "netbsd", 311 ))) 312 )] 313 #[cfg(any( 314 target_os = "linux", 315 target_os = "macos", 316 target_os = "ios", 317 target_os = "freebsd", 318 target_os = "netbsd", 319 ))] get_keepalive_retries(&self) -> io::Result<Option<u32>>320 pub fn get_keepalive_retries(&self) -> io::Result<Option<u32>> { 321 sys::tcp::get_keepalive_retries(self.sys) 322 } 323 324 /// Returns the local address of this socket 325 /// 326 /// Will return `Err` result in windows if called before calling `bind` get_localaddr(&self) -> io::Result<SocketAddr>327 pub fn get_localaddr(&self) -> io::Result<SocketAddr> { 328 sys::tcp::get_localaddr(self.sys) 329 } 330 } 331 332 impl Drop for TcpSocket { drop(&mut self)333 fn drop(&mut self) { 334 sys::tcp::close(self.sys); 335 } 336 } 337 338 #[cfg(unix)] 339 impl IntoRawFd for TcpSocket { into_raw_fd(self) -> RawFd340 fn into_raw_fd(self) -> RawFd { 341 let ret = self.sys; 342 // Avoid closing the socket 343 mem::forget(self); 344 ret 345 } 346 } 347 348 #[cfg(unix)] 349 impl AsRawFd for TcpSocket { as_raw_fd(&self) -> RawFd350 fn as_raw_fd(&self) -> RawFd { 351 self.sys 352 } 353 } 354 355 #[cfg(unix)] 356 impl FromRawFd for TcpSocket { 357 /// Converts a `RawFd` to a `TcpSocket`. 358 /// 359 /// # Notes 360 /// 361 /// The caller is responsible for ensuring that the socket is in 362 /// non-blocking mode. from_raw_fd(fd: RawFd) -> TcpSocket363 unsafe fn from_raw_fd(fd: RawFd) -> TcpSocket { 364 TcpSocket { sys: fd } 365 } 366 } 367 368 #[cfg(windows)] 369 impl IntoRawSocket for TcpSocket { into_raw_socket(self) -> RawSocket370 fn into_raw_socket(self) -> RawSocket { 371 // The winapi crate defines `SOCKET` as `usize`. The Rust std 372 // conditionally defines `RawSocket` as a fixed size unsigned integer 373 // matching the pointer width. These end up being the same type but we 374 // must cast between them. 375 let ret = self.sys as RawSocket; 376 377 // Avoid closing the socket 378 mem::forget(self); 379 380 ret 381 } 382 } 383 384 #[cfg(windows)] 385 impl AsRawSocket for TcpSocket { as_raw_socket(&self) -> RawSocket386 fn as_raw_socket(&self) -> RawSocket { 387 self.sys as RawSocket 388 } 389 } 390 391 #[cfg(windows)] 392 impl FromRawSocket for TcpSocket { 393 /// Converts a `RawSocket` to a `TcpSocket`. 394 /// 395 /// # Notes 396 /// 397 /// The caller is responsible for ensuring that the socket is in 398 /// non-blocking mode. from_raw_socket(socket: RawSocket) -> TcpSocket399 unsafe fn from_raw_socket(socket: RawSocket) -> TcpSocket { 400 TcpSocket { 401 sys: socket as sys::tcp::TcpSocket, 402 } 403 } 404 } 405 406 impl TcpKeepalive { 407 // Sets the amount of time after which TCP keepalive probes will be sent 408 /// on idle connections. 409 /// 410 /// This will set the value of `SO_KEEPALIVE` + `IPPROTO_TCP` on OpenBSD, 411 /// NetBSD, and Haiku, `TCP_KEEPALIVE` on macOS and iOS, and `TCP_KEEPIDLE` 412 /// on all other Unix operating systems. On Windows, this sets the value of 413 /// the `tcp_keepalive` struct's `keepalivetime` field. 414 /// 415 /// Some platforms specify this value in seconds, so sub-second 416 /// specifications may be omitted. with_time(self, time: Duration) -> Self417 pub fn with_time(self, time: Duration) -> Self { 418 Self { 419 time: Some(time), 420 ..self 421 } 422 } 423 424 /// Sets the time interval between TCP keepalive probes. 425 /// This sets the value of `TCP_KEEPINTVL` on supported Unix operating 426 /// systems. On Windows, this sets the value of the `tcp_keepalive` struct's 427 /// `keepaliveinterval` field. 428 /// 429 /// Some platforms specify this value in seconds, so sub-second 430 /// specifications may be omitted. 431 #[cfg_attr( 432 docsrs, 433 doc(cfg(any( 434 target_os = "linux", 435 target_os = "macos", 436 target_os = "ios", 437 target_os = "freebsd", 438 target_os = "netbsd", 439 target_os = "windows" 440 ))) 441 )] 442 #[cfg(any( 443 target_os = "linux", 444 target_os = "macos", 445 target_os = "ios", 446 target_os = "freebsd", 447 target_os = "netbsd", 448 target_os = "windows" 449 ))] with_interval(self, interval: Duration) -> Self450 pub fn with_interval(self, interval: Duration) -> Self { 451 Self { 452 interval: Some(interval), 453 ..self 454 } 455 } 456 457 /// Sets the maximum number of TCP keepalive probes that will be sent before 458 /// dropping a connection, if TCP keepalive is enabled on this socket. 459 /// 460 /// This will set the value of `TCP_KEEPCNT` on Unix operating systems that 461 /// support this option. 462 #[cfg_attr( 463 docsrs, 464 doc(cfg(any( 465 target_os = "linux", 466 target_os = "macos", 467 target_os = "ios", 468 target_os = "freebsd", 469 target_os = "netbsd", 470 ))) 471 )] 472 #[cfg(any( 473 target_os = "linux", 474 target_os = "macos", 475 target_os = "ios", 476 target_os = "freebsd", 477 target_os = "netbsd", 478 ))] with_retries(self, retries: u32) -> Self479 pub fn with_retries(self, retries: u32) -> Self { 480 Self { 481 retries: Some(retries), 482 ..self 483 } 484 } 485 486 /// Returns a new, empty set of TCP keepalive parameters. new() -> Self487 pub fn new() -> Self { 488 Self::default() 489 } 490 } 491