1 // Copyright 2015 The Rust Project Developers. 2 // 3 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or 4 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license 5 // <LICENSE-MIT or http://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.3")] 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(unix)] 123 #[path = "sys/unix.rs"] 124 mod sys; 125 #[cfg(windows)] 126 #[path = "sys/windows.rs"] 127 mod sys; 128 129 use sys::c_int; 130 131 pub use sockaddr::SockAddr; 132 pub use socket::Socket; 133 pub use sockref::SockRef; 134 135 /// Specification of the communication domain for a socket. 136 /// 137 /// This is a newtype wrapper around an integer which provides a nicer API in 138 /// addition to an injection point for documentation. Convenience constants such 139 /// as [`Domain::IPV4`], [`Domain::IPV6`], etc, are provided to avoid reaching 140 /// into libc for various constants. 141 /// 142 /// This type is freely interconvertible with C's `int` type, however, if a raw 143 /// value needs to be provided. 144 #[derive(Copy, Clone, Eq, PartialEq)] 145 pub struct Domain(c_int); 146 147 impl Domain { 148 /// Domain for IPv4 communication, corresponding to `AF_INET`. 149 pub const IPV4: Domain = Domain(sys::AF_INET); 150 151 /// Domain for IPv6 communication, corresponding to `AF_INET6`. 152 pub const IPV6: Domain = Domain(sys::AF_INET6); 153 154 /// Returns the correct domain for `address`. for_address(address: SocketAddr) -> Domain155 pub const fn for_address(address: SocketAddr) -> Domain { 156 match address { 157 SocketAddr::V4(_) => Domain::IPV4, 158 SocketAddr::V6(_) => Domain::IPV6, 159 } 160 } 161 } 162 163 impl From<c_int> for Domain { from(d: c_int) -> Domain164 fn from(d: c_int) -> Domain { 165 Domain(d) 166 } 167 } 168 169 impl From<Domain> for c_int { from(d: Domain) -> c_int170 fn from(d: Domain) -> c_int { 171 d.0 172 } 173 } 174 175 /// Specification of communication semantics on a socket. 176 /// 177 /// This is a newtype wrapper around an integer which provides a nicer API in 178 /// addition to an injection point for documentation. Convenience constants such 179 /// as [`Type::STREAM`], [`Type::DGRAM`], etc, are provided to avoid reaching 180 /// into libc for various constants. 181 /// 182 /// This type is freely interconvertible with C's `int` type, however, if a raw 183 /// value needs to be provided. 184 #[derive(Copy, Clone, Eq, PartialEq)] 185 pub struct Type(c_int); 186 187 impl Type { 188 /// Type corresponding to `SOCK_STREAM`. 189 /// 190 /// Used for protocols such as TCP. 191 pub const STREAM: Type = Type(sys::SOCK_STREAM); 192 193 /// Type corresponding to `SOCK_DGRAM`. 194 /// 195 /// Used for protocols such as UDP. 196 pub const DGRAM: Type = Type(sys::SOCK_DGRAM); 197 198 /// Type corresponding to `SOCK_SEQPACKET`. 199 #[cfg(feature = "all")] 200 #[cfg_attr(docsrs, doc(cfg(feature = "all")))] 201 pub const SEQPACKET: Type = Type(sys::SOCK_SEQPACKET); 202 203 /// Type corresponding to `SOCK_RAW`. 204 #[cfg(all(feature = "all", not(target_os = "redox")))] 205 #[cfg_attr(docsrs, doc(cfg(all(feature = "all", not(target_os = "redox")))))] 206 pub const RAW: Type = Type(sys::SOCK_RAW); 207 } 208 209 impl From<c_int> for Type { from(t: c_int) -> Type210 fn from(t: c_int) -> Type { 211 Type(t) 212 } 213 } 214 215 impl From<Type> for c_int { from(t: Type) -> c_int216 fn from(t: Type) -> c_int { 217 t.0 218 } 219 } 220 221 /// Protocol specification used for creating sockets via `Socket::new`. 222 /// 223 /// This is a newtype wrapper around an integer which provides a nicer API in 224 /// addition to an injection point for documentation. 225 /// 226 /// This type is freely interconvertible with C's `int` type, however, if a raw 227 /// value needs to be provided. 228 #[derive(Copy, Clone, Eq, PartialEq)] 229 pub struct Protocol(c_int); 230 231 impl Protocol { 232 /// Protocol corresponding to `ICMPv4`. 233 pub const ICMPV4: Protocol = Protocol(sys::IPPROTO_ICMP); 234 235 /// Protocol corresponding to `ICMPv6`. 236 pub const ICMPV6: Protocol = Protocol(sys::IPPROTO_ICMPV6); 237 238 /// Protocol corresponding to `TCP`. 239 pub const TCP: Protocol = Protocol(sys::IPPROTO_TCP); 240 241 /// Protocol corresponding to `UDP`. 242 pub const UDP: Protocol = Protocol(sys::IPPROTO_UDP); 243 } 244 245 impl From<c_int> for Protocol { from(p: c_int) -> Protocol246 fn from(p: c_int) -> Protocol { 247 Protocol(p) 248 } 249 } 250 251 impl From<Protocol> for c_int { from(p: Protocol) -> c_int252 fn from(p: Protocol) -> c_int { 253 p.0 254 } 255 } 256 257 /// Flags for incoming messages. 258 /// 259 /// Flags provide additional information about incoming messages. 260 #[cfg(not(target_os = "redox"))] 261 #[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))] 262 #[derive(Copy, Clone, Eq, PartialEq)] 263 pub struct RecvFlags(c_int); 264 265 #[cfg(not(target_os = "redox"))] 266 impl RecvFlags { 267 /// Check if the message contains a truncated datagram. 268 /// 269 /// This flag is only used for datagram-based sockets, 270 /// not for stream sockets. 271 /// 272 /// On Unix this corresponds to the `MSG_TRUNC` flag. 273 /// On Windows this corresponds to the `WSAEMSGSIZE` error code. is_truncated(self) -> bool274 pub const fn is_truncated(self) -> bool { 275 self.0 & sys::MSG_TRUNC != 0 276 } 277 } 278 279 /// A version of [`IoSliceMut`] that allows the buffer to be uninitialised. 280 /// 281 /// [`IoSliceMut`]: std::io::IoSliceMut 282 #[repr(transparent)] 283 pub struct MaybeUninitSlice<'a>(sys::MaybeUninitSlice<'a>); 284 285 unsafe impl<'a> Send for MaybeUninitSlice<'a> {} 286 287 unsafe impl<'a> Sync for MaybeUninitSlice<'a> {} 288 289 impl<'a> fmt::Debug for MaybeUninitSlice<'a> { fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result290 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { 291 fmt::Debug::fmt(self.0.as_slice(), fmt) 292 } 293 } 294 295 impl<'a> MaybeUninitSlice<'a> { 296 /// Creates a new `MaybeUninitSlice` wrapping a byte slice. 297 /// 298 /// # Panics 299 /// 300 /// Panics on Windows if the slice is larger than 4GB. new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a>301 pub fn new(buf: &'a mut [MaybeUninit<u8>]) -> MaybeUninitSlice<'a> { 302 MaybeUninitSlice(sys::MaybeUninitSlice::new(buf)) 303 } 304 } 305 306 impl<'a> Deref for MaybeUninitSlice<'a> { 307 type Target = [MaybeUninit<u8>]; 308 deref(&self) -> &[MaybeUninit<u8>]309 fn deref(&self) -> &[MaybeUninit<u8>] { 310 self.0.as_slice() 311 } 312 } 313 314 impl<'a> DerefMut for MaybeUninitSlice<'a> { deref_mut(&mut self) -> &mut [MaybeUninit<u8>]315 fn deref_mut(&mut self) -> &mut [MaybeUninit<u8>] { 316 self.0.as_mut_slice() 317 } 318 } 319 320 /// Configures a socket's TCP keepalive parameters. 321 /// 322 /// See [`Socket::set_tcp_keepalive`]. 323 #[derive(Debug, Clone)] 324 pub struct TcpKeepalive { 325 time: Option<Duration>, 326 #[cfg_attr(target_os = "redox", allow(dead_code))] 327 interval: Option<Duration>, 328 #[cfg_attr(target_os = "redox", allow(dead_code))] 329 retries: Option<u32>, 330 } 331 332 impl TcpKeepalive { 333 /// Returns a new, empty set of TCP keepalive parameters. new() -> TcpKeepalive334 pub const fn new() -> TcpKeepalive { 335 TcpKeepalive { 336 time: None, 337 interval: None, 338 retries: None, 339 } 340 } 341 342 /// Set the amount of time after which TCP keepalive probes will be sent on 343 /// idle connections. 344 /// 345 /// This will set `TCP_KEEPALIVE` on macOS and iOS, and 346 /// `TCP_KEEPIDLE` on all other Unix operating systems, except 347 /// OpenBSD and Haiku which don't support any way to set this 348 /// option. On Windows, this sets the value of the `tcp_keepalive` 349 /// struct's `keepalivetime` field. 350 /// 351 /// Some platforms specify this value in seconds, so sub-second 352 /// specifications may be omitted. with_time(self, time: Duration) -> Self353 pub const fn with_time(self, time: Duration) -> Self { 354 Self { 355 time: Some(time), 356 ..self 357 } 358 } 359 360 /// Set the value of the `TCP_KEEPINTVL` option. On Windows, this sets the 361 /// value of the `tcp_keepalive` struct's `keepaliveinterval` field. 362 /// 363 /// Sets the time interval between TCP keepalive probes. 364 /// 365 /// Some platforms specify this value in seconds, so sub-second 366 /// specifications may be omitted. 367 #[cfg(all( 368 feature = "all", 369 any( 370 target_os = "dragonfly", 371 target_os = "freebsd", 372 target_os = "fuchsia", 373 target_os = "linux", 374 target_os = "netbsd", 375 target_vendor = "apple", 376 windows, 377 ) 378 ))] 379 #[cfg_attr( 380 docsrs, 381 doc(cfg(all( 382 feature = "all", 383 any( 384 target_os = "freebsd", 385 target_os = "fuchsia", 386 target_os = "linux", 387 target_os = "netbsd", 388 target_vendor = "apple", 389 windows, 390 ) 391 ))) 392 )] with_interval(self, interval: Duration) -> Self393 pub const fn with_interval(self, interval: Duration) -> Self { 394 Self { 395 interval: Some(interval), 396 ..self 397 } 398 } 399 400 /// Set the value of the `TCP_KEEPCNT` option. 401 /// 402 /// Set the maximum number of TCP keepalive probes that will be sent before 403 /// dropping a connection, if TCP keepalive is enabled on this socket. 404 #[cfg(all( 405 feature = "all", 406 any( 407 doc, 408 target_os = "dragonfly", 409 target_os = "freebsd", 410 target_os = "fuchsia", 411 target_os = "linux", 412 target_os = "netbsd", 413 target_vendor = "apple", 414 ) 415 ))] 416 #[cfg_attr( 417 docsrs, 418 doc(cfg(all( 419 feature = "all", 420 any( 421 target_os = "freebsd", 422 target_os = "fuchsia", 423 target_os = "linux", 424 target_os = "netbsd", 425 target_vendor = "apple", 426 ) 427 ))) 428 )] with_retries(self, retries: u32) -> Self429 pub const fn with_retries(self, retries: u32) -> Self { 430 Self { 431 retries: Some(retries), 432 ..self 433 } 434 } 435 } 436