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