1//! Socket interface functions 2//! 3//! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) 4#[cfg(target_os = "linux")] 5#[cfg(feature = "uio")] 6use crate::sys::time::TimeSpec; 7#[cfg(feature = "uio")] 8use crate::sys::time::TimeVal; 9use crate::{errno::Errno, Result}; 10use cfg_if::cfg_if; 11use libc::{ 12 self, c_int, c_void, iovec, size_t, socklen_t, CMSG_DATA, CMSG_FIRSTHDR, 13 CMSG_LEN, CMSG_NXTHDR, 14}; 15use std::convert::{TryFrom, TryInto}; 16use std::io::{IoSlice, IoSliceMut}; 17#[cfg(feature = "net")] 18use std::net; 19use std::os::unix::io::RawFd; 20use std::{mem, ptr, slice}; 21 22#[deny(missing_docs)] 23mod addr; 24#[deny(missing_docs)] 25pub mod sockopt; 26 27/* 28 * 29 * ===== Re-exports ===== 30 * 31 */ 32 33pub use self::addr::{SockaddrLike, SockaddrStorage}; 34 35#[cfg(not(any(target_os = "illumos", target_os = "solaris")))] 36#[allow(deprecated)] 37pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; 38#[cfg(any(target_os = "illumos", target_os = "solaris"))] 39#[allow(deprecated)] 40pub use self::addr::{AddressFamily, SockAddr, UnixAddr}; 41#[allow(deprecated)] 42#[cfg(not(any( 43 target_os = "illumos", 44 target_os = "solaris", 45 target_os = "haiku" 46)))] 47#[cfg(feature = "net")] 48pub use self::addr::{ 49 InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, LinkAddr, SockaddrIn, SockaddrIn6, 50}; 51#[allow(deprecated)] 52#[cfg(any( 53 target_os = "illumos", 54 target_os = "solaris", 55 target_os = "haiku" 56))] 57#[cfg(feature = "net")] 58pub use self::addr::{ 59 InetAddr, IpAddr, Ipv4Addr, Ipv6Addr, SockaddrIn, SockaddrIn6, 60}; 61 62#[cfg(any(target_os = "android", target_os = "linux"))] 63pub use crate::sys::socket::addr::alg::AlgAddr; 64#[cfg(any(target_os = "android", target_os = "linux"))] 65pub use crate::sys::socket::addr::netlink::NetlinkAddr; 66#[cfg(any(target_os = "ios", target_os = "macos"))] 67#[cfg(feature = "ioctl")] 68pub use crate::sys::socket::addr::sys_control::SysControlAddr; 69#[cfg(any(target_os = "android", target_os = "linux"))] 70pub use crate::sys::socket::addr::vsock::VsockAddr; 71 72#[cfg(feature = "uio")] 73pub use libc::{cmsghdr, msghdr}; 74pub use libc::{sa_family_t, sockaddr, sockaddr_storage, sockaddr_un}; 75#[cfg(feature = "net")] 76pub use libc::{sockaddr_in, sockaddr_in6}; 77 78// Needed by the cmsg_space macro 79#[doc(hidden)] 80pub use libc::{c_uint, CMSG_SPACE}; 81 82#[cfg(feature = "net")] 83use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc}; 84 85/// These constants are used to specify the communication semantics 86/// when creating a socket with [`socket()`](fn.socket.html) 87#[derive(Clone, Copy, PartialEq, Eq, Debug)] 88#[repr(i32)] 89#[non_exhaustive] 90pub enum SockType { 91 /// Provides sequenced, reliable, two-way, connection- 92 /// based byte streams. An out-of-band data transmission 93 /// mechanism may be supported. 94 Stream = libc::SOCK_STREAM, 95 /// Supports datagrams (connectionless, unreliable 96 /// messages of a fixed maximum length). 97 Datagram = libc::SOCK_DGRAM, 98 /// Provides a sequenced, reliable, two-way connection- 99 /// based data transmission path for datagrams of fixed 100 /// maximum length; a consumer is required to read an 101 /// entire packet with each input system call. 102 SeqPacket = libc::SOCK_SEQPACKET, 103 /// Provides raw network protocol access. 104 Raw = libc::SOCK_RAW, 105 /// Provides a reliable datagram layer that does not 106 /// guarantee ordering. 107 #[cfg(not(any(target_os = "haiku")))] 108 Rdm = libc::SOCK_RDM, 109} 110// The TryFrom impl could've been derived using libc_enum!. But for 111// backwards-compatibility with Nix-0.25.0 we manually implement it, so as to 112// keep the old variant names. 113impl TryFrom<i32> for SockType { 114 type Error = crate::Error; 115 116 fn try_from(x: i32) -> Result<Self> { 117 match x { 118 libc::SOCK_STREAM => Ok(Self::Stream), 119 libc::SOCK_DGRAM => Ok(Self::Datagram), 120 libc::SOCK_SEQPACKET => Ok(Self::SeqPacket), 121 libc::SOCK_RAW => Ok(Self::Raw), 122 #[cfg(not(any(target_os = "haiku")))] 123 libc::SOCK_RDM => Ok(Self::Rdm), 124 _ => Err(Errno::EINVAL) 125 } 126 } 127} 128 129/// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) 130/// to specify the protocol to use. 131#[repr(i32)] 132#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 133#[non_exhaustive] 134pub enum SockProtocol { 135 /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) 136 Tcp = libc::IPPROTO_TCP, 137 /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) 138 Udp = libc::IPPROTO_UDP, 139 /// Raw sockets ([raw(7)](https://man7.org/linux/man-pages/man7/raw.7.html)) 140 Raw = libc::IPPROTO_RAW, 141 /// Allows applications and other KEXTs to be notified when certain kernel events occur 142 /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) 143 #[cfg(any(target_os = "ios", target_os = "macos"))] 144 #[cfg_attr(docsrs, doc(cfg(all())))] 145 KextEvent = libc::SYSPROTO_EVENT, 146 /// Allows applications to configure and control a KEXT 147 /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) 148 #[cfg(any(target_os = "ios", target_os = "macos"))] 149 #[cfg_attr(docsrs, doc(cfg(all())))] 150 KextControl = libc::SYSPROTO_CONTROL, 151 /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link 152 // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers 153 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 154 #[cfg(any(target_os = "android", target_os = "linux"))] 155 #[cfg_attr(docsrs, doc(cfg(all())))] 156 NetlinkRoute = libc::NETLINK_ROUTE, 157 /// Reserved for user-mode socket protocols 158 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 159 #[cfg(any(target_os = "android", target_os = "linux"))] 160 #[cfg_attr(docsrs, doc(cfg(all())))] 161 NetlinkUserSock = libc::NETLINK_USERSOCK, 162 /// Query information about sockets of various protocol families from the kernel 163 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 164 #[cfg(any(target_os = "android", target_os = "linux"))] 165 #[cfg_attr(docsrs, doc(cfg(all())))] 166 NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, 167 /// SELinux event notifications. 168 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 169 #[cfg(any(target_os = "android", target_os = "linux"))] 170 #[cfg_attr(docsrs, doc(cfg(all())))] 171 NetlinkSELinux = libc::NETLINK_SELINUX, 172 /// Open-iSCSI 173 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 174 #[cfg(any(target_os = "android", target_os = "linux"))] 175 #[cfg_attr(docsrs, doc(cfg(all())))] 176 NetlinkISCSI = libc::NETLINK_ISCSI, 177 /// Auditing 178 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 179 #[cfg(any(target_os = "android", target_os = "linux"))] 180 #[cfg_attr(docsrs, doc(cfg(all())))] 181 NetlinkAudit = libc::NETLINK_AUDIT, 182 /// Access to FIB lookup from user space 183 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 184 #[cfg(any(target_os = "android", target_os = "linux"))] 185 #[cfg_attr(docsrs, doc(cfg(all())))] 186 NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP, 187 /// Netfilter subsystem 188 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 189 #[cfg(any(target_os = "android", target_os = "linux"))] 190 #[cfg_attr(docsrs, doc(cfg(all())))] 191 NetlinkNetFilter = libc::NETLINK_NETFILTER, 192 /// SCSI Transports 193 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 194 #[cfg(any(target_os = "android", target_os = "linux"))] 195 #[cfg_attr(docsrs, doc(cfg(all())))] 196 NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT, 197 /// Infiniband RDMA 198 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 199 #[cfg(any(target_os = "android", target_os = "linux"))] 200 #[cfg_attr(docsrs, doc(cfg(all())))] 201 NetlinkRDMA = libc::NETLINK_RDMA, 202 /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module. 203 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 204 #[cfg(any(target_os = "android", target_os = "linux"))] 205 #[cfg_attr(docsrs, doc(cfg(all())))] 206 NetlinkIPv6Firewall = libc::NETLINK_IP6_FW, 207 /// DECnet routing messages 208 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 209 #[cfg(any(target_os = "android", target_os = "linux"))] 210 #[cfg_attr(docsrs, doc(cfg(all())))] 211 NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG, 212 /// Kernel messages to user space 213 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 214 #[cfg(any(target_os = "android", target_os = "linux"))] 215 #[cfg_attr(docsrs, doc(cfg(all())))] 216 NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, 217 /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow 218 /// configuration of the kernel crypto API. 219 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 220 #[cfg(any(target_os = "android", target_os = "linux"))] 221 #[cfg_attr(docsrs, doc(cfg(all())))] 222 NetlinkCrypto = libc::NETLINK_CRYPTO, 223 /// Non-DIX type protocol number defined for the Ethernet IEEE 802.3 interface that allows packets of all protocols 224 /// defined in the interface to be received. 225 /// ([ref](https://man7.org/linux/man-pages/man7/packet.7.html)) 226 // The protocol number is fed into the socket syscall in network byte order. 227 #[cfg(any(target_os = "android", target_os = "linux"))] 228 #[cfg_attr(docsrs, doc(cfg(all())))] 229 EthAll = libc::ETH_P_ALL.to_be(), 230} 231 232#[cfg(any(target_os = "linux"))] 233libc_bitflags! { 234 /// Configuration flags for `SO_TIMESTAMPING` interface 235 /// 236 /// For use with [`Timestamping`][sockopt::Timestamping]. 237 /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) 238 pub struct TimestampingFlag: c_uint { 239 /// Report any software timestamps when available. 240 SOF_TIMESTAMPING_SOFTWARE; 241 /// Report hardware timestamps as generated by SOF_TIMESTAMPING_TX_HARDWARE when available. 242 SOF_TIMESTAMPING_RAW_HARDWARE; 243 /// Collect transmiting timestamps as reported by hardware 244 SOF_TIMESTAMPING_TX_HARDWARE; 245 /// Collect transmiting timestamps as reported by software 246 SOF_TIMESTAMPING_TX_SOFTWARE; 247 /// Collect receiving timestamps as reported by hardware 248 SOF_TIMESTAMPING_RX_HARDWARE; 249 /// Collect receiving timestamps as reported by software 250 SOF_TIMESTAMPING_RX_SOFTWARE; 251 } 252} 253 254libc_bitflags! { 255 /// Additional socket options 256 pub struct SockFlag: c_int { 257 /// Set non-blocking mode on the new socket 258 #[cfg(any(target_os = "android", 259 target_os = "dragonfly", 260 target_os = "freebsd", 261 target_os = "illumos", 262 target_os = "linux", 263 target_os = "netbsd", 264 target_os = "openbsd"))] 265 #[cfg_attr(docsrs, doc(cfg(all())))] 266 SOCK_NONBLOCK; 267 /// Set close-on-exec on the new descriptor 268 #[cfg(any(target_os = "android", 269 target_os = "dragonfly", 270 target_os = "freebsd", 271 target_os = "illumos", 272 target_os = "linux", 273 target_os = "netbsd", 274 target_os = "openbsd"))] 275 #[cfg_attr(docsrs, doc(cfg(all())))] 276 SOCK_CLOEXEC; 277 /// Return `EPIPE` instead of raising `SIGPIPE` 278 #[cfg(target_os = "netbsd")] 279 #[cfg_attr(docsrs, doc(cfg(all())))] 280 SOCK_NOSIGPIPE; 281 /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` 282 /// to the DNS port (typically 53) 283 #[cfg(target_os = "openbsd")] 284 #[cfg_attr(docsrs, doc(cfg(all())))] 285 SOCK_DNS; 286 } 287} 288 289libc_bitflags! { 290 /// Flags for send/recv and their relatives 291 pub struct MsgFlags: c_int { 292 /// Sends or requests out-of-band data on sockets that support this notion 293 /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also 294 /// support out-of-band data. 295 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 296 MSG_OOB; 297 /// Peeks at an incoming message. The data is treated as unread and the next 298 /// [`recv()`](fn.recv.html) 299 /// or similar function shall still return this data. 300 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 301 MSG_PEEK; 302 /// Receive operation blocks until the full amount of data can be 303 /// returned. The function may return smaller amount of data if a signal 304 /// is caught, an error or disconnect occurs. 305 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 306 MSG_WAITALL; 307 /// Enables nonblocking operation; if the operation would block, 308 /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar 309 /// behavior to setting the `O_NONBLOCK` flag 310 /// (via the [`fcntl`](../../fcntl/fn.fcntl.html) 311 /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per- 312 /// call option, whereas `O_NONBLOCK` is a setting on the open file 313 /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)), 314 /// which will affect all threads in 315 /// the calling process and as well as other processes that hold 316 /// file descriptors referring to the same open file description. 317 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 318 MSG_DONTWAIT; 319 /// Receive flags: Control Data was discarded (buffer too small) 320 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 321 MSG_CTRUNC; 322 /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram 323 /// (since Linux 2.4.27/2.6.8), 324 /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4) 325 /// sockets: return the real length of the packet or datagram, even 326 /// when it was longer than the passed buffer. Not implemented for UNIX 327 /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. 328 /// 329 /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). 330 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 331 MSG_TRUNC; 332 /// Terminates a record (when this notion is supported, as for 333 /// sockets of type [`SeqPacket`](enum.SockType.html)). 334 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 335 MSG_EOR; 336 /// This flag specifies that queued errors should be received from 337 /// the socket error queue. (For more details, see 338 /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) 339 #[cfg(any(target_os = "android", target_os = "linux"))] 340 #[cfg_attr(docsrs, doc(cfg(all())))] 341 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 342 MSG_ERRQUEUE; 343 /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain 344 /// file descriptor using the `SCM_RIGHTS` operation (described in 345 /// [unix(7)](https://linux.die.net/man/7/unix)). 346 /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of 347 /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). 348 /// 349 /// Only used in [`recvmsg`](fn.recvmsg.html) function. 350 #[cfg(any(target_os = "android", 351 target_os = "dragonfly", 352 target_os = "freebsd", 353 target_os = "linux", 354 target_os = "netbsd", 355 target_os = "openbsd"))] 356 #[cfg_attr(docsrs, doc(cfg(all())))] 357 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 358 MSG_CMSG_CLOEXEC; 359 /// Requests not to send `SIGPIPE` errors when the other end breaks the connection. 360 /// (For more details, see [send(2)](https://linux.die.net/man/2/send)). 361 #[cfg(any(target_os = "android", 362 target_os = "dragonfly", 363 target_os = "freebsd", 364 target_os = "fuchsia", 365 target_os = "haiku", 366 target_os = "illumos", 367 target_os = "linux", 368 target_os = "netbsd", 369 target_os = "openbsd", 370 target_os = "solaris"))] 371 #[cfg_attr(docsrs, doc(cfg(all())))] 372 #[allow(deprecated)] // Suppress useless warnings from libc PR 2963 373 MSG_NOSIGNAL; 374 } 375} 376 377cfg_if! { 378 if #[cfg(any(target_os = "android", target_os = "linux"))] { 379 /// Unix credentials of the sending process. 380 /// 381 /// This struct is used with the `SO_PEERCRED` ancillary message 382 /// and the `SCM_CREDENTIALS` control message for UNIX sockets. 383 #[repr(transparent)] 384 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 385 pub struct UnixCredentials(libc::ucred); 386 387 impl UnixCredentials { 388 /// Creates a new instance with the credentials of the current process 389 pub fn new() -> Self { 390 // Safe because these FFI functions are inherently safe 391 unsafe { 392 UnixCredentials(libc::ucred { 393 pid: libc::getpid(), 394 uid: libc::getuid(), 395 gid: libc::getgid() 396 }) 397 } 398 } 399 400 /// Returns the process identifier 401 pub fn pid(&self) -> libc::pid_t { 402 self.0.pid 403 } 404 405 /// Returns the user identifier 406 pub fn uid(&self) -> libc::uid_t { 407 self.0.uid 408 } 409 410 /// Returns the group identifier 411 pub fn gid(&self) -> libc::gid_t { 412 self.0.gid 413 } 414 } 415 416 impl Default for UnixCredentials { 417 fn default() -> Self { 418 Self::new() 419 } 420 } 421 422 impl From<libc::ucred> for UnixCredentials { 423 fn from(cred: libc::ucred) -> Self { 424 UnixCredentials(cred) 425 } 426 } 427 428 impl From<UnixCredentials> for libc::ucred { 429 fn from(uc: UnixCredentials) -> Self { 430 uc.0 431 } 432 } 433 } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { 434 /// Unix credentials of the sending process. 435 /// 436 /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets. 437 #[repr(transparent)] 438 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 439 pub struct UnixCredentials(libc::cmsgcred); 440 441 impl UnixCredentials { 442 /// Returns the process identifier 443 pub fn pid(&self) -> libc::pid_t { 444 self.0.cmcred_pid 445 } 446 447 /// Returns the real user identifier 448 pub fn uid(&self) -> libc::uid_t { 449 self.0.cmcred_uid 450 } 451 452 /// Returns the effective user identifier 453 pub fn euid(&self) -> libc::uid_t { 454 self.0.cmcred_euid 455 } 456 457 /// Returns the real group identifier 458 pub fn gid(&self) -> libc::gid_t { 459 self.0.cmcred_gid 460 } 461 462 /// Returns a list group identifiers (the first one being the effective GID) 463 pub fn groups(&self) -> &[libc::gid_t] { 464 unsafe { 465 slice::from_raw_parts( 466 self.0.cmcred_groups.as_ptr() as *const libc::gid_t, 467 self.0.cmcred_ngroups as _ 468 ) 469 } 470 } 471 } 472 473 impl From<libc::cmsgcred> for UnixCredentials { 474 fn from(cred: libc::cmsgcred) -> Self { 475 UnixCredentials(cred) 476 } 477 } 478 } 479} 480 481cfg_if! { 482 if #[cfg(any( 483 target_os = "dragonfly", 484 target_os = "freebsd", 485 target_os = "macos", 486 target_os = "ios" 487 ))] { 488 /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) 489 #[repr(transparent)] 490 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 491 pub struct XuCred(libc::xucred); 492 493 impl XuCred { 494 /// Structure layout version 495 pub fn version(&self) -> u32 { 496 self.0.cr_version 497 } 498 499 /// Effective user ID 500 pub fn uid(&self) -> libc::uid_t { 501 self.0.cr_uid 502 } 503 504 /// Returns a list of group identifiers (the first one being the 505 /// effective GID) 506 pub fn groups(&self) -> &[libc::gid_t] { 507 &self.0.cr_groups 508 } 509 } 510 } 511} 512 513feature! { 514#![feature = "net"] 515/// Request for multicast socket operations 516/// 517/// This is a wrapper type around `ip_mreq`. 518#[repr(transparent)] 519#[derive(Clone, Copy, Debug, Eq, PartialEq)] 520pub struct IpMembershipRequest(libc::ip_mreq); 521 522impl IpMembershipRequest { 523 /// Instantiate a new `IpMembershipRequest` 524 /// 525 /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface. 526 pub fn new(group: net::Ipv4Addr, interface: Option<net::Ipv4Addr>) 527 -> Self 528 { 529 let imr_addr = match interface { 530 None => net::Ipv4Addr::UNSPECIFIED, 531 Some(addr) => addr 532 }; 533 IpMembershipRequest(libc::ip_mreq { 534 imr_multiaddr: ipv4addr_to_libc(group), 535 imr_interface: ipv4addr_to_libc(imr_addr) 536 }) 537 } 538} 539 540/// Request for ipv6 multicast socket operations 541/// 542/// This is a wrapper type around `ipv6_mreq`. 543#[repr(transparent)] 544#[derive(Clone, Copy, Debug, Eq, PartialEq)] 545pub struct Ipv6MembershipRequest(libc::ipv6_mreq); 546 547impl Ipv6MembershipRequest { 548 /// Instantiate a new `Ipv6MembershipRequest` 549 pub const fn new(group: net::Ipv6Addr) -> Self { 550 Ipv6MembershipRequest(libc::ipv6_mreq { 551 ipv6mr_multiaddr: ipv6addr_to_libc(&group), 552 ipv6mr_interface: 0, 553 }) 554 } 555} 556} 557 558feature! { 559#![feature = "uio"] 560 561/// Create a buffer large enough for storing some control messages as returned 562/// by [`recvmsg`](fn.recvmsg.html). 563/// 564/// # Examples 565/// 566/// ``` 567/// # #[macro_use] extern crate nix; 568/// # use nix::sys::time::TimeVal; 569/// # use std::os::unix::io::RawFd; 570/// # fn main() { 571/// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message 572/// let _ = cmsg_space!(TimeVal); 573/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message 574/// // with two file descriptors 575/// let _ = cmsg_space!([RawFd; 2]); 576/// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message 577/// // and a `ControlMessageOwned::ScmTimestamp` message 578/// let _ = cmsg_space!(RawFd, TimeVal); 579/// # } 580/// ``` 581// Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a 582// stack-allocated array. 583#[macro_export] 584macro_rules! cmsg_space { 585 ( $( $x:ty ),* ) => { 586 { 587 let mut space = 0; 588 $( 589 // CMSG_SPACE is always safe 590 space += unsafe { 591 $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint) 592 } as usize; 593 )* 594 Vec::<u8>::with_capacity(space) 595 } 596 } 597} 598 599#[derive(Clone, Copy, Debug, Eq, PartialEq)] 600/// Contains outcome of sending or receiving a message 601/// 602/// Use [`cmsgs`][RecvMsg::cmsgs] to access all the control messages present, and 603/// [`iovs`][RecvMsg::iovs`] to access underlying io slices. 604pub struct RecvMsg<'a, 's, S> { 605 pub bytes: usize, 606 cmsghdr: Option<&'a cmsghdr>, 607 pub address: Option<S>, 608 pub flags: MsgFlags, 609 iobufs: std::marker::PhantomData<& 's()>, 610 mhdr: msghdr, 611} 612 613impl<'a, S> RecvMsg<'a, '_, S> { 614 /// Iterate over the valid control messages pointed to by this 615 /// msghdr. 616 pub fn cmsgs(&self) -> CmsgIterator { 617 CmsgIterator { 618 cmsghdr: self.cmsghdr, 619 mhdr: &self.mhdr 620 } 621 } 622} 623 624#[derive(Clone, Copy, Debug, Eq, PartialEq)] 625pub struct CmsgIterator<'a> { 626 /// Control message buffer to decode from. Must adhere to cmsg alignment. 627 cmsghdr: Option<&'a cmsghdr>, 628 mhdr: &'a msghdr 629} 630 631impl<'a> Iterator for CmsgIterator<'a> { 632 type Item = ControlMessageOwned; 633 634 fn next(&mut self) -> Option<ControlMessageOwned> { 635 match self.cmsghdr { 636 None => None, // No more messages 637 Some(hdr) => { 638 // Get the data. 639 // Safe if cmsghdr points to valid data returned by recvmsg(2) 640 let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))}; 641 // Advance the internal pointer. Safe if mhdr and cmsghdr point 642 // to valid data returned by recvmsg(2) 643 self.cmsghdr = unsafe { 644 let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _); 645 p.as_ref() 646 }; 647 cm 648 } 649 } 650 } 651} 652 653/// A type-safe wrapper around a single control message, as used with 654/// [`recvmsg`](#fn.recvmsg). 655/// 656/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) 657// Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and 658// sendmsg. However, on some platforms the messages returned by recvmsg may be 659// unaligned. ControlMessageOwned takes those messages by copy, obviating any 660// alignment issues. 661// 662// See https://github.com/nix-rust/nix/issues/999 663#[derive(Clone, Debug, Eq, PartialEq)] 664#[non_exhaustive] 665pub enum ControlMessageOwned { 666 /// Received version of [`ControlMessage::ScmRights`] 667 ScmRights(Vec<RawFd>), 668 /// Received version of [`ControlMessage::ScmCredentials`] 669 #[cfg(any(target_os = "android", target_os = "linux"))] 670 #[cfg_attr(docsrs, doc(cfg(all())))] 671 ScmCredentials(UnixCredentials), 672 /// Received version of [`ControlMessage::ScmCreds`] 673 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 674 #[cfg_attr(docsrs, doc(cfg(all())))] 675 ScmCreds(UnixCredentials), 676 /// A message of type `SCM_TIMESTAMP`, containing the time the 677 /// packet was received by the kernel. 678 /// 679 /// See the kernel's explanation in "SO_TIMESTAMP" of 680 /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt). 681 /// 682 /// # Examples 683 /// 684 /// ``` 685 /// # #[macro_use] extern crate nix; 686 /// # use nix::sys::socket::*; 687 /// # use nix::sys::time::*; 688 /// # use std::io::{IoSlice, IoSliceMut}; 689 /// # use std::time::*; 690 /// # use std::str::FromStr; 691 /// # fn main() { 692 /// // Set up 693 /// let message = "Ohayō!".as_bytes(); 694 /// let in_socket = socket( 695 /// AddressFamily::Inet, 696 /// SockType::Datagram, 697 /// SockFlag::empty(), 698 /// None).unwrap(); 699 /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); 700 /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap(); 701 /// bind(in_socket, &localhost).unwrap(); 702 /// let address: SockaddrIn = getsockname(in_socket).unwrap(); 703 /// // Get initial time 704 /// let time0 = SystemTime::now(); 705 /// // Send the message 706 /// let iov = [IoSlice::new(message)]; 707 /// let flags = MsgFlags::empty(); 708 /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); 709 /// assert_eq!(message.len(), l); 710 /// // Receive the message 711 /// let mut buffer = vec![0u8; message.len()]; 712 /// let mut cmsgspace = cmsg_space!(TimeVal); 713 /// let mut iov = [IoSliceMut::new(&mut buffer)]; 714 /// let r = recvmsg::<SockaddrIn>(in_socket, &mut iov, Some(&mut cmsgspace), flags) 715 /// .unwrap(); 716 /// let rtime = match r.cmsgs().next() { 717 /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, 718 /// Some(_) => panic!("Unexpected control message"), 719 /// None => panic!("No control message") 720 /// }; 721 /// // Check the final time 722 /// let time1 = SystemTime::now(); 723 /// // the packet's received timestamp should lie in-between the two system 724 /// // times, unless the system clock was adjusted in the meantime. 725 /// let rduration = Duration::new(rtime.tv_sec() as u64, 726 /// rtime.tv_usec() as u32 * 1000); 727 /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); 728 /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); 729 /// // Close socket 730 /// nix::unistd::close(in_socket).unwrap(); 731 /// # } 732 /// ``` 733 ScmTimestamp(TimeVal), 734 /// A set of nanosecond resolution timestamps 735 /// 736 /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) 737 #[cfg(all(target_os = "linux"))] 738 ScmTimestampsns(Timestamps), 739 /// Nanoseconds resolution timestamp 740 /// 741 /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) 742 #[cfg(all(target_os = "linux"))] 743 #[cfg_attr(docsrs, doc(cfg(all())))] 744 ScmTimestampns(TimeSpec), 745 #[cfg(any( 746 target_os = "android", 747 target_os = "ios", 748 target_os = "linux", 749 target_os = "macos", 750 target_os = "netbsd", 751 ))] 752 #[cfg(feature = "net")] 753 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 754 Ipv4PacketInfo(libc::in_pktinfo), 755 #[cfg(any( 756 target_os = "android", 757 target_os = "dragonfly", 758 target_os = "freebsd", 759 target_os = "ios", 760 target_os = "linux", 761 target_os = "macos", 762 target_os = "openbsd", 763 target_os = "netbsd", 764 ))] 765 #[cfg(feature = "net")] 766 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 767 Ipv6PacketInfo(libc::in6_pktinfo), 768 #[cfg(any( 769 target_os = "freebsd", 770 target_os = "ios", 771 target_os = "macos", 772 target_os = "netbsd", 773 target_os = "openbsd", 774 ))] 775 #[cfg(feature = "net")] 776 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 777 Ipv4RecvIf(libc::sockaddr_dl), 778 #[cfg(any( 779 target_os = "freebsd", 780 target_os = "ios", 781 target_os = "macos", 782 target_os = "netbsd", 783 target_os = "openbsd", 784 ))] 785 #[cfg(feature = "net")] 786 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 787 Ipv4RecvDstAddr(libc::in_addr), 788 #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] 789 #[cfg(feature = "net")] 790 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 791 Ipv4OrigDstAddr(libc::sockaddr_in), 792 #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] 793 #[cfg(feature = "net")] 794 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 795 Ipv6OrigDstAddr(libc::sockaddr_in6), 796 797 /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP 798 /// packets from a single sender. 799 /// Fixed-size payloads are following one by one in a receive buffer. 800 /// This Control Message indicates the size of all smaller packets, 801 /// except, maybe, the last one. 802 /// 803 /// `UdpGroSegment` socket option should be enabled on a socket 804 /// to allow receiving GRO packets. 805 #[cfg(target_os = "linux")] 806 #[cfg(feature = "net")] 807 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 808 UdpGroSegments(u16), 809 810 /// SO_RXQ_OVFL indicates that an unsigned 32 bit value 811 /// ancilliary msg (cmsg) should be attached to recieved 812 /// skbs indicating the number of packets dropped by the 813 /// socket between the last recieved packet and this 814 /// received packet. 815 /// 816 /// `RxqOvfl` socket option should be enabled on a socket 817 /// to allow receiving the drop counter. 818 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 819 #[cfg_attr(docsrs, doc(cfg(all())))] 820 RxqOvfl(u32), 821 822 /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. 823 #[cfg(any(target_os = "android", target_os = "linux"))] 824 #[cfg(feature = "net")] 825 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 826 Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>), 827 /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. 828 #[cfg(any(target_os = "android", target_os = "linux"))] 829 #[cfg(feature = "net")] 830 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 831 Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>), 832 833 /// Catch-all variant for unimplemented cmsg types. 834 #[doc(hidden)] 835 Unknown(UnknownCmsg), 836} 837 838/// For representing packet timestamps via `SO_TIMESTAMPING` interface 839#[cfg(all(target_os = "linux"))] 840#[derive(Copy, Clone, Debug, Eq, PartialEq)] 841pub struct Timestamps { 842 /// software based timestamp, usually one containing data 843 pub system: TimeSpec, 844 /// legacy timestamp, usually empty 845 pub hw_trans: TimeSpec, 846 /// hardware based timestamp 847 pub hw_raw: TimeSpec, 848} 849 850impl ControlMessageOwned { 851 /// Decodes a `ControlMessageOwned` from raw bytes. 852 /// 853 /// This is only safe to call if the data is correct for the message type 854 /// specified in the header. Normally, the kernel ensures that this is the 855 /// case. "Correct" in this case includes correct length, alignment and 856 /// actual content. 857 // Clippy complains about the pointer alignment of `p`, not understanding 858 // that it's being fed to a function that can handle that. 859 #[allow(clippy::cast_ptr_alignment)] 860 unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned 861 { 862 let p = CMSG_DATA(header); 863 // The cast is not unnecessary on all platforms. 864 #[allow(clippy::unnecessary_cast)] 865 let len = header as *const _ as usize + header.cmsg_len as usize 866 - p as usize; 867 match (header.cmsg_level, header.cmsg_type) { 868 (libc::SOL_SOCKET, libc::SCM_RIGHTS) => { 869 let n = len / mem::size_of::<RawFd>(); 870 let mut fds = Vec::with_capacity(n); 871 for i in 0..n { 872 let fdp = (p as *const RawFd).add(i); 873 fds.push(ptr::read_unaligned(fdp)); 874 } 875 ControlMessageOwned::ScmRights(fds) 876 }, 877 #[cfg(any(target_os = "android", target_os = "linux"))] 878 (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { 879 let cred: libc::ucred = ptr::read_unaligned(p as *const _); 880 ControlMessageOwned::ScmCredentials(cred.into()) 881 } 882 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 883 (libc::SOL_SOCKET, libc::SCM_CREDS) => { 884 let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); 885 ControlMessageOwned::ScmCreds(cred.into()) 886 } 887 #[cfg(not(target_os = "haiku"))] 888 (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { 889 let tv: libc::timeval = ptr::read_unaligned(p as *const _); 890 ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) 891 }, 892 #[cfg(all(target_os = "linux"))] 893 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { 894 let ts: libc::timespec = ptr::read_unaligned(p as *const _); 895 ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) 896 } 897 #[cfg(all(target_os = "linux"))] 898 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => { 899 let tp = p as *const libc::timespec; 900 let ts: libc::timespec = ptr::read_unaligned(tp); 901 let system = TimeSpec::from(ts); 902 let ts: libc::timespec = ptr::read_unaligned(tp.add(1)); 903 let hw_trans = TimeSpec::from(ts); 904 let ts: libc::timespec = ptr::read_unaligned(tp.add(2)); 905 let hw_raw = TimeSpec::from(ts); 906 let timestamping = Timestamps { system, hw_trans, hw_raw }; 907 ControlMessageOwned::ScmTimestampsns(timestamping) 908 } 909 #[cfg(any( 910 target_os = "android", 911 target_os = "freebsd", 912 target_os = "ios", 913 target_os = "linux", 914 target_os = "macos" 915 ))] 916 #[cfg(feature = "net")] 917 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { 918 let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); 919 ControlMessageOwned::Ipv6PacketInfo(info) 920 } 921 #[cfg(any( 922 target_os = "android", 923 target_os = "ios", 924 target_os = "linux", 925 target_os = "macos", 926 target_os = "netbsd", 927 ))] 928 #[cfg(feature = "net")] 929 (libc::IPPROTO_IP, libc::IP_PKTINFO) => { 930 let info = ptr::read_unaligned(p as *const libc::in_pktinfo); 931 ControlMessageOwned::Ipv4PacketInfo(info) 932 } 933 #[cfg(any( 934 target_os = "freebsd", 935 target_os = "ios", 936 target_os = "macos", 937 target_os = "netbsd", 938 target_os = "openbsd", 939 ))] 940 #[cfg(feature = "net")] 941 (libc::IPPROTO_IP, libc::IP_RECVIF) => { 942 let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); 943 ControlMessageOwned::Ipv4RecvIf(dl) 944 }, 945 #[cfg(any( 946 target_os = "freebsd", 947 target_os = "ios", 948 target_os = "macos", 949 target_os = "netbsd", 950 target_os = "openbsd", 951 ))] 952 #[cfg(feature = "net")] 953 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { 954 let dl = ptr::read_unaligned(p as *const libc::in_addr); 955 ControlMessageOwned::Ipv4RecvDstAddr(dl) 956 }, 957 #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] 958 #[cfg(feature = "net")] 959 (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => { 960 let dl = ptr::read_unaligned(p as *const libc::sockaddr_in); 961 ControlMessageOwned::Ipv4OrigDstAddr(dl) 962 }, 963 #[cfg(target_os = "linux")] 964 #[cfg(feature = "net")] 965 (libc::SOL_UDP, libc::UDP_GRO) => { 966 let gso_size: u16 = ptr::read_unaligned(p as *const _); 967 ControlMessageOwned::UdpGroSegments(gso_size) 968 }, 969 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 970 (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { 971 let drop_counter = ptr::read_unaligned(p as *const u32); 972 ControlMessageOwned::RxqOvfl(drop_counter) 973 }, 974 #[cfg(any(target_os = "android", target_os = "linux"))] 975 #[cfg(feature = "net")] 976 (libc::IPPROTO_IP, libc::IP_RECVERR) => { 977 let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len); 978 ControlMessageOwned::Ipv4RecvErr(err, addr) 979 }, 980 #[cfg(any(target_os = "android", target_os = "linux"))] 981 #[cfg(feature = "net")] 982 (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { 983 let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len); 984 ControlMessageOwned::Ipv6RecvErr(err, addr) 985 }, 986 #[cfg(any(target_os = "android", target_os = "freebsd", target_os = "linux"))] 987 #[cfg(feature = "net")] 988 (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => { 989 let dl = ptr::read_unaligned(p as *const libc::sockaddr_in6); 990 ControlMessageOwned::Ipv6OrigDstAddr(dl) 991 }, 992 (_, _) => { 993 let sl = slice::from_raw_parts(p, len); 994 let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl)); 995 ControlMessageOwned::Unknown(ucmsg) 996 } 997 } 998 } 999 1000 #[cfg(any(target_os = "android", target_os = "linux"))] 1001 #[cfg(feature = "net")] 1002 #[allow(clippy::cast_ptr_alignment)] // False positive 1003 unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) { 1004 let ee = p as *const libc::sock_extended_err; 1005 let err = ptr::read_unaligned(ee); 1006 1007 // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len] 1008 // CMSG_DATA buffer. For local errors, there is no address included in the control 1009 // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to 1010 // validate that the address object is in-bounds before we attempt to copy it. 1011 let addrp = libc::SO_EE_OFFENDER(ee) as *const T; 1012 1013 if addrp.offset(1) as usize - (p as usize) > len { 1014 (err, None) 1015 } else { 1016 (err, Some(ptr::read_unaligned(addrp))) 1017 } 1018 } 1019} 1020 1021/// A type-safe zero-copy wrapper around a single control message, as used wih 1022/// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not 1023/// exhaustively pattern-match it. 1024/// 1025/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) 1026#[derive(Clone, Copy, Debug, Eq, PartialEq)] 1027#[non_exhaustive] 1028pub enum ControlMessage<'a> { 1029 /// A message of type `SCM_RIGHTS`, containing an array of file 1030 /// descriptors passed between processes. 1031 /// 1032 /// See the description in the "Ancillary messages" section of the 1033 /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html). 1034 /// 1035 /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't 1036 /// recommended since it causes platform-dependent behaviour: It might 1037 /// swallow all but the first `ScmRights` message or fail with `EINVAL`. 1038 /// Instead, you can put all fds to be passed into a single `ScmRights` 1039 /// message. 1040 ScmRights(&'a [RawFd]), 1041 /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of 1042 /// a process connected to the socket. 1043 /// 1044 /// This is similar to the socket option `SO_PEERCRED`, but requires a 1045 /// process to explicitly send its credentials. A process running as root is 1046 /// allowed to specify any credentials, while credentials sent by other 1047 /// processes are verified by the kernel. 1048 /// 1049 /// For further information, please refer to the 1050 /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. 1051 #[cfg(any(target_os = "android", target_os = "linux"))] 1052 #[cfg_attr(docsrs, doc(cfg(all())))] 1053 ScmCredentials(&'a UnixCredentials), 1054 /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of 1055 /// a process connected to the socket. 1056 /// 1057 /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but 1058 /// requires a process to explicitly send its credentials. 1059 /// 1060 /// Credentials are always overwritten by the kernel, so this variant does have 1061 /// any data, unlike the receive-side 1062 /// [`ControlMessageOwned::ScmCreds`]. 1063 /// 1064 /// For further information, please refer to the 1065 /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. 1066 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1067 #[cfg_attr(docsrs, doc(cfg(all())))] 1068 ScmCreds, 1069 1070 /// Set IV for `AF_ALG` crypto API. 1071 /// 1072 /// For further information, please refer to the 1073 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) 1074 #[cfg(any( 1075 target_os = "android", 1076 target_os = "linux", 1077 ))] 1078 #[cfg_attr(docsrs, doc(cfg(all())))] 1079 AlgSetIv(&'a [u8]), 1080 /// Set crypto operation for `AF_ALG` crypto API. It may be one of 1081 /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` 1082 /// 1083 /// For further information, please refer to the 1084 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) 1085 #[cfg(any( 1086 target_os = "android", 1087 target_os = "linux", 1088 ))] 1089 #[cfg_attr(docsrs, doc(cfg(all())))] 1090 AlgSetOp(&'a libc::c_int), 1091 /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) 1092 /// for `AF_ALG` crypto API. 1093 /// 1094 /// For further information, please refer to the 1095 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) 1096 #[cfg(any( 1097 target_os = "android", 1098 target_os = "linux", 1099 ))] 1100 #[cfg_attr(docsrs, doc(cfg(all())))] 1101 AlgSetAeadAssoclen(&'a u32), 1102 1103 /// UDP GSO makes it possible for applications to generate network packets 1104 /// for a virtual MTU much greater than the real one. 1105 /// The length of the send data no longer matches the expected length on 1106 /// the wire. 1107 /// The size of the datagram payload as it should appear on the wire may be 1108 /// passed through this control message. 1109 /// Send buffer should consist of multiple fixed-size wire payloads 1110 /// following one by one, and the last, possibly smaller one. 1111 #[cfg(target_os = "linux")] 1112 #[cfg(feature = "net")] 1113 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 1114 UdpGsoSegments(&'a u16), 1115 1116 /// Configure the sending addressing and interface for v4 1117 /// 1118 /// For further information, please refer to the 1119 /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page. 1120 #[cfg(any(target_os = "linux", 1121 target_os = "macos", 1122 target_os = "netbsd", 1123 target_os = "android", 1124 target_os = "ios",))] 1125 #[cfg(feature = "net")] 1126 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 1127 Ipv4PacketInfo(&'a libc::in_pktinfo), 1128 1129 /// Configure the sending addressing and interface for v6 1130 /// 1131 /// For further information, please refer to the 1132 /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. 1133 #[cfg(any(target_os = "linux", 1134 target_os = "macos", 1135 target_os = "netbsd", 1136 target_os = "freebsd", 1137 target_os = "android", 1138 target_os = "ios",))] 1139 #[cfg(feature = "net")] 1140 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 1141 Ipv6PacketInfo(&'a libc::in6_pktinfo), 1142 1143 /// Configure the IPv4 source address with `IP_SENDSRCADDR`. 1144 #[cfg(any( 1145 target_os = "netbsd", 1146 target_os = "freebsd", 1147 target_os = "openbsd", 1148 target_os = "dragonfly", 1149 ))] 1150 #[cfg(feature = "net")] 1151 #[cfg_attr(docsrs, doc(cfg(feature = "net")))] 1152 Ipv4SendSrcAddr(&'a libc::in_addr), 1153 1154 /// SO_RXQ_OVFL indicates that an unsigned 32 bit value 1155 /// ancilliary msg (cmsg) should be attached to recieved 1156 /// skbs indicating the number of packets dropped by the 1157 /// socket between the last recieved packet and this 1158 /// received packet. 1159 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1160 #[cfg_attr(docsrs, doc(cfg(all())))] 1161 RxqOvfl(&'a u32), 1162 1163 /// Configure the transmission time of packets. 1164 /// 1165 /// For further information, please refer to the 1166 /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man 1167 /// page. 1168 #[cfg(target_os = "linux")] 1169 TxTime(&'a u64), 1170} 1171 1172// An opaque structure used to prevent cmsghdr from being a public type 1173#[doc(hidden)] 1174#[derive(Clone, Debug, Eq, PartialEq)] 1175pub struct UnknownCmsg(cmsghdr, Vec<u8>); 1176 1177impl<'a> ControlMessage<'a> { 1178 /// The value of CMSG_SPACE on this message. 1179 /// Safe because CMSG_SPACE is always safe 1180 fn space(&self) -> usize { 1181 unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize} 1182 } 1183 1184 /// The value of CMSG_LEN on this message. 1185 /// Safe because CMSG_LEN is always safe 1186 #[cfg(any(target_os = "android", 1187 all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos")))))] 1188 fn cmsg_len(&self) -> usize { 1189 unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize} 1190 } 1191 1192 #[cfg(not(any(target_os = "android", 1193 all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos"))))))] 1194 fn cmsg_len(&self) -> libc::c_uint { 1195 unsafe{CMSG_LEN(self.len() as libc::c_uint)} 1196 } 1197 1198 /// Return a reference to the payload data as a byte pointer 1199 fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) { 1200 let data_ptr = match *self { 1201 ControlMessage::ScmRights(fds) => { 1202 fds as *const _ as *const u8 1203 }, 1204 #[cfg(any(target_os = "android", target_os = "linux"))] 1205 ControlMessage::ScmCredentials(creds) => { 1206 &creds.0 as *const libc::ucred as *const u8 1207 } 1208 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1209 ControlMessage::ScmCreds => { 1210 // The kernel overwrites the data, we just zero it 1211 // to make sure it's not uninitialized memory 1212 unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) }; 1213 return 1214 } 1215 #[cfg(any(target_os = "android", target_os = "linux"))] 1216 ControlMessage::AlgSetIv(iv) => { 1217 #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 1218 let af_alg_iv = libc::af_alg_iv { 1219 ivlen: iv.len() as u32, 1220 iv: [0u8; 0], 1221 }; 1222 1223 let size = mem::size_of_val(&af_alg_iv); 1224 1225 unsafe { 1226 ptr::copy_nonoverlapping( 1227 &af_alg_iv as *const _ as *const u8, 1228 cmsg_data, 1229 size, 1230 ); 1231 ptr::copy_nonoverlapping( 1232 iv.as_ptr(), 1233 cmsg_data.add(size), 1234 iv.len() 1235 ); 1236 }; 1237 1238 return 1239 }, 1240 #[cfg(any(target_os = "android", target_os = "linux"))] 1241 ControlMessage::AlgSetOp(op) => { 1242 op as *const _ as *const u8 1243 }, 1244 #[cfg(any(target_os = "android", target_os = "linux"))] 1245 ControlMessage::AlgSetAeadAssoclen(len) => { 1246 len as *const _ as *const u8 1247 }, 1248 #[cfg(target_os = "linux")] 1249 #[cfg(feature = "net")] 1250 ControlMessage::UdpGsoSegments(gso_size) => { 1251 gso_size as *const _ as *const u8 1252 }, 1253 #[cfg(any(target_os = "linux", target_os = "macos", 1254 target_os = "netbsd", target_os = "android", 1255 target_os = "ios",))] 1256 #[cfg(feature = "net")] 1257 ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8, 1258 #[cfg(any(target_os = "linux", target_os = "macos", 1259 target_os = "netbsd", target_os = "freebsd", 1260 target_os = "android", target_os = "ios",))] 1261 #[cfg(feature = "net")] 1262 ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, 1263 #[cfg(any(target_os = "netbsd", target_os = "freebsd", 1264 target_os = "openbsd", target_os = "dragonfly"))] 1265 #[cfg(feature = "net")] 1266 ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8, 1267 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1268 ControlMessage::RxqOvfl(drop_count) => { 1269 drop_count as *const _ as *const u8 1270 }, 1271 #[cfg(target_os = "linux")] 1272 ControlMessage::TxTime(tx_time) => { 1273 tx_time as *const _ as *const u8 1274 }, 1275 }; 1276 unsafe { 1277 ptr::copy_nonoverlapping( 1278 data_ptr, 1279 cmsg_data, 1280 self.len() 1281 ) 1282 }; 1283 } 1284 1285 /// The size of the payload, excluding its cmsghdr 1286 fn len(&self) -> usize { 1287 match *self { 1288 ControlMessage::ScmRights(fds) => { 1289 mem::size_of_val(fds) 1290 }, 1291 #[cfg(any(target_os = "android", target_os = "linux"))] 1292 ControlMessage::ScmCredentials(creds) => { 1293 mem::size_of_val(creds) 1294 } 1295 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1296 ControlMessage::ScmCreds => { 1297 mem::size_of::<libc::cmsgcred>() 1298 } 1299 #[cfg(any(target_os = "android", target_os = "linux"))] 1300 ControlMessage::AlgSetIv(iv) => { 1301 mem::size_of::<&[u8]>() + iv.len() 1302 }, 1303 #[cfg(any(target_os = "android", target_os = "linux"))] 1304 ControlMessage::AlgSetOp(op) => { 1305 mem::size_of_val(op) 1306 }, 1307 #[cfg(any(target_os = "android", target_os = "linux"))] 1308 ControlMessage::AlgSetAeadAssoclen(len) => { 1309 mem::size_of_val(len) 1310 }, 1311 #[cfg(target_os = "linux")] 1312 #[cfg(feature = "net")] 1313 ControlMessage::UdpGsoSegments(gso_size) => { 1314 mem::size_of_val(gso_size) 1315 }, 1316 #[cfg(any(target_os = "linux", target_os = "macos", 1317 target_os = "netbsd", target_os = "android", 1318 target_os = "ios",))] 1319 #[cfg(feature = "net")] 1320 ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info), 1321 #[cfg(any(target_os = "linux", target_os = "macos", 1322 target_os = "netbsd", target_os = "freebsd", 1323 target_os = "android", target_os = "ios",))] 1324 #[cfg(feature = "net")] 1325 ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), 1326 #[cfg(any(target_os = "netbsd", target_os = "freebsd", 1327 target_os = "openbsd", target_os = "dragonfly"))] 1328 #[cfg(feature = "net")] 1329 ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr), 1330 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1331 ControlMessage::RxqOvfl(drop_count) => { 1332 mem::size_of_val(drop_count) 1333 }, 1334 #[cfg(target_os = "linux")] 1335 ControlMessage::TxTime(tx_time) => { 1336 mem::size_of_val(tx_time) 1337 }, 1338 } 1339 } 1340 1341 /// Returns the value to put into the `cmsg_level` field of the header. 1342 fn cmsg_level(&self) -> libc::c_int { 1343 match *self { 1344 ControlMessage::ScmRights(_) => libc::SOL_SOCKET, 1345 #[cfg(any(target_os = "android", target_os = "linux"))] 1346 ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, 1347 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1348 ControlMessage::ScmCreds => libc::SOL_SOCKET, 1349 #[cfg(any(target_os = "android", target_os = "linux"))] 1350 ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) | 1351 ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, 1352 #[cfg(target_os = "linux")] 1353 #[cfg(feature = "net")] 1354 ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, 1355 #[cfg(any(target_os = "linux", target_os = "macos", 1356 target_os = "netbsd", target_os = "android", 1357 target_os = "ios",))] 1358 #[cfg(feature = "net")] 1359 ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, 1360 #[cfg(any(target_os = "linux", target_os = "macos", 1361 target_os = "netbsd", target_os = "freebsd", 1362 target_os = "android", target_os = "ios",))] 1363 #[cfg(feature = "net")] 1364 ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, 1365 #[cfg(any(target_os = "netbsd", target_os = "freebsd", 1366 target_os = "openbsd", target_os = "dragonfly"))] 1367 #[cfg(feature = "net")] 1368 ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP, 1369 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1370 ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, 1371 #[cfg(target_os = "linux")] 1372 ControlMessage::TxTime(_) => libc::SOL_SOCKET, 1373 } 1374 } 1375 1376 /// Returns the value to put into the `cmsg_type` field of the header. 1377 fn cmsg_type(&self) -> libc::c_int { 1378 match *self { 1379 ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, 1380 #[cfg(any(target_os = "android", target_os = "linux"))] 1381 ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, 1382 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1383 ControlMessage::ScmCreds => libc::SCM_CREDS, 1384 #[cfg(any(target_os = "android", target_os = "linux"))] 1385 ControlMessage::AlgSetIv(_) => { 1386 libc::ALG_SET_IV 1387 }, 1388 #[cfg(any(target_os = "android", target_os = "linux"))] 1389 ControlMessage::AlgSetOp(_) => { 1390 libc::ALG_SET_OP 1391 }, 1392 #[cfg(any(target_os = "android", target_os = "linux"))] 1393 ControlMessage::AlgSetAeadAssoclen(_) => { 1394 libc::ALG_SET_AEAD_ASSOCLEN 1395 }, 1396 #[cfg(target_os = "linux")] 1397 #[cfg(feature = "net")] 1398 ControlMessage::UdpGsoSegments(_) => { 1399 libc::UDP_SEGMENT 1400 }, 1401 #[cfg(any(target_os = "linux", target_os = "macos", 1402 target_os = "netbsd", target_os = "android", 1403 target_os = "ios",))] 1404 #[cfg(feature = "net")] 1405 ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO, 1406 #[cfg(any(target_os = "linux", target_os = "macos", 1407 target_os = "netbsd", target_os = "freebsd", 1408 target_os = "android", target_os = "ios",))] 1409 #[cfg(feature = "net")] 1410 ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, 1411 #[cfg(any(target_os = "netbsd", target_os = "freebsd", 1412 target_os = "openbsd", target_os = "dragonfly"))] 1413 #[cfg(feature = "net")] 1414 ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR, 1415 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1416 ControlMessage::RxqOvfl(_) => { 1417 libc::SO_RXQ_OVFL 1418 }, 1419 #[cfg(target_os = "linux")] 1420 ControlMessage::TxTime(_) => { 1421 libc::SCM_TXTIME 1422 }, 1423 } 1424 } 1425 1426 // Unsafe: cmsg must point to a valid cmsghdr with enough space to 1427 // encode self. 1428 unsafe fn encode_into(&self, cmsg: *mut cmsghdr) { 1429 (*cmsg).cmsg_level = self.cmsg_level(); 1430 (*cmsg).cmsg_type = self.cmsg_type(); 1431 (*cmsg).cmsg_len = self.cmsg_len(); 1432 self.copy_to_cmsg_data(CMSG_DATA(cmsg)); 1433 } 1434} 1435 1436 1437/// Send data in scatter-gather vectors to a socket, possibly accompanied 1438/// by ancillary data. Optionally direct the message at the given address, 1439/// as with sendto. 1440/// 1441/// Allocates if cmsgs is nonempty. 1442/// 1443/// # Examples 1444/// When not directing to any specific address, use `()` for the generic type 1445/// ``` 1446/// # use nix::sys::socket::*; 1447/// # use nix::unistd::pipe; 1448/// # use std::io::IoSlice; 1449/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None, 1450/// SockFlag::empty()) 1451/// .unwrap(); 1452/// let (r, w) = pipe().unwrap(); 1453/// 1454/// let iov = [IoSlice::new(b"hello")]; 1455/// let fds = [r]; 1456/// let cmsg = ControlMessage::ScmRights(&fds); 1457/// sendmsg::<()>(fd1, &iov, &[cmsg], MsgFlags::empty(), None).unwrap(); 1458/// ``` 1459/// When directing to a specific address, the generic type will be inferred. 1460/// ``` 1461/// # use nix::sys::socket::*; 1462/// # use nix::unistd::pipe; 1463/// # use std::io::IoSlice; 1464/// # use std::str::FromStr; 1465/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap(); 1466/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(), 1467/// None).unwrap(); 1468/// let (r, w) = pipe().unwrap(); 1469/// 1470/// let iov = [IoSlice::new(b"hello")]; 1471/// let fds = [r]; 1472/// let cmsg = ControlMessage::ScmRights(&fds); 1473/// sendmsg(fd, &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap(); 1474/// ``` 1475pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage], 1476 flags: MsgFlags, addr: Option<&S>) -> Result<usize> 1477 where S: SockaddrLike 1478{ 1479 let capacity = cmsgs.iter().map(|c| c.space()).sum(); 1480 1481 // First size the buffer needed to hold the cmsgs. It must be zeroed, 1482 // because subsequent code will not clear the padding bytes. 1483 let mut cmsg_buffer = vec![0u8; capacity]; 1484 1485 let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr); 1486 1487 let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) }; 1488 1489 Errno::result(ret).map(|r| r as usize) 1490} 1491 1492 1493/// An extension of `sendmsg` that allows the caller to transmit multiple 1494/// messages on a socket using a single system call. This has performance 1495/// benefits for some applications. 1496/// 1497/// Allocations are performed for cmsgs and to build `msghdr` buffer 1498/// 1499/// # Arguments 1500/// 1501/// * `fd`: Socket file descriptor 1502/// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items 1503/// * `flags`: Optional flags passed directly to the operating system. 1504/// 1505/// # Returns 1506/// `Vec` with numbers of sent bytes on each sent message. 1507/// 1508/// # References 1509/// [`sendmsg`](fn.sendmsg.html) 1510#[cfg(any( 1511 target_os = "linux", 1512 target_os = "android", 1513 target_os = "freebsd", 1514 target_os = "netbsd", 1515))] 1516pub fn sendmmsg<'a, XS, AS, C, I, S>( 1517 fd: RawFd, 1518 data: &'a mut MultiHeaders<S>, 1519 slices: XS, 1520 // one address per group of slices 1521 addrs: AS, 1522 // shared across all the messages 1523 cmsgs: C, 1524 flags: MsgFlags 1525) -> crate::Result<MultiResults<'a, S>> 1526 where 1527 XS: IntoIterator<Item = &'a I>, 1528 AS: AsRef<[Option<S>]>, 1529 I: AsRef<[IoSlice<'a>]> + 'a, 1530 C: AsRef<[ControlMessage<'a>]> + 'a, 1531 S: SockaddrLike + 'a 1532{ 1533 1534 let mut count = 0; 1535 1536 1537 for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() { 1538 let mut p = &mut mmsghdr.msg_hdr; 1539 p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; 1540 p.msg_iovlen = slice.as_ref().len() as _; 1541 1542 p.msg_namelen = addr.as_ref().map_or(0, S::len); 1543 p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr) as _; 1544 1545 // Encode each cmsg. This must happen after initializing the header because 1546 // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. 1547 // CMSG_FIRSTHDR is always safe 1548 let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) }; 1549 for cmsg in cmsgs.as_ref() { 1550 assert_ne!(pmhdr, ptr::null_mut()); 1551 // Safe because we know that pmhdr is valid, and we initialized it with 1552 // sufficient space 1553 unsafe { cmsg.encode_into(pmhdr) }; 1554 // Safe because mhdr is valid 1555 pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) }; 1556 } 1557 1558 count = i+1; 1559 } 1560 1561 let sent = Errno::result(unsafe { 1562 libc::sendmmsg( 1563 fd, 1564 data.items.as_mut_ptr(), 1565 count as _, 1566 flags.bits() as _ 1567 ) 1568 })? as usize; 1569 1570 Ok(MultiResults { 1571 rmm: data, 1572 current_index: 0, 1573 received: sent 1574 }) 1575 1576} 1577 1578 1579#[cfg(any( 1580 target_os = "linux", 1581 target_os = "android", 1582 target_os = "freebsd", 1583 target_os = "netbsd", 1584))] 1585#[derive(Debug)] 1586/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions 1587pub struct MultiHeaders<S> { 1588 // preallocated boxed slice of mmsghdr 1589 items: Box<[libc::mmsghdr]>, 1590 addresses: Box<[mem::MaybeUninit<S>]>, 1591 // while we are not using it directly - this is used to store control messages 1592 // and we retain pointers to them inside items array 1593 #[allow(dead_code)] 1594 cmsg_buffers: Option<Box<[u8]>>, 1595 msg_controllen: usize, 1596} 1597 1598#[cfg(any( 1599 target_os = "linux", 1600 target_os = "android", 1601 target_os = "freebsd", 1602 target_os = "netbsd", 1603))] 1604impl<S> MultiHeaders<S> { 1605 /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate 1606 /// 1607 /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed 1608 pub fn preallocate(num_slices: usize, cmsg_buffer: Option<Vec<u8>>) -> Self 1609 where 1610 S: Copy + SockaddrLike, 1611 { 1612 // we will be storing pointers to addresses inside mhdr - convert it into boxed 1613 // slice so it can'be changed later by pushing anything into self.addresses 1614 let mut addresses = vec![std::mem::MaybeUninit::uninit(); num_slices].into_boxed_slice(); 1615 1616 let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity()); 1617 1618 // we'll need a cmsg_buffer for each slice, we preallocate a vector and split 1619 // it into "slices" parts 1620 let cmsg_buffers = 1621 cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice()); 1622 1623 let items = addresses 1624 .iter_mut() 1625 .enumerate() 1626 .map(|(ix, address)| { 1627 let (ptr, cap) = match &cmsg_buffers { 1628 Some(v) => ((&v[ix * msg_controllen] as *const u8), msg_controllen), 1629 None => (std::ptr::null(), 0), 1630 }; 1631 let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null(), 0, ptr, cap, address.as_mut_ptr()) }; 1632 libc::mmsghdr { 1633 msg_hdr, 1634 msg_len: 0, 1635 } 1636 }) 1637 .collect::<Vec<_>>(); 1638 1639 Self { 1640 items: items.into_boxed_slice(), 1641 addresses, 1642 cmsg_buffers, 1643 msg_controllen, 1644 } 1645 } 1646} 1647 1648/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call. 1649/// 1650/// This has performance benefits for some applications. 1651/// 1652/// This method performs no allocations. 1653/// 1654/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce 1655/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and 1656/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs]. 1657/// 1658/// # Bugs (in underlying implementation, at least in Linux) 1659/// The timeout argument does not work as intended. The timeout is checked only after the receipt 1660/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires, 1661/// but then no further datagrams are received, the call will block forever. 1662/// 1663/// If an error occurs after at least one message has been received, the call succeeds, and returns 1664/// the number of messages received. The error code is expected to be returned on a subsequent 1665/// call to recvmmsg(). In the current implementation, however, the error code can be 1666/// overwritten in the meantime by an unrelated network event on a socket, for example an 1667/// incoming ICMP packet. 1668 1669// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not 1670// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more 1671// details 1672 1673#[cfg(any( 1674 target_os = "linux", 1675 target_os = "android", 1676 target_os = "freebsd", 1677 target_os = "netbsd", 1678))] 1679pub fn recvmmsg<'a, XS, S, I>( 1680 fd: RawFd, 1681 data: &'a mut MultiHeaders<S>, 1682 slices: XS, 1683 flags: MsgFlags, 1684 mut timeout: Option<crate::sys::time::TimeSpec>, 1685) -> crate::Result<MultiResults<'a, S>> 1686where 1687 XS: IntoIterator<Item = &'a I>, 1688 I: AsRef<[IoSliceMut<'a>]> + 'a, 1689{ 1690 let mut count = 0; 1691 for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() { 1692 let mut p = &mut mmsghdr.msg_hdr; 1693 p.msg_iov = slice.as_ref().as_ptr() as *mut libc::iovec; 1694 p.msg_iovlen = slice.as_ref().len() as _; 1695 count = i + 1; 1696 } 1697 1698 let timeout_ptr = timeout 1699 .as_mut() 1700 .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec); 1701 1702 let received = Errno::result(unsafe { 1703 libc::recvmmsg( 1704 fd, 1705 data.items.as_mut_ptr(), 1706 count as _, 1707 flags.bits() as _, 1708 timeout_ptr, 1709 ) 1710 })? as usize; 1711 1712 Ok(MultiResults { 1713 rmm: data, 1714 current_index: 0, 1715 received, 1716 }) 1717} 1718 1719#[cfg(any( 1720 target_os = "linux", 1721 target_os = "android", 1722 target_os = "freebsd", 1723 target_os = "netbsd", 1724))] 1725#[derive(Debug)] 1726/// Iterator over results of [`recvmmsg`]/[`sendmmsg`] 1727/// 1728/// 1729pub struct MultiResults<'a, S> { 1730 // preallocated structures 1731 rmm: &'a MultiHeaders<S>, 1732 current_index: usize, 1733 received: usize, 1734} 1735 1736#[cfg(any( 1737 target_os = "linux", 1738 target_os = "android", 1739 target_os = "freebsd", 1740 target_os = "netbsd", 1741))] 1742impl<'a, S> Iterator for MultiResults<'a, S> 1743where 1744 S: Copy + SockaddrLike, 1745{ 1746 type Item = RecvMsg<'a, 'a, S>; 1747 1748 // The cast is not unnecessary on all platforms. 1749 #[allow(clippy::unnecessary_cast)] 1750 fn next(&mut self) -> Option<Self::Item> { 1751 if self.current_index >= self.received { 1752 return None; 1753 } 1754 let mmsghdr = self.rmm.items[self.current_index]; 1755 1756 // as long as we are not reading past the index writen by recvmmsg - address 1757 // will be initialized 1758 let address = unsafe { self.rmm.addresses[self.current_index].assume_init() }; 1759 1760 self.current_index += 1; 1761 Some(unsafe { 1762 read_mhdr( 1763 mmsghdr.msg_hdr, 1764 mmsghdr.msg_len as isize, 1765 self.rmm.msg_controllen, 1766 address, 1767 ) 1768 }) 1769 } 1770} 1771 1772impl<'a, S> RecvMsg<'_, 'a, S> { 1773 /// Iterate over the filled io slices pointed by this msghdr 1774 pub fn iovs(&self) -> IoSliceIterator<'a> { 1775 IoSliceIterator { 1776 index: 0, 1777 remaining: self.bytes, 1778 slices: unsafe { 1779 // safe for as long as mgdr is properly initialized and references are valid. 1780 // for multi messages API we initialize it with an empty 1781 // slice and replace with a concrete buffer 1782 // for single message API we hold a lifetime reference to ioslices 1783 std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _) 1784 }, 1785 } 1786 } 1787} 1788 1789#[derive(Debug)] 1790pub struct IoSliceIterator<'a> { 1791 index: usize, 1792 remaining: usize, 1793 slices: &'a [IoSlice<'a>], 1794} 1795 1796impl<'a> Iterator for IoSliceIterator<'a> { 1797 type Item = &'a [u8]; 1798 1799 fn next(&mut self) -> Option<Self::Item> { 1800 if self.index >= self.slices.len() { 1801 return None; 1802 } 1803 let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())]; 1804 self.remaining -= slice.len(); 1805 self.index += 1; 1806 if slice.is_empty() { 1807 return None; 1808 } 1809 1810 Some(slice) 1811 } 1812} 1813 1814// test contains both recvmmsg and timestaping which is linux only 1815// there are existing tests for recvmmsg only in tests/ 1816#[cfg(target_os = "linux")] 1817#[cfg(test)] 1818mod test { 1819 use crate::sys::socket::{AddressFamily, ControlMessageOwned}; 1820 use crate::*; 1821 use std::str::FromStr; 1822 1823 #[cfg_attr(qemu, ignore)] 1824 #[test] 1825 fn test_recvmm2() -> crate::Result<()> { 1826 use crate::sys::socket::{ 1827 sendmsg, setsockopt, socket, sockopt::Timestamping, MsgFlags, SockFlag, SockType, 1828 SockaddrIn, TimestampingFlag, 1829 }; 1830 use std::io::{IoSlice, IoSliceMut}; 1831 1832 let sock_addr = SockaddrIn::from_str("127.0.0.1:6790").unwrap(); 1833 1834 let ssock = socket( 1835 AddressFamily::Inet, 1836 SockType::Datagram, 1837 SockFlag::empty(), 1838 None, 1839 )?; 1840 1841 let rsock = socket( 1842 AddressFamily::Inet, 1843 SockType::Datagram, 1844 SockFlag::SOCK_NONBLOCK, 1845 None, 1846 )?; 1847 1848 crate::sys::socket::bind(rsock, &sock_addr)?; 1849 1850 setsockopt(rsock, Timestamping, &TimestampingFlag::all())?; 1851 1852 let sbuf = (0..400).map(|i| i as u8).collect::<Vec<_>>(); 1853 1854 let mut recv_buf = vec![0; 1024]; 1855 1856 let mut recv_iovs = Vec::new(); 1857 let mut pkt_iovs = Vec::new(); 1858 1859 for (ix, chunk) in recv_buf.chunks_mut(256).enumerate() { 1860 pkt_iovs.push(IoSliceMut::new(chunk)); 1861 if ix % 2 == 1 { 1862 recv_iovs.push(pkt_iovs); 1863 pkt_iovs = Vec::new(); 1864 } 1865 } 1866 drop(pkt_iovs); 1867 1868 let flags = MsgFlags::empty(); 1869 let iov1 = [IoSlice::new(&sbuf)]; 1870 1871 let cmsg = cmsg_space!(crate::sys::socket::Timestamps); 1872 sendmsg(ssock, &iov1, &[], flags, Some(&sock_addr)).unwrap(); 1873 1874 let mut data = super::MultiHeaders::<()>::preallocate(recv_iovs.len(), Some(cmsg)); 1875 1876 let t = sys::time::TimeSpec::from_duration(std::time::Duration::from_secs(10)); 1877 1878 let recv = super::recvmmsg(rsock, &mut data, recv_iovs.iter(), flags, Some(t))?; 1879 1880 for rmsg in recv { 1881 #[cfg(not(any(qemu, target_arch = "aarch64")))] 1882 let mut saw_time = false; 1883 let mut recvd = 0; 1884 for cmsg in rmsg.cmsgs() { 1885 if let ControlMessageOwned::ScmTimestampsns(timestamps) = cmsg { 1886 let ts = timestamps.system; 1887 1888 let sys_time = 1889 crate::time::clock_gettime(crate::time::ClockId::CLOCK_REALTIME)?; 1890 let diff = if ts > sys_time { 1891 ts - sys_time 1892 } else { 1893 sys_time - ts 1894 }; 1895 assert!(std::time::Duration::from(diff).as_secs() < 60); 1896 #[cfg(not(any(qemu, target_arch = "aarch64")))] 1897 { 1898 saw_time = true; 1899 } 1900 } 1901 } 1902 1903 #[cfg(not(any(qemu, target_arch = "aarch64")))] 1904 assert!(saw_time); 1905 1906 for iov in rmsg.iovs() { 1907 recvd += iov.len(); 1908 } 1909 assert_eq!(recvd, 400); 1910 } 1911 1912 Ok(()) 1913 } 1914} 1915unsafe fn read_mhdr<'a, 'i, S>( 1916 mhdr: msghdr, 1917 r: isize, 1918 msg_controllen: usize, 1919 address: S, 1920) -> RecvMsg<'a, 'i, S> 1921 where S: SockaddrLike 1922{ 1923 // The cast is not unnecessary on all platforms. 1924 #[allow(clippy::unnecessary_cast)] 1925 let cmsghdr = { 1926 if mhdr.msg_controllen > 0 { 1927 debug_assert!(!mhdr.msg_control.is_null()); 1928 debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); 1929 CMSG_FIRSTHDR(&mhdr as *const msghdr) 1930 } else { 1931 ptr::null() 1932 }.as_ref() 1933 }; 1934 1935 RecvMsg { 1936 bytes: r as usize, 1937 cmsghdr, 1938 address: Some(address), 1939 flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), 1940 mhdr, 1941 iobufs: std::marker::PhantomData, 1942 } 1943} 1944 1945/// Pack pointers to various structures into into msghdr 1946/// 1947/// # Safety 1948/// `iov_buffer` and `iov_buffer_len` must point to a slice 1949/// of `IoSliceMut` and number of available elements or be a null pointer and 0 1950/// 1951/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used 1952/// to store control headers later or be a null pointer and 0 if control 1953/// headers are not used 1954/// 1955/// Buffers must remain valid for the whole lifetime of msghdr 1956unsafe fn pack_mhdr_to_receive<S>( 1957 iov_buffer: *const IoSliceMut, 1958 iov_buffer_len: usize, 1959 cmsg_buffer: *const u8, 1960 cmsg_capacity: usize, 1961 address: *mut S, 1962) -> msghdr 1963 where 1964 S: SockaddrLike 1965{ 1966 // Musl's msghdr has private fields, so this is the only way to 1967 // initialize it. 1968 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); 1969 let p = mhdr.as_mut_ptr(); 1970 (*p).msg_name = (*address).as_mut_ptr() as *mut c_void; 1971 (*p).msg_namelen = S::size(); 1972 (*p).msg_iov = iov_buffer as *mut iovec; 1973 (*p).msg_iovlen = iov_buffer_len as _; 1974 (*p).msg_control = cmsg_buffer as *mut c_void; 1975 (*p).msg_controllen = cmsg_capacity as _; 1976 (*p).msg_flags = 0; 1977 mhdr.assume_init() 1978} 1979 1980fn pack_mhdr_to_send<'a, I, C, S>( 1981 cmsg_buffer: &mut [u8], 1982 iov: I, 1983 cmsgs: C, 1984 addr: Option<&S> 1985) -> msghdr 1986 where 1987 I: AsRef<[IoSlice<'a>]>, 1988 C: AsRef<[ControlMessage<'a>]>, 1989 S: SockaddrLike + 'a 1990{ 1991 let capacity = cmsg_buffer.len(); 1992 1993 // The message header must be initialized before the individual cmsgs. 1994 let cmsg_ptr = if capacity > 0 { 1995 cmsg_buffer.as_ptr() as *mut c_void 1996 } else { 1997 ptr::null_mut() 1998 }; 1999 2000 let mhdr = unsafe { 2001 // Musl's msghdr has private fields, so this is the only way to 2002 // initialize it. 2003 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); 2004 let p = mhdr.as_mut_ptr(); 2005 (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _; 2006 (*p).msg_namelen = addr.map(S::len).unwrap_or(0); 2007 // transmute iov into a mutable pointer. sendmsg doesn't really mutate 2008 // the buffer, but the standard says that it takes a mutable pointer 2009 (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; 2010 (*p).msg_iovlen = iov.as_ref().len() as _; 2011 (*p).msg_control = cmsg_ptr; 2012 (*p).msg_controllen = capacity as _; 2013 (*p).msg_flags = 0; 2014 mhdr.assume_init() 2015 }; 2016 2017 // Encode each cmsg. This must happen after initializing the header because 2018 // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. 2019 // CMSG_FIRSTHDR is always safe 2020 let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) }; 2021 for cmsg in cmsgs.as_ref() { 2022 assert_ne!(pmhdr, ptr::null_mut()); 2023 // Safe because we know that pmhdr is valid, and we initialized it with 2024 // sufficient space 2025 unsafe { cmsg.encode_into(pmhdr) }; 2026 // Safe because mhdr is valid 2027 pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) }; 2028 } 2029 2030 mhdr 2031} 2032 2033/// Receive message in scatter-gather vectors from a socket, and 2034/// optionally receive ancillary data into the provided buffer. 2035/// If no ancillary data is desired, use () as the type parameter. 2036/// 2037/// # Arguments 2038/// 2039/// * `fd`: Socket file descriptor 2040/// * `iov`: Scatter-gather list of buffers to receive the message 2041/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by 2042/// [`cmsg_space!`](../../macro.cmsg_space.html) 2043/// * `flags`: Optional flags passed directly to the operating system. 2044/// 2045/// # References 2046/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) 2047pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>], 2048 mut cmsg_buffer: Option<&'a mut Vec<u8>>, 2049 flags: MsgFlags) -> Result<RecvMsg<'a, 'inner, S>> 2050 where S: SockaddrLike + 'a, 2051 'inner: 'outer 2052{ 2053 let mut address = mem::MaybeUninit::uninit(); 2054 2055 let (msg_control, msg_controllen) = cmsg_buffer.as_mut() 2056 .map(|v| (v.as_mut_ptr(), v.capacity())) 2057 .unwrap_or((ptr::null_mut(), 0)); 2058 let mut mhdr = unsafe { 2059 pack_mhdr_to_receive(iov.as_ref().as_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr()) 2060 }; 2061 2062 let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; 2063 2064 let r = Errno::result(ret)?; 2065 2066 Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) }) 2067} 2068} 2069 2070/// Create an endpoint for communication 2071/// 2072/// The `protocol` specifies a particular protocol to be used with the 2073/// socket. Normally only a single protocol exists to support a 2074/// particular socket type within a given protocol family, in which case 2075/// protocol can be specified as `None`. However, it is possible that many 2076/// protocols may exist, in which case a particular protocol must be 2077/// specified in this manner. 2078/// 2079/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) 2080pub fn socket<T: Into<Option<SockProtocol>>>( 2081 domain: AddressFamily, 2082 ty: SockType, 2083 flags: SockFlag, 2084 protocol: T, 2085) -> Result<RawFd> { 2086 let protocol = match protocol.into() { 2087 None => 0, 2088 Some(p) => p as c_int, 2089 }; 2090 2091 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a 2092 // little easier to understand by separating it out. So we have to merge these bitfields 2093 // here. 2094 let mut ty = ty as c_int; 2095 ty |= flags.bits(); 2096 2097 let res = unsafe { libc::socket(domain as c_int, ty, protocol) }; 2098 2099 Errno::result(res) 2100} 2101 2102/// Create a pair of connected sockets 2103/// 2104/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) 2105pub fn socketpair<T: Into<Option<SockProtocol>>>( 2106 domain: AddressFamily, 2107 ty: SockType, 2108 protocol: T, 2109 flags: SockFlag, 2110) -> Result<(RawFd, RawFd)> { 2111 let protocol = match protocol.into() { 2112 None => 0, 2113 Some(p) => p as c_int, 2114 }; 2115 2116 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a 2117 // little easier to understand by separating it out. So we have to merge these bitfields 2118 // here. 2119 let mut ty = ty as c_int; 2120 ty |= flags.bits(); 2121 2122 let mut fds = [-1, -1]; 2123 2124 let res = unsafe { 2125 libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) 2126 }; 2127 Errno::result(res)?; 2128 2129 Ok((fds[0], fds[1])) 2130} 2131 2132/// Listen for connections on a socket 2133/// 2134/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) 2135pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { 2136 let res = unsafe { libc::listen(sockfd, backlog as c_int) }; 2137 2138 Errno::result(res).map(drop) 2139} 2140 2141/// Bind a name to a socket 2142/// 2143/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) 2144pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { 2145 let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) }; 2146 2147 Errno::result(res).map(drop) 2148} 2149 2150/// Accept a connection on a socket 2151/// 2152/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) 2153pub fn accept(sockfd: RawFd) -> Result<RawFd> { 2154 let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }; 2155 2156 Errno::result(res) 2157} 2158 2159/// Accept a connection on a socket 2160/// 2161/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html) 2162#[cfg(any( 2163 all( 2164 target_os = "android", 2165 any( 2166 target_arch = "aarch64", 2167 target_arch = "x86", 2168 target_arch = "x86_64" 2169 ) 2170 ), 2171 target_os = "dragonfly", 2172 target_os = "emscripten", 2173 target_os = "freebsd", 2174 target_os = "fuchsia", 2175 target_os = "illumos", 2176 target_os = "linux", 2177 target_os = "netbsd", 2178 target_os = "openbsd" 2179))] 2180pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { 2181 let res = unsafe { 2182 libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) 2183 }; 2184 2185 Errno::result(res) 2186} 2187 2188/// Initiate a connection on a socket 2189/// 2190/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) 2191pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> { 2192 let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) }; 2193 2194 Errno::result(res).map(drop) 2195} 2196 2197/// Receive data from a connection-oriented socket. Returns the number of 2198/// bytes read 2199/// 2200/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) 2201pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { 2202 unsafe { 2203 let ret = libc::recv( 2204 sockfd, 2205 buf.as_ptr() as *mut c_void, 2206 buf.len() as size_t, 2207 flags.bits(), 2208 ); 2209 2210 Errno::result(ret).map(|r| r as usize) 2211 } 2212} 2213 2214/// Receive data from a connectionless or connection-oriented socket. Returns 2215/// the number of bytes read and, for connectionless sockets, the socket 2216/// address of the sender. 2217/// 2218/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) 2219pub fn recvfrom<T: SockaddrLike>( 2220 sockfd: RawFd, 2221 buf: &mut [u8], 2222) -> Result<(usize, Option<T>)> { 2223 unsafe { 2224 let mut addr = mem::MaybeUninit::<T>::uninit(); 2225 let mut len = mem::size_of_val(&addr) as socklen_t; 2226 2227 let ret = Errno::result(libc::recvfrom( 2228 sockfd, 2229 buf.as_ptr() as *mut c_void, 2230 buf.len() as size_t, 2231 0, 2232 addr.as_mut_ptr() as *mut libc::sockaddr, 2233 &mut len as *mut socklen_t, 2234 ))? as usize; 2235 2236 Ok(( 2237 ret, 2238 T::from_raw( 2239 addr.assume_init().as_ptr() as *const libc::sockaddr, 2240 Some(len), 2241 ), 2242 )) 2243 } 2244} 2245 2246/// Send a message to a socket 2247/// 2248/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) 2249pub fn sendto( 2250 fd: RawFd, 2251 buf: &[u8], 2252 addr: &dyn SockaddrLike, 2253 flags: MsgFlags, 2254) -> Result<usize> { 2255 let ret = unsafe { 2256 libc::sendto( 2257 fd, 2258 buf.as_ptr() as *const c_void, 2259 buf.len() as size_t, 2260 flags.bits(), 2261 addr.as_ptr(), 2262 addr.len(), 2263 ) 2264 }; 2265 2266 Errno::result(ret).map(|r| r as usize) 2267} 2268 2269/// Send data to a connection-oriented socket. Returns the number of bytes read 2270/// 2271/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) 2272pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { 2273 let ret = unsafe { 2274 libc::send( 2275 fd, 2276 buf.as_ptr() as *const c_void, 2277 buf.len() as size_t, 2278 flags.bits(), 2279 ) 2280 }; 2281 2282 Errno::result(ret).map(|r| r as usize) 2283} 2284 2285/* 2286 * 2287 * ===== Socket Options ===== 2288 * 2289 */ 2290 2291/// Represents a socket option that can be retrieved. 2292pub trait GetSockOpt: Copy { 2293 type Val; 2294 2295 /// Look up the value of this socket option on the given socket. 2296 fn get(&self, fd: RawFd) -> Result<Self::Val>; 2297} 2298 2299/// Represents a socket option that can be set. 2300pub trait SetSockOpt: Clone { 2301 type Val; 2302 2303 /// Set the value of this socket option on the given socket. 2304 fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; 2305} 2306 2307/// Get the current value for the requested socket option 2308/// 2309/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) 2310pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { 2311 opt.get(fd) 2312} 2313 2314/// Sets the value for the requested socket option 2315/// 2316/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) 2317/// 2318/// # Examples 2319/// 2320/// ``` 2321/// use nix::sys::socket::setsockopt; 2322/// use nix::sys::socket::sockopt::KeepAlive; 2323/// use std::net::TcpListener; 2324/// use std::os::unix::io::AsRawFd; 2325/// 2326/// let listener = TcpListener::bind("0.0.0.0:0").unwrap(); 2327/// let fd = listener.as_raw_fd(); 2328/// let res = setsockopt(fd, KeepAlive, &true); 2329/// assert!(res.is_ok()); 2330/// ``` 2331pub fn setsockopt<O: SetSockOpt>( 2332 fd: RawFd, 2333 opt: O, 2334 val: &O::Val, 2335) -> Result<()> { 2336 opt.set(fd, val) 2337} 2338 2339/// Get the address of the peer connected to the socket `fd`. 2340/// 2341/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) 2342pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> { 2343 unsafe { 2344 let mut addr = mem::MaybeUninit::<T>::uninit(); 2345 let mut len = T::size(); 2346 2347 let ret = libc::getpeername( 2348 fd, 2349 addr.as_mut_ptr() as *mut libc::sockaddr, 2350 &mut len, 2351 ); 2352 2353 Errno::result(ret)?; 2354 2355 T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) 2356 } 2357} 2358 2359/// Get the current address to which the socket `fd` is bound. 2360/// 2361/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) 2362pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> { 2363 unsafe { 2364 let mut addr = mem::MaybeUninit::<T>::uninit(); 2365 let mut len = T::size(); 2366 2367 let ret = libc::getsockname( 2368 fd, 2369 addr.as_mut_ptr() as *mut libc::sockaddr, 2370 &mut len, 2371 ); 2372 2373 Errno::result(ret)?; 2374 2375 T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL) 2376 } 2377} 2378 2379/// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a 2380/// certain size. 2381/// 2382/// In C this would usually be done by casting. The `len` argument 2383/// should be the number of bytes in the `sockaddr_storage` that are actually 2384/// allocated and valid. It must be at least as large as all the useful parts 2385/// of the structure. Note that in the case of a `sockaddr_un`, `len` need not 2386/// include the terminating null. 2387#[deprecated( 2388 since = "0.24.0", 2389 note = "use SockaddrLike or SockaddrStorage instead" 2390)] 2391#[allow(deprecated)] 2392pub fn sockaddr_storage_to_addr( 2393 addr: &sockaddr_storage, 2394 len: usize, 2395) -> Result<SockAddr> { 2396 assert!(len <= mem::size_of::<sockaddr_storage>()); 2397 if len < mem::size_of_val(&addr.ss_family) { 2398 return Err(Errno::ENOTCONN); 2399 } 2400 2401 match c_int::from(addr.ss_family) { 2402 #[cfg(feature = "net")] 2403 libc::AF_INET => { 2404 assert!(len >= mem::size_of::<sockaddr_in>()); 2405 let sin = unsafe { 2406 *(addr as *const sockaddr_storage as *const sockaddr_in) 2407 }; 2408 Ok(SockAddr::Inet(InetAddr::V4(sin))) 2409 } 2410 #[cfg(feature = "net")] 2411 libc::AF_INET6 => { 2412 assert!(len >= mem::size_of::<sockaddr_in6>()); 2413 let sin6 = unsafe { *(addr as *const _ as *const sockaddr_in6) }; 2414 Ok(SockAddr::Inet(InetAddr::V6(sin6))) 2415 } 2416 libc::AF_UNIX => unsafe { 2417 let sun = *(addr as *const _ as *const sockaddr_un); 2418 let sun_len = len.try_into().unwrap(); 2419 Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len))) 2420 }, 2421 #[cfg(any(target_os = "android", target_os = "linux"))] 2422 #[cfg(feature = "net")] 2423 libc::AF_PACKET => { 2424 use libc::sockaddr_ll; 2425 // Don't assert anything about the size. 2426 // Apparently the Linux kernel can return smaller sizes when 2427 // the value in the last element of sockaddr_ll (`sll_addr`) is 2428 // smaller than the declared size of that field 2429 let sll = unsafe { *(addr as *const _ as *const sockaddr_ll) }; 2430 Ok(SockAddr::Link(LinkAddr(sll))) 2431 } 2432 #[cfg(any(target_os = "android", target_os = "linux"))] 2433 libc::AF_NETLINK => { 2434 use libc::sockaddr_nl; 2435 let snl = unsafe { *(addr as *const _ as *const sockaddr_nl) }; 2436 Ok(SockAddr::Netlink(NetlinkAddr(snl))) 2437 } 2438 #[cfg(any(target_os = "android", target_os = "linux"))] 2439 libc::AF_ALG => { 2440 use libc::sockaddr_alg; 2441 let salg = unsafe { *(addr as *const _ as *const sockaddr_alg) }; 2442 Ok(SockAddr::Alg(AlgAddr(salg))) 2443 } 2444 #[cfg(any(target_os = "android", target_os = "linux"))] 2445 libc::AF_VSOCK => { 2446 use libc::sockaddr_vm; 2447 let svm = unsafe { *(addr as *const _ as *const sockaddr_vm) }; 2448 Ok(SockAddr::Vsock(VsockAddr(svm))) 2449 } 2450 af => panic!("unexpected address family {}", af), 2451 } 2452} 2453 2454#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 2455pub enum Shutdown { 2456 /// Further receptions will be disallowed. 2457 Read, 2458 /// Further transmissions will be disallowed. 2459 Write, 2460 /// Further receptions and transmissions will be disallowed. 2461 Both, 2462} 2463 2464/// Shut down part of a full-duplex connection. 2465/// 2466/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) 2467pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { 2468 unsafe { 2469 use libc::shutdown; 2470 2471 let how = match how { 2472 Shutdown::Read => libc::SHUT_RD, 2473 Shutdown::Write => libc::SHUT_WR, 2474 Shutdown::Both => libc::SHUT_RDWR, 2475 }; 2476 2477 Errno::result(shutdown(df, how)).map(drop) 2478 } 2479} 2480 2481#[cfg(test)] 2482mod tests { 2483 #[test] 2484 fn can_use_cmsg_space() { 2485 let _ = cmsg_space!(u8); 2486 } 2487} 2488