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