1 // Copyright 2015 The Rust Project Developers. 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // https://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or https://opensource.org/licenses/MIT>, at your 6 // option. This file may not be copied, modified, or distributed 7 // except according to those terms. 8 9 //! Utilities for creating and using sockets. 10 //! 11 //! The goal of this crate is to create and use a socket using advanced 12 //! configuration options (those that are not available in the types in the 13 //! standard library) without using any unsafe code. 14 //! 15 //! This crate provides as direct as possible access to the system's 16 //! functionality for sockets, this means little effort to provide 17 //! cross-platform utilities. It is up to the user to know how to use sockets 18 //! when using this crate. *If you don't know how to create a socket using 19 //! libc/system calls then this crate is not for you*. Most, if not all, 20 //! functions directly relate to the equivalent system call with no error 21 //! handling applied, so no handling errors such as [`EINTR`]. As a result using 22 //! this crate can be a little wordy, but it should give you maximal flexibility 23 //! over configuration of sockets. 24 //! 25 //! [`EINTR`]: std::io::ErrorKind::Interrupted 26 //! 27 //! # Examples 28 //! 29 //! ```no_run 30 //! # fn main() -> std::io::Result<()> { 31 //! use std::net::{SocketAddr, TcpListener}; 32 //! use socket2::{Socket, Domain, Type}; 33 //! 34 //! // Create a TCP listener bound to two addresses. 35 //! let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?; 36 //! 37 //! socket.set_only_v6(false)?; 38 //! let address: SocketAddr = "[::1]:12345".parse().unwrap(); 39 //! socket.bind(&address.into())?; 40 //! socket.listen(128)?; 41 //! 42 //! let listener: TcpListener = socket.into(); 43 //! // ... 44 //! # drop(listener); 45 //! # Ok(()) } 46 //! ``` 47 //! 48 //! ## Features 49 //! 50 //! This crate has a single feature `all`, which enables all functions even ones 51 //! that are not available on all OSs. 52 53 #![doc(html_root_url = "https://docs.rs/socket2/0.4")] 54 #![deny(missing_docs, missing_debug_implementations, rust_2018_idioms)] 55 // Show required OS/features on docs.rs. 56 #![cfg_attr(docsrs, feature(doc_cfg))] 57 // Disallow warnings when running tests. 58 #![cfg_attr(test, deny(warnings))] 59 // Disallow warnings in examples. 60 #![doc(test(attr(deny(warnings))))] 61 62 use std::fmt; 63 use std::mem::MaybeUninit; 64 use std::net::SocketAddr; 65 use std::ops::{Deref, DerefMut}; 66 use std::time::Duration; 67 68 /// Macro to implement `fmt::Debug` for a type, printing the constant names 69 /// rather than a number. 70 /// 71 /// Note this is used in the `sys` module and thus must be defined before 72 /// defining the modules. 73 macro_rules! impl_debug { 74 ( 75 // Type name for which to implement `fmt::Debug`. 76 $type: path, 77 $( 78 $(#[$target: meta])* 79 // The flag(s) to check. 80 // Need to specific the libc crate because Windows doesn't use 81 // `libc` but `winapi`. 82 $libc: ident :: $flag: ident 83 ),+ $(,)* 84 ) => { 85 impl std::fmt::Debug for $type { 86 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { 87 let string = match self.0 { 88 $( 89 $(#[$target])* 90 $libc :: $flag => stringify!($flag), 91 )+ 92 n => return write!(f, "{}", n), 93 }; 94 f.write_str(string) 95 } 96 } 97 }; 98 } 99 100 /// Macro to convert from one network type to another. 101 macro_rules! from { 102 ($from: ty, $for: ty) => { 103 impl From<$from> for $for { 104 fn from(socket: $from) -> $for { 105 #[cfg(unix)] 106 unsafe { 107 <$for>::from_raw_fd(socket.into_raw_fd()) 108 } 109 #[cfg(windows)] 110 unsafe { 111 <$for>::from_raw_socket(socket.into_raw_socket()) 112 } 113 } 114 } 115 }; 116 } 117 118 mod sockaddr; 119 mod socket; 120 mod sockref; 121 122 #[cfg_attr(unix, path = "sys/unix.rs")] 123 #[cfg_attr(windows, path = "sys/windows.rs")] 124 mod sys; 125 126 #[cfg(not(any(windows, unix)))] 127 compile_error!("Socket2 doesn't support the compile target"); 128 129 use sys::c_int; 130 131 pub use sockaddr::SockAddr; 132 pub use socket::Socket; 133 pub use sockref::SockRef; 134 135 #[cfg(not(any( 136 target_os = "haiku", 137 target_os = "illumos", 138 target_os = "netbsd", 139 target_os = "redox", 140 target_os = "solaris", 141 )))] 142 pub use socket::InterfaceIndexOrAddress; 143 144 /// Specification of the communication domain for a socket. 145 /// 146 /// This is a newtype wrapper around an integer which provides a nicer API in 147 /// addition to an injection point for documentation. Convenience constants such 148 /// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching 149 /// into libc for various constants. 150 /// 151 /// This type is freely interconvertible with C's `int` type, however, if a raw 152 /// value needs to be provided. 153 #[derive(Copy, Clone, Eq, PartialEq)] 154 pub struct Domain(c_int); 155 156 impl Domain { 157 /// Domain for IPv4 communication, corresponding to `AF_INET`. 158 pub const IPV4: Domain = Domain(sys::AF_INET); 159 160 /// Domain for IPv6 communication, corresponding to `AF_INET6`. 161 pub const IPV6: Domain = Domain(sys::AF_INET6); 162 163 /// Returns the correct domain for `address`. for_address(address: SocketAddr) -> Domain164 pub const fn for_address(address: SocketAddr) -> Domain { 165 match address { 166 SocketAddr::V4(_) => Domain::IPV4, 167 SocketAddr::V6(_) => Domain::IPV6, 168 } 169 } 170 } 171 172 impl From<c_int> for Domain { from(d: c_int) -> Domain173 fn from(d: c_int) -> Domain { 174 Domain(d) 175 } 176 } 177 178 impl From<Domain> for c_int { from(d: Domain) -> c_int179 fn from(d: Domain) -> c_int { 180 d.0 181 } 182 } 183 184 /// Specification of communication semantics on a socket. 185 /// 186 /// This is a newtype wrapper around an integer which provides a nicer API in 187 /// addition to an injection point for documentation. Convenience constants such 188 /// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching 189 /// into libc for various constants. 190 /// 191 /// This type is freely interconvertible with C's `int` type, however, if a raw 192 /// value needs to be provided. 193 #[derive(Copy, Clone, Eq, PartialEq)] 194 pub struct Type(c_int); 195 196 impl Type { 197 /// Type corresponding to `SOCK_STREAM`. 198 /// 199 /// Used for protocols such as TCP. 200 pub const STREAM: Type = Type(sys::SOCK_STREAM); 201 202 /// Type corresponding to `SOCK_DGRAM`. 203 /// 204 /// Used for protocols such as UDP. 205 pub const DGRAM: Type = Type(sys::SOCK_DGRAM); 206 207 /// Type corresponding to `SOCK_SEQPACKET`. 208 #[cfg(feature = "all")] 209 #[cfg_attr(docsrs, doc(cfg(feature = "all")))] 210 pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET); 211 212 /// Type corresponding to `SOCK_RAW`. 213 #[cfg(all(feature = "all", not(target_os = "redox")))] 214 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "redox")))))] 215 pub const RAW: Type = Type(sys::SOCK_RAW); 216 } 217 218 impl From<c_int> for Type { from(t: c_int) -> Type219 fn from(t: c_int) -> Type { 220 Type(t) 221 } 222 } 223 224 impl From<Type> for c_int { from(t: Type) -> c_int225 fn from(t: Type) -> c_int { 226 t.0 227 } 228 } 229 230 /// Protocol specification used for creating sockets via `Socket::new`. 231 /// 232 /// This is a newtype wrapper around an integer which provides a nicer API in 233 /// addition to an injection point for documentation. 234 /// 235 /// This type is freely interconvertible with C's `int` type, however, if a raw 236 /// value needs to be provided. 237 #[derive(Copy, Clone, Eq, PartialEq)] 238 pub struct Protocol(c_int); 239 240 impl Protocol { 241 /// Protocol corresponding to `ICMPv4`. 242 pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP); 243 244 /// Protocol corresponding to `ICMPv6`. 245 pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6); 246 247 /// Protocol corresponding to `TCP`. 248 pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP); 249 250 /// Protocol corresponding to `UDP`. 251 pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP); 252 } 253 254 impl From<c_int> for Protocol { from(p: c_int) -> Protocol255 fn from(p: c_int) -> Protocol { 256 Protocol(p) 257 } 258 } 259 260 impl From<Protocol> for c_int { from(p: Protocol) -> c_int261 fn from(p: Protocol) -> c_int { 262 p.0 263 } 264 } 265 266 /// Flags for incoming messages. 267 /// 268 /// Flags provide additional information about incoming messages. 269 #[cfg(not(target_os = "redox"))] 270 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] 271 #[derive(Copy, Clone, Eq, PartialEq)] 272 pub struct RecvFlags(c_int); 273 274 #[cfg(not(target_os = "redox"))] 275 impl RecvFlags { 276 /// Check if the message contains a truncated datagram. 277 /// 278 /// This flag is only used for datagram-based sockets, 279 /// not for stream sockets. 280 /// 281 /// On Unix this corresponds to the `MSG_TRUNC` flag. 282 /// On Windows this corresponds to the `WSAEMSGSIZE` error code. is_truncated(self) -> bool283 pub const fn is_truncated(self) -> bool { 284 self.0 & sys::MSG_TRUNC != 0 285 } 286 } 287 288 /// A version of [`IoSliceMut`] that allows the buffer to be uninitialised. 289 /// 290 /// [`IoSliceMut`]: std::io::IoSliceMut 291 #[repr(transparent)] 292 pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>); 293 294 impl<'a> fmt::Debug for MaybeUninitSlice<'a> { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result295 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 296 fmt::Debug::fmt(self.0.as_slice(), fmt) 297 } 298 } 299 300 impl<'a> MaybeUninitSlice<'a> { 301 /// Creates a new `MaybeUninitSlice` wrapping a byte slice. 302 /// 303 /// # Panics 304 /// 305 /// Panics on Windows if the slice is larger than 4GB. new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a>306 pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> { 307 MaybeUninitSlice(sys::MaybeUninitSlice::new(buf)) 308 } 309 } 310 311 impl<'a> Deref for MaybeUninitSlice<'a> { 312 type Target = [MaybeUninit<u8>]; 313 deref(&self) -> &[MaybeUninit<u8>]314 fn deref(&self) -> &[MaybeUninit<u8>] { 315 self.0.as_slice() 316 } 317 } 318 319 impl<'a> DerefMut for MaybeUninitSlice<'a> { deref_mut(&mut self) -> &mut [MaybeUninit<u8>]320 fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] { 321 self.0.as_mut_slice() 322 } 323 } 324 325 /// Configures a socket's TCP keepalive parameters. 326 /// 327 /// See [`Socket::set_tcp_keepalive`]. 328 #[derive(Debug, Clone)] 329 pub struct TcpKeepalive { 330 #[cfg_attr(target_os = "openbsd", allow(dead_code))] 331 time: Option<Duration>, 332 #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris")))] 333 interval: Option<Duration>, 334 #[cfg(not(any( 335 target_os = "openbsd", 336 target_os = "redox", 337 target_os = "solaris", 338 target_os = "windows" 339 )))] 340 retries: Option<u32>, 341 } 342 343 impl TcpKeepalive { 344 /// Returns a new, empty set of TCP keepalive parameters. new() -> TcpKeepalive345 pub const fn new() -> TcpKeepalive { 346 TcpKeepalive { 347 time: None, 348 #[cfg(not(any(target_os = "openbsd", target_os = "redox", target_os = "solaris")))] 349 interval: None, 350 #[cfg(not(any( 351 target_os = "openbsd", 352 target_os = "redox", 353 target_os = "solaris", 354 target_os = "windows" 355 )))] 356 retries: None, 357 } 358 } 359 360 /// Set the amount of time after which TCP keepalive probes will be sent on 361 /// idle connections. 362 /// 363 /// This will set `TCP_KEEPALIVE` on macOS and iOS, and 364 /// `TCP_KEEPIDLE` on all other Unix operating systems, except 365 /// OpenBSD and Haiku which don't support any way to set this 366 /// option. On Windows, this sets the value of the `tcp_keepalive` 367 /// struct's `keepalivetime` field. 368 /// 369 /// Some platforms specify this value in seconds, so sub-second 370 /// specifications may be omitted. with_time(self, time: Duration) -> Self371 pub const fn with_time(self, time: Duration) -> Self { 372 Self { 373 time: Some(time), 374 ..self 375 } 376 } 377 378 /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the 379 /// value of the `tcp_keepalive` struct's `keepaliveinterval` field. 380 /// 381 /// Sets the time interval between TCP keepalive probes. 382 /// 383 /// Some platforms specify this value in seconds, so sub-second 384 /// specifications may be omitted. 385 #[cfg(all( 386 feature = "all", 387 any( 388 target_os = "android", 389 target_os = "dragonfly", 390 target_os = "freebsd", 391 target_os = "fuchsia", 392 target_os = "illumos", 393 target_os = "linux", 394 target_os = "netbsd", 395 target_vendor = "apple", 396 windows, 397 ) 398 ))] 399 #[cfg_attr( 400 docsrs, 401 doc(cfg(all( 402 feature = "all", 403 any( 404 target_os = "android", 405 target_os = "dragonfly", 406 target_os = "freebsd", 407 target_os = "fuchsia", 408 target_os = "illumos", 409 target_os = "linux", 410 target_os = "netbsd", 411 target_vendor = "apple", 412 windows, 413 ) 414 ))) 415 )] with_interval(self, interval: Duration) -> Self416 pub const fn with_interval(self, interval: Duration) -> Self { 417 Self { 418 interval: Some(interval), 419 ..self 420 } 421 } 422 423 /// Set the value of the `TCP_KEEPCNT` option. 424 /// 425 /// Set the maximum number of TCP keepalive probes that will be sent before 426 /// dropping a connection, if TCP keepalive is enabled on this socket. 427 #[cfg(all( 428 feature = "all", 429 any( 430 doc, 431 target_os = "android", 432 target_os = "dragonfly", 433 target_os = "freebsd", 434 target_os = "fuchsia", 435 target_os = "illumos", 436 target_os = "linux", 437 target_os = "netbsd", 438 target_vendor = "apple", 439 ) 440 ))] 441 #[cfg_attr( 442 docsrs, 443 doc(cfg(all( 444 feature = "all", 445 any( 446 target_os = "android", 447 target_os = "dragonfly", 448 target_os = "freebsd", 449 target_os = "fuchsia", 450 target_os = "illumos", 451 target_os = "linux", 452 target_os = "netbsd", 453 target_vendor = "apple", 454 ) 455 ))) 456 )] with_retries(self, retries: u32) -> Self457 pub const fn with_retries(self, retries: u32) -> Self { 458 Self { 459 retries: Some(retries), 460 ..self 461 } 462 } 463 } 464