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 /// ```
776 /// # #[macro_use] extern crate nix;
777 /// # use nix::sys::socket::*;
778 /// # use nix::sys::time::*;
779 /// # use std::io::{IoSlice, IoSliceMut};
780 /// # use std::time::*;
781 /// # use std::str::FromStr;
782 /// # use std::os::unix::io::AsRawFd;
783 /// # fn main() {
784 /// // Set up
785 /// let message = "Ohayō!".as_bytes();
786 /// let in_socket = socket(
787 /// AddressFamily::Inet,
788 /// SockType::Datagram,
789 /// SockFlag::empty(),
790 /// None).unwrap();
791 /// setsockopt(&in_socket, sockopt::ReceiveTimestamp, &true).unwrap();
792 /// let localhost = SockaddrIn::from_str("127.0.0.1:0").unwrap();
793 /// bind(in_socket.as_raw_fd(), &localhost).unwrap();
794 /// let address: SockaddrIn = getsockname(in_socket.as_raw_fd()).unwrap();
795 /// // Get initial time
796 /// let time0 = SystemTime::now();
797 /// // Send the message
798 /// let iov = [IoSlice::new(message)];
799 /// let flags = MsgFlags::empty();
800 /// let l = sendmsg(in_socket.as_raw_fd(), &iov, &[], flags, Some(&address)).unwrap();
801 /// assert_eq!(message.len(), l);
802 /// // Receive the message
803 /// let mut buffer = vec![0u8; message.len()];
804 /// let mut cmsgspace = cmsg_space!(TimeVal);
805 /// let mut iov = [IoSliceMut::new(&mut buffer)];
806 /// let r = recvmsg::<SockaddrIn>(in_socket.as_raw_fd(), &mut iov, Some(&mut cmsgspace), flags)
807 /// .unwrap();
808 /// let rtime = match r.cmsgs().unwrap().next() {
809 /// Some(ControlMessageOwned::ScmTimestamp(rtime)) => rtime,
810 /// Some(_) => panic!("Unexpected control message"),
811 /// None => panic!("No control message")
812 /// };
813 /// // Check the final time
814 /// let time1 = SystemTime::now();
815 /// // the packet's received timestamp should lie in-between the two system
816 /// // times, unless the system clock was adjusted in the meantime.
817 /// let rduration = Duration::new(rtime.tv_sec() as u64,
818 /// rtime.tv_usec() as u32 * 1000);
819 /// assert!(time0.duration_since(UNIX_EPOCH).unwrap() <= rduration);
820 /// assert!(rduration <= time1.duration_since(UNIX_EPOCH).unwrap());
821 /// // Close socket
822 /// # }
823 /// ```
824 ScmTimestamp(TimeVal),
825 /// A set of nanosecond resolution timestamps
826 ///
827 /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
828 #[cfg(linux_android)]
829 ScmTimestampsns(Timestamps),
830 /// Nanoseconds resolution timestamp
831 ///
832 /// [Further reading](https://www.kernel.org/doc/html/latest/networking/timestamping.html)
833 #[cfg(linux_android)]
834 ScmTimestampns(TimeSpec),
835 /// Realtime clock timestamp
836 ///
837 /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt)
838 #[cfg(target_os = "freebsd")]
839 ScmRealtime(TimeSpec),
840 /// Monotonic clock timestamp
841 ///
842 /// [Further reading](https://man.freebsd.org/cgi/man.cgi?setsockopt)
843 #[cfg(target_os = "freebsd")]
844 ScmMonotonic(TimeSpec),
845 #[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
846 #[cfg(feature = "net")]
847 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
848 Ipv4PacketInfo(libc::in_pktinfo),
849 #[cfg(any(linux_android, bsd))]
850 #[cfg(feature = "net")]
851 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
852 Ipv6PacketInfo(libc::in6_pktinfo),
853 #[cfg(bsd)]
854 #[cfg(feature = "net")]
855 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
856 Ipv4RecvIf(libc::sockaddr_dl),
857 #[cfg(bsd)]
858 #[cfg(feature = "net")]
859 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
860 Ipv4RecvDstAddr(libc::in_addr),
861 #[cfg(any(linux_android, target_os = "freebsd"))]
862 #[cfg(feature = "net")]
863 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
864 Ipv4OrigDstAddr(libc::sockaddr_in),
865 #[cfg(any(linux_android, target_os = "freebsd"))]
866 #[cfg(feature = "net")]
867 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
868 Ipv6OrigDstAddr(libc::sockaddr_in6),
869
870 /// Time-to-Live (TTL) header field of the incoming IPv4 packet.
871 ///
872 /// [Further reading](https://www.man7.org/linux/man-pages/man7/ip.7.html)
873 #[cfg(linux_android)]
874 #[cfg(feature = "net")]
875 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
876 Ipv4Ttl(i32),
877
878 /// Time-to-Live (TTL) header field of the incoming IPv4 packet.
879 ///
880 /// [Further reading](https://datatracker.ietf.org/doc/html/rfc3542.html)
881 #[cfg(target_os = "freebsd")]
882 #[cfg(feature = "net")]
883 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
884 Ipv4Ttl(u8),
885
886 /// Hop Limit header field of the incoming IPv6 packet.
887 ///
888 /// [Further reading for Linux](https://www.man7.org/linux/man-pages/man7/ip.7.html)
889 /// [Further reading for FreeBSD](https://datatracker.ietf.org/doc/html/rfc3542.html)
890 #[cfg(any(linux_android, target_os = "freebsd"))]
891 #[cfg(feature = "net")]
892 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
893 Ipv6HopLimit(i32),
894
895 /// Retrieve the DSCP (ToS) header field of the incoming IPv4 packet.
896 #[cfg(any(linux_android, target_os = "freebsd"))]
897 #[cfg(feature = "net")]
898 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
899 Ipv4Tos(u8),
900
901 /// Retrieve the DSCP (Traffic Class) header field of the incoming IPv6 packet.
902 #[cfg(any(linux_android, target_os = "freebsd"))]
903 #[cfg(feature = "net")]
904 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
905 Ipv6TClass(i32),
906
907 /// UDP Generic Receive Offload (GRO) allows receiving multiple UDP
908 /// packets from a single sender.
909 /// Fixed-size payloads are following one by one in a receive buffer.
910 /// This Control Message indicates the size of all smaller packets,
911 /// except, maybe, the last one.
912 ///
913 /// `UdpGroSegment` socket option should be enabled on a socket
914 /// to allow receiving GRO packets.
915 #[cfg(target_os = "linux")]
916 #[cfg(feature = "net")]
917 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
918 UdpGroSegments(i32),
919
920 /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
921 /// ancilliary msg (cmsg) should be attached to recieved
922 /// skbs indicating the number of packets dropped by the
923 /// socket between the last recieved packet and this
924 /// received packet.
925 ///
926 /// `RxqOvfl` socket option should be enabled on a socket
927 /// to allow receiving the drop counter.
928 #[cfg(any(linux_android, target_os = "fuchsia"))]
929 RxqOvfl(u32),
930
931 /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
932 #[cfg(linux_android)]
933 #[cfg(feature = "net")]
934 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
935 Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>),
936 /// Socket error queue control messages read with the `MSG_ERRQUEUE` flag.
937 #[cfg(linux_android)]
938 #[cfg(feature = "net")]
939 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
940 Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>),
941
942 /// `SOL_TLS` messages of type `TLS_GET_RECORD_TYPE`
943 #[cfg(any(target_os = "linux"))]
944 TlsGetRecordType(TlsGetRecordType),
945
946 /// Catch-all variant for unimplemented cmsg types.
947 Unknown(UnknownCmsg),
948}
949
950/// For representing packet timestamps via `SO_TIMESTAMPING` interface
951#[cfg(linux_android)]
952#[derive(Copy, Clone, Debug, Eq, PartialEq)]
953pub struct Timestamps {
954 /// software based timestamp, usually one containing data
955 pub system: TimeSpec,
956 /// legacy timestamp, usually empty
957 pub hw_trans: TimeSpec,
958 /// hardware based timestamp
959 pub hw_raw: TimeSpec,
960}
961
962/// These constants correspond to TLS 1.2 message types, as defined in
963/// RFC 5246, Appendix A.1
964#[cfg(any(target_os = "linux"))]
965#[derive(Clone, Copy, PartialEq, Eq, Debug)]
966#[repr(u8)]
967#[non_exhaustive]
968pub enum TlsGetRecordType {
969 ChangeCipherSpec ,
970 Alert,
971 Handshake,
972 ApplicationData,
973 Unknown(u8),
974}
975
976#[cfg(any(target_os = "linux"))]
977impl From<u8> for TlsGetRecordType {
978 fn from(x: u8) -> Self {
979 match x {
980 20 => TlsGetRecordType::ChangeCipherSpec,
981 21 => TlsGetRecordType::Alert,
982 22 => TlsGetRecordType::Handshake,
983 23 => TlsGetRecordType::ApplicationData,
984 _ => TlsGetRecordType::Unknown(x),
985 }
986 }
987}
988
989impl ControlMessageOwned {
990 /// Decodes a `ControlMessageOwned` from raw bytes.
991 ///
992 /// This is only safe to call if the data is correct for the message type
993 /// specified in the header. Normally, the kernel ensures that this is the
994 /// case. "Correct" in this case includes correct length, alignment and
995 /// actual content.
996 // Clippy complains about the pointer alignment of `p`, not understanding
997 // that it's being fed to a function that can handle that.
998 #[allow(clippy::cast_ptr_alignment)]
999 unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
1000 {
1001 let p = unsafe { CMSG_DATA(header) };
1002 // The cast is not unnecessary on all platforms.
1003 #[allow(clippy::unnecessary_cast)]
1004 let len = header as *const _ as usize + header.cmsg_len as usize
1005 - p as usize;
1006 match (header.cmsg_level, header.cmsg_type) {
1007 (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
1008 let n = len / mem::size_of::<RawFd>();
1009 let mut fds = Vec::with_capacity(n);
1010 for i in 0..n {
1011 unsafe {
1012 let fdp = (p as *const RawFd).add(i);
1013 fds.push(ptr::read_unaligned(fdp));
1014 }
1015 }
1016 ControlMessageOwned::ScmRights(fds)
1017 },
1018 #[cfg(linux_android)]
1019 (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
1020 let cred: libc::ucred = unsafe { ptr::read_unaligned(p as *const _) };
1021 ControlMessageOwned::ScmCredentials(cred.into())
1022 }
1023 #[cfg(freebsdlike)]
1024 (libc::SOL_SOCKET, libc::SCM_CREDS) => {
1025 let cred: libc::cmsgcred = unsafe { ptr::read_unaligned(p as *const _) };
1026 ControlMessageOwned::ScmCreds(cred.into())
1027 }
1028 #[cfg(not(any(target_os = "aix", target_os = "haiku", target_os = "cygwin")))]
1029 (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
1030 let tv: libc::timeval = unsafe { ptr::read_unaligned(p as *const _) };
1031 ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
1032 },
1033 #[cfg(linux_android)]
1034 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
1035 let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) };
1036 ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts))
1037 }
1038 #[cfg(target_os = "freebsd")]
1039 (libc::SOL_SOCKET, libc::SCM_REALTIME) => {
1040 let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) };
1041 ControlMessageOwned::ScmRealtime(TimeSpec::from(ts))
1042 }
1043 #[cfg(target_os = "freebsd")]
1044 (libc::SOL_SOCKET, libc::SCM_MONOTONIC) => {
1045 let ts: libc::timespec = unsafe { ptr::read_unaligned(p as *const _) };
1046 ControlMessageOwned::ScmMonotonic(TimeSpec::from(ts))
1047 }
1048 #[cfg(linux_android)]
1049 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => {
1050 let tp = p as *const libc::timespec;
1051 let ts: libc::timespec = unsafe { ptr::read_unaligned(tp) };
1052 let system = TimeSpec::from(ts);
1053 let ts: libc::timespec = unsafe { ptr::read_unaligned(tp.add(1)) };
1054 let hw_trans = TimeSpec::from(ts);
1055 let ts: libc::timespec = unsafe { ptr::read_unaligned(tp.add(2)) };
1056 let hw_raw = TimeSpec::from(ts);
1057 let timestamping = Timestamps { system, hw_trans, hw_raw };
1058 ControlMessageOwned::ScmTimestampsns(timestamping)
1059 }
1060 #[cfg(any(target_os = "freebsd", linux_android, apple_targets))]
1061 #[cfg(feature = "net")]
1062 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
1063 let info = unsafe { ptr::read_unaligned(p as *const libc::in6_pktinfo) };
1064 ControlMessageOwned::Ipv6PacketInfo(info)
1065 }
1066 #[cfg(any(linux_android, apple_targets, target_os = "netbsd"))]
1067 #[cfg(feature = "net")]
1068 (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
1069 let info = unsafe { ptr::read_unaligned(p as *const libc::in_pktinfo) };
1070 ControlMessageOwned::Ipv4PacketInfo(info)
1071 }
1072 #[cfg(bsd)]
1073 #[cfg(feature = "net")]
1074 (libc::IPPROTO_IP, libc::IP_RECVIF) => {
1075 let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_dl) };
1076 ControlMessageOwned::Ipv4RecvIf(dl)
1077 },
1078 #[cfg(bsd)]
1079 #[cfg(feature = "net")]
1080 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
1081 let dl = unsafe { ptr::read_unaligned(p as *const libc::in_addr) };
1082 ControlMessageOwned::Ipv4RecvDstAddr(dl)
1083 },
1084 #[cfg(any(linux_android, target_os = "freebsd"))]
1085 #[cfg(feature = "net")]
1086 (libc::IPPROTO_IP, libc::IP_ORIGDSTADDR) => {
1087 let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_in) };
1088 ControlMessageOwned::Ipv4OrigDstAddr(dl)
1089 },
1090 #[cfg(target_os = "linux")]
1091 #[cfg(feature = "net")]
1092 (libc::SOL_UDP, libc::UDP_GRO) => {
1093 let gso_size: i32 = unsafe { ptr::read_unaligned(p as *const _) };
1094 ControlMessageOwned::UdpGroSegments(gso_size)
1095 },
1096 #[cfg(any(linux_android, target_os = "fuchsia"))]
1097 (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
1098 let drop_counter = unsafe { ptr::read_unaligned(p as *const u32) };
1099 ControlMessageOwned::RxqOvfl(drop_counter)
1100 },
1101 #[cfg(linux_android)]
1102 #[cfg(feature = "net")]
1103 (libc::IPPROTO_IP, libc::IP_RECVERR) => {
1104 let (err, addr) = unsafe { Self::recv_err_helper::<sockaddr_in>(p, len) };
1105 ControlMessageOwned::Ipv4RecvErr(err, addr)
1106 },
1107 #[cfg(linux_android)]
1108 #[cfg(feature = "net")]
1109 (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => {
1110 let (err, addr) = unsafe { Self::recv_err_helper::<sockaddr_in6>(p, len) };
1111 ControlMessageOwned::Ipv6RecvErr(err, addr)
1112 },
1113 #[cfg(any(linux_android, target_os = "freebsd"))]
1114 #[cfg(feature = "net")]
1115 (libc::IPPROTO_IPV6, libc::IPV6_ORIGDSTADDR) => {
1116 let dl = unsafe { ptr::read_unaligned(p as *const libc::sockaddr_in6) };
1117 ControlMessageOwned::Ipv6OrigDstAddr(dl)
1118 },
1119 #[cfg(any(target_os = "linux"))]
1120 (libc::SOL_TLS, libc::TLS_GET_RECORD_TYPE) => {
1121 let content_type = unsafe { ptr::read_unaligned(p as *const u8) };
1122 ControlMessageOwned::TlsGetRecordType(content_type.into())
1123 },
1124 #[cfg(linux_android)]
1125 #[cfg(feature = "net")]
1126 (libc::IPPROTO_IP, libc::IP_TTL) => {
1127 let ttl = unsafe { ptr::read_unaligned(p as *const i32) };
1128 ControlMessageOwned::Ipv4Ttl(ttl)
1129 },
1130 #[cfg(target_os = "freebsd")]
1131 #[cfg(feature = "net")]
1132 (libc::IPPROTO_IP, libc::IP_RECVTTL) => {
1133 let ttl: u8 = unsafe { ptr::read_unaligned(p as *const u8) };
1134 ControlMessageOwned::Ipv4Ttl(ttl)
1135 },
1136 #[cfg(any(linux_android, target_os = "freebsd"))]
1137 #[cfg(feature = "net")]
1138 (libc::IPPROTO_IPV6, libc::IPV6_HOPLIMIT) => {
1139 let ttl = unsafe { ptr::read_unaligned(p as *const i32) };
1140 ControlMessageOwned::Ipv6HopLimit(ttl)
1141 },
1142 #[cfg(linux_android)]
1143 #[cfg(feature = "net")]
1144 (libc::IPPROTO_IP, libc::IP_TOS) => {
1145 let tos = unsafe { ptr::read_unaligned(p as *const u8) };
1146 ControlMessageOwned::Ipv4Tos(tos)
1147 },
1148 #[cfg(target_os = "freebsd")]
1149 #[cfg(feature = "net")]
1150 (libc::IPPROTO_IP, libc::IP_RECVTOS) => {
1151 let tos = unsafe { ptr::read_unaligned(p as *const u8) };
1152 ControlMessageOwned::Ipv4Tos(tos)
1153 },
1154 #[cfg(any(linux_android, target_os = "freebsd"))]
1155 #[cfg(feature = "net")]
1156 (libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => {
1157 let tc = unsafe { ptr::read_unaligned(p as *const i32) };
1158 ControlMessageOwned::Ipv6TClass(tc)
1159 },
1160 (_, _) => {
1161 let sl = unsafe { std::slice::from_raw_parts(p, len) };
1162 let ucmsg = UnknownCmsg {
1163 cmsg_header: *header,
1164 data_bytes: Vec::<u8>::from(sl),
1165 };
1166 ControlMessageOwned::Unknown(ucmsg)
1167 }
1168 }
1169 }
1170
1171 #[cfg(linux_android)]
1172 #[cfg(feature = "net")]
1173 #[allow(clippy::cast_ptr_alignment)] // False positive
1174 unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) {
1175 let ee = p as *const libc::sock_extended_err;
1176 let err = unsafe { ptr::read_unaligned(ee) };
1177
1178 // For errors originating on the network, SO_EE_OFFENDER(ee) points inside the p[..len]
1179 // CMSG_DATA buffer. For local errors, there is no address included in the control
1180 // message, and SO_EE_OFFENDER(ee) points beyond the end of the buffer. So, we need to
1181 // validate that the address object is in-bounds before we attempt to copy it.
1182 let addrp = unsafe { libc::SO_EE_OFFENDER(ee) as *const T };
1183
1184 if unsafe { addrp.offset(1) } as usize - (p as usize) > len {
1185 (err, None)
1186 } else {
1187 (err, Some(unsafe { ptr::read_unaligned(addrp) }))
1188 }
1189 }
1190}
1191
1192/// A type-safe zero-copy wrapper around a single control message, as used with
1193/// [`sendmsg`]. More types may be added to this enum; do not exhaustively
1194/// pattern-match it.
1195///
1196/// [Further reading](https://man7.org/linux/man-pages/man3/cmsg.3.html)
1197#[derive(Clone, Copy, Debug, Eq, PartialEq)]
1198#[non_exhaustive]
1199pub enum ControlMessage<'a> {
1200 /// A message of type `SCM_RIGHTS`, containing an array of file
1201 /// descriptors passed between processes.
1202 ///
1203 /// See the description in the "Ancillary messages" section of the
1204 /// [unix(7) man page](https://man7.org/linux/man-pages/man7/unix.7.html).
1205 ///
1206 /// Using multiple `ScmRights` messages for a single `sendmsg` call isn't
1207 /// recommended since it causes platform-dependent behaviour: It might
1208 /// swallow all but the first `ScmRights` message or fail with `EINVAL`.
1209 /// Instead, you can put all fds to be passed into a single `ScmRights`
1210 /// message.
1211 ScmRights(&'a [RawFd]),
1212 /// A message of type `SCM_CREDENTIALS`, containing the pid, uid and gid of
1213 /// a process connected to the socket.
1214 ///
1215 /// This is similar to the socket option `SO_PEERCRED`, but requires a
1216 /// process to explicitly send its credentials. A process running as root is
1217 /// allowed to specify any credentials, while credentials sent by other
1218 /// processes are verified by the kernel.
1219 ///
1220 /// For further information, please refer to the
1221 /// [`unix(7)`](https://man7.org/linux/man-pages/man7/unix.7.html) man page.
1222 #[cfg(linux_android)]
1223 ScmCredentials(&'a UnixCredentials),
1224 /// A message of type `SCM_CREDS`, containing the pid, uid, euid, gid and groups of
1225 /// a process connected to the socket.
1226 ///
1227 /// This is similar to the socket options `LOCAL_CREDS` and `LOCAL_PEERCRED`, but
1228 /// requires a process to explicitly send its credentials.
1229 ///
1230 /// Credentials are always overwritten by the kernel, so this variant does have
1231 /// any data, unlike the receive-side
1232 /// [`ControlMessageOwned::ScmCreds`].
1233 ///
1234 /// For further information, please refer to the
1235 /// [`unix(4)`](https://www.freebsd.org/cgi/man.cgi?query=unix) man page.
1236 #[cfg(freebsdlike)]
1237 ScmCreds,
1238
1239 /// Set IV for `AF_ALG` crypto API.
1240 ///
1241 /// For further information, please refer to the
1242 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
1243 #[cfg(linux_android)]
1244 AlgSetIv(&'a [u8]),
1245 /// Set crypto operation for `AF_ALG` crypto API. It may be one of
1246 /// `ALG_OP_ENCRYPT` or `ALG_OP_DECRYPT`
1247 ///
1248 /// For further information, please refer to the
1249 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
1250 #[cfg(linux_android)]
1251 AlgSetOp(&'a libc::c_int),
1252 /// Set the length of associated authentication data (AAD) (applicable only to AEAD algorithms)
1253 /// for `AF_ALG` crypto API.
1254 ///
1255 /// For further information, please refer to the
1256 /// [`documentation`](https://kernel.readthedocs.io/en/sphinx-samples/crypto-API.html)
1257 #[cfg(linux_android)]
1258 AlgSetAeadAssoclen(&'a u32),
1259
1260 /// UDP GSO makes it possible for applications to generate network packets
1261 /// for a virtual MTU much greater than the real one.
1262 /// The length of the send data no longer matches the expected length on
1263 /// the wire.
1264 /// The size of the datagram payload as it should appear on the wire may be
1265 /// passed through this control message.
1266 /// Send buffer should consist of multiple fixed-size wire payloads
1267 /// following one by one, and the last, possibly smaller one.
1268 #[cfg(target_os = "linux")]
1269 #[cfg(feature = "net")]
1270 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1271 UdpGsoSegments(&'a u16),
1272
1273 /// Configure the sending addressing and interface for v4.
1274 ///
1275 /// For further information, please refer to the
1276 /// [`ip(7)`](https://man7.org/linux/man-pages/man7/ip.7.html) man page.
1277 #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
1278 #[cfg(feature = "net")]
1279 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1280 Ipv4PacketInfo(&'a libc::in_pktinfo),
1281
1282 /// Configure the sending addressing and interface for v6.
1283 ///
1284 /// For further information, please refer to the
1285 /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
1286 #[cfg(any(linux_android,
1287 target_os = "netbsd",
1288 target_os = "freebsd",
1289 apple_targets))]
1290 #[cfg(feature = "net")]
1291 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1292 Ipv6PacketInfo(&'a libc::in6_pktinfo),
1293
1294 /// Configure the IPv4 source address with `IP_SENDSRCADDR`.
1295 #[cfg(any(freebsdlike, netbsdlike))]
1296 #[cfg(feature = "net")]
1297 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1298 Ipv4SendSrcAddr(&'a libc::in_addr),
1299
1300 /// Configure the Time-to-Live for v4 traffic.
1301 #[cfg(linux_android)]
1302 #[cfg(feature = "net")]
1303 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1304 Ipv4Ttl(&'a libc::c_int),
1305
1306 /// Configure the Time-to-Live for v4 traffic.
1307 #[cfg(target_os = "freebsd")]
1308 #[cfg(feature = "net")]
1309 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1310 Ipv4Ttl(&'a libc::c_uchar),
1311
1312 /// Configure the hop limit for v6 multicast traffic.
1313 ///
1314 /// Set the IPv6 hop limit for this message. The argument is an integer
1315 /// between 0 and 255. A value of -1 will set the hop limit to the route
1316 /// default if possible on the interface. Without this cmsg, packets sent
1317 /// with sendmsg have a hop limit of 1 and will not leave the local network.
1318 /// For further information, please refer to the
1319 /// [`ipv6(7)`](https://man7.org/linux/man-pages/man7/ipv6.7.html) man page.
1320 #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
1321 #[cfg(feature = "net")]
1322 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1323 Ipv6HopLimit(&'a libc::c_int),
1324
1325 /// SO_RXQ_OVFL indicates that an unsigned 32 bit value
1326 /// ancillary msg (cmsg) should be attached to received
1327 /// skbs indicating the number of packets dropped by the
1328 /// socket between the last received packet and this
1329 /// received packet.
1330 #[cfg(any(linux_android, target_os = "fuchsia"))]
1331 RxqOvfl(&'a u32),
1332
1333 /// Configure the transmission time of packets.
1334 ///
1335 /// For further information, please refer to the
1336 /// [`tc-etf(8)`](https://man7.org/linux/man-pages/man8/tc-etf.8.html) man
1337 /// page.
1338 #[cfg(target_os = "linux")]
1339 TxTime(&'a u64),
1340
1341 /// Configure DSCP / IP TOS for outgoing v4 packets.
1342 ///
1343 /// Further information can be found [here](https://en.wikipedia.org/wiki/Differentiated_services).
1344 #[cfg(any(linux_android, target_os = "freebsd"))]
1345 #[cfg(feature = "net")]
1346 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1347 Ipv4Tos(&'a u8),
1348
1349 /// Configure DSCP / IPv6 TCLASS for outgoing v6 packets.
1350 ///
1351 /// Further information can be found [here](https://en.wikipedia.org/wiki/Differentiated_services).
1352 #[cfg(any(linux_android, target_os = "freebsd"))]
1353 #[cfg(feature = "net")]
1354 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1355 Ipv6TClass(&'a i32),
1356}
1357
1358/// Control messages that are currently not supported by Nix.
1359#[derive(Clone, Debug, Eq, PartialEq)]
1360pub struct UnknownCmsg {
1361 /// Control message header.
1362 pub cmsg_header: cmsghdr,
1363 /// Bytes of the control message data.
1364 pub data_bytes: Vec<u8>
1365}
1366
1367impl ControlMessage<'_> {
1368 /// The value of CMSG_SPACE on this message.
1369 /// Safe because CMSG_SPACE is always safe
1370 fn space(&self) -> usize {
1371 unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
1372 }
1373
1374 /// The value of CMSG_LEN on this message.
1375 /// Safe because CMSG_LEN is always safe
1376 #[cfg(any(target_os = "android",
1377 all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos"))),
1378 target_os = "cygwin"))]
1379 fn cmsg_len(&self) -> usize {
1380 unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
1381 }
1382
1383 #[cfg(not(any(target_os = "android",
1384 all(target_os = "linux", not(any(target_env = "musl", target_env = "ohos"))),
1385 target_os = "cygwin")))]
1386 fn cmsg_len(&self) -> libc::c_uint {
1387 unsafe{CMSG_LEN(self.len() as libc::c_uint)}
1388 }
1389
1390 /// Return a reference to the payload data as a byte pointer
1391 fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
1392 let data_ptr = match *self {
1393 ControlMessage::ScmRights(fds) => {
1394 fds as *const _ as *const u8
1395 },
1396 #[cfg(linux_android)]
1397 ControlMessage::ScmCredentials(creds) => {
1398 &creds.0 as *const libc::ucred as *const u8
1399 }
1400 #[cfg(freebsdlike)]
1401 ControlMessage::ScmCreds => {
1402 // The kernel overwrites the data, we just zero it
1403 // to make sure it's not uninitialized memory
1404 unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
1405 return
1406 }
1407 #[cfg(linux_android)]
1408 ControlMessage::AlgSetIv(iv) => {
1409 #[allow(deprecated)] // https://github.com/rust-lang/libc/issues/1501
1410 let af_alg_iv = libc::af_alg_iv {
1411 ivlen: iv.len() as u32,
1412 iv: [0u8; 0],
1413 };
1414
1415 let size = mem::size_of_val(&af_alg_iv);
1416
1417 unsafe {
1418 ptr::copy_nonoverlapping(
1419 &af_alg_iv as *const _ as *const u8,
1420 cmsg_data,
1421 size,
1422 );
1423 ptr::copy_nonoverlapping(
1424 iv.as_ptr(),
1425 cmsg_data.add(size),
1426 iv.len()
1427 );
1428 };
1429
1430 return
1431 },
1432 #[cfg(linux_android)]
1433 ControlMessage::AlgSetOp(op) => {
1434 op as *const _ as *const u8
1435 },
1436 #[cfg(linux_android)]
1437 ControlMessage::AlgSetAeadAssoclen(len) => {
1438 len as *const _ as *const u8
1439 },
1440 #[cfg(target_os = "linux")]
1441 #[cfg(feature = "net")]
1442 ControlMessage::UdpGsoSegments(gso_size) => {
1443 gso_size as *const _ as *const u8
1444 },
1445 #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
1446 #[cfg(feature = "net")]
1447 ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
1448 #[cfg(any(linux_android, target_os = "netbsd",
1449 target_os = "freebsd", apple_targets))]
1450 #[cfg(feature = "net")]
1451 ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
1452 #[cfg(any(freebsdlike, netbsdlike))]
1453 #[cfg(feature = "net")]
1454 ControlMessage::Ipv4SendSrcAddr(addr) => addr as *const _ as *const u8,
1455 #[cfg(linux_android)]
1456 #[cfg(feature = "net")]
1457 ControlMessage::Ipv4Ttl(ttl) => ttl as *const i32 as *const u8,
1458 #[cfg(target_os = "freebsd")]
1459 #[cfg(feature = "net")]
1460 ControlMessage::Ipv4Ttl(ttl) => ttl as *const u8,
1461 #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
1462 #[cfg(feature = "net")]
1463 ControlMessage::Ipv6HopLimit(limit) => limit as *const _ as *const u8,
1464 #[cfg(any(linux_android, target_os = "fuchsia"))]
1465 ControlMessage::RxqOvfl(drop_count) => {
1466 drop_count as *const _ as *const u8
1467 },
1468 #[cfg(target_os = "linux")]
1469 ControlMessage::TxTime(tx_time) => {
1470 tx_time as *const _ as *const u8
1471 },
1472 #[cfg(any(linux_android, target_os = "freebsd"))]
1473 #[cfg(feature = "net")]
1474 ControlMessage::Ipv4Tos(tos) => {
1475 tos as *const _
1476 },
1477 #[cfg(any(linux_android, target_os = "freebsd"))]
1478 #[cfg(feature = "net")]
1479 ControlMessage::Ipv6TClass(tclass) => {
1480 tclass as *const _ as *const u8
1481 },
1482 };
1483 unsafe {
1484 ptr::copy_nonoverlapping(
1485 data_ptr,
1486 cmsg_data,
1487 self.len()
1488 )
1489 };
1490 }
1491
1492 /// The size of the payload, excluding its cmsghdr
1493 fn len(&self) -> usize {
1494 match *self {
1495 ControlMessage::ScmRights(fds) => {
1496 mem::size_of_val(fds)
1497 },
1498 #[cfg(linux_android)]
1499 ControlMessage::ScmCredentials(creds) => {
1500 mem::size_of_val(creds)
1501 }
1502 #[cfg(freebsdlike)]
1503 ControlMessage::ScmCreds => {
1504 mem::size_of::<libc::cmsgcred>()
1505 }
1506 #[cfg(linux_android)]
1507 ControlMessage::AlgSetIv(iv) => {
1508 mem::size_of::<&[u8]>() + iv.len()
1509 },
1510 #[cfg(linux_android)]
1511 ControlMessage::AlgSetOp(op) => {
1512 mem::size_of_val(op)
1513 },
1514 #[cfg(linux_android)]
1515 ControlMessage::AlgSetAeadAssoclen(len) => {
1516 mem::size_of_val(len)
1517 },
1518 #[cfg(target_os = "linux")]
1519 #[cfg(feature = "net")]
1520 ControlMessage::UdpGsoSegments(gso_size) => {
1521 mem::size_of_val(gso_size)
1522 },
1523 #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
1524 #[cfg(feature = "net")]
1525 ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
1526 #[cfg(any(linux_android, target_os = "netbsd",
1527 target_os = "freebsd", apple_targets))]
1528 #[cfg(feature = "net")]
1529 ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
1530 #[cfg(any(freebsdlike, netbsdlike))]
1531 #[cfg(feature = "net")]
1532 ControlMessage::Ipv4SendSrcAddr(addr) => mem::size_of_val(addr),
1533 #[cfg(any(linux_android, target_os = "freebsd"))]
1534 #[cfg(feature = "net")]
1535 ControlMessage::Ipv4Ttl(ttl) => {
1536 mem::size_of_val(ttl)
1537 },
1538 #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
1539 #[cfg(feature = "net")]
1540 ControlMessage::Ipv6HopLimit(limit) => {
1541 mem::size_of_val(limit)
1542 },
1543 #[cfg(any(linux_android, target_os = "fuchsia"))]
1544 ControlMessage::RxqOvfl(drop_count) => {
1545 mem::size_of_val(drop_count)
1546 },
1547 #[cfg(target_os = "linux")]
1548 ControlMessage::TxTime(tx_time) => {
1549 mem::size_of_val(tx_time)
1550 },
1551 #[cfg(any(linux_android, target_os = "freebsd"))]
1552 #[cfg(feature = "net")]
1553 ControlMessage::Ipv4Tos(tos) => {
1554 mem::size_of_val(tos)
1555 },
1556 #[cfg(any(linux_android, target_os = "freebsd"))]
1557 #[cfg(feature = "net")]
1558 ControlMessage::Ipv6TClass(tclass) => {
1559 mem::size_of_val(tclass)
1560 },
1561 }
1562 }
1563
1564 /// Returns the value to put into the `cmsg_level` field of the header.
1565 fn cmsg_level(&self) -> libc::c_int {
1566 match *self {
1567 ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
1568 #[cfg(linux_android)]
1569 ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
1570 #[cfg(freebsdlike)]
1571 ControlMessage::ScmCreds => libc::SOL_SOCKET,
1572 #[cfg(linux_android)]
1573 ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
1574 ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
1575 #[cfg(target_os = "linux")]
1576 #[cfg(feature = "net")]
1577 ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
1578 #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
1579 #[cfg(feature = "net")]
1580 ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
1581 #[cfg(any(linux_android, target_os = "netbsd",
1582 target_os = "freebsd", apple_targets))]
1583 #[cfg(feature = "net")]
1584 ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
1585 #[cfg(any(freebsdlike, netbsdlike))]
1586 #[cfg(feature = "net")]
1587 ControlMessage::Ipv4SendSrcAddr(_) => libc::IPPROTO_IP,
1588 #[cfg(any(linux_android, target_os = "freebsd"))]
1589 #[cfg(feature = "net")]
1590 ControlMessage::Ipv4Ttl(_) => libc::IPPROTO_IP,
1591 #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
1592 #[cfg(feature = "net")]
1593 ControlMessage::Ipv6HopLimit(_) => libc::IPPROTO_IPV6,
1594 #[cfg(any(linux_android, target_os = "fuchsia"))]
1595 ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
1596 #[cfg(target_os = "linux")]
1597 ControlMessage::TxTime(_) => libc::SOL_SOCKET,
1598 #[cfg(any(linux_android, target_os = "freebsd"))]
1599 #[cfg(feature = "net")]
1600 ControlMessage::Ipv4Tos(_) => libc::IPPROTO_IP,
1601 #[cfg(any(linux_android, target_os = "freebsd"))]
1602 #[cfg(feature = "net")]
1603 ControlMessage::Ipv6TClass(_) => libc::IPPROTO_IPV6,
1604 }
1605 }
1606
1607 /// Returns the value to put into the `cmsg_type` field of the header.
1608 fn cmsg_type(&self) -> libc::c_int {
1609 match *self {
1610 ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
1611 #[cfg(linux_android)]
1612 ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
1613 #[cfg(freebsdlike)]
1614 ControlMessage::ScmCreds => libc::SCM_CREDS,
1615 #[cfg(linux_android)]
1616 ControlMessage::AlgSetIv(_) => {
1617 libc::ALG_SET_IV
1618 },
1619 #[cfg(linux_android)]
1620 ControlMessage::AlgSetOp(_) => {
1621 libc::ALG_SET_OP
1622 },
1623 #[cfg(linux_android)]
1624 ControlMessage::AlgSetAeadAssoclen(_) => {
1625 libc::ALG_SET_AEAD_ASSOCLEN
1626 },
1627 #[cfg(target_os = "linux")]
1628 #[cfg(feature = "net")]
1629 ControlMessage::UdpGsoSegments(_) => {
1630 libc::UDP_SEGMENT
1631 },
1632 #[cfg(any(linux_android, target_os = "netbsd", apple_targets))]
1633 #[cfg(feature = "net")]
1634 ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
1635 #[cfg(any(linux_android, target_os = "netbsd",
1636 target_os = "freebsd", apple_targets))]
1637 #[cfg(feature = "net")]
1638 ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
1639 #[cfg(any(freebsdlike, netbsdlike))]
1640 #[cfg(feature = "net")]
1641 ControlMessage::Ipv4SendSrcAddr(_) => libc::IP_SENDSRCADDR,
1642 #[cfg(any(linux_android, target_os = "freebsd"))]
1643 #[cfg(feature = "net")]
1644 ControlMessage::Ipv4Ttl(_) => libc::IP_TTL,
1645 #[cfg(any(linux_android, freebsdlike, apple_targets, target_os = "haiku"))]
1646 #[cfg(feature = "net")]
1647 ControlMessage::Ipv6HopLimit(_) => libc::IPV6_HOPLIMIT,
1648 #[cfg(any(linux_android, target_os = "fuchsia"))]
1649 ControlMessage::RxqOvfl(_) => {
1650 libc::SO_RXQ_OVFL
1651 },
1652 #[cfg(target_os = "linux")]
1653 ControlMessage::TxTime(_) => {
1654 libc::SCM_TXTIME
1655 },
1656 #[cfg(any(linux_android, target_os = "freebsd"))]
1657 #[cfg(feature = "net")]
1658 ControlMessage::Ipv4Tos(_) => {
1659 libc::IP_TOS
1660 },
1661 #[cfg(any(linux_android, target_os = "freebsd"))]
1662 #[cfg(feature = "net")]
1663 ControlMessage::Ipv6TClass(_) => {
1664 libc::IPV6_TCLASS
1665 },
1666 }
1667 }
1668
1669 // Unsafe: cmsg must point to a valid cmsghdr with enough space to
1670 // encode self.
1671 unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
1672 unsafe {
1673 (*cmsg).cmsg_level = self.cmsg_level();
1674 (*cmsg).cmsg_type = self.cmsg_type();
1675 (*cmsg).cmsg_len = self.cmsg_len();
1676 self.copy_to_cmsg_data( CMSG_DATA(cmsg) );
1677 }
1678 }
1679}
1680
1681
1682/// Send data in scatter-gather vectors to a socket, possibly accompanied
1683/// by ancillary data. Optionally direct the message at the given address,
1684/// as with sendto.
1685///
1686/// Allocates if cmsgs is nonempty.
1687///
1688/// # Examples
1689/// When not directing to any specific address, use `()` for the generic type
1690/// ```
1691/// # use nix::sys::socket::*;
1692/// # use nix::unistd::pipe;
1693/// # use std::io::IoSlice;
1694/// # use std::os::unix::io::AsRawFd;
1695/// let (fd1, fd2) = socketpair(AddressFamily::Unix, SockType::Stream, None,
1696/// SockFlag::empty())
1697/// .unwrap();
1698/// let (r, w) = pipe().unwrap();
1699///
1700/// let iov = [IoSlice::new(b"hello")];
1701/// let fds = [r.as_raw_fd()];
1702/// let cmsg = ControlMessage::ScmRights(&fds);
1703/// sendmsg::<()>(fd1.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), None).unwrap();
1704/// ```
1705/// When directing to a specific address, the generic type will be inferred.
1706/// Note that SCM_RIGHTS ancillary data are valid only for AF_UNIX sockets on Solaris.
1707/// ```
1708/// # use nix::sys::socket::*;
1709/// # use nix::unistd::pipe;
1710/// # use std::io::IoSlice;
1711/// # use std::str::FromStr;
1712/// # use std::os::unix::io::AsRawFd;
1713/// let localhost = SockaddrIn::from_str("1.2.3.4:8080").unwrap();
1714/// let fd = socket(AddressFamily::Inet, SockType::Datagram, SockFlag::empty(),
1715/// None).unwrap();
1716/// let (r, w) = pipe().unwrap();
1717///
1718/// let iov = [IoSlice::new(b"hello")];
1719/// let fds = [r.as_raw_fd()];
1720/// let cmsg = ControlMessage::ScmRights(&fds);
1721/// #[cfg(not(target_os = "solaris"))]
1722/// sendmsg(fd.as_raw_fd(), &iov, &[cmsg], MsgFlags::empty(), Some(&localhost)).unwrap();
1723/// ```
1724pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
1725 flags: MsgFlags, addr: Option<&S>) -> Result<usize>
1726 where S: SockaddrLike
1727{
1728 let capacity = cmsgs.iter().map(|c| c.space()).sum();
1729
1730 // First size the buffer needed to hold the cmsgs. It must be zeroed,
1731 // because subsequent code will not clear the padding bytes.
1732 let mut cmsg_buffer = vec![0u8; capacity];
1733
1734 let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr);
1735
1736 let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
1737
1738 Errno::result(ret).map(|r| r as usize)
1739}
1740
1741
1742/// An extension of `sendmsg` that allows the caller to transmit multiple
1743/// messages on a socket using a single system call. This has performance
1744/// benefits for some applications.
1745///
1746/// Allocations are performed for cmsgs and to build `msghdr` buffer
1747///
1748/// # Arguments
1749///
1750/// * `fd`: Socket file descriptor
1751/// * `data`: Struct that implements `IntoIterator` with `SendMmsgData` items
1752/// * `flags`: Optional flags passed directly to the operating system.
1753///
1754/// # Returns
1755/// `Vec` with numbers of sent bytes on each sent message.
1756///
1757/// # References
1758/// [`sendmsg`](fn.sendmsg.html)
1759#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
1760pub fn sendmmsg<'a, XS, AS, C, I, S>(
1761 fd: RawFd,
1762 data: &'a mut MultiHeaders<S>,
1763 slices: XS,
1764 // one address per group of slices
1765 addrs: AS,
1766 // shared across all the messages
1767 cmsgs: C,
1768 flags: MsgFlags
1769) -> crate::Result<MultiResults<'a, S>>
1770 where
1771 XS: IntoIterator<Item = &'a I>,
1772 AS: AsRef<[Option<S>]>,
1773 I: AsRef<[IoSlice<'a>]> + 'a,
1774 C: AsRef<[ControlMessage<'a>]> + 'a,
1775 S: SockaddrLike + 'a,
1776{
1777
1778 let mut count = 0;
1779
1780
1781 for (i, ((slice, addr), mmsghdr)) in slices.into_iter().zip(addrs.as_ref()).zip(data.items.iter_mut() ).enumerate() {
1782 let p = &mut mmsghdr.msg_hdr;
1783 p.msg_iov = slice.as_ref().as_ptr().cast_mut().cast();
1784 p.msg_iovlen = slice.as_ref().len() as _;
1785
1786 p.msg_namelen = addr.as_ref().map_or(0, S::len);
1787 p.msg_name = addr.as_ref().map_or(ptr::null(), S::as_ptr).cast_mut().cast();
1788
1789 // Encode each cmsg. This must happen after initializing the header because
1790 // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
1791 // CMSG_FIRSTHDR is always safe
1792 let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(p) };
1793 for cmsg in cmsgs.as_ref() {
1794 assert_ne!(pmhdr, ptr::null_mut());
1795 // Safe because we know that pmhdr is valid, and we initialized it with
1796 // sufficient space
1797 unsafe { cmsg.encode_into(pmhdr) };
1798 // Safe because mhdr is valid
1799 pmhdr = unsafe { CMSG_NXTHDR(p, pmhdr) };
1800 }
1801
1802 // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders`
1803 // is through the `preallocate` function, which takes an `usize` as an argument to define its size,
1804 // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in
1805 // other words: `count` doesn't overflow
1806 count = i + 1;
1807 }
1808
1809 // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the
1810 // maximum number of messages that can be sent safely (i.e. `count` is the minimum of the sizes of `slices`,
1811 // `data.items` and `addrs`)
1812 let sent = Errno::result(unsafe {
1813 libc::sendmmsg(
1814 fd,
1815 data.items.as_mut_ptr(),
1816 count as _,
1817 flags.bits() as _
1818 )
1819 })? as usize;
1820
1821 Ok(MultiResults {
1822 rmm: data,
1823 current_index: 0,
1824 received: sent
1825 })
1826
1827}
1828
1829
1830#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
1831#[derive(Debug)]
1832/// Preallocated structures needed for [`recvmmsg`] and [`sendmmsg`] functions
1833pub struct MultiHeaders<S> {
1834 // preallocated boxed slice of mmsghdr
1835 items: Box<[libc::mmsghdr]>,
1836 addresses: Box<[mem::MaybeUninit<S>]>,
1837 // while we are not using it directly - this is used to store control messages
1838 // and we retain pointers to them inside items array
1839 _cmsg_buffers: Option<Box<[u8]>>,
1840 msg_controllen: usize,
1841}
1842
1843#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
1844impl<S> MultiHeaders<S> {
1845 /// Preallocate structure used by [`recvmmsg`] and [`sendmmsg`] takes number of headers to preallocate
1846 ///
1847 /// `cmsg_buffer` should be created with [`cmsg_space!`] if needed
1848 pub fn preallocate(num_slices: usize, cmsg_buffer: Option<Vec<u8>>) -> Self
1849 where
1850 S: Copy + SockaddrLike,
1851 {
1852 // we will be storing pointers to addresses inside mhdr - convert it into boxed
1853 // slice so it can'be changed later by pushing anything into self.addresses
1854 let mut addresses = vec![std::mem::MaybeUninit::<S>::uninit(); num_slices].into_boxed_slice();
1855
1856 let msg_controllen = cmsg_buffer.as_ref().map_or(0, |v| v.capacity());
1857
1858 // we'll need a cmsg_buffer for each slice, we preallocate a vector and split
1859 // it into "slices" parts
1860 let mut cmsg_buffers =
1861 cmsg_buffer.map(|v| vec![0u8; v.capacity() * num_slices].into_boxed_slice());
1862
1863 let items = addresses
1864 .iter_mut()
1865 .enumerate()
1866 .map(|(ix, address)| {
1867 let (ptr, cap) = match &mut cmsg_buffers {
1868 Some(v) => (&mut v[ix * msg_controllen] as *mut u8, msg_controllen),
1869 None => (std::ptr::null_mut(), 0),
1870 };
1871 let msg_hdr = unsafe { pack_mhdr_to_receive(std::ptr::null_mut(), 0, ptr, cap, address.as_mut_ptr()) };
1872 libc::mmsghdr {
1873 msg_hdr,
1874 msg_len: 0,
1875 }
1876 })
1877 .collect::<Vec<_>>();
1878
1879 Self {
1880 items: items.into_boxed_slice(),
1881 addresses,
1882 _cmsg_buffers: cmsg_buffers,
1883 msg_controllen,
1884 }
1885 }
1886}
1887
1888/// An extension of recvmsg that allows the caller to receive multiple messages from a socket using a single system call.
1889///
1890/// This has performance benefits for some applications.
1891///
1892/// This method performs no allocations.
1893///
1894/// Returns an iterator producing [`RecvMsg`], one per received messages. Each `RecvMsg` can produce
1895/// iterators over [`IoSlice`] with [`iovs`][RecvMsg::iovs`] and
1896/// `ControlMessageOwned` with [`cmsgs`][RecvMsg::cmsgs].
1897///
1898/// # Bugs (in underlying implementation, at least in Linux)
1899/// The timeout argument does not work as intended. The timeout is checked only after the receipt
1900/// of each datagram, so that if up to `vlen`-1 datagrams are received before the timeout expires,
1901/// but then no further datagrams are received, the call will block forever.
1902///
1903/// If an error occurs after at least one message has been received, the call succeeds, and returns
1904/// the number of messages received. The error code is expected to be returned on a subsequent
1905/// call to recvmmsg(). In the current implementation, however, the error code can be
1906/// overwritten in the meantime by an unrelated network event on a socket, for example an
1907/// incoming ICMP packet.
1908// On aarch64 linux using recvmmsg and trying to get hardware/kernel timestamps might not
1909// always produce the desired results - see https://github.com/nix-rust/nix/pull/1744 for more
1910// details
1911#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
1912pub fn recvmmsg<'a, XS, S, I>(
1913 fd: RawFd,
1914 data: &'a mut MultiHeaders<S>,
1915 slices: XS,
1916 flags: MsgFlags,
1917 mut timeout: Option<crate::sys::time::TimeSpec>,
1918) -> crate::Result<MultiResults<'a, S>>
1919where
1920 XS: IntoIterator<Item = &'a mut I>,
1921 I: AsMut<[IoSliceMut<'a>]> + 'a,
1922{
1923 let mut count = 0;
1924 for (i, (slice, mmsghdr)) in slices.into_iter().zip(data.items.iter_mut()).enumerate() {
1925 let p = &mut mmsghdr.msg_hdr;
1926 p.msg_iov = slice.as_mut().as_mut_ptr().cast();
1927 p.msg_iovlen = slice.as_mut().len() as _;
1928
1929 // Doing an unchecked addition is alright here, as the only way to obtain an instance of `MultiHeaders`
1930 // is through the `preallocate` function, which takes an `usize` as an argument to define its size,
1931 // which also provides an upper bound for the size of this zipped iterator. Thus, `i < usize::MAX` or in
1932 // other words: `count` doesn't overflow
1933 count = i + 1;
1934 }
1935
1936 let timeout_ptr = timeout
1937 .as_mut()
1938 .map_or_else(std::ptr::null_mut, |t| t as *mut _ as *mut libc::timespec);
1939
1940 // SAFETY: all pointers are guaranteed to be valid for the scope of this function. `count` does represent the
1941 // maximum number of messages that can be received safely (i.e. `count` is the minimum of the sizes of `slices` and `data.items`)
1942 let received = Errno::result(unsafe {
1943 libc::recvmmsg(
1944 fd,
1945 data.items.as_mut_ptr(),
1946 count as _,
1947 flags.bits() as _,
1948 timeout_ptr,
1949 )
1950 })? as usize;
1951
1952 Ok(MultiResults {
1953 rmm: data,
1954 current_index: 0,
1955 received,
1956 })
1957}
1958
1959/// Iterator over results of [`recvmmsg`]/[`sendmmsg`]
1960#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
1961#[derive(Debug)]
1962pub struct MultiResults<'a, S> {
1963 // preallocated structures
1964 rmm: &'a MultiHeaders<S>,
1965 current_index: usize,
1966 received: usize,
1967}
1968
1969#[cfg(any(linux_android, target_os = "freebsd", target_os = "netbsd"))]
1970impl<'a, S> Iterator for MultiResults<'a, S>
1971where
1972 S: Copy + SockaddrLike,
1973{
1974 type Item = RecvMsg<'a, 'a, S>;
1975
1976 // The cast is not unnecessary on all platforms.
1977 #[allow(clippy::unnecessary_cast)]
1978 fn next(&mut self) -> Option<Self::Item> {
1979 if self.current_index >= self.received {
1980 return None;
1981 }
1982 let mmsghdr = self.rmm.items[self.current_index];
1983
1984 // as long as we are not reading past the index writen by recvmmsg - address
1985 // will be initialized
1986 let address = unsafe { self.rmm.addresses[self.current_index].assume_init() };
1987
1988 self.current_index += 1;
1989 Some(unsafe {
1990 read_mhdr(
1991 mmsghdr.msg_hdr,
1992 mmsghdr.msg_len as isize,
1993 self.rmm.msg_controllen,
1994 address,
1995 )
1996 })
1997 }
1998}
1999
2000impl<'a, S> RecvMsg<'_, 'a, S> {
2001 /// Iterate over the filled io slices pointed by this msghdr
2002 pub fn iovs(&self) -> IoSliceIterator<'a> {
2003 IoSliceIterator {
2004 index: 0,
2005 remaining: self.bytes,
2006 slices: unsafe {
2007 // safe for as long as mgdr is properly initialized and references are valid.
2008 // for multi messages API we initialize it with an empty
2009 // slice and replace with a concrete buffer
2010 // for single message API we hold a lifetime reference to ioslices
2011 std::slice::from_raw_parts(self.mhdr.msg_iov as *const _, self.mhdr.msg_iovlen as _)
2012 },
2013 }
2014 }
2015}
2016
2017#[derive(Debug)]
2018pub struct IoSliceIterator<'a> {
2019 index: usize,
2020 remaining: usize,
2021 slices: &'a [IoSlice<'a>],
2022}
2023
2024impl<'a> Iterator for IoSliceIterator<'a> {
2025 type Item = &'a [u8];
2026
2027 fn next(&mut self) -> Option<Self::Item> {
2028 if self.index >= self.slices.len() {
2029 return None;
2030 }
2031 let slice = &self.slices[self.index][..self.remaining.min(self.slices[self.index].len())];
2032 self.remaining -= slice.len();
2033 self.index += 1;
2034 if slice.is_empty() {
2035 return None;
2036 }
2037
2038 Some(slice)
2039 }
2040}
2041
2042unsafe fn read_mhdr<'a, 'i, S>(
2043 mhdr: msghdr,
2044 r: isize,
2045 msg_controllen: usize,
2046 mut address: S,
2047) -> RecvMsg<'a, 'i, S>
2048 where S: SockaddrLike
2049{
2050 // The cast is not unnecessary on all platforms.
2051 #[allow(clippy::unnecessary_cast)]
2052 let cmsghdr = {
2053 let ptr = if mhdr.msg_controllen > 0 {
2054 debug_assert!(!mhdr.msg_control.is_null());
2055 debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
2056 unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) }
2057 } else {
2058 ptr::null()
2059 };
2060
2061 unsafe {
2062 ptr.as_ref()
2063 }
2064 };
2065
2066 // Ignore errors if this socket address has statically-known length
2067 //
2068 // This is to ensure that unix socket addresses have their length set appropriately.
2069 let _ = unsafe { address.set_length(mhdr.msg_namelen as usize) };
2070
2071 RecvMsg {
2072 bytes: r as usize,
2073 cmsghdr,
2074 address: Some(address),
2075 flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
2076 mhdr,
2077 iobufs: std::marker::PhantomData,
2078 }
2079}
2080
2081/// Pack pointers to various structures into into msghdr
2082///
2083/// # Safety
2084/// `iov_buffer` and `iov_buffer_len` must point to a slice
2085/// of `IoSliceMut` and number of available elements or be a null pointer and 0
2086///
2087/// `cmsg_buffer` and `cmsg_capacity` must point to a byte buffer used
2088/// to store control headers later or be a null pointer and 0 if control
2089/// headers are not used
2090///
2091/// Buffers must remain valid for the whole lifetime of msghdr
2092unsafe fn pack_mhdr_to_receive<S>(
2093 iov_buffer: *mut IoSliceMut,
2094 iov_buffer_len: usize,
2095 cmsg_buffer: *mut u8,
2096 cmsg_capacity: usize,
2097 address: *mut S,
2098) -> msghdr
2099 where
2100 S: SockaddrLike
2101{
2102 // Musl's msghdr has private fields, so this is the only way to
2103 // initialize it.
2104 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
2105 let p = mhdr.as_mut_ptr();
2106 unsafe {
2107 // it is important to use as_mut_ptr() here since S can be
2108 // a zero sized type representing by a dangling pointer.
2109 // as_mut_ptr() handles this case and uses a null pointer instead
2110 (*p).msg_name = (*address).as_mut_ptr() as *mut c_void;
2111 (*p).msg_namelen = S::size();
2112 (*p).msg_iov = iov_buffer as *mut iovec;
2113 (*p).msg_iovlen = iov_buffer_len as _;
2114 (*p).msg_control = cmsg_buffer as *mut c_void;
2115 (*p).msg_controllen = cmsg_capacity as _;
2116 (*p).msg_flags = 0;
2117 mhdr.assume_init()
2118 }
2119}
2120
2121fn pack_mhdr_to_send<'a, I, C, S>(
2122 cmsg_buffer: &mut [u8],
2123 iov: I,
2124 cmsgs: C,
2125 addr: Option<&S>
2126) -> msghdr
2127 where
2128 I: AsRef<[IoSlice<'a>]>,
2129 C: AsRef<[ControlMessage<'a>]>,
2130 S: SockaddrLike + 'a
2131{
2132 let capacity = cmsg_buffer.len();
2133
2134 // The message header must be initialized before the individual cmsgs.
2135 let cmsg_ptr = if capacity > 0 {
2136 cmsg_buffer.as_mut_ptr().cast()
2137 } else {
2138 ptr::null_mut()
2139 };
2140
2141 let mhdr = unsafe {
2142 // Musl's msghdr has private fields, so this is the only way to
2143 // initialize it.
2144 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
2145 let p = mhdr.as_mut_ptr();
2146 (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()).cast_mut().cast();
2147 (*p).msg_namelen = addr.map(S::len).unwrap_or(0);
2148 // transmute iov into a mutable pointer. sendmsg doesn't really mutate
2149 // the buffer, but the standard says that it takes a mutable pointer
2150 (*p).msg_iov = iov.as_ref().as_ptr().cast_mut().cast();
2151 (*p).msg_iovlen = iov.as_ref().len() as _;
2152 (*p).msg_control = cmsg_ptr;
2153 (*p).msg_controllen = capacity as _;
2154 (*p).msg_flags = 0;
2155 mhdr.assume_init()
2156 };
2157
2158 // Encode each cmsg. This must happen after initializing the header because
2159 // CMSG_NEXT_HDR and friends read the msg_control and msg_controllen fields.
2160 // CMSG_FIRSTHDR is always safe
2161 let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) };
2162 for cmsg in cmsgs.as_ref() {
2163 assert_ne!(pmhdr, ptr::null_mut());
2164 // Safe because we know that pmhdr is valid, and we initialized it with
2165 // sufficient space
2166 unsafe { cmsg.encode_into(pmhdr) };
2167 // Safe because mhdr is valid
2168 pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) };
2169 }
2170
2171 mhdr
2172}
2173
2174/// Receive message in scatter-gather vectors from a socket, and
2175/// optionally receive ancillary data into the provided buffer.
2176/// If no ancillary data is desired, use () as the type parameter.
2177///
2178/// # Arguments
2179///
2180/// * `fd`: Socket file descriptor
2181/// * `iov`: Scatter-gather list of buffers to receive the message
2182/// * `cmsg_buffer`: Space to receive ancillary data. Should be created by
2183/// [`cmsg_space!`](../../macro.cmsg_space.html)
2184/// * `flags`: Optional flags passed directly to the operating system.
2185///
2186/// # References
2187/// [recvmsg(2)](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvmsg.html)
2188pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>],
2189 mut cmsg_buffer: Option<&'a mut [u8]>,
2190 flags: MsgFlags) -> Result<RecvMsg<'a, 'outer, S>>
2191 where S: SockaddrLike + 'a,
2192 'inner: 'outer
2193{
2194 let mut address = mem::MaybeUninit::uninit();
2195
2196 let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
2197 .map(|v| (v.as_mut_ptr(), v.len()))
2198 .unwrap_or((ptr::null_mut(), 0));
2199 let mut mhdr = unsafe {
2200 pack_mhdr_to_receive(iov.as_mut().as_mut_ptr(), iov.len(), msg_control, msg_controllen, address.as_mut_ptr())
2201 };
2202
2203 let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
2204
2205 let r = Errno::result(ret)?;
2206
2207 Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init()) })
2208}
2209}
2210
2211/// Create an endpoint for communication
2212///
2213/// The `protocol` specifies a particular protocol to be used with the
2214/// socket. Normally only a single protocol exists to support a
2215/// particular socket type within a given protocol family, in which case
2216/// protocol can be specified as `None`. However, it is possible that many
2217/// protocols may exist, in which case a particular protocol must be
2218/// specified in this manner.
2219///
2220/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socket.html)
2221pub fn socket<T: Into<Option<SockProtocol>>>(
2222 domain: AddressFamily,
2223 ty: SockType,
2224 flags: SockFlag,
2225 protocol: T,
2226) -> Result<OwnedFd> {
2227 let protocol = match protocol.into() {
2228 None => 0,
2229 Some(p) => p as c_int,
2230 };
2231
2232 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
2233 // little easier to understand by separating it out. So we have to merge these bitfields
2234 // here.
2235 let mut ty = ty as c_int;
2236 ty |= flags.bits();
2237
2238 let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
2239
2240 match res {
2241 -1 => Err(Errno::last()),
2242 fd => {
2243 // Safe because libc::socket returned success
2244 unsafe { Ok(OwnedFd::from_raw_fd(fd)) }
2245 }
2246 }
2247}
2248
2249/// Create a pair of connected sockets
2250///
2251/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/socketpair.html)
2252pub fn socketpair<T: Into<Option<SockProtocol>>>(
2253 domain: AddressFamily,
2254 ty: SockType,
2255 protocol: T,
2256 flags: SockFlag,
2257) -> Result<(OwnedFd, OwnedFd)> {
2258 let protocol = match protocol.into() {
2259 None => 0,
2260 Some(p) => p as c_int,
2261 };
2262
2263 // SockFlags are usually embedded into `ty`, but we don't do that in `nix` because it's a
2264 // little easier to understand by separating it out. So we have to merge these bitfields
2265 // here.
2266 let mut ty = ty as c_int;
2267 ty |= flags.bits();
2268
2269 let mut fds = [-1, -1];
2270
2271 let res = unsafe {
2272 libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr())
2273 };
2274 Errno::result(res)?;
2275
2276 // Safe because socketpair returned success.
2277 unsafe { Ok((OwnedFd::from_raw_fd(fds[0]), OwnedFd::from_raw_fd(fds[1]))) }
2278}
2279
2280#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2281pub struct Backlog(i32);
2282
2283impl Backlog {
2284 /// Sets the listen queue size to system `SOMAXCONN` value
2285 pub const MAXCONN: Self = Self(libc::SOMAXCONN);
2286 /// Sets the listen queue size to -1 for system supporting it
2287 #[cfg(any(target_os = "linux", target_os = "freebsd"))]
2288 pub const MAXALLOWABLE: Self = Self(-1);
2289
2290 /// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid.
2291 pub fn new<I: Into<i32>>(val: I) -> Result<Self> {
2292 cfg_if! {
2293 if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
2294 const MIN: i32 = -1;
2295 } else {
2296 const MIN: i32 = 0;
2297 }
2298 }
2299
2300 let val = val.into();
2301
2302 if !(MIN..=Self::MAXCONN.0).contains(&val) {
2303 return Err(Errno::EINVAL);
2304 }
2305
2306 Ok(Self(val))
2307 }
2308}
2309
2310impl From<Backlog> for i32 {
2311 fn from(backlog: Backlog) -> Self {
2312 backlog.0
2313 }
2314}
2315
2316/// Listen for connections on a socket
2317///
2318/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
2319pub fn listen<F: AsFd>(sock: &F, backlog: Backlog) -> Result<()> {
2320 let fd = sock.as_fd().as_raw_fd();
2321 let res = unsafe { libc::listen(fd, backlog.into()) };
2322
2323 Errno::result(res).map(drop)
2324}
2325
2326/// Bind a name to a socket
2327///
2328/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/bind.html)
2329pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
2330 let res = unsafe { libc::bind(fd, addr.as_ptr(), addr.len()) };
2331
2332 Errno::result(res).map(drop)
2333}
2334
2335/// Accept a connection on a socket
2336///
2337/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/accept.html)
2338pub fn accept(sockfd: RawFd) -> Result<RawFd> {
2339 let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
2340
2341 Errno::result(res)
2342}
2343
2344/// Accept a connection on a socket
2345///
2346/// [Further reading](https://man7.org/linux/man-pages/man2/accept.2.html)
2347#[cfg(any(
2348 all(
2349 target_os = "android",
2350 any(
2351 target_arch = "aarch64",
2352 target_arch = "x86",
2353 target_arch = "x86_64"
2354 )
2355 ),
2356 freebsdlike,
2357 netbsdlike,
2358 target_os = "emscripten",
2359 target_os = "fuchsia",
2360 solarish,
2361 target_os = "linux",
2362))]
2363pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
2364 let res = unsafe {
2365 libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits())
2366 };
2367
2368 Errno::result(res)
2369}
2370
2371/// Initiate a connection on a socket
2372///
2373/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/connect.html)
2374pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
2375 let res = unsafe { libc::connect(fd, addr.as_ptr(), addr.len()) };
2376
2377 Errno::result(res).map(drop)
2378}
2379
2380/// Receive data from a connection-oriented socket. Returns the number of
2381/// bytes read
2382///
2383/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recv.html)
2384pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
2385 unsafe {
2386 let ret = libc::recv(
2387 sockfd,
2388 buf.as_mut_ptr().cast(),
2389 buf.len() as size_t,
2390 flags.bits(),
2391 );
2392
2393 Errno::result(ret).map(|r| r as usize)
2394 }
2395}
2396
2397/// Receive data from a connectionless or connection-oriented socket. Returns
2398/// the number of bytes read and, for connectionless sockets, the socket
2399/// address of the sender.
2400///
2401/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/recvfrom.html)
2402pub fn recvfrom<T: SockaddrLike>(
2403 sockfd: RawFd,
2404 buf: &mut [u8],
2405) -> Result<(usize, Option<T>)> {
2406 unsafe {
2407 let mut addr = mem::MaybeUninit::<T>::uninit();
2408 let mut len = mem::size_of_val(&addr) as socklen_t;
2409
2410 let ret = Errno::result(libc::recvfrom(
2411 sockfd,
2412 buf.as_mut_ptr().cast(),
2413 buf.len() as size_t,
2414 0,
2415 addr.as_mut_ptr().cast(),
2416 &mut len as *mut socklen_t,
2417 ))? as usize;
2418
2419 Ok((ret, T::from_raw(addr.assume_init().as_ptr(), Some(len))))
2420 }
2421}
2422
2423/// Send a message to a socket
2424///
2425/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/sendto.html)
2426pub fn sendto(
2427 fd: RawFd,
2428 buf: &[u8],
2429 addr: &dyn SockaddrLike,
2430 flags: MsgFlags,
2431) -> Result<usize> {
2432 let ret = unsafe {
2433 libc::sendto(
2434 fd,
2435 buf.as_ptr().cast(),
2436 buf.len() as size_t,
2437 flags.bits(),
2438 addr.as_ptr(),
2439 addr.len(),
2440 )
2441 };
2442
2443 Errno::result(ret).map(|r| r as usize)
2444}
2445
2446/// Send data to a connection-oriented socket. Returns the number of bytes read
2447///
2448/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/send.html)
2449pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
2450 let ret = unsafe {
2451 libc::send(fd, buf.as_ptr().cast(), buf.len() as size_t, flags.bits())
2452 };
2453
2454 Errno::result(ret).map(|r| r as usize)
2455}
2456
2457/*
2458 *
2459 * ===== Socket Options =====
2460 *
2461 */
2462
2463/// Represents a socket option that can be retrieved.
2464pub trait GetSockOpt: Copy {
2465 type Val;
2466
2467 /// Look up the value of this socket option on the given socket.
2468 fn get<F: AsFd>(&self, fd: &F) -> Result<Self::Val>;
2469}
2470
2471/// Represents a socket option that can be set.
2472pub trait SetSockOpt: Clone {
2473 type Val: ?Sized;
2474
2475 /// Set the value of this socket option on the given socket.
2476 fn set<F: AsFd>(&self, fd: &F, val: &Self::Val) -> Result<()>;
2477}
2478
2479/// Get the current value for the requested socket option
2480///
2481/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockopt.html)
2482pub fn getsockopt<F: AsFd, O: GetSockOpt>(fd: &F, opt: O) -> Result<O::Val> {
2483 opt.get(fd)
2484}
2485
2486/// Sets the value for the requested socket option
2487///
2488/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/setsockopt.html)
2489///
2490/// # Examples
2491///
2492/// ```
2493/// use nix::sys::socket::setsockopt;
2494/// use nix::sys::socket::sockopt::KeepAlive;
2495/// use std::net::TcpListener;
2496///
2497/// let listener = TcpListener::bind("0.0.0.0:0").unwrap();
2498/// let fd = listener;
2499/// let res = setsockopt(&fd, KeepAlive, &true);
2500/// assert!(res.is_ok());
2501/// ```
2502pub fn setsockopt<F: AsFd, O: SetSockOpt>(
2503 fd: &F,
2504 opt: O,
2505 val: &O::Val,
2506) -> Result<()> {
2507 opt.set(fd, val)
2508}
2509
2510/// Get the address of the peer connected to the socket `fd`.
2511///
2512/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getpeername.html)
2513pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> {
2514 unsafe {
2515 let mut addr = mem::MaybeUninit::<T>::uninit();
2516 let mut len = T::size();
2517
2518 let ret = libc::getpeername(fd, addr.as_mut_ptr().cast(), &mut len);
2519
2520 Errno::result(ret)?;
2521
2522 T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL)
2523 }
2524}
2525
2526/// Get the current address to which the socket `fd` is bound.
2527///
2528/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/getsockname.html)
2529pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> {
2530 unsafe {
2531 let mut addr = mem::MaybeUninit::<T>::uninit();
2532 let mut len = T::size();
2533
2534 let ret = libc::getsockname(fd, addr.as_mut_ptr().cast(), &mut len);
2535
2536 Errno::result(ret)?;
2537
2538 T::from_raw(addr.assume_init().as_ptr(), Some(len)).ok_or(Errno::EINVAL)
2539 }
2540}
2541
2542#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2543pub enum Shutdown {
2544 /// Further receptions will be disallowed.
2545 Read,
2546 /// Further transmissions will be disallowed.
2547 Write,
2548 /// Further receptions and transmissions will be disallowed.
2549 Both,
2550}
2551
2552/// Shut down part of a full-duplex connection.
2553///
2554/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/shutdown.html)
2555pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
2556 unsafe {
2557 use libc::shutdown;
2558
2559 let how = match how {
2560 Shutdown::Read => libc::SHUT_RD,
2561 Shutdown::Write => libc::SHUT_WR,
2562 Shutdown::Both => libc::SHUT_RDWR,
2563 };
2564
2565 Errno::result(shutdown(df, how)).map(drop)
2566 }
2567}