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