1 //! Socket interface functions 2 //! 3 //! [Further reading](https://man7.org/linux/man-pages/man7/socket.7.html) 4 use cfg_if::cfg_if; 5 use crate::{Result, errno::Errno}; 6 use libc::{self, c_void, c_int, iovec, socklen_t, size_t, 7 CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN}; 8 use memoffset::offset_of; 9 use std::{mem, ptr, slice}; 10 use std::os::unix::io::RawFd; 11 #[cfg(all(target_os = "linux"))] 12 use crate::sys::time::TimeSpec; 13 use crate::sys::time::TimeVal; 14 use crate::sys::uio::IoVec; 15 16 mod addr; 17 #[deny(missing_docs)] 18 pub mod sockopt; 19 20 /* 21 * 22 * ===== Re-exports ===== 23 * 24 */ 25 26 #[cfg(not(any(target_os = "illumos", target_os = "solaris")))] 27 pub use self::addr::{ 28 AddressFamily, 29 SockAddr, 30 InetAddr, 31 UnixAddr, 32 IpAddr, 33 Ipv4Addr, 34 Ipv6Addr, 35 LinkAddr, 36 }; 37 #[cfg(any(target_os = "illumos", target_os = "solaris"))] 38 pub use self::addr::{ 39 AddressFamily, 40 SockAddr, 41 InetAddr, 42 UnixAddr, 43 IpAddr, 44 Ipv4Addr, 45 Ipv6Addr, 46 }; 47 48 #[cfg(any(target_os = "android", target_os = "linux"))] 49 pub use crate::sys::socket::addr::netlink::NetlinkAddr; 50 #[cfg(any(target_os = "android", target_os = "linux"))] 51 pub use crate::sys::socket::addr::alg::AlgAddr; 52 #[cfg(any(target_os = "android", target_os = "linux"))] 53 pub use crate::sys::socket::addr::vsock::VsockAddr; 54 55 pub use libc::{ 56 cmsghdr, 57 msghdr, 58 sa_family_t, 59 sockaddr, 60 sockaddr_in, 61 sockaddr_in6, 62 sockaddr_storage, 63 sockaddr_un, 64 }; 65 66 // Needed by the cmsg_space macro 67 #[doc(hidden)] 68 pub use libc::{c_uint, CMSG_SPACE}; 69 70 /// These constants are used to specify the communication semantics 71 /// when creating a socket with [`socket()`](fn.socket.html) 72 #[derive(Clone, Copy, PartialEq, Eq, Debug)] 73 #[repr(i32)] 74 #[non_exhaustive] 75 pub enum SockType { 76 /// Provides sequenced, reliable, two-way, connection- 77 /// based byte streams. An out-of-band data transmission 78 /// mechanism may be supported. 79 Stream = libc::SOCK_STREAM, 80 /// Supports datagrams (connectionless, unreliable 81 /// messages of a fixed maximum length). 82 Datagram = libc::SOCK_DGRAM, 83 /// Provides a sequenced, reliable, two-way connection- 84 /// based data transmission path for datagrams of fixed 85 /// maximum length; a consumer is required to read an 86 /// entire packet with each input system call. 87 SeqPacket = libc::SOCK_SEQPACKET, 88 /// Provides raw network protocol access. 89 Raw = libc::SOCK_RAW, 90 /// Provides a reliable datagram layer that does not 91 /// guarantee ordering. 92 Rdm = libc::SOCK_RDM, 93 } 94 95 /// Constants used in [`socket`](fn.socket.html) and [`socketpair`](fn.socketpair.html) 96 /// to specify the protocol to use. 97 #[repr(i32)] 98 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 99 #[non_exhaustive] 100 pub enum SockProtocol { 101 /// TCP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) 102 Tcp = libc::IPPROTO_TCP, 103 /// UDP protocol ([ip(7)](https://man7.org/linux/man-pages/man7/ip.7.html)) 104 Udp = libc::IPPROTO_UDP, 105 /// Allows applications and other KEXTs to be notified when certain kernel events occur 106 /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) 107 #[cfg(any(target_os = "ios", target_os = "macos"))] 108 KextEvent = libc::SYSPROTO_EVENT, 109 /// Allows applications to configure and control a KEXT 110 /// ([ref](https://developer.apple.com/library/content/documentation/Darwin/Conceptual/NKEConceptual/control/control.html)) 111 #[cfg(any(target_os = "ios", target_os = "macos"))] 112 KextControl = libc::SYSPROTO_CONTROL, 113 /// Receives routing and link updates and may be used to modify the routing tables (both IPv4 and IPv6), IP addresses, link 114 // parameters, neighbor setups, queueing disciplines, traffic classes and packet classifiers 115 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 116 #[cfg(any(target_os = "android", target_os = "linux"))] 117 NetlinkRoute = libc::NETLINK_ROUTE, 118 /// Reserved for user-mode socket protocols 119 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 120 #[cfg(any(target_os = "android", target_os = "linux"))] 121 NetlinkUserSock = libc::NETLINK_USERSOCK, 122 /// Query information about sockets of various protocol families from the kernel 123 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 124 #[cfg(any(target_os = "android", target_os = "linux"))] 125 NetlinkSockDiag = libc::NETLINK_SOCK_DIAG, 126 /// SELinux event notifications. 127 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 128 #[cfg(any(target_os = "android", target_os = "linux"))] 129 NetlinkSELinux = libc::NETLINK_SELINUX, 130 /// Open-iSCSI 131 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 132 #[cfg(any(target_os = "android", target_os = "linux"))] 133 NetlinkISCSI = libc::NETLINK_ISCSI, 134 /// Auditing 135 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 136 #[cfg(any(target_os = "android", target_os = "linux"))] 137 NetlinkAudit = libc::NETLINK_AUDIT, 138 /// Access to FIB lookup from user space 139 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 140 #[cfg(any(target_os = "android", target_os = "linux"))] 141 NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP, 142 /// Netfilter subsystem 143 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 144 #[cfg(any(target_os = "android", target_os = "linux"))] 145 NetlinkNetFilter = libc::NETLINK_NETFILTER, 146 /// SCSI Transports 147 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 148 #[cfg(any(target_os = "android", target_os = "linux"))] 149 NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT, 150 /// Infiniband RDMA 151 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 152 #[cfg(any(target_os = "android", target_os = "linux"))] 153 NetlinkRDMA = libc::NETLINK_RDMA, 154 /// Transport IPv6 packets from netfilter to user space. Used by ip6_queue kernel module. 155 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 156 #[cfg(any(target_os = "android", target_os = "linux"))] 157 NetlinkIPv6Firewall = libc::NETLINK_IP6_FW, 158 /// DECnet routing messages 159 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 160 #[cfg(any(target_os = "android", target_os = "linux"))] 161 NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG, 162 /// Kernel messages to user space 163 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 164 #[cfg(any(target_os = "android", target_os = "linux"))] 165 NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT, 166 /// Netlink interface to request information about ciphers registered with the kernel crypto API as well as allow 167 /// configuration of the kernel crypto API. 168 /// ([ref](https://www.man7.org/linux/man-pages/man7/netlink.7.html)) 169 #[cfg(any(target_os = "android", target_os = "linux"))] 170 NetlinkCrypto = libc::NETLINK_CRYPTO, 171 } 172 173 libc_bitflags!{ 174 /// Additional socket options 175 pub struct SockFlag: c_int { 176 /// Set non-blocking mode on the new socket 177 #[cfg(any(target_os = "android", 178 target_os = "dragonfly", 179 target_os = "freebsd", 180 target_os = "illumos", 181 target_os = "linux", 182 target_os = "netbsd", 183 target_os = "openbsd"))] 184 SOCK_NONBLOCK; 185 /// Set close-on-exec on the new descriptor 186 #[cfg(any(target_os = "android", 187 target_os = "dragonfly", 188 target_os = "freebsd", 189 target_os = "illumos", 190 target_os = "linux", 191 target_os = "netbsd", 192 target_os = "openbsd"))] 193 SOCK_CLOEXEC; 194 /// Return `EPIPE` instead of raising `SIGPIPE` 195 #[cfg(target_os = "netbsd")] 196 SOCK_NOSIGPIPE; 197 /// For domains `AF_INET(6)`, only allow `connect(2)`, `sendto(2)`, or `sendmsg(2)` 198 /// to the DNS port (typically 53) 199 #[cfg(target_os = "openbsd")] 200 SOCK_DNS; 201 } 202 } 203 204 libc_bitflags!{ 205 /// Flags for send/recv and their relatives 206 pub struct MsgFlags: c_int { 207 /// Sends or requests out-of-band data on sockets that support this notion 208 /// (e.g., of type [`Stream`](enum.SockType.html)); the underlying protocol must also 209 /// support out-of-band data. 210 MSG_OOB; 211 /// Peeks at an incoming message. The data is treated as unread and the next 212 /// [`recv()`](fn.recv.html) 213 /// or similar function shall still return this data. 214 MSG_PEEK; 215 /// Receive operation blocks until the full amount of data can be 216 /// returned. The function may return smaller amount of data if a signal 217 /// is caught, an error or disconnect occurs. 218 MSG_WAITALL; 219 /// Enables nonblocking operation; if the operation would block, 220 /// `EAGAIN` or `EWOULDBLOCK` is returned. This provides similar 221 /// behavior to setting the `O_NONBLOCK` flag 222 /// (via the [`fcntl`](../../fcntl/fn.fcntl.html) 223 /// `F_SETFL` operation), but differs in that `MSG_DONTWAIT` is a per- 224 /// call option, whereas `O_NONBLOCK` is a setting on the open file 225 /// description (see [open(2)](https://man7.org/linux/man-pages/man2/open.2.html)), 226 /// which will affect all threads in 227 /// the calling process and as well as other processes that hold 228 /// file descriptors referring to the same open file description. 229 MSG_DONTWAIT; 230 /// Receive flags: Control Data was discarded (buffer too small) 231 MSG_CTRUNC; 232 /// For raw ([`Packet`](addr/enum.AddressFamily.html)), Internet datagram 233 /// (since Linux 2.4.27/2.6.8), 234 /// netlink (since Linux 2.6.22) and UNIX datagram (since Linux 3.4) 235 /// sockets: return the real length of the packet or datagram, even 236 /// when it was longer than the passed buffer. Not implemented for UNIX 237 /// domain ([unix(7)](https://linux.die.net/man/7/unix)) sockets. 238 /// 239 /// For use with Internet stream sockets, see [tcp(7)](https://linux.die.net/man/7/tcp). 240 MSG_TRUNC; 241 /// Terminates a record (when this notion is supported, as for 242 /// sockets of type [`SeqPacket`](enum.SockType.html)). 243 MSG_EOR; 244 /// This flag specifies that queued errors should be received from 245 /// the socket error queue. (For more details, see 246 /// [recvfrom(2)](https://linux.die.net/man/2/recvfrom)) 247 #[cfg(any(target_os = "android", target_os = "linux"))] 248 MSG_ERRQUEUE; 249 /// Set the `close-on-exec` flag for the file descriptor received via a UNIX domain 250 /// file descriptor using the `SCM_RIGHTS` operation (described in 251 /// [unix(7)](https://linux.die.net/man/7/unix)). 252 /// This flag is useful for the same reasons as the `O_CLOEXEC` flag of 253 /// [open(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/open.html). 254 /// 255 /// Only used in [`recvmsg`](fn.recvmsg.html) function. 256 #[cfg(any(target_os = "android", 257 target_os = "dragonfly", 258 target_os = "freebsd", 259 target_os = "linux", 260 target_os = "netbsd", 261 target_os = "openbsd"))] 262 MSG_CMSG_CLOEXEC; 263 } 264 } 265 266 cfg_if! { 267 if #[cfg(any(target_os = "android", target_os = "linux"))] { 268 /// Unix credentials of the sending process. 269 /// 270 /// This struct is used with the `SO_PEERCRED` ancillary message 271 /// and the `SCM_CREDENTIALS` control message for UNIX sockets. 272 #[repr(transparent)] 273 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 274 pub struct UnixCredentials(libc::ucred); 275 276 impl UnixCredentials { 277 /// Creates a new instance with the credentials of the current process 278 pub fn new() -> Self { 279 UnixCredentials(libc::ucred { 280 pid: crate::unistd::getpid().as_raw(), 281 uid: crate::unistd::getuid().as_raw(), 282 gid: crate::unistd::getgid().as_raw(), 283 }) 284 } 285 286 /// Returns the process identifier 287 pub fn pid(&self) -> libc::pid_t { 288 self.0.pid 289 } 290 291 /// Returns the user identifier 292 pub fn uid(&self) -> libc::uid_t { 293 self.0.uid 294 } 295 296 /// Returns the group identifier 297 pub fn gid(&self) -> libc::gid_t { 298 self.0.gid 299 } 300 } 301 302 impl Default for UnixCredentials { 303 fn default() -> Self { 304 Self::new() 305 } 306 } 307 308 impl From<libc::ucred> for UnixCredentials { 309 fn from(cred: libc::ucred) -> Self { 310 UnixCredentials(cred) 311 } 312 } 313 314 impl From<UnixCredentials> for libc::ucred { 315 fn from(uc: UnixCredentials) -> Self { 316 uc.0 317 } 318 } 319 } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] { 320 /// Unix credentials of the sending process. 321 /// 322 /// This struct is used with the `SCM_CREDS` ancillary message for UNIX sockets. 323 #[repr(transparent)] 324 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 325 pub struct UnixCredentials(libc::cmsgcred); 326 327 impl UnixCredentials { 328 /// Returns the process identifier 329 pub fn pid(&self) -> libc::pid_t { 330 self.0.cmcred_pid 331 } 332 333 /// Returns the real user identifier 334 pub fn uid(&self) -> libc::uid_t { 335 self.0.cmcred_uid 336 } 337 338 /// Returns the effective user identifier 339 pub fn euid(&self) -> libc::uid_t { 340 self.0.cmcred_euid 341 } 342 343 /// Returns the real group identifier 344 pub fn gid(&self) -> libc::gid_t { 345 self.0.cmcred_gid 346 } 347 348 /// Returns a list group identifiers (the first one being the effective GID) 349 pub fn groups(&self) -> &[libc::gid_t] { 350 unsafe { slice::from_raw_parts(self.0.cmcred_groups.as_ptr() as *const libc::gid_t, self.0.cmcred_ngroups as _) } 351 } 352 } 353 354 impl From<libc::cmsgcred> for UnixCredentials { 355 fn from(cred: libc::cmsgcred) -> Self { 356 UnixCredentials(cred) 357 } 358 } 359 } 360 } 361 362 cfg_if!{ 363 if #[cfg(any( 364 target_os = "dragonfly", 365 target_os = "freebsd", 366 target_os = "macos", 367 target_os = "ios" 368 ))] { 369 /// Return type of [`LocalPeerCred`](crate::sys::socket::sockopt::LocalPeerCred) 370 #[repr(transparent)] 371 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 372 pub struct XuCred(libc::xucred); 373 374 impl XuCred { 375 /// Structure layout version 376 pub fn version(&self) -> u32 { 377 self.0.cr_version 378 } 379 380 /// Effective user ID 381 pub fn uid(&self) -> libc::uid_t { 382 self.0.cr_uid 383 } 384 385 /// Returns a list of group identifiers (the first one being the 386 /// effective GID) 387 pub fn groups(&self) -> &[libc::gid_t] { 388 &self.0.cr_groups 389 } 390 } 391 } 392 } 393 394 /// Request for multicast socket operations 395 /// 396 /// This is a wrapper type around `ip_mreq`. 397 #[repr(transparent)] 398 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 399 pub struct IpMembershipRequest(libc::ip_mreq); 400 401 impl IpMembershipRequest { 402 /// Instantiate a new `IpMembershipRequest` 403 /// 404 /// If `interface` is `None`, then `Ipv4Addr::any()` will be used for the interface. 405 pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self { 406 IpMembershipRequest(libc::ip_mreq { 407 imr_multiaddr: group.0, 408 imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0, 409 }) 410 } 411 } 412 413 /// Request for ipv6 multicast socket operations 414 /// 415 /// This is a wrapper type around `ipv6_mreq`. 416 #[repr(transparent)] 417 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 418 pub struct Ipv6MembershipRequest(libc::ipv6_mreq); 419 420 impl Ipv6MembershipRequest { 421 /// Instantiate a new `Ipv6MembershipRequest` 422 pub const fn new(group: Ipv6Addr) -> Self { 423 Ipv6MembershipRequest(libc::ipv6_mreq { 424 ipv6mr_multiaddr: group.0, 425 ipv6mr_interface: 0, 426 }) 427 } 428 } 429 430 /// Create a buffer large enough for storing some control messages as returned 431 /// by [`recvmsg`](fn.recvmsg.html). 432 /// 433 /// # Examples 434 /// 435 /// ``` 436 /// # #[macro_use] extern crate nix; 437 /// # use nix::sys::time::TimeVal; 438 /// # use std::os::unix::io::RawFd; 439 /// # fn main() { 440 /// // Create a buffer for a `ControlMessageOwned::ScmTimestamp` message 441 /// let _ = cmsg_space!(TimeVal); 442 /// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message 443 /// // with two file descriptors 444 /// let _ = cmsg_space!([RawFd; 2]); 445 /// // Create a buffer big enough for a `ControlMessageOwned::ScmRights` message 446 /// // and a `ControlMessageOwned::ScmTimestamp` message 447 /// let _ = cmsg_space!(RawFd, TimeVal); 448 /// # } 449 /// ``` 450 // Unfortunately, CMSG_SPACE isn't a const_fn, or else we could return a 451 // stack-allocated array. 452 #[macro_export] 453 macro_rules! cmsg_space { 454 ( $( $x:ty ),* ) => { 455 { 456 let mut space = 0; 457 $( 458 // CMSG_SPACE is always safe 459 space += unsafe { 460 $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint) 461 } as usize; 462 )* 463 Vec::<u8>::with_capacity(space) 464 } 465 } 466 } 467 468 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 469 pub struct RecvMsg<'a> { 470 pub bytes: usize, 471 cmsghdr: Option<&'a cmsghdr>, 472 pub address: Option<SockAddr>, 473 pub flags: MsgFlags, 474 mhdr: msghdr, 475 } 476 477 impl<'a> RecvMsg<'a> { 478 /// Iterate over the valid control messages pointed to by this 479 /// msghdr. 480 pub fn cmsgs(&self) -> CmsgIterator { 481 CmsgIterator { 482 cmsghdr: self.cmsghdr, 483 mhdr: &self.mhdr 484 } 485 } 486 } 487 488 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 489 pub struct CmsgIterator<'a> { 490 /// Control message buffer to decode from. Must adhere to cmsg alignment. 491 cmsghdr: Option<&'a cmsghdr>, 492 mhdr: &'a msghdr 493 } 494 495 impl<'a> Iterator for CmsgIterator<'a> { 496 type Item = ControlMessageOwned; 497 498 fn next(&mut self) -> Option<ControlMessageOwned> { 499 match self.cmsghdr { 500 None => None, // No more messages 501 Some(hdr) => { 502 // Get the data. 503 // Safe if cmsghdr points to valid data returned by recvmsg(2) 504 let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))}; 505 // Advance the internal pointer. Safe if mhdr and cmsghdr point 506 // to valid data returned by recvmsg(2) 507 self.cmsghdr = unsafe { 508 let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _); 509 p.as_ref() 510 }; 511 cm 512 } 513 } 514 } 515 } 516 517 /// A type-safe wrapper around a single control message, as used with 518 /// [`recvmsg`](#fn.recvmsg). 519 /// 520 /// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) 521 // Nix version 0.13.0 and earlier used ControlMessage for both recvmsg and 522 // sendmsg. However, on some platforms the messages returned by recvmsg may be 523 // unaligned. ControlMessageOwned takes those messages by copy, obviating any 524 // alignment issues. 525 // 526 // See https://github.com/nix-rust/nix/issues/999 527 #[derive(Clone, Debug, Eq, PartialEq)] 528 #[non_exhaustive] 529 pub enum ControlMessageOwned { 530 /// Received version of [`ControlMessage::ScmRights`] 531 ScmRights(Vec<RawFd>), 532 /// Received version of [`ControlMessage::ScmCredentials`] 533 #[cfg(any(target_os = "android", target_os = "linux"))] 534 ScmCredentials(UnixCredentials), 535 /// Received version of [`ControlMessage::ScmCreds`] 536 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 537 ScmCreds(UnixCredentials), 538 /// A message of type `SCM_TIMESTAMP`, containing the time the 539 /// packet was received by the kernel. 540 /// 541 /// See the kernel's explanation in "SO_TIMESTAMP" of 542 /// [networking/timestamping](https://www.kernel.org/doc/Documentation/networking/timestamping.txt). 543 /// 544 /// # Examples 545 /// 546 /// ``` 547 /// # #[macro_use] extern crate nix; 548 /// # use nix::sys::socket::*; 549 /// # use nix::sys::uio::IoVec; 550 /// # use nix::sys::time::*; 551 /// # use std::time::*; 552 /// # fn main() { 553 /// // Set up 554 /// let message = "Ohayō!".as_bytes(); 555 /// let in_socket = socket( 556 /// AddressFamily::Inet, 557 /// SockType::Datagram, 558 /// SockFlag::empty(), 559 /// None).unwrap(); 560 /// setsockopt(in_socket, sockopt::ReceiveTimestamp, &true).unwrap(); 561 /// let localhost = InetAddr::new(IpAddr::new_v4(127, 0, 0, 1), 0); 562 /// bind(in_socket, &SockAddr::new_inet(localhost)).unwrap(); 563 /// let address = getsockname(in_socket).unwrap(); 564 /// // Get initial time 565 /// let time0 = SystemTime::now(); 566 /// // Send the message 567 /// let iov = [IoVec::from_slice(message)]; 568 /// let flags = MsgFlags::empty(); 569 /// let l = sendmsg(in_socket, &iov, &[], flags, Some(&address)).unwrap(); 570 /// assert_eq!(message.len(), l); 571 /// // Receive the message 572 /// let mut buffer = vec![0u8; message.len()]; 573 /// let mut cmsgspace = cmsg_space!(TimeVal); 574 /// let iov = [IoVec::from_mut_slice(&mut buffer)]; 575 /// let r = recvmsg(in_socket, &iov, Some(&mut cmsgspace), flags).unwrap(); 576 /// let rtime = match r.cmsgs().next() { 577 /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime, 578 /// Some(_) => panic!("Unexpected control message"), 579 /// None => panic!("No control message") 580 /// }; 581 /// // Check the final time 582 /// let time1 = SystemTime::now(); 583 /// // the packet's received timestamp should lie in-between the two system 584 /// // times, unless the system clock was adjusted in the meantime. 585 /// let rduration = Duration::new(rtime.tv_sec() as u64, 586 /// rtime.tv_usec() as u32 * 1000); 587 /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration); 588 /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap()); 589 /// // Close socket 590 /// nix::unistd::close(in_socket).unwrap(); 591 /// # } 592 /// ``` 593 ScmTimestamp(TimeVal), 594 /// Nanoseconds resolution timestamp 595 /// 596 /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html) 597 #[cfg(all(target_os = "linux"))] 598 ScmTimestampns(TimeSpec), 599 #[cfg(any( 600 target_os = "android", 601 target_os = "ios", 602 target_os = "linux", 603 target_os = "macos", 604 target_os = "netbsd", 605 ))] 606 Ipv4PacketInfo(libc::in_pktinfo), 607 #[cfg(any( 608 target_os = "android", 609 target_os = "dragonfly", 610 target_os = "freebsd", 611 target_os = "ios", 612 target_os = "linux", 613 target_os = "macos", 614 target_os = "openbsd", 615 target_os = "netbsd", 616 ))] 617 Ipv6PacketInfo(libc::in6_pktinfo), 618 #[cfg(any( 619 target_os = "freebsd", 620 target_os = "ios", 621 target_os = "macos", 622 target_os = "netbsd", 623 target_os = "openbsd", 624 ))] 625 Ipv4RecvIf(libc::sockaddr_dl), 626 #[cfg(any( 627 target_os = "freebsd", 628 target_os = "ios", 629 target_os = "macos", 630 target_os = "netbsd", 631 target_os = "openbsd", 632 ))] 633 Ipv4RecvDstAddr(libc::in_addr), 634 635 /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP 636 /// packets from a single sender. 637 /// Fixed-size payloads are following one by one in a receive buffer. 638 /// This Control Message indicates the size of all smaller packets, 639 /// except, maybe, the last one. 640 /// 641 /// `UdpGroSegment` socket option should be enabled on a socket 642 /// to allow receiving GRO packets. 643 #[cfg(target_os = "linux")] 644 UdpGroSegments(u16), 645 646 /// SO_RXQ_OVFL indicates that an unsigned 32 bit value 647 /// ancilliary msg (cmsg) should be attached to recieved 648 /// skbs indicating the number of packets dropped by the 649 /// socket between the last recieved packet and this 650 /// received packet. 651 /// 652 /// `RxqOvfl` socket option should be enabled on a socket 653 /// to allow receiving the drop counter. 654 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 655 RxqOvfl(u32), 656 657 /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. 658 #[cfg(any(target_os = "android", target_os = "linux"))] 659 Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>), 660 /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag. 661 #[cfg(any(target_os = "android", target_os = "linux"))] 662 Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>), 663 664 /// Catch-all variant for unimplemented cmsg types. 665 #[doc(hidden)] 666 Unknown(UnknownCmsg), 667 } 668 669 impl ControlMessageOwned { 670 /// Decodes a `ControlMessageOwned` from raw bytes. 671 /// 672 /// This is only safe to call if the data is correct for the message type 673 /// specified in the header. Normally, the kernel ensures that this is the 674 /// case. "Correct" in this case includes correct length, alignment and 675 /// actual content. 676 // Clippy complains about the pointer alignment of `p`, not understanding 677 // that it's being fed to a function that can handle that. 678 #[allow(clippy::cast_ptr_alignment)] 679 unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned 680 { 681 let p = CMSG_DATA(header); 682 let len = header as *const _ as usize + header.cmsg_len as usize 683 - p as usize; 684 match (header.cmsg_level, header.cmsg_type) { 685 (libc::SOL_SOCKET, libc::SCM_RIGHTS) => { 686 let n = len / mem::size_of::<RawFd>(); 687 let mut fds = Vec::with_capacity(n); 688 for i in 0..n { 689 let fdp = (p as *const RawFd).add(i); 690 fds.push(ptr::read_unaligned(fdp)); 691 } 692 ControlMessageOwned::ScmRights(fds) 693 }, 694 #[cfg(any(target_os = "android", target_os = "linux"))] 695 (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => { 696 let cred: libc::ucred = ptr::read_unaligned(p as *const _); 697 ControlMessageOwned::ScmCredentials(cred.into()) 698 } 699 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 700 (libc::SOL_SOCKET, libc::SCM_CREDS) => { 701 let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _); 702 ControlMessageOwned::ScmCreds(cred.into()) 703 } 704 (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => { 705 let tv: libc::timeval = ptr::read_unaligned(p as *const _); 706 ControlMessageOwned::ScmTimestamp(TimeVal::from(tv)) 707 }, 708 #[cfg(all(target_os = "linux"))] 709 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => { 710 let ts: libc::timespec = ptr::read_unaligned(p as *const _); 711 ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts)) 712 } 713 #[cfg(any( 714 target_os = "android", 715 target_os = "freebsd", 716 target_os = "ios", 717 target_os = "linux", 718 target_os = "macos" 719 ))] 720 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => { 721 let info = ptr::read_unaligned(p as *const libc::in6_pktinfo); 722 ControlMessageOwned::Ipv6PacketInfo(info) 723 } 724 #[cfg(any( 725 target_os = "android", 726 target_os = "ios", 727 target_os = "linux", 728 target_os = "macos", 729 target_os = "netbsd", 730 ))] 731 (libc::IPPROTO_IP, libc::IP_PKTINFO) => { 732 let info = ptr::read_unaligned(p as *const libc::in_pktinfo); 733 ControlMessageOwned::Ipv4PacketInfo(info) 734 } 735 #[cfg(any( 736 target_os = "freebsd", 737 target_os = "ios", 738 target_os = "macos", 739 target_os = "netbsd", 740 target_os = "openbsd", 741 ))] 742 (libc::IPPROTO_IP, libc::IP_RECVIF) => { 743 let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl); 744 ControlMessageOwned::Ipv4RecvIf(dl) 745 }, 746 #[cfg(any( 747 target_os = "freebsd", 748 target_os = "ios", 749 target_os = "macos", 750 target_os = "netbsd", 751 target_os = "openbsd", 752 ))] 753 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => { 754 let dl = ptr::read_unaligned(p as *const libc::in_addr); 755 ControlMessageOwned::Ipv4RecvDstAddr(dl) 756 }, 757 #[cfg(target_os = "linux")] 758 (libc::SOL_UDP, libc::UDP_GRO) => { 759 let gso_size: u16 = ptr::read_unaligned(p as *const _); 760 ControlMessageOwned::UdpGroSegments(gso_size) 761 }, 762 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 763 (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => { 764 let drop_counter = ptr::read_unaligned(p as *const u32); 765 ControlMessageOwned::RxqOvfl(drop_counter) 766 }, 767 #[cfg(any(target_os = "android", target_os = "linux"))] 768 (libc::IPPROTO_IP, libc::IP_RECVERR) => { 769 let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len); 770 ControlMessageOwned::Ipv4RecvErr(err, addr) 771 }, 772 #[cfg(any(target_os = "android", target_os = "linux"))] 773 (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => { 774 let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len); 775 ControlMessageOwned::Ipv6RecvErr(err, addr) 776 }, 777 (_, _) => { 778 let sl = slice::from_raw_parts(p, len); 779 let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl)); 780 ControlMessageOwned::Unknown(ucmsg) 781 } 782 } 783 } 784 785 #[cfg(any(target_os = "android", target_os = "linux"))] 786 unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) { 787 let ee = p as *const libc::sock_extended_err; 788 let err = ptr::read_unaligned(ee); 789 790 // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len] 791 // CMSG_DATA buffer. For local errors, there is no address included in the control 792 // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to 793 // validate that the address object is in-bounds before we attempt to copy it. 794 let addrp = libc::SO_EE_OFFENDER(ee) as *const T; 795 796 if addrp.offset(1) as usize - (p as usize) > len { 797 (err, None) 798 } else { 799 (err, Some(ptr::read_unaligned(addrp))) 800 } 801 } 802 } 803 804 /// A type-safe zero-copy wrapper around a single control message, as used wih 805 /// [`sendmsg`](#fn.sendmsg). More types may be added to this enum; do not 806 /// exhaustively pattern-match it. 807 /// 808 /// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html) 809 #[derive(Clone, Copy, Debug, Eq, PartialEq)] 810 #[non_exhaustive] 811 pub enum ControlMessage<'a> { 812 /// A message of type `SCM_RIGHTS`, containing an array of file 813 /// descriptors passed between processes. 814 /// 815 /// See the description in the "Ancillary messages" section of the 816 /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html). 817 /// 818 /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't 819 /// recommended since it causes platform-dependent behaviour: It might 820 /// swallow all but the first `ScmRights` message or fail with `EINVAL`. 821 /// Instead, you can put all fds to be passed into a single `ScmRights` 822 /// message. 823 ScmRights(&'a [RawFd]), 824 /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of 825 /// a process connected to the socket. 826 /// 827 /// This is similar to the socket option `SO_PEERCRED`, but requires a 828 /// process to explicitly send its credentials. A process running as root is 829 /// allowed to specify any credentials, while credentials sent by other 830 /// processes are verified by the kernel. 831 /// 832 /// For further information, please refer to the 833 /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page. 834 #[cfg(any(target_os = "android", target_os = "linux"))] 835 ScmCredentials(&'a UnixCredentials), 836 /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of 837 /// a process connected to the socket. 838 /// 839 /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but 840 /// requires a process to explicitly send its credentials. 841 /// 842 /// Credentials are always overwritten by the kernel, so this variant does have 843 /// any data, unlike the receive-side 844 /// [`ControlMessageOwned::ScmCreds`]. 845 /// 846 /// For further information, please refer to the 847 /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page. 848 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 849 ScmCreds, 850 851 /// Set IV for `AF_ALG` crypto API. 852 /// 853 /// For further information, please refer to the 854 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) 855 #[cfg(any( 856 target_os = "android", 857 target_os = "linux", 858 ))] 859 AlgSetIv(&'a [u8]), 860 /// Set crypto operation for `AF_ALG` crypto API. It may be one of 861 /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT` 862 /// 863 /// For further information, please refer to the 864 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) 865 #[cfg(any( 866 target_os = "android", 867 target_os = "linux", 868 ))] 869 AlgSetOp(&'a libc::c_int), 870 /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms) 871 /// for `AF_ALG` crypto API. 872 /// 873 /// For further information, please refer to the 874 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html) 875 #[cfg(any( 876 target_os = "android", 877 target_os = "linux", 878 ))] 879 AlgSetAeadAssoclen(&'a u32), 880 881 /// UDP GSO makes it possible for applications to generate network packets 882 /// for a virtual MTU much greater than the real one. 883 /// The length of the send data no longer matches the expected length on 884 /// the wire. 885 /// The size of the datagram payload as it should appear on the wire may be 886 /// passed through this control message. 887 /// Send buffer should consist of multiple fixed-size wire payloads 888 /// following one by one, and the last, possibly smaller one. 889 #[cfg(target_os = "linux")] 890 UdpGsoSegments(&'a u16), 891 892 /// Configure the sending addressing and interface for v4 893 /// 894 /// For further information, please refer to the 895 /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page. 896 #[cfg(any(target_os = "linux", 897 target_os = "macos", 898 target_os = "netbsd", 899 target_os = "android", 900 target_os = "ios",))] 901 Ipv4PacketInfo(&'a libc::in_pktinfo), 902 903 /// Configure the sending addressing and interface for v6 904 /// 905 /// For further information, please refer to the 906 /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page. 907 #[cfg(any(target_os = "linux", 908 target_os = "macos", 909 target_os = "netbsd", 910 target_os = "freebsd", 911 target_os = "android", 912 target_os = "ios",))] 913 Ipv6PacketInfo(&'a libc::in6_pktinfo), 914 915 /// SO_RXQ_OVFL indicates that an unsigned 32 bit value 916 /// ancilliary msg (cmsg) should be attached to recieved 917 /// skbs indicating the number of packets dropped by the 918 /// socket between the last recieved packet and this 919 /// received packet. 920 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 921 RxqOvfl(&'a u32), 922 } 923 924 // An opaque structure used to prevent cmsghdr from being a public type 925 #[doc(hidden)] 926 #[derive(Clone, Debug, Eq, PartialEq)] 927 pub struct UnknownCmsg(cmsghdr, Vec<u8>); 928 929 impl<'a> ControlMessage<'a> { 930 /// The value of CMSG_SPACE on this message. 931 /// Safe because CMSG_SPACE is always safe 932 fn space(&self) -> usize { 933 unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize} 934 } 935 936 /// The value of CMSG_LEN on this message. 937 /// Safe because CMSG_LEN is always safe 938 #[cfg(any(target_os = "android", 939 all(target_os = "linux", not(target_env = "musl"))))] 940 fn cmsg_len(&self) -> usize { 941 unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize} 942 } 943 944 #[cfg(not(any(target_os = "android", 945 all(target_os = "linux", not(target_env = "musl")))))] 946 fn cmsg_len(&self) -> libc::c_uint { 947 unsafe{CMSG_LEN(self.len() as libc::c_uint)} 948 } 949 950 /// Return a reference to the payload data as a byte pointer 951 fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) { 952 let data_ptr = match *self { 953 ControlMessage::ScmRights(fds) => { 954 fds as *const _ as *const u8 955 }, 956 #[cfg(any(target_os = "android", target_os = "linux"))] 957 ControlMessage::ScmCredentials(creds) => { 958 &creds.0 as *const libc::ucred as *const u8 959 } 960 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 961 ControlMessage::ScmCreds => { 962 // The kernel overwrites the data, we just zero it 963 // to make sure it's not uninitialized memory 964 unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) }; 965 return 966 } 967 #[cfg(any(target_os = "android", target_os = "linux"))] 968 ControlMessage::AlgSetIv(iv) => { 969 #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501 970 let af_alg_iv = libc::af_alg_iv { 971 ivlen: iv.len() as u32, 972 iv: [0u8; 0], 973 }; 974 975 let size = mem::size_of_val(&af_alg_iv); 976 977 unsafe { 978 ptr::copy_nonoverlapping( 979 &af_alg_iv as *const _ as *const u8, 980 cmsg_data, 981 size, 982 ); 983 ptr::copy_nonoverlapping( 984 iv.as_ptr(), 985 cmsg_data.add(size), 986 iv.len() 987 ); 988 }; 989 990 return 991 }, 992 #[cfg(any(target_os = "android", target_os = "linux"))] 993 ControlMessage::AlgSetOp(op) => { 994 op as *const _ as *const u8 995 }, 996 #[cfg(any(target_os = "android", target_os = "linux"))] 997 ControlMessage::AlgSetAeadAssoclen(len) => { 998 len as *const _ as *const u8 999 }, 1000 #[cfg(target_os = "linux")] 1001 ControlMessage::UdpGsoSegments(gso_size) => { 1002 gso_size as *const _ as *const u8 1003 }, 1004 #[cfg(any(target_os = "linux", target_os = "macos", 1005 target_os = "netbsd", target_os = "android", 1006 target_os = "ios",))] 1007 ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8, 1008 #[cfg(any(target_os = "linux", target_os = "macos", 1009 target_os = "netbsd", target_os = "freebsd", 1010 target_os = "android", target_os = "ios",))] 1011 ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8, 1012 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1013 ControlMessage::RxqOvfl(drop_count) => { 1014 drop_count as *const _ as *const u8 1015 }, 1016 }; 1017 unsafe { 1018 ptr::copy_nonoverlapping( 1019 data_ptr, 1020 cmsg_data, 1021 self.len() 1022 ) 1023 }; 1024 } 1025 1026 /// The size of the payload, excluding its cmsghdr 1027 fn len(&self) -> usize { 1028 match *self { 1029 ControlMessage::ScmRights(fds) => { 1030 mem::size_of_val(fds) 1031 }, 1032 #[cfg(any(target_os = "android", target_os = "linux"))] 1033 ControlMessage::ScmCredentials(creds) => { 1034 mem::size_of_val(creds) 1035 } 1036 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1037 ControlMessage::ScmCreds => { 1038 mem::size_of::<libc::cmsgcred>() 1039 } 1040 #[cfg(any(target_os = "android", target_os = "linux"))] 1041 ControlMessage::AlgSetIv(iv) => { 1042 mem::size_of_val(&iv) + iv.len() 1043 }, 1044 #[cfg(any(target_os = "android", target_os = "linux"))] 1045 ControlMessage::AlgSetOp(op) => { 1046 mem::size_of_val(op) 1047 }, 1048 #[cfg(any(target_os = "android", target_os = "linux"))] 1049 ControlMessage::AlgSetAeadAssoclen(len) => { 1050 mem::size_of_val(len) 1051 }, 1052 #[cfg(target_os = "linux")] 1053 ControlMessage::UdpGsoSegments(gso_size) => { 1054 mem::size_of_val(gso_size) 1055 }, 1056 #[cfg(any(target_os = "linux", target_os = "macos", 1057 target_os = "netbsd", target_os = "android", 1058 target_os = "ios",))] 1059 ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info), 1060 #[cfg(any(target_os = "linux", target_os = "macos", 1061 target_os = "netbsd", target_os = "freebsd", 1062 target_os = "android", target_os = "ios",))] 1063 ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info), 1064 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1065 ControlMessage::RxqOvfl(drop_count) => { 1066 mem::size_of_val(drop_count) 1067 }, 1068 } 1069 } 1070 1071 /// Returns the value to put into the `cmsg_level` field of the header. 1072 fn cmsg_level(&self) -> libc::c_int { 1073 match *self { 1074 ControlMessage::ScmRights(_) => libc::SOL_SOCKET, 1075 #[cfg(any(target_os = "android", target_os = "linux"))] 1076 ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET, 1077 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1078 ControlMessage::ScmCreds => libc::SOL_SOCKET, 1079 #[cfg(any(target_os = "android", target_os = "linux"))] 1080 ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) | 1081 ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG, 1082 #[cfg(target_os = "linux")] 1083 ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP, 1084 #[cfg(any(target_os = "linux", target_os = "macos", 1085 target_os = "netbsd", target_os = "android", 1086 target_os = "ios",))] 1087 ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP, 1088 #[cfg(any(target_os = "linux", target_os = "macos", 1089 target_os = "netbsd", target_os = "freebsd", 1090 target_os = "android", target_os = "ios",))] 1091 ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6, 1092 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1093 ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET, 1094 } 1095 } 1096 1097 /// Returns the value to put into the `cmsg_type` field of the header. 1098 fn cmsg_type(&self) -> libc::c_int { 1099 match *self { 1100 ControlMessage::ScmRights(_) => libc::SCM_RIGHTS, 1101 #[cfg(any(target_os = "android", target_os = "linux"))] 1102 ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS, 1103 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] 1104 ControlMessage::ScmCreds => libc::SCM_CREDS, 1105 #[cfg(any(target_os = "android", target_os = "linux"))] 1106 ControlMessage::AlgSetIv(_) => { 1107 libc::ALG_SET_IV 1108 }, 1109 #[cfg(any(target_os = "android", target_os = "linux"))] 1110 ControlMessage::AlgSetOp(_) => { 1111 libc::ALG_SET_OP 1112 }, 1113 #[cfg(any(target_os = "android", target_os = "linux"))] 1114 ControlMessage::AlgSetAeadAssoclen(_) => { 1115 libc::ALG_SET_AEAD_ASSOCLEN 1116 }, 1117 #[cfg(target_os = "linux")] 1118 ControlMessage::UdpGsoSegments(_) => { 1119 libc::UDP_SEGMENT 1120 }, 1121 #[cfg(any(target_os = "linux", target_os = "macos", 1122 target_os = "netbsd", target_os = "android", 1123 target_os = "ios",))] 1124 ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO, 1125 #[cfg(any(target_os = "linux", target_os = "macos", 1126 target_os = "netbsd", target_os = "freebsd", 1127 target_os = "android", target_os = "ios",))] 1128 ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO, 1129 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))] 1130 ControlMessage::RxqOvfl(_) => { 1131 libc::SO_RXQ_OVFL 1132 }, 1133 } 1134 } 1135 1136 // Unsafe: cmsg must point to a valid cmsghdr with enough space to 1137 // encode self. 1138 unsafe fn encode_into(&self, cmsg: *mut cmsghdr) { 1139 (*cmsg).cmsg_level = self.cmsg_level(); 1140 (*cmsg).cmsg_type = self.cmsg_type(); 1141 (*cmsg).cmsg_len = self.cmsg_len(); 1142 self.copy_to_cmsg_data(CMSG_DATA(cmsg)); 1143 } 1144 } 1145 1146 1147 /// Send data in scatter-gather vectors to a socket, possibly accompanied 1148 /// by ancillary data. Optionally direct the message at the given address, 1149 /// as with sendto. 1150 /// 1151 /// Allocates if cmsgs is nonempty. 1152 pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage], 1153 flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize> 1154 { 1155 let capacity = cmsgs.iter().map(|c| c.space()).sum(); 1156 1157 // First size the buffer needed to hold the cmsgs. It must be zeroed, 1158 // because subsequent code will not clear the padding bytes. 1159 let mut cmsg_buffer = vec![0u8; capacity]; 1160 1161 let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], &iov, &cmsgs, addr); 1162 1163 let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) }; 1164 1165 Errno::result(ret).map(|r| r as usize) 1166 } 1167 1168 #[cfg(any( 1169 target_os = "linux", 1170 target_os = "android", 1171 target_os = "freebsd", 1172 target_os = "netbsd", 1173 ))] 1174 #[derive(Debug)] 1175 pub struct SendMmsgData<'a, I, C> 1176 where 1177 I: AsRef<[IoVec<&'a [u8]>]>, 1178 C: AsRef<[ControlMessage<'a>]> 1179 { 1180 pub iov: I, 1181 pub cmsgs: C, 1182 pub addr: Option<SockAddr>, 1183 pub _lt: std::marker::PhantomData<&'a I>, 1184 } 1185 1186 /// An extension of `sendmsg` that allows the caller to transmit multiple 1187 /// messages on a socket using a single system call. This has performance 1188 /// benefits for some applications. 1189 /// 1190 /// Allocations are performed for cmsgs and to build `msghdr` buffer 1191 /// 1192 /// # Arguments 1193 /// 1194 /// * `fd`: Socket file descriptor 1195 /// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items 1196 /// * `flags`: Optional flags passed directly to the operating system. 1197 /// 1198 /// # Returns 1199 /// `Vec` with numbers of sent bytes on each sent message. 1200 /// 1201 /// # References 1202 /// [`sendmsg`](fn.sendmsg.html) 1203 #[cfg(any( 1204 target_os = "linux", 1205 target_os = "android", 1206 target_os = "freebsd", 1207 target_os = "netbsd", 1208 ))] 1209 pub fn sendmmsg<'a, I, C>( 1210 fd: RawFd, 1211 data: impl std::iter::IntoIterator<Item=&'a SendMmsgData<'a, I, C>>, 1212 flags: MsgFlags 1213 ) -> Result<Vec<usize>> 1214 where 1215 I: AsRef<[IoVec<&'a [u8]>]> + 'a, 1216 C: AsRef<[ControlMessage<'a>]> + 'a, 1217 { 1218 let iter = data.into_iter(); 1219 1220 let size_hint = iter.size_hint(); 1221 let reserve_items = size_hint.1.unwrap_or(size_hint.0); 1222 1223 let mut output = Vec::<libc::mmsghdr>::with_capacity(reserve_items); 1224 1225 let mut cmsgs_buffers = Vec::<Vec<u8>>::with_capacity(reserve_items); 1226 1227 for d in iter { 1228 let capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum(); 1229 let mut cmsgs_buffer = vec![0u8; capacity]; 1230 1231 output.push(libc::mmsghdr { 1232 msg_hdr: pack_mhdr_to_send( 1233 &mut cmsgs_buffer, 1234 &d.iov, 1235 &d.cmsgs, 1236 d.addr.as_ref() 1237 ), 1238 msg_len: 0, 1239 }); 1240 cmsgs_buffers.push(cmsgs_buffer); 1241 }; 1242 1243 let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) }; 1244 1245 let sent_messages = Errno::result(ret)? as usize; 1246 let mut sent_bytes = Vec::with_capacity(sent_messages); 1247 1248 for item in &output { 1249 sent_bytes.push(item.msg_len as usize); 1250 } 1251 1252 Ok(sent_bytes) 1253 } 1254 1255 1256 #[cfg(any( 1257 target_os = "linux", 1258 target_os = "android", 1259 target_os = "freebsd", 1260 target_os = "netbsd", 1261 ))] 1262 #[derive(Debug)] 1263 pub struct RecvMmsgData<'a, I> 1264 where 1265 I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, 1266 { 1267 pub iov: I, 1268 pub cmsg_buffer: Option<&'a mut Vec<u8>>, 1269 } 1270 1271 /// An extension of `recvmsg` that allows the caller to receive multiple 1272 /// messages from a socket using a single system call. This has 1273 /// performance benefits for some applications. 1274 /// 1275 /// `iov` and `cmsg_buffer` should be constructed similarly to `recvmsg` 1276 /// 1277 /// Multiple allocations are performed 1278 /// 1279 /// # Arguments 1280 /// 1281 /// * `fd`: Socket file descriptor 1282 /// * `data`: Struct that implements `IntoIterator` with `RecvMmsgData` items 1283 /// * `flags`: Optional flags passed directly to the operating system. 1284 /// 1285 /// # RecvMmsgData 1286 /// 1287 /// * `iov`: Scatter-gather list of buffers to receive the message 1288 /// * `cmsg_buffer`: Space to receive ancillary data. Should be created by 1289 /// [`cmsg_space!`](macro.cmsg_space.html) 1290 /// 1291 /// # Returns 1292 /// A `Vec` with multiple `RecvMsg`, one per received message 1293 /// 1294 /// # References 1295 /// - [`recvmsg`](fn.recvmsg.html) 1296 /// - [`RecvMsg`](struct.RecvMsg.html) 1297 #[cfg(any( 1298 target_os = "linux", 1299 target_os = "android", 1300 target_os = "freebsd", 1301 target_os = "netbsd", 1302 ))] 1303 #[allow(clippy::needless_collect)] // Complicated false positive 1304 pub fn recvmmsg<'a, I>( 1305 fd: RawFd, 1306 data: impl std::iter::IntoIterator<Item=&'a mut RecvMmsgData<'a, I>, 1307 IntoIter=impl ExactSizeIterator + Iterator<Item=&'a mut RecvMmsgData<'a, I>>>, 1308 flags: MsgFlags, 1309 timeout: Option<crate::sys::time::TimeSpec> 1310 ) -> Result<Vec<RecvMsg<'a>>> 1311 where 1312 I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, 1313 { 1314 let iter = data.into_iter(); 1315 1316 let num_messages = iter.len(); 1317 1318 let mut output: Vec<libc::mmsghdr> = Vec::with_capacity(num_messages); 1319 1320 // Addresses should be pre-allocated. pack_mhdr_to_receive will store them 1321 // as raw pointers, so we may not move them. Turn the vec into a boxed 1322 // slice so we won't inadvertently reallocate the vec. 1323 let mut addresses = vec![mem::MaybeUninit::uninit(); num_messages] 1324 .into_boxed_slice(); 1325 1326 let results: Vec<_> = iter.enumerate().map(|(i, d)| { 1327 let (msg_controllen, mhdr) = unsafe { 1328 pack_mhdr_to_receive( 1329 d.iov.as_ref(), 1330 &mut d.cmsg_buffer, 1331 addresses[i].as_mut_ptr(), 1332 ) 1333 }; 1334 1335 output.push( 1336 libc::mmsghdr { 1337 msg_hdr: mhdr, 1338 msg_len: 0, 1339 } 1340 ); 1341 1342 (msg_controllen as usize, &mut d.cmsg_buffer) 1343 }).collect(); 1344 1345 let timeout = if let Some(mut t) = timeout { 1346 t.as_mut() as *mut libc::timespec 1347 } else { 1348 ptr::null_mut() 1349 }; 1350 1351 let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) }; 1352 1353 let _ = Errno::result(ret)?; 1354 1355 Ok(output 1356 .into_iter() 1357 .take(ret as usize) 1358 .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()})) 1359 .zip(results.into_iter()) 1360 .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| { 1361 unsafe { 1362 read_mhdr( 1363 mmsghdr.msg_hdr, 1364 mmsghdr.msg_len as isize, 1365 msg_controllen, 1366 address, 1367 cmsg_buffer 1368 ) 1369 } 1370 }) 1371 .collect()) 1372 } 1373 1374 unsafe fn read_mhdr<'a, 'b>( 1375 mhdr: msghdr, 1376 r: isize, 1377 msg_controllen: usize, 1378 address: sockaddr_storage, 1379 cmsg_buffer: &'a mut Option<&'b mut Vec<u8>> 1380 ) -> RecvMsg<'b> { 1381 let cmsghdr = { 1382 if mhdr.msg_controllen > 0 { 1383 // got control message(s) 1384 cmsg_buffer 1385 .as_mut() 1386 .unwrap() 1387 .set_len(mhdr.msg_controllen as usize); 1388 debug_assert!(!mhdr.msg_control.is_null()); 1389 debug_assert!(msg_controllen >= mhdr.msg_controllen as usize); 1390 CMSG_FIRSTHDR(&mhdr as *const msghdr) 1391 } else { 1392 ptr::null() 1393 }.as_ref() 1394 }; 1395 1396 let address = sockaddr_storage_to_addr( 1397 &address , 1398 mhdr.msg_namelen as usize 1399 ).ok(); 1400 1401 RecvMsg { 1402 bytes: r as usize, 1403 cmsghdr, 1404 address, 1405 flags: MsgFlags::from_bits_truncate(mhdr.msg_flags), 1406 mhdr, 1407 } 1408 } 1409 1410 unsafe fn pack_mhdr_to_receive<'a, I>( 1411 iov: I, 1412 cmsg_buffer: &mut Option<&mut Vec<u8>>, 1413 address: *mut sockaddr_storage, 1414 ) -> (usize, msghdr) 1415 where 1416 I: AsRef<[IoVec<&'a mut [u8]>]> + 'a, 1417 { 1418 let (msg_control, msg_controllen) = cmsg_buffer.as_mut() 1419 .map(|v| (v.as_mut_ptr(), v.capacity())) 1420 .unwrap_or((ptr::null_mut(), 0)); 1421 1422 let mhdr = { 1423 // Musl's msghdr has private fields, so this is the only way to 1424 // initialize it. 1425 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); 1426 let p = mhdr.as_mut_ptr(); 1427 (*p).msg_name = address as *mut c_void; 1428 (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t; 1429 (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec; 1430 (*p).msg_iovlen = iov.as_ref().len() as _; 1431 (*p).msg_control = msg_control as *mut c_void; 1432 (*p).msg_controllen = msg_controllen as _; 1433 (*p).msg_flags = 0; 1434 mhdr.assume_init() 1435 }; 1436 1437 (msg_controllen, mhdr) 1438 } 1439 1440 fn pack_mhdr_to_send<'a, I, C>( 1441 cmsg_buffer: &mut [u8], 1442 iov: I, 1443 cmsgs: C, 1444 addr: Option<&SockAddr> 1445 ) -> msghdr 1446 where 1447 I: AsRef<[IoVec<&'a [u8]>]>, 1448 C: AsRef<[ControlMessage<'a>]> 1449 { 1450 let capacity = cmsg_buffer.len(); 1451 1452 // Next encode the sending address, if provided 1453 let (name, namelen) = match addr { 1454 Some(addr) => { 1455 let (x, y) = addr.as_ffi_pair(); 1456 (x as *const _, y) 1457 }, 1458 None => (ptr::null(), 0), 1459 }; 1460 1461 // The message header must be initialized before the individual cmsgs. 1462 let cmsg_ptr = if capacity > 0 { 1463 cmsg_buffer.as_ptr() as *mut c_void 1464 } else { 1465 ptr::null_mut() 1466 }; 1467 1468 let mhdr = unsafe { 1469 // Musl's msghdr has private fields, so this is the only way to 1470 // initialize it. 1471 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed(); 1472 let p = mhdr.as_mut_ptr(); 1473 (*p).msg_name = name as *mut _; 1474 (*p).msg_namelen = namelen; 1475 // transmute iov into a mutable pointer. sendmsg doesn't really mutate 1476 // the buffer, but the standard says that it takes a mutable pointer 1477 (*p).msg_iov = iov.as_ref().as_ptr() as *mut _; 1478 (*p).msg_iovlen = iov.as_ref().len() as _; 1479 (*p).msg_control = cmsg_ptr; 1480 (*p).msg_controllen = capacity as _; 1481 (*p).msg_flags = 0; 1482 mhdr.assume_init() 1483 }; 1484 1485 // Encode each cmsg. This must happen after initializing the header because 1486 // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields. 1487 // CMSG_FIRSTHDR is always safe 1488 let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) }; 1489 for cmsg in cmsgs.as_ref() { 1490 assert_ne!(pmhdr, ptr::null_mut()); 1491 // Safe because we know that pmhdr is valid, and we initialized it with 1492 // sufficient space 1493 unsafe { cmsg.encode_into(pmhdr) }; 1494 // Safe because mhdr is valid 1495 pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) }; 1496 } 1497 1498 mhdr 1499 } 1500 1501 /// Receive message in scatter-gather vectors from a socket, and 1502 /// optionally receive ancillary data into the provided buffer. 1503 /// If no ancillary data is desired, use () as the type parameter. 1504 /// 1505 /// # Arguments 1506 /// 1507 /// * `fd`: Socket file descriptor 1508 /// * `iov`: Scatter-gather list of buffers to receive the message 1509 /// * `cmsg_buffer`: Space to receive ancillary data. Should be created by 1510 /// [`cmsg_space!`](macro.cmsg_space.html) 1511 /// * `flags`: Optional flags passed directly to the operating system. 1512 /// 1513 /// # References 1514 /// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html) 1515 pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>], 1516 mut cmsg_buffer: Option<&'a mut Vec<u8>>, 1517 flags: MsgFlags) -> Result<RecvMsg<'a>> 1518 { 1519 let mut address = mem::MaybeUninit::uninit(); 1520 1521 let (msg_controllen, mut mhdr) = unsafe { 1522 pack_mhdr_to_receive(&iov, &mut cmsg_buffer, address.as_mut_ptr()) 1523 }; 1524 1525 let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) }; 1526 1527 let r = Errno::result(ret)?; 1528 1529 Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init(), &mut cmsg_buffer) }) 1530 } 1531 1532 1533 /// Create an endpoint for communication 1534 /// 1535 /// The `protocol` specifies a particular protocol to be used with the 1536 /// socket. Normally only a single protocol exists to support a 1537 /// particular socket type within a given protocol family, in which case 1538 /// protocol can be specified as `None`. However, it is possible that many 1539 /// protocols may exist, in which case a particular protocol must be 1540 /// specified in this manner. 1541 /// 1542 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html) 1543 pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> { 1544 let protocol = match protocol.into() { 1545 None => 0, 1546 Some(p) => p as c_int, 1547 }; 1548 1549 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a 1550 // little easier to understand by separating it out. So we have to merge these bitfields 1551 // here. 1552 let mut ty = ty as c_int; 1553 ty |= flags.bits(); 1554 1555 let res = unsafe { libc::socket(domain as c_int, ty, protocol) }; 1556 1557 Errno::result(res) 1558 } 1559 1560 /// Create a pair of connected sockets 1561 /// 1562 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html) 1563 pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T, 1564 flags: SockFlag) -> Result<(RawFd, RawFd)> { 1565 let protocol = match protocol.into() { 1566 None => 0, 1567 Some(p) => p as c_int, 1568 }; 1569 1570 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a 1571 // little easier to understand by separating it out. So we have to merge these bitfields 1572 // here. 1573 let mut ty = ty as c_int; 1574 ty |= flags.bits(); 1575 1576 let mut fds = [-1, -1]; 1577 1578 let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) }; 1579 Errno::result(res)?; 1580 1581 Ok((fds[0], fds[1])) 1582 } 1583 1584 /// Listen for connections on a socket 1585 /// 1586 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html) 1587 pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> { 1588 let res = unsafe { libc::listen(sockfd, backlog as c_int) }; 1589 1590 Errno::result(res).map(drop) 1591 } 1592 1593 /// Bind a name to a socket 1594 /// 1595 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html) 1596 pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> { 1597 let res = unsafe { 1598 let (ptr, len) = addr.as_ffi_pair(); 1599 libc::bind(fd, ptr, len) 1600 }; 1601 1602 Errno::result(res).map(drop) 1603 } 1604 1605 /// Accept a connection on a socket 1606 /// 1607 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html) 1608 pub fn accept(sockfd: RawFd) -> Result<RawFd> { 1609 let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) }; 1610 1611 Errno::result(res) 1612 } 1613 1614 /// Accept a connection on a socket 1615 /// 1616 /// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html) 1617 #[cfg(any(all( 1618 target_os = "android", 1619 any( 1620 target_arch = "aarch64", 1621 target_arch = "x86", 1622 target_arch = "x86_64" 1623 ) 1624 ), 1625 target_os = "freebsd", 1626 target_os = "linux", 1627 target_os = "openbsd"))] 1628 pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> { 1629 let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) }; 1630 1631 Errno::result(res) 1632 } 1633 1634 /// Initiate a connection on a socket 1635 /// 1636 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html) 1637 pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> { 1638 let res = unsafe { 1639 let (ptr, len) = addr.as_ffi_pair(); 1640 libc::connect(fd, ptr, len) 1641 }; 1642 1643 Errno::result(res).map(drop) 1644 } 1645 1646 /// Receive data from a connection-oriented socket. Returns the number of 1647 /// bytes read 1648 /// 1649 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html) 1650 pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> { 1651 unsafe { 1652 let ret = libc::recv( 1653 sockfd, 1654 buf.as_ptr() as *mut c_void, 1655 buf.len() as size_t, 1656 flags.bits()); 1657 1658 Errno::result(ret).map(|r| r as usize) 1659 } 1660 } 1661 1662 /// Receive data from a connectionless or connection-oriented socket. Returns 1663 /// the number of bytes read and, for connectionless sockets, the socket 1664 /// address of the sender. 1665 /// 1666 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html) 1667 pub fn recvfrom(sockfd: RawFd, buf: &mut [u8]) 1668 -> Result<(usize, Option<SockAddr>)> 1669 { 1670 unsafe { 1671 let mut addr: sockaddr_storage = mem::zeroed(); 1672 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; 1673 1674 let ret = Errno::result(libc::recvfrom( 1675 sockfd, 1676 buf.as_ptr() as *mut c_void, 1677 buf.len() as size_t, 1678 0, 1679 &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr, 1680 &mut len as *mut socklen_t))? as usize; 1681 1682 match sockaddr_storage_to_addr(&addr, len as usize) { 1683 Err(Errno::ENOTCONN) => Ok((ret, None)), 1684 Ok(addr) => Ok((ret, Some(addr))), 1685 Err(e) => Err(e) 1686 } 1687 } 1688 } 1689 1690 /// Send a message to a socket 1691 /// 1692 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html) 1693 pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> { 1694 let ret = unsafe { 1695 let (ptr, len) = addr.as_ffi_pair(); 1696 libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len) 1697 }; 1698 1699 Errno::result(ret).map(|r| r as usize) 1700 } 1701 1702 /// Send data to a connection-oriented socket. Returns the number of bytes read 1703 /// 1704 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html) 1705 pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> { 1706 let ret = unsafe { 1707 libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits()) 1708 }; 1709 1710 Errno::result(ret).map(|r| r as usize) 1711 } 1712 1713 /* 1714 * 1715 * ===== Socket Options ===== 1716 * 1717 */ 1718 1719 /// Represents a socket option that can be retrieved. 1720 pub trait GetSockOpt : Copy { 1721 type Val; 1722 1723 /// Look up the value of this socket option on the given socket. 1724 fn get(&self, fd: RawFd) -> Result<Self::Val>; 1725 } 1726 1727 /// Represents a socket option that can be set. 1728 pub trait SetSockOpt : Clone { 1729 type Val; 1730 1731 /// Set the value of this socket option on the given socket. 1732 fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>; 1733 } 1734 1735 /// Get the current value for the requested socket option 1736 /// 1737 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html) 1738 pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> { 1739 opt.get(fd) 1740 } 1741 1742 /// Sets the value for the requested socket option 1743 /// 1744 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html) 1745 /// 1746 /// # Examples 1747 /// 1748 /// ``` 1749 /// use nix::sys::socket::setsockopt; 1750 /// use nix::sys::socket::sockopt::KeepAlive; 1751 /// use std::net::TcpListener; 1752 /// use std::os::unix::io::AsRawFd; 1753 /// 1754 /// let listener = TcpListener::bind("0.0.0.0:0").unwrap(); 1755 /// let fd = listener.as_raw_fd(); 1756 /// let res = setsockopt(fd, KeepAlive, &true); 1757 /// assert!(res.is_ok()); 1758 /// ``` 1759 pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> { 1760 opt.set(fd, val) 1761 } 1762 1763 /// Get the address of the peer connected to the socket `fd`. 1764 /// 1765 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html) 1766 pub fn getpeername(fd: RawFd) -> Result<SockAddr> { 1767 unsafe { 1768 let mut addr = mem::MaybeUninit::uninit(); 1769 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; 1770 1771 let ret = libc::getpeername( 1772 fd, 1773 addr.as_mut_ptr() as *mut libc::sockaddr, 1774 &mut len 1775 ); 1776 1777 Errno::result(ret)?; 1778 1779 sockaddr_storage_to_addr(&addr.assume_init(), len as usize) 1780 } 1781 } 1782 1783 /// Get the current address to which the socket `fd` is bound. 1784 /// 1785 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html) 1786 pub fn getsockname(fd: RawFd) -> Result<SockAddr> { 1787 unsafe { 1788 let mut addr = mem::MaybeUninit::uninit(); 1789 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t; 1790 1791 let ret = libc::getsockname( 1792 fd, 1793 addr.as_mut_ptr() as *mut libc::sockaddr, 1794 &mut len 1795 ); 1796 1797 Errno::result(ret)?; 1798 1799 sockaddr_storage_to_addr(&addr.assume_init(), len as usize) 1800 } 1801 } 1802 1803 /// Return the appropriate `SockAddr` type from a `sockaddr_storage` of a 1804 /// certain size. 1805 /// 1806 /// In C this would usually be done by casting. The `len` argument 1807 /// should be the number of bytes in the `sockaddr_storage` that are actually 1808 /// allocated and valid. It must be at least as large as all the useful parts 1809 /// of the structure. Note that in the case of a `sockaddr_un`, `len` need not 1810 /// include the terminating null. 1811 pub fn sockaddr_storage_to_addr( 1812 addr: &sockaddr_storage, 1813 len: usize) -> Result<SockAddr> { 1814 1815 assert!(len <= mem::size_of::<sockaddr_storage>()); 1816 if len < mem::size_of_val(&addr.ss_family) { 1817 return Err(Errno::ENOTCONN); 1818 } 1819 1820 match c_int::from(addr.ss_family) { 1821 libc::AF_INET => { 1822 assert!(len as usize >= mem::size_of::<sockaddr_in>()); 1823 let sin = unsafe { 1824 *(addr as *const sockaddr_storage as *const sockaddr_in) 1825 }; 1826 Ok(SockAddr::Inet(InetAddr::V4(sin))) 1827 } 1828 libc::AF_INET6 => { 1829 assert!(len as usize >= mem::size_of::<sockaddr_in6>()); 1830 let sin6 = unsafe { 1831 *(addr as *const _ as *const sockaddr_in6) 1832 }; 1833 Ok(SockAddr::Inet(InetAddr::V6(sin6))) 1834 } 1835 libc::AF_UNIX => { 1836 let pathlen = len - offset_of!(sockaddr_un, sun_path); 1837 unsafe { 1838 let sun = *(addr as *const _ as *const sockaddr_un); 1839 Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, pathlen))) 1840 } 1841 } 1842 #[cfg(any(target_os = "android", target_os = "linux"))] 1843 libc::AF_PACKET => { 1844 use libc::sockaddr_ll; 1845 // Don't assert anything about the size. 1846 // Apparently the Linux kernel can return smaller sizes when 1847 // the value in the last element of sockaddr_ll (`sll_addr`) is 1848 // smaller than the declared size of that field 1849 let sll = unsafe { 1850 *(addr as *const _ as *const sockaddr_ll) 1851 }; 1852 Ok(SockAddr::Link(LinkAddr(sll))) 1853 } 1854 #[cfg(any(target_os = "android", target_os = "linux"))] 1855 libc::AF_NETLINK => { 1856 use libc::sockaddr_nl; 1857 let snl = unsafe { 1858 *(addr as *const _ as *const sockaddr_nl) 1859 }; 1860 Ok(SockAddr::Netlink(NetlinkAddr(snl))) 1861 } 1862 #[cfg(any(target_os = "android", target_os = "linux"))] 1863 libc::AF_ALG => { 1864 use libc::sockaddr_alg; 1865 let salg = unsafe { 1866 *(addr as *const _ as *const sockaddr_alg) 1867 }; 1868 Ok(SockAddr::Alg(AlgAddr(salg))) 1869 } 1870 #[cfg(any(target_os = "android", target_os = "linux"))] 1871 libc::AF_VSOCK => { 1872 use libc::sockaddr_vm; 1873 let svm = unsafe { 1874 *(addr as *const _ as *const sockaddr_vm) 1875 }; 1876 Ok(SockAddr::Vsock(VsockAddr(svm))) 1877 } 1878 af => panic!("unexpected address family {}", af), 1879 } 1880 } 1881 1882 1883 #[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] 1884 pub enum Shutdown { 1885 /// Further receptions will be disallowed. 1886 Read, 1887 /// Further transmissions will be disallowed. 1888 Write, 1889 /// Further receptions and transmissions will be disallowed. 1890 Both, 1891 } 1892 1893 /// Shut down part of a full-duplex connection. 1894 /// 1895 /// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html) 1896 pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> { 1897 unsafe { 1898 use libc::shutdown; 1899 1900 let how = match how { 1901 Shutdown::Read => libc::SHUT_RD, 1902 Shutdown::Write => libc::SHUT_WR, 1903 Shutdown::Both => libc::SHUT_RDWR, 1904 }; 1905 1906 Errno::result(shutdown(df, how)).map(drop) 1907 } 1908 } 1909 1910 #[cfg(test)] 1911 mod tests { 1912 #[test] 1913 fn can_use_cmsg_space() { 1914 let _ = cmsg_space!(u8); 1915 } 1916 } 1917