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