1use cfg_if::cfg_if;
5use crate::{Result, errno::Errno};
6use libc::{self, c_void, c_int, iovec, socklen_t, size_t,
7 CMSG_FIRSTHDR, CMSG_NXTHDR, CMSG_DATA, CMSG_LEN};
8use std::convert::{TryFrom, TryInto};
9use std::{mem, ptr, slice};
10use std::os::unix::io::RawFd;
11#[cfg(feature = "net")]
12use std::net;
13#[cfg(target_os = "linux")]
14#[cfg(feature = "uio")]
15use crate::sys::time::TimeSpec;
16#[cfg(feature = "uio")]
17use crate::sys::time::TimeVal;
18use std::io::{IoSlice, IoSliceMut};
19
20#[deny(missing_docs)]
21mod addr;
22#[deny(missing_docs)]
23pub mod sockopt;
24
25pub use self::addr::{SockaddrLike, SockaddrStorage};
32
33#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
34#[allow(deprecated)]
35pub use self::addr::{
36 AddressFamily,
37 SockAddr,
38 UnixAddr,
39};
40#[allow(deprecated)]
41#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
42#[cfg(feature = "net")]
43pub use self::addr::{
44 InetAddr,
45 IpAddr,
46 Ipv4Addr,
47 Ipv6Addr,
48 LinkAddr,
49 SockaddrIn,
50 SockaddrIn6
51};
52#[cfg(any(target_os = "illumos", target_os = "solaris"))]
53#[allow(deprecated)]
54pub use self::addr::{
55 AddressFamily,
56 SockAddr,
57 UnixAddr,
58};
59#[allow(deprecated)]
60#[cfg(any(target_os = "illumos", target_os = "solaris"))]
61#[cfg(feature = "net")]
62pub use self::addr::{
63 InetAddr,
64 IpAddr,
65 Ipv4Addr,
66 Ipv6Addr,
67 SockaddrIn,
68 SockaddrIn6
69};
70
71#[cfg(any(target_os = "ios", target_os = "macos"))]
72#[cfg(feature = "ioctl")]
73pub use crate::sys::socket::addr::sys_control::SysControlAddr;
74#[cfg(any(target_os = "android", target_os = "linux"))]
75pub use crate::sys::socket::addr::netlink::NetlinkAddr;
76#[cfg(any(target_os = "android", target_os = "linux"))]
77pub use crate::sys::socket::addr::alg::AlgAddr;
78#[cfg(any(target_os = "android", target_os = "linux"))]
79pub use crate::sys::socket::addr::vsock::VsockAddr;
80
81#[cfg(feature = "uio")]
82pub use libc::{cmsghdr, msghdr};
83pub use libc::{
84 sa_family_t,
85 sockaddr,
86 sockaddr_storage,
87 sockaddr_un,
88};
89#[cfg(feature = "net")]
90pub use libc::{sockaddr_in, sockaddr_in6};
91
92#[doc(hidden)]
94pub use libc::{c_uint, CMSG_SPACE};
95
96#[cfg(feature = "net")]
97use crate::sys::socket::addr::{ipv4addr_to_libc, ipv6addr_to_libc};
98
99#[derive(Clone, Copy, PartialEq, Eq, Debug)]
102#[repr(i32)]
103#[non_exhaustive]
104pub enum SockType {
105 Stream = libc::SOCK_STREAM,
109 Datagram = libc::SOCK_DGRAM,
112 SeqPacket = libc::SOCK_SEQPACKET,
117 Raw = libc::SOCK_RAW,
119 Rdm = libc::SOCK_RDM,
122}
123impl TryFrom<i32> for SockType {
127 type Error = crate::Error;
128
129 fn try_from(x: i32) -> Result<Self> {
130 match x {
131 libc::SOCK_STREAM => Ok(Self::Stream),
132 libc::SOCK_DGRAM => Ok(Self::Datagram),
133 libc::SOCK_SEQPACKET => Ok(Self::SeqPacket),
134 libc::SOCK_RAW => Ok(Self::Raw),
135 #[cfg(not(any(target_os = "haiku")))]
136 libc::SOCK_RDM => Ok(Self::Rdm),
137 _ => Err(Errno::EINVAL)
138 }
139 }
140}
141
142#[repr(i32)]
145#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
146#[non_exhaustive]
147pub enum SockProtocol {
148 Tcp = libc::IPPROTO_TCP,
150 Udp = libc::IPPROTO_UDP,
152 #[cfg(any(target_os = "ios", target_os = "macos"))]
155 #[cfg_attr(docsrs, doc(cfg(all())))]
156 KextEvent = libc::SYSPROTO_EVENT,
157 #[cfg(any(target_os = "ios", target_os = "macos"))]
160 #[cfg_attr(docsrs, doc(cfg(all())))]
161 KextControl = libc::SYSPROTO_CONTROL,
162 #[cfg(any(target_os = "android", target_os = "linux"))]
166 #[cfg_attr(docsrs, doc(cfg(all())))]
167 NetlinkRoute = libc::NETLINK_ROUTE,
168 #[cfg(any(target_os = "android", target_os = "linux"))]
171 #[cfg_attr(docsrs, doc(cfg(all())))]
172 NetlinkUserSock = libc::NETLINK_USERSOCK,
173 #[cfg(any(target_os = "android", target_os = "linux"))]
176 #[cfg_attr(docsrs, doc(cfg(all())))]
177 NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
178 #[cfg(any(target_os = "android", target_os = "linux"))]
181 #[cfg_attr(docsrs, doc(cfg(all())))]
182 NetlinkSELinux = libc::NETLINK_SELINUX,
183 #[cfg(any(target_os = "android", target_os = "linux"))]
186 #[cfg_attr(docsrs, doc(cfg(all())))]
187 NetlinkISCSI = libc::NETLINK_ISCSI,
188 #[cfg(any(target_os = "android", target_os = "linux"))]
191 #[cfg_attr(docsrs, doc(cfg(all())))]
192 NetlinkAudit = libc::NETLINK_AUDIT,
193 #[cfg(any(target_os = "android", target_os = "linux"))]
196 #[cfg_attr(docsrs, doc(cfg(all())))]
197 NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP,
198 #[cfg(any(target_os = "android", target_os = "linux"))]
201 #[cfg_attr(docsrs, doc(cfg(all())))]
202 NetlinkNetFilter = libc::NETLINK_NETFILTER,
203 #[cfg(any(target_os = "android", target_os = "linux"))]
206 #[cfg_attr(docsrs, doc(cfg(all())))]
207 NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT,
208 #[cfg(any(target_os = "android", target_os = "linux"))]
211 #[cfg_attr(docsrs, doc(cfg(all())))]
212 NetlinkRDMA = libc::NETLINK_RDMA,
213 #[cfg(any(target_os = "android", target_os = "linux"))]
216 #[cfg_attr(docsrs, doc(cfg(all())))]
217 NetlinkIPv6Firewall = libc::NETLINK_IP6_FW,
218 #[cfg(any(target_os = "android", target_os = "linux"))]
221 #[cfg_attr(docsrs, doc(cfg(all())))]
222 NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG,
223 #[cfg(any(target_os = "android", target_os = "linux"))]
226 #[cfg_attr(docsrs, doc(cfg(all())))]
227 NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
228 #[cfg(any(target_os = "android", target_os = "linux"))]
232 #[cfg_attr(docsrs, doc(cfg(all())))]
233 NetlinkCrypto = libc::NETLINK_CRYPTO,
234}
235
236#[cfg(any(target_os = "linux"))]
237libc_bitflags! {
238 pub struct TimestampingFlag: c_uint {
243 SOF_TIMESTAMPING_SOFTWARE;
245 SOF_TIMESTAMPING_RAW_HARDWARE;
247 SOF_TIMESTAMPING_TX_HARDWARE;
249 SOF_TIMESTAMPING_TX_SOFTWARE;
251 SOF_TIMESTAMPING_RX_HARDWARE;
253 SOF_TIMESTAMPING_RX_SOFTWARE;
255 }
256}
257
258libc_bitflags!{
259 pub struct SockFlag: c_int {
261 #[cfg(any(target_os = "android",
263 target_os = "dragonfly",
264 target_os = "freebsd",
265 target_os = "illumos",
266 target_os = "linux",
267 target_os = "netbsd",
268 target_os = "openbsd"))]
269 #[cfg_attr(docsrs, doc(cfg(all())))]
270 SOCK_NONBLOCK;
271 #[cfg(any(target_os = "android",
273 target_os = "dragonfly",
274 target_os = "freebsd",
275 target_os = "illumos",
276 target_os = "linux",
277 target_os = "netbsd",
278 target_os = "openbsd"))]
279 #[cfg_attr(docsrs, doc(cfg(all())))]
280 SOCK_CLOEXEC;
281 #[cfg(target_os = "netbsd")]
283 #[cfg_attr(docsrs, doc(cfg(all())))]
284 SOCK_NOSIGPIPE;
285 #[cfg(target_os = "openbsd")]
288 #[cfg_attr(docsrs, doc(cfg(all())))]
289 SOCK_DNS;
290 }
291}
292
293libc_bitflags!{
294 pub struct MsgFlags: c_int {
296 MSG_OOB;
300 MSG_PEEK;
304 MSG_WAITALL;
308 MSG_DONTWAIT;
319 MSG_CTRUNC;
321 MSG_TRUNC;
330 MSG_EOR;
333 #[cfg(any(target_os = "android", target_os = "linux"))]
337 #[cfg_attr(docsrs, doc(cfg(all())))]
338 MSG_ERRQUEUE;
339 #[cfg(any(target_os = "android",
347 target_os = "dragonfly",
348 target_os = "freebsd",
349 target_os = "linux",
350 target_os = "netbsd",
351 target_os = "openbsd"))]
352 #[cfg_attr(docsrs, doc(cfg(all())))]
353 MSG_CMSG_CLOEXEC;
354 #[cfg(any(target_os = "android",
357 target_os = "dragonfly",
358 target_os = "freebsd",
359 target_os = "fuchsia",
360 target_os = "haiku",
361 target_os = "illumos",
362 target_os = "linux",
363 target_os = "netbsd",
364 target_os = "openbsd",
365 target_os = "solaris"))]
366 #[cfg_attr(docsrs, doc(cfg(all())))]
367 MSG_NOSIGNAL;
368 }
369}
370
371cfg_if! {
372 if #[cfg(any(target_os = "android", target_os = "linux"))] {
373 #[repr(transparent)]
378 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
379 pub struct UnixCredentials(libc::ucred);
380
381 impl UnixCredentials {
382 pub fn new() -> Self {
384 unsafe {
386 UnixCredentials(libc::ucred {
387 pid: libc::getpid(),
388 uid: libc::getuid(),
389 gid: libc::getgid()
390 })
391 }
392 }
393
394 pub fn pid(&self) -> libc::pid_t {
396 self.0.pid
397 }
398
399 pub fn uid(&self) -> libc::uid_t {
401 self.0.uid
402 }
403
404 pub fn gid(&self) -> libc::gid_t {
406 self.0.gid
407 }
408 }
409
410 impl Default for UnixCredentials {
411 fn default() -> Self {
412 Self::new()
413 }
414 }
415
416 impl From<libc::ucred> for UnixCredentials {
417 fn from(cred: libc::ucred) -> Self {
418 UnixCredentials(cred)
419 }
420 }
421
422 impl From<UnixCredentials> for libc::ucred {
423 fn from(uc: UnixCredentials) -> Self {
424 uc.0
425 }
426 }
427 } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
428 #[repr(transparent)]
432 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
433 pub struct UnixCredentials(libc::cmsgcred);
434
435 impl UnixCredentials {
436 pub fn pid(&self) -> libc::pid_t {
438 self.0.cmcred_pid
439 }
440
441 pub fn uid(&self) -> libc::uid_t {
443 self.0.cmcred_uid
444 }
445
446 pub fn euid(&self) -> libc::uid_t {
448 self.0.cmcred_euid
449 }
450
451 pub fn gid(&self) -> libc::gid_t {
453 self.0.cmcred_gid
454 }
455
456 pub fn groups(&self) -> &[libc::gid_t] {
458 unsafe {
459 slice::from_raw_parts(
460 self.0.cmcred_groups.as_ptr() as *const libc::gid_t,
461 self.0.cmcred_ngroups as _
462 )
463 }
464 }
465 }
466
467 impl From<libc::cmsgcred> for UnixCredentials {
468 fn from(cred: libc::cmsgcred) -> Self {
469 UnixCredentials(cred)
470 }
471 }
472 }
473}
474
475cfg_if!{
476 if #[cfg(any(
477 target_os = "dragonfly",
478 target_os = "freebsd",
479 target_os = "macos",
480 target_os = "ios"
481 ))] {
482 #[repr(transparent)]
484 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
485 pub struct XuCred(libc::xucred);
486
487 impl XuCred {
488 pub fn version(&self) -> u32 {
490 self.0.cr_version
491 }
492
493 pub fn uid(&self) -> libc::uid_t {
495 self.0.cr_uid
496 }
497
498 pub fn groups(&self) -> &[libc::gid_t] {
501 &self.0.cr_groups
502 }
503 }
504 }
505}
506
507feature! {
508#![feature = "net"]
509#[repr(transparent)]
513#[derive(Clone, Copy, Debug, Eq, PartialEq)]
514pub struct IpMembershipRequest(libc::ip_mreq);
515
516impl IpMembershipRequest {
517 pub fn new(group: net::Ipv4Addr, interface: Option<net::Ipv4Addr>)
521 -> Self
522 {
523 let imr_addr = match interface {
524 None => net::Ipv4Addr::UNSPECIFIED,
525 Some(addr) => addr
526 };
527 IpMembershipRequest(libc::ip_mreq {
528 imr_multiaddr: ipv4addr_to_libc(group),
529 imr_interface: ipv4addr_to_libc(imr_addr)
530 })
531 }
532}
533
534#[repr(transparent)]
538#[derive(Clone, Copy, Debug, Eq, PartialEq)]
539pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
540
541impl Ipv6MembershipRequest {
542 pub const fn new(group: net::Ipv6Addr) -> Self {
544 Ipv6MembershipRequest(libc::ipv6_mreq {
545 ipv6mr_multiaddr: ipv6addr_to_libc(&group),
546 ipv6mr_interface: 0,
547 })
548 }
549}
550}
551
552feature! {
553#![feature = "uio"]
554
555#[macro_export]
578macro_rules! cmsg_space {
579 ( $( $x:ty ),* ) => {
580 {
581 let mut space = 0;
582 $(
583 space += unsafe {
585 $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint)
586 } as usize;
587 )*
588 Vec::<u8>::with_capacity(space)
589 }
590 }
591}
592
593#[derive(Clone, Copy, Debug, Eq, PartialEq)]
594pub struct RecvMsg<'a, S> {
595 pub bytes: usize,
596 cmsghdr: Option<&'a cmsghdr>,
597 pub address: Option<S>,
598 pub flags: MsgFlags,
599 mhdr: msghdr,
600}
601
602impl<'a, S> RecvMsg<'a, S> {
603 pub fn cmsgs(&self) -> CmsgIterator {
606 CmsgIterator {
607 cmsghdr: self.cmsghdr,
608 mhdr: &self.mhdr
609 }
610 }
611}
612
613#[derive(Clone, Copy, Debug, Eq, PartialEq)]
614pub struct CmsgIterator<'a> {
615 cmsghdr: Option<&'a cmsghdr>,
617 mhdr: &'a msghdr
618}
619
620impl<'a> Iterator for CmsgIterator<'a> {
621 type Item = ControlMessageOwned;
622
623 fn next(&mut self) -> Option<ControlMessageOwned> {
624 match self.cmsghdr {
625 None => None, Some(hdr) => {
627 let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))};
630 self.cmsghdr = unsafe {
633 let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _);
634 p.as_ref()
635 };
636 cm
637 }
638 }
639 }
640}
641
642#[derive(Clone, Debug, Eq, PartialEq)]
653#[non_exhaustive]
654pub enum ControlMessageOwned {
655 ScmRights(Vec<RawFd>),
657 #[cfg(any(target_os = "android", target_os = "linux"))]
659 #[cfg_attr(docsrs, doc(cfg(all())))]
660 ScmCredentials(UnixCredentials),
661 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
663 #[cfg_attr(docsrs, doc(cfg(all())))]
664 ScmCreds(UnixCredentials),
665 ScmTimestamp(TimeVal),
723 #[cfg(all(target_os = "linux"))]
727 ScmTimestampsns(Timestamps),
728 #[cfg(all(target_os = "linux"))]
732 #[cfg_attr(docsrs, doc(cfg(all())))]
733 ScmTimestampns(TimeSpec),
734 #[cfg(any(
735 target_os = "android",
736 target_os = "ios",
737 target_os = "linux",
738 target_os = "macos",
739 target_os = "netbsd",
740 ))]
741 #[cfg(feature = "net")]
742 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
743 Ipv4PacketInfo(libc::in_pktinfo),
744 #[cfg(any(
745 target_os = "android",
746 target_os = "dragonfly",
747 target_os = "freebsd",
748 target_os = "ios",
749 target_os = "linux",
750 target_os = "macos",
751 target_os = "openbsd",
752 target_os = "netbsd",
753 ))]
754 #[cfg(feature = "net")]
755 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
756 Ipv6PacketInfo(libc::in6_pktinfo),
757 #[cfg(any(
758 target_os = "freebsd",
759 target_os = "ios",
760 target_os = "macos",
761 target_os = "netbsd",
762 target_os = "openbsd",
763 ))]
764 #[cfg(feature = "net")]
765 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
766 Ipv4RecvIf(libc::sockaddr_dl),
767 #[cfg(any(
768 target_os = "freebsd",
769 target_os = "ios",
770 target_os = "macos",
771 target_os = "netbsd",
772 target_os = "openbsd",
773 ))]
774 #[cfg(feature = "net")]
775 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
776 Ipv4RecvDstAddr(libc::in_addr),
777
778 #[cfg(target_os = "linux")]
787 #[cfg(feature = "net")]
788 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
789 UdpGroSegments(u16),
790
791 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
800 #[cfg_attr(docsrs, doc(cfg(all())))]
801 RxqOvfl(u32),
802
803 #[cfg(any(target_os = "android", target_os = "linux"))]
805 #[cfg(feature = "net")]
806 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
807 Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>),
808 #[cfg(any(target_os = "android", target_os = "linux"))]
810 #[cfg(feature = "net")]
811 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
812 Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>),
813
814 #[doc(hidden)]
816 Unknown(UnknownCmsg),
817}
818
819#[cfg(all(target_os = "linux"))]
821#[derive(Copy, Clone, Debug, Eq, PartialEq)]
822pub struct Timestamps {
823 pub system: TimeSpec,
825 pub hw_trans: TimeSpec,
827 pub hw_raw: TimeSpec,
829}
830
831impl ControlMessageOwned {
832 #[allow(clippy::cast_ptr_alignment)]
841 unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
842 {
843 let p = CMSG_DATA(header);
844 #[allow(clippy::unnecessary_cast)]
846 let len = header as *const _ as usize + header.cmsg_len as usize
847 - p as usize;
848 match (header.cmsg_level, header.cmsg_type) {
849 (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
850 let n = len / mem::size_of::<RawFd>();
851 let mut fds = Vec::with_capacity(n);
852 for i in 0..n {
853 let fdp = (p as *const RawFd).add(i);
854 fds.push(ptr::read_unaligned(fdp));
855 }
856 ControlMessageOwned::ScmRights(fds)
857 },
858 #[cfg(any(target_os = "android", target_os = "linux"))]
859 (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
860 let cred: libc::ucred = ptr::read_unaligned(p as *const _);
861 ControlMessageOwned::ScmCredentials(cred.into())
862 }
863 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
864 (libc::SOL_SOCKET, libc::SCM_CREDS) => {
865 let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
866 ControlMessageOwned::ScmCreds(cred.into())
867 }
868 (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
869 let tv: libc::timeval = ptr::read_unaligned(p as *const _);
870 ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
871 },
872 #[cfg(all(target_os = "linux"))]
873 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
874 let ts: libc::timespec = ptr::read_unaligned(p as *const _);
875 ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts))
876 }
877 #[cfg(all(target_os = "linux"))]
878 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPING) => {
879 let tp = p as *const libc::timespec;
880 let ts: libc::timespec = ptr::read_unaligned(tp);
881 let system = TimeSpec::from(ts);
882 let ts: libc::timespec = ptr::read_unaligned(tp.add(1));
883 let hw_trans = TimeSpec::from(ts);
884 let ts: libc::timespec = ptr::read_unaligned(tp.add(2));
885 let hw_raw = TimeSpec::from(ts);
886 let timestamping = Timestamps { system, hw_trans, hw_raw };
887 ControlMessageOwned::ScmTimestampsns(timestamping)
888 }
889 #[cfg(any(
890 target_os = "android",
891 target_os = "freebsd",
892 target_os = "ios",
893 target_os = "linux",
894 target_os = "macos"
895 ))]
896 #[cfg(feature = "net")]
897 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
898 let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
899 ControlMessageOwned::Ipv6PacketInfo(info)
900 }
901 #[cfg(any(
902 target_os = "android",
903 target_os = "ios",
904 target_os = "linux",
905 target_os = "macos",
906 target_os = "netbsd",
907 ))]
908 #[cfg(feature = "net")]
909 (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
910 let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
911 ControlMessageOwned::Ipv4PacketInfo(info)
912 }
913 #[cfg(any(
914 target_os = "freebsd",
915 target_os = "ios",
916 target_os = "macos",
917 target_os = "netbsd",
918 target_os = "openbsd",
919 ))]
920 #[cfg(feature = "net")]
921 (libc::IPPROTO_IP, libc::IP_RECVIF) => {
922 let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
923 ControlMessageOwned::Ipv4RecvIf(dl)
924 },
925 #[cfg(any(
926 target_os = "freebsd",
927 target_os = "ios",
928 target_os = "macos",
929 target_os = "netbsd",
930 target_os = "openbsd",
931 ))]
932 #[cfg(feature = "net")]
933 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
934 let dl = ptr::read_unaligned(p as *const libc::in_addr);
935 ControlMessageOwned::Ipv4RecvDstAddr(dl)
936 },
937 #[cfg(target_os = "linux")]
938 #[cfg(feature = "net")]
939 (libc::SOL_UDP, libc::UDP_GRO) => {
940 let gso_size: u16 = ptr::read_unaligned(p as *const _);
941 ControlMessageOwned::UdpGroSegments(gso_size)
942 },
943 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
944 (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
945 let drop_counter = ptr::read_unaligned(p as *const u32);
946 ControlMessageOwned::RxqOvfl(drop_counter)
947 },
948 #[cfg(any(target_os = "android", target_os = "linux"))]
949 #[cfg(feature = "net")]
950 (libc::IPPROTO_IP, libc::IP_RECVERR) => {
951 let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len);
952 ControlMessageOwned::Ipv4RecvErr(err, addr)
953 },
954 #[cfg(any(target_os = "android", target_os = "linux"))]
955 #[cfg(feature = "net")]
956 (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => {
957 let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len);
958 ControlMessageOwned::Ipv6RecvErr(err, addr)
959 },
960 (_, _) => {
961 let sl = slice::from_raw_parts(p, len);
962 let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
963 ControlMessageOwned::Unknown(ucmsg)
964 }
965 }
966 }
967
968 #[cfg(any(target_os = "android", target_os = "linux"))]
969 #[cfg(feature = "net")]
970 unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) {
971 let ee = p as *const libc::sock_extended_err;
972 let err = ptr::read_unaligned(ee);
973
974 let addrp = libc::SO_EE_OFFENDER(ee) as *const T;
979
980 if addrp.offset(1) as usize - (p as usize) > len {
981 (err, None)
982 } else {
983 (err, Some(ptr::read_unaligned(addrp)))
984 }
985 }
986}
987
988#[derive(Clone, Copy, Debug, Eq, PartialEq)]
994#[non_exhaustive]
995pub enum ControlMessage<'a> {
996 ScmRights(&'a [RawFd]),
1008 #[cfg(any(target_os = "android", target_os = "linux"))]
1019 #[cfg_attr(docsrs, doc(cfg(all())))]
1020 ScmCredentials(&'a UnixCredentials),
1021 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1034 #[cfg_attr(docsrs, doc(cfg(all())))]
1035 ScmCreds,
1036
1037 #[cfg(any(
1042 target_os = "android",
1043 target_os = "linux",
1044 ))]
1045 #[cfg_attr(docsrs, doc(cfg(all())))]
1046 AlgSetIv(&'a [u8]),
1047 #[cfg(any(
1053 target_os = "android",
1054 target_os = "linux",
1055 ))]
1056 #[cfg_attr(docsrs, doc(cfg(all())))]
1057 AlgSetOp(&'a libc::c_int),
1058 #[cfg(any(
1064 target_os = "android",
1065 target_os = "linux",
1066 ))]
1067 #[cfg_attr(docsrs, doc(cfg(all())))]
1068 AlgSetAeadAssoclen(&'a u32),
1069
1070 #[cfg(target_os = "linux")]
1079 #[cfg(feature = "net")]
1080 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1081 UdpGsoSegments(&'a u16),
1082
1083 #[cfg(any(target_os = "linux",
1088 target_os = "macos",
1089 target_os = "netbsd",
1090 target_os = "android",
1091 target_os = "ios",))]
1092 #[cfg(feature = "net")]
1093 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1094 Ipv4PacketInfo(&'a libc::in_pktinfo),
1095
1096 #[cfg(any(target_os = "linux",
1101 target_os = "macos",
1102 target_os = "netbsd",
1103 target_os = "freebsd",
1104 target_os = "android",
1105 target_os = "ios",))]
1106 #[cfg(feature = "net")]
1107 #[cfg_attr(docsrs, doc(cfg(feature = "net")))]
1108 Ipv6PacketInfo(&'a libc::in6_pktinfo),
1109
1110 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1116 #[cfg_attr(docsrs, doc(cfg(all())))]
1117 RxqOvfl(&'a u32),
1118
1119 #[cfg(target_os = "linux")]
1125 TxTime(&'a u64),
1126}
1127
1128#[doc(hidden)]
1130#[derive(Clone, Debug, Eq, PartialEq)]
1131pub struct UnknownCmsg(cmsghdr, Vec<u8>);
1132
1133impl<'a> ControlMessage<'a> {
1134 fn space(&self) -> usize {
1137 unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
1138 }
1139
1140 #[cfg(any(target_os = "android",
1143 all(target_os = "linux", not(target_env = "musl"))))]
1144 fn cmsg_len(&self) -> usize {
1145 unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
1146 }
1147
1148 #[cfg(not(any(target_os = "android",
1149 all(target_os = "linux", not(target_env = "musl")))))]
1150 fn cmsg_len(&self) -> libc::c_uint {
1151 unsafe{CMSG_LEN(self.len() as libc::c_uint)}
1152 }
1153
1154 fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
1156 let data_ptr = match *self {
1157 ControlMessage::ScmRights(fds) => {
1158 fds as *const _ as *const u8
1159 },
1160 #[cfg(any(target_os = "android", target_os = "linux"))]
1161 ControlMessage::ScmCredentials(creds) => {
1162 &creds.0 as *const libc::ucred as *const u8
1163 }
1164 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1165 ControlMessage::ScmCreds => {
1166 unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
1169 return
1170 }
1171 #[cfg(any(target_os = "android", target_os = "linux"))]
1172 ControlMessage::AlgSetIv(iv) => {
1173 #[allow(deprecated)] let af_alg_iv = libc::af_alg_iv {
1175 ivlen: iv.len() as u32,
1176 iv: [0u8; 0],
1177 };
1178
1179 let size = mem::size_of_val(&af_alg_iv);
1180
1181 unsafe {
1182 ptr::copy_nonoverlapping(
1183 &af_alg_iv as *const _ as *const u8,
1184 cmsg_data,
1185 size,
1186 );
1187 ptr::copy_nonoverlapping(
1188 iv.as_ptr(),
1189 cmsg_data.add(size),
1190 iv.len()
1191 );
1192 };
1193
1194 return
1195 },
1196 #[cfg(any(target_os = "android", target_os = "linux"))]
1197 ControlMessage::AlgSetOp(op) => {
1198 op as *const _ as *const u8
1199 },
1200 #[cfg(any(target_os = "android", target_os = "linux"))]
1201 ControlMessage::AlgSetAeadAssoclen(len) => {
1202 len as *const _ as *const u8
1203 },
1204 #[cfg(target_os = "linux")]
1205 #[cfg(feature = "net")]
1206 ControlMessage::UdpGsoSegments(gso_size) => {
1207 gso_size as *const _ as *const u8
1208 },
1209 #[cfg(any(target_os = "linux", target_os = "macos",
1210 target_os = "netbsd", target_os = "android",
1211 target_os = "ios",))]
1212 #[cfg(feature = "net")]
1213 ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
1214 #[cfg(any(target_os = "linux", target_os = "macos",
1215 target_os = "netbsd", target_os = "freebsd",
1216 target_os = "android", target_os = "ios",))]
1217 #[cfg(feature = "net")]
1218 ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
1219 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1220 ControlMessage::RxqOvfl(drop_count) => {
1221 drop_count as *const _ as *const u8
1222 },
1223 #[cfg(target_os = "linux")]
1224 ControlMessage::TxTime(tx_time) => {
1225 tx_time as *const _ as *const u8
1226 },
1227 };
1228 unsafe {
1229 ptr::copy_nonoverlapping(
1230 data_ptr,
1231 cmsg_data,
1232 self.len()
1233 )
1234 };
1235 }
1236
1237 fn len(&self) -> usize {
1239 match *self {
1240 ControlMessage::ScmRights(fds) => {
1241 mem::size_of_val(fds)
1242 },
1243 #[cfg(any(target_os = "android", target_os = "linux"))]
1244 ControlMessage::ScmCredentials(creds) => {
1245 mem::size_of_val(creds)
1246 }
1247 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1248 ControlMessage::ScmCreds => {
1249 mem::size_of::<libc::cmsgcred>()
1250 }
1251 #[cfg(any(target_os = "android", target_os = "linux"))]
1252 ControlMessage::AlgSetIv(iv) => {
1253 mem::size_of_val(&iv) + iv.len()
1254 },
1255 #[cfg(any(target_os = "android", target_os = "linux"))]
1256 ControlMessage::AlgSetOp(op) => {
1257 mem::size_of_val(op)
1258 },
1259 #[cfg(any(target_os = "android", target_os = "linux"))]
1260 ControlMessage::AlgSetAeadAssoclen(len) => {
1261 mem::size_of_val(len)
1262 },
1263 #[cfg(target_os = "linux")]
1264 #[cfg(feature = "net")]
1265 ControlMessage::UdpGsoSegments(gso_size) => {
1266 mem::size_of_val(gso_size)
1267 },
1268 #[cfg(any(target_os = "linux", target_os = "macos",
1269 target_os = "netbsd", target_os = "android",
1270 target_os = "ios",))]
1271 #[cfg(feature = "net")]
1272 ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
1273 #[cfg(any(target_os = "linux", target_os = "macos",
1274 target_os = "netbsd", target_os = "freebsd",
1275 target_os = "android", target_os = "ios",))]
1276 #[cfg(feature = "net")]
1277 ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
1278 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1279 ControlMessage::RxqOvfl(drop_count) => {
1280 mem::size_of_val(drop_count)
1281 },
1282 #[cfg(target_os = "linux")]
1283 ControlMessage::TxTime(tx_time) => {
1284 mem::size_of_val(tx_time)
1285 },
1286 }
1287 }
1288
1289 fn cmsg_level(&self) -> libc::c_int {
1291 match *self {
1292 ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
1293 #[cfg(any(target_os = "android", target_os = "linux"))]
1294 ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
1295 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1296 ControlMessage::ScmCreds => libc::SOL_SOCKET,
1297 #[cfg(any(target_os = "android", target_os = "linux"))]
1298 ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
1299 ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
1300 #[cfg(target_os = "linux")]
1301 #[cfg(feature = "net")]
1302 ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
1303 #[cfg(any(target_os = "linux", target_os = "macos",
1304 target_os = "netbsd", target_os = "android",
1305 target_os = "ios",))]
1306 #[cfg(feature = "net")]
1307 ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
1308 #[cfg(any(target_os = "linux", target_os = "macos",
1309 target_os = "netbsd", target_os = "freebsd",
1310 target_os = "android", target_os = "ios",))]
1311 #[cfg(feature = "net")]
1312 ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
1313 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1314 ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
1315 #[cfg(target_os = "linux")]
1316 ControlMessage::TxTime(_) => libc::SOL_SOCKET,
1317 }
1318 }
1319
1320 fn cmsg_type(&self) -> libc::c_int {
1322 match *self {
1323 ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
1324 #[cfg(any(target_os = "android", target_os = "linux"))]
1325 ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
1326 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1327 ControlMessage::ScmCreds => libc::SCM_CREDS,
1328 #[cfg(any(target_os = "android", target_os = "linux"))]
1329 ControlMessage::AlgSetIv(_) => {
1330 libc::ALG_SET_IV
1331 },
1332 #[cfg(any(target_os = "android", target_os = "linux"))]
1333 ControlMessage::AlgSetOp(_) => {
1334 libc::ALG_SET_OP
1335 },
1336 #[cfg(any(target_os = "android", target_os = "linux"))]
1337 ControlMessage::AlgSetAeadAssoclen(_) => {
1338 libc::ALG_SET_AEAD_ASSOCLEN
1339 },
1340 #[cfg(target_os = "linux")]
1341 #[cfg(feature = "net")]
1342 ControlMessage::UdpGsoSegments(_) => {
1343 libc::UDP_SEGMENT
1344 },
1345 #[cfg(any(target_os = "linux", target_os = "macos",
1346 target_os = "netbsd", target_os = "android",
1347 target_os = "ios",))]
1348 #[cfg(feature = "net")]
1349 ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
1350 #[cfg(any(target_os = "linux", target_os = "macos",
1351 target_os = "netbsd", target_os = "freebsd",
1352 target_os = "android", target_os = "ios",))]
1353 #[cfg(feature = "net")]
1354 ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
1355 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1356 ControlMessage::RxqOvfl(_) => {
1357 libc::SO_RXQ_OVFL
1358 },
1359 #[cfg(target_os = "linux")]
1360 ControlMessage::TxTime(_) => {
1361 libc::SCM_TXTIME
1362 },
1363 }
1364 }
1365
1366 unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
1369 (*cmsg).cmsg_level = self.cmsg_level();
1370 (*cmsg).cmsg_type = self.cmsg_type();
1371 (*cmsg).cmsg_len = self.cmsg_len();
1372 self.copy_to_cmsg_data(CMSG_DATA(cmsg));
1373 }
1374}
1375
1376
1377pub fn sendmsg<S>(fd: RawFd, iov: &[IoSlice<'_>], cmsgs: &[ControlMessage],
1416 flags: MsgFlags, addr: Option<&S>) -> Result<usize>
1417 where S: SockaddrLike
1418{
1419 let capacity = cmsgs.iter().map(|c| c.space()).sum();
1420
1421 let mut cmsg_buffer = vec![0u8; capacity];
1424
1425 let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr);
1426
1427 let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
1428
1429 Errno::result(ret).map(|r| r as usize)
1430}
1431
1432#[cfg(any(
1433 target_os = "linux",
1434 target_os = "android",
1435 target_os = "freebsd",
1436 target_os = "netbsd",
1437))]
1438#[derive(Debug)]
1439pub struct SendMmsgData<'a, I, C, S>
1440 where
1441 I: AsRef<[IoSlice<'a>]>,
1442 C: AsRef<[ControlMessage<'a>]>,
1443 S: SockaddrLike + 'a
1444{
1445 pub iov: I,
1446 pub cmsgs: C,
1447 pub addr: Option<S>,
1448 pub _lt: std::marker::PhantomData<&'a I>,
1449}
1450
1451#[cfg(any(
1469 target_os = "linux",
1470 target_os = "android",
1471 target_os = "freebsd",
1472 target_os = "netbsd",
1473))]
1474pub fn sendmmsg<'a, I, C, S>(
1475 fd: RawFd,
1476 data: impl std::iter::IntoIterator<Item=&'a SendMmsgData<'a, I, C, S>>,
1477 flags: MsgFlags
1478) -> Result<Vec<usize>>
1479 where
1480 I: AsRef<[IoSlice<'a>]> + 'a,
1481 C: AsRef<[ControlMessage<'a>]> + 'a,
1482 S: SockaddrLike + 'a
1483{
1484 let iter = data.into_iter();
1485
1486 let size_hint = iter.size_hint();
1487 let reserve_items = size_hint.1.unwrap_or(size_hint.0);
1488
1489 let mut output = Vec::<libc::mmsghdr>::with_capacity(reserve_items);
1490
1491 let mut cmsgs_buffers = Vec::<Vec<u8>>::with_capacity(reserve_items);
1492
1493 for d in iter {
1494 let capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum();
1495 let mut cmsgs_buffer = vec![0u8; capacity];
1496
1497 output.push(libc::mmsghdr {
1498 msg_hdr: pack_mhdr_to_send(
1499 &mut cmsgs_buffer,
1500 &d.iov,
1501 &d.cmsgs,
1502 d.addr.as_ref()
1503 ),
1504 msg_len: 0,
1505 });
1506 cmsgs_buffers.push(cmsgs_buffer);
1507 };
1508
1509 let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) };
1510
1511 let sent_messages = Errno::result(ret)? as usize;
1512 let mut sent_bytes = Vec::with_capacity(sent_messages);
1513
1514 for item in &output {
1515 sent_bytes.push(item.msg_len as usize);
1516 }
1517
1518 Ok(sent_bytes)
1519}
1520
1521
1522#[cfg(any(
1523 target_os = "linux",
1524 target_os = "android",
1525 target_os = "freebsd",
1526 target_os = "netbsd",
1527))]
1528#[derive(Debug)]
1529pub struct RecvMmsgData<'a, I>
1530 where
1531 I: AsRef<[IoSliceMut<'a>]> + 'a,
1532{
1533 pub iov: I,
1534 pub cmsg_buffer: Option<&'a mut Vec<u8>>,
1535}
1536
1537#[cfg(any(
1564 target_os = "linux",
1565 target_os = "android",
1566 target_os = "freebsd",
1567 target_os = "netbsd",
1568))]
1569#[allow(clippy::needless_collect)] pub fn recvmmsg<'a, I, S>(
1571 fd: RawFd,
1572 data: impl std::iter::IntoIterator<Item=&'a mut RecvMmsgData<'a, I>,
1573 IntoIter=impl ExactSizeIterator + Iterator<Item=&'a mut RecvMmsgData<'a, I>>>,
1574 flags: MsgFlags,
1575 timeout: Option<crate::sys::time::TimeSpec>
1576) -> Result<Vec<RecvMsg<'a, S>>>
1577 where
1578 I: AsRef<[IoSliceMut<'a>]> + 'a,
1579 S: Copy + SockaddrLike + 'a
1580{
1581 let iter = data.into_iter();
1582
1583 let num_messages = iter.len();
1584
1585 let mut output: Vec<libc::mmsghdr> = Vec::with_capacity(num_messages);
1586
1587 let mut addresses = vec![mem::MaybeUninit::uninit(); num_messages]
1591 .into_boxed_slice();
1592
1593 let results: Vec<_> = iter.enumerate().map(|(i, d)| {
1594 let (msg_controllen, mhdr) = unsafe {
1595 pack_mhdr_to_receive(
1596 d.iov.as_ref(),
1597 &mut d.cmsg_buffer,
1598 addresses[i].as_mut_ptr(),
1599 )
1600 };
1601
1602 output.push(
1603 libc::mmsghdr {
1604 msg_hdr: mhdr,
1605 msg_len: 0,
1606 }
1607 );
1608
1609 (msg_controllen, &mut d.cmsg_buffer)
1610 }).collect();
1611
1612 let timeout = if let Some(mut t) = timeout {
1613 t.as_mut() as *mut libc::timespec
1614 } else {
1615 ptr::null_mut()
1616 };
1617
1618 let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) };
1619
1620 let _ = Errno::result(ret)?;
1621
1622 Ok(output
1623 .into_iter()
1624 .take(ret as usize)
1625 .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()}))
1626 .zip(results.into_iter())
1627 .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| {
1628 #[allow(clippy::unnecessary_cast)]
1630 unsafe {
1631 read_mhdr(
1632 mmsghdr.msg_hdr,
1633 mmsghdr.msg_len as isize,
1634 msg_controllen,
1635 address,
1636 cmsg_buffer
1637 )
1638 }
1639 })
1640 .collect())
1641}
1642
1643unsafe fn read_mhdr<'a, S>(
1644 mhdr: msghdr,
1645 r: isize,
1646 msg_controllen: usize,
1647 address: S,
1648 cmsg_buffer: &mut Option<&'a mut Vec<u8>>
1649) -> RecvMsg<'a, S>
1650 where S: SockaddrLike
1651{
1652 #[allow(clippy::unnecessary_cast)]
1654 let cmsghdr = {
1655 if mhdr.msg_controllen > 0 {
1656 cmsg_buffer
1658 .as_mut()
1659 .unwrap()
1660 .set_len(mhdr.msg_controllen as usize);
1661 debug_assert!(!mhdr.msg_control.is_null());
1662 debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
1663 CMSG_FIRSTHDR(&mhdr as *const msghdr)
1664 } else {
1665 ptr::null()
1666 }.as_ref()
1667 };
1668
1669 RecvMsg {
1670 bytes: r as usize,
1671 cmsghdr,
1672 address: Some(address),
1673 flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
1674 mhdr,
1675 }
1676}
1677
1678unsafe fn pack_mhdr_to_receive<'outer, 'inner, I, S>(
1679 iov: I,
1680 cmsg_buffer: &mut Option<&mut Vec<u8>>,
1681 address: *mut S,
1682) -> (usize, msghdr)
1683 where
1684 I: AsRef<[IoSliceMut<'inner>]> + 'outer,
1685 S: SockaddrLike + 'outer
1686{
1687 let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
1688 .map(|v| (v.as_mut_ptr(), v.capacity()))
1689 .unwrap_or((ptr::null_mut(), 0));
1690
1691 let mhdr = {
1692 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
1695 let p = mhdr.as_mut_ptr();
1696 (*p).msg_name = (*address).as_mut_ptr() as *mut c_void;
1697 (*p).msg_namelen = S::size();
1698 (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec;
1699 (*p).msg_iovlen = iov.as_ref().len() as _;
1700 (*p).msg_control = msg_control as *mut c_void;
1701 (*p).msg_controllen = msg_controllen as _;
1702 (*p).msg_flags = 0;
1703 mhdr.assume_init()
1704 };
1705
1706 (msg_controllen, mhdr)
1707}
1708
1709fn pack_mhdr_to_send<'a, I, C, S>(
1710 cmsg_buffer: &mut [u8],
1711 iov: I,
1712 cmsgs: C,
1713 addr: Option<&S>
1714) -> msghdr
1715 where
1716 I: AsRef<[IoSlice<'a>]>,
1717 C: AsRef<[ControlMessage<'a>]>,
1718 S: SockaddrLike + 'a
1719{
1720 let capacity = cmsg_buffer.len();
1721
1722 let cmsg_ptr = if capacity > 0 {
1724 cmsg_buffer.as_ptr() as *mut c_void
1725 } else {
1726 ptr::null_mut()
1727 };
1728
1729 let mhdr = unsafe {
1730 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
1733 let p = mhdr.as_mut_ptr();
1734 (*p).msg_name = addr.map(S::as_ptr).unwrap_or(ptr::null()) as *mut _;
1735 (*p).msg_namelen = addr.map(S::len).unwrap_or(0);
1736 (*p).msg_iov = iov.as_ref().as_ptr() as *mut _;
1739 (*p).msg_iovlen = iov.as_ref().len() as _;
1740 (*p).msg_control = cmsg_ptr;
1741 (*p).msg_controllen = capacity as _;
1742 (*p).msg_flags = 0;
1743 mhdr.assume_init()
1744 };
1745
1746 let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) };
1750 for cmsg in cmsgs.as_ref() {
1751 assert_ne!(pmhdr, ptr::null_mut());
1752 unsafe { cmsg.encode_into(pmhdr) };
1755 pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) };
1757 }
1758
1759 mhdr
1760}
1761
1762pub fn recvmsg<'a, 'outer, 'inner, S>(fd: RawFd, iov: &'outer mut [IoSliceMut<'inner>],
1777 mut cmsg_buffer: Option<&'a mut Vec<u8>>,
1778 flags: MsgFlags) -> Result<RecvMsg<'a, S>>
1779 where S: SockaddrLike + 'a
1780{
1781 let mut address = mem::MaybeUninit::uninit();
1782
1783 let (msg_controllen, mut mhdr) = unsafe {
1784 pack_mhdr_to_receive::<_, S>(iov, &mut cmsg_buffer, address.as_mut_ptr())
1785 };
1786
1787 let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
1788
1789 let r = Errno::result(ret)?;
1790
1791 Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init(), &mut cmsg_buffer) })
1792}
1793}
1794
1795
1796pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> {
1807 let protocol = match protocol.into() {
1808 None => 0,
1809 Some(p) => p as c_int,
1810 };
1811
1812 let mut ty = ty as c_int;
1816 ty |= flags.bits();
1817
1818 let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
1819
1820 Errno::result(res)
1821}
1822
1823pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T,
1827 flags: SockFlag) -> Result<(RawFd, RawFd)> {
1828 let protocol = match protocol.into() {
1829 None => 0,
1830 Some(p) => p as c_int,
1831 };
1832
1833 let mut ty = ty as c_int;
1837 ty |= flags.bits();
1838
1839 let mut fds = [-1, -1];
1840
1841 let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) };
1842 Errno::result(res)?;
1843
1844 Ok((fds[0], fds[1]))
1845}
1846
1847pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
1851 let res = unsafe { libc::listen(sockfd, backlog as c_int) };
1852
1853 Errno::result(res).map(drop)
1854}
1855
1856pub fn bind(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
1860 let res = unsafe {
1861 libc::bind(fd, addr.as_ptr(), addr.len())
1862 };
1863
1864 Errno::result(res).map(drop)
1865}
1866
1867pub fn accept(sockfd: RawFd) -> Result<RawFd> {
1871 let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
1872
1873 Errno::result(res)
1874}
1875
1876#[cfg(any(all(
1880 target_os = "android",
1881 any(
1882 target_arch = "aarch64",
1883 target_arch = "x86",
1884 target_arch = "x86_64"
1885 )
1886 ),
1887 target_os = "dragonfly",
1888 target_os = "emscripten",
1889 target_os = "freebsd",
1890 target_os = "fuchsia",
1891 target_os = "illumos",
1892 target_os = "linux",
1893 target_os = "netbsd",
1894 target_os = "openbsd"))]
1895pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
1896 let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) };
1897
1898 Errno::result(res)
1899}
1900
1901pub fn connect(fd: RawFd, addr: &dyn SockaddrLike) -> Result<()> {
1905 let res = unsafe {
1906 libc::connect(fd, addr.as_ptr(), addr.len())
1907 };
1908
1909 Errno::result(res).map(drop)
1910}
1911
1912pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
1917 unsafe {
1918 let ret = libc::recv(
1919 sockfd,
1920 buf.as_ptr() as *mut c_void,
1921 buf.len() as size_t,
1922 flags.bits());
1923
1924 Errno::result(ret).map(|r| r as usize)
1925 }
1926}
1927
1928pub fn recvfrom<T:SockaddrLike>(sockfd: RawFd, buf: &mut [u8])
1934 -> Result<(usize, Option<T>)>
1935{
1936 unsafe {
1937 let mut addr = mem::MaybeUninit::<T>::uninit();
1938 let mut len = mem::size_of_val(&addr) as socklen_t;
1939
1940 let ret = Errno::result(libc::recvfrom(
1941 sockfd,
1942 buf.as_ptr() as *mut c_void,
1943 buf.len() as size_t,
1944 0,
1945 addr.as_mut_ptr() as *mut libc::sockaddr,
1946 &mut len as *mut socklen_t))? as usize;
1947
1948 Ok((ret, T::from_raw(
1949 addr.assume_init().as_ptr() as *const libc::sockaddr,
1950 Some(len))
1951 ))
1952 }
1953}
1954
1955pub fn sendto(fd: RawFd, buf: &[u8], addr: &dyn SockaddrLike, flags: MsgFlags) -> Result<usize> {
1959 let ret = unsafe {
1960 libc::sendto(
1961 fd,
1962 buf.as_ptr() as *const c_void,
1963 buf.len() as size_t,
1964 flags.bits(),
1965 addr.as_ptr(),
1966 addr.len()
1967 )
1968 };
1969
1970 Errno::result(ret).map(|r| r as usize)
1971}
1972
1973pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
1977 let ret = unsafe {
1978 libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
1979 };
1980
1981 Errno::result(ret).map(|r| r as usize)
1982}
1983
1984pub trait GetSockOpt : Copy {
1992 type Val;
1993
1994 fn get(&self, fd: RawFd) -> Result<Self::Val>;
1996}
1997
1998pub trait SetSockOpt : Clone {
2000 type Val;
2001
2002 fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
2004}
2005
2006pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
2010 opt.get(fd)
2011}
2012
2013pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
2031 opt.set(fd, val)
2032}
2033
2034pub fn getpeername<T: SockaddrLike>(fd: RawFd) -> Result<T> {
2038 unsafe {
2039 let mut addr = mem::MaybeUninit::<T>::uninit();
2040 let mut len = T::size();
2041
2042 let ret = libc::getpeername(
2043 fd,
2044 addr.as_mut_ptr() as *mut libc::sockaddr,
2045 &mut len
2046 );
2047
2048 Errno::result(ret)?;
2049
2050 T::from_raw(addr.assume_init().as_ptr(), Some(len))
2051 .ok_or(Errno::EINVAL)
2052 }
2053}
2054
2055pub fn getsockname<T: SockaddrLike>(fd: RawFd) -> Result<T> {
2059 unsafe {
2060 let mut addr = mem::MaybeUninit::<T>::uninit();
2061 let mut len = T::size();
2062
2063 let ret = libc::getsockname(
2064 fd,
2065 addr.as_mut_ptr() as *mut libc::sockaddr,
2066 &mut len
2067 );
2068
2069 Errno::result(ret)?;
2070
2071 T::from_raw(addr.assume_init().as_ptr(), Some(len))
2072 .ok_or(Errno::EINVAL)
2073 }
2074}
2075
2076#[deprecated(
2085 since = "0.24.0",
2086 note = "use SockaddrLike or SockaddrStorage instead"
2087)]
2088#[allow(deprecated)]
2089pub fn sockaddr_storage_to_addr(
2090 addr: &sockaddr_storage,
2091 len: usize) -> Result<SockAddr> {
2092
2093 assert!(len <= mem::size_of::<sockaddr_storage>());
2094 if len < mem::size_of_val(&addr.ss_family) {
2095 return Err(Errno::ENOTCONN);
2096 }
2097
2098 match c_int::from(addr.ss_family) {
2099 #[cfg(feature = "net")]
2100 libc::AF_INET => {
2101 assert!(len >= mem::size_of::<sockaddr_in>());
2102 let sin = unsafe {
2103 *(addr as *const sockaddr_storage as *const sockaddr_in)
2104 };
2105 Ok(SockAddr::Inet(InetAddr::V4(sin)))
2106 }
2107 #[cfg(feature = "net")]
2108 libc::AF_INET6 => {
2109 assert!(len >= mem::size_of::<sockaddr_in6>());
2110 let sin6 = unsafe {
2111 *(addr as *const _ as *const sockaddr_in6)
2112 };
2113 Ok(SockAddr::Inet(InetAddr::V6(sin6)))
2114 }
2115 libc::AF_UNIX => {
2116 unsafe {
2117 let sun = *(addr as *const _ as *const sockaddr_un);
2118 let sun_len = len.try_into().unwrap();
2119 Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, sun_len)))
2120 }
2121 }
2122 #[cfg(any(target_os = "android", target_os = "linux"))]
2123 #[cfg(feature = "net")]
2124 libc::AF_PACKET => {
2125 use libc::sockaddr_ll;
2126 let sll = unsafe {
2131 *(addr as *const _ as *const sockaddr_ll)
2132 };
2133 Ok(SockAddr::Link(LinkAddr(sll)))
2134 }
2135 #[cfg(any(target_os = "android", target_os = "linux"))]
2136 libc::AF_NETLINK => {
2137 use libc::sockaddr_nl;
2138 let snl = unsafe {
2139 *(addr as *const _ as *const sockaddr_nl)
2140 };
2141 Ok(SockAddr::Netlink(NetlinkAddr(snl)))
2142 }
2143 #[cfg(any(target_os = "android", target_os = "linux"))]
2144 libc::AF_ALG => {
2145 use libc::sockaddr_alg;
2146 let salg = unsafe {
2147 *(addr as *const _ as *const sockaddr_alg)
2148 };
2149 Ok(SockAddr::Alg(AlgAddr(salg)))
2150 }
2151 #[cfg(any(target_os = "android", target_os = "linux"))]
2152 libc::AF_VSOCK => {
2153 use libc::sockaddr_vm;
2154 let svm = unsafe {
2155 *(addr as *const _ as *const sockaddr_vm)
2156 };
2157 Ok(SockAddr::Vsock(VsockAddr(svm)))
2158 }
2159 af => panic!("unexpected address family {}", af),
2160 }
2161}
2162
2163
2164#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
2165pub enum Shutdown {
2166 Read,
2168 Write,
2170 Both,
2172}
2173
2174pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
2178 unsafe {
2179 use libc::shutdown;
2180
2181 let how = match how {
2182 Shutdown::Read => libc::SHUT_RD,
2183 Shutdown::Write => libc::SHUT_WR,
2184 Shutdown::Both => libc::SHUT_RDWR,
2185 };
2186
2187 Errno::result(shutdown(df, how)).map(drop)
2188 }
2189}
2190
2191#[cfg(test)]
2192mod tests {
2193 #[test]
2194 fn can_use_cmsg_space() {
2195 let _ = cmsg_space!(u8);
2196 }
2197}