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