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