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