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 memoffset::offset_of;
9use std::convert::TryFrom;
10use std::{mem, ptr, slice};
11use std::os::unix::io::RawFd;
12#[cfg(all(target_os = "linux"))]
13use crate::sys::time::TimeSpec;
14use crate::sys::time::TimeVal;
15use crate::sys::uio::IoVec;
16
17mod addr;
18#[deny(missing_docs)]
19pub mod sockopt;
20
21#[cfg(not(any(target_os = "illumos", target_os = "solaris")))]
28pub use self::addr::{
29 AddressFamily,
30 SockAddr,
31 InetAddr,
32 UnixAddr,
33 IpAddr,
34 Ipv4Addr,
35 Ipv6Addr,
36 LinkAddr,
37};
38#[cfg(any(target_os = "illumos", target_os = "solaris"))]
39pub use self::addr::{
40 AddressFamily,
41 SockAddr,
42 InetAddr,
43 UnixAddr,
44 IpAddr,
45 Ipv4Addr,
46 Ipv6Addr,
47};
48
49#[cfg(any(target_os = "android", target_os = "linux"))]
50pub use crate::sys::socket::addr::netlink::NetlinkAddr;
51#[cfg(any(target_os = "android", target_os = "linux"))]
52pub use crate::sys::socket::addr::alg::AlgAddr;
53#[cfg(any(target_os = "android", target_os = "linux"))]
54pub use crate::sys::socket::addr::vsock::VsockAddr;
55
56pub use libc::{
57 cmsghdr,
58 msghdr,
59 sa_family_t,
60 sockaddr,
61 sockaddr_in,
62 sockaddr_in6,
63 sockaddr_storage,
64 sockaddr_un,
65};
66
67#[doc(hidden)]
69pub use libc::{c_uint, CMSG_SPACE};
70
71#[derive(Clone, Copy, PartialEq, Eq, Debug)]
74#[repr(i32)]
75#[non_exhaustive]
76pub enum SockType {
77 Stream = libc::SOCK_STREAM,
81 Datagram = libc::SOCK_DGRAM,
84 SeqPacket = libc::SOCK_SEQPACKET,
89 Raw = libc::SOCK_RAW,
91 Rdm = libc::SOCK_RDM,
94}
95impl TryFrom<i32> for SockType {
99 type Error = crate::Error;
100
101 fn try_from(x: i32) -> Result<Self> {
102 match x {
103 libc::SOCK_STREAM => Ok(Self::Stream),
104 libc::SOCK_DGRAM => Ok(Self::Datagram),
105 libc::SOCK_SEQPACKET => Ok(Self::SeqPacket),
106 libc::SOCK_RAW => Ok(Self::Raw),
107 #[cfg(not(any(target_os = "haiku")))]
108 libc::SOCK_RDM => Ok(Self::Rdm),
109 _ => Err(Errno::EINVAL)
110 }
111 }
112}
113
114#[repr(i32)]
117#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
118#[non_exhaustive]
119pub enum SockProtocol {
120 Tcp = libc::IPPROTO_TCP,
122 Udp = libc::IPPROTO_UDP,
124 #[cfg(any(target_os = "ios", target_os = "macos"))]
127 KextEvent = libc::SYSPROTO_EVENT,
128 #[cfg(any(target_os = "ios", target_os = "macos"))]
131 KextControl = libc::SYSPROTO_CONTROL,
132 #[cfg(any(target_os = "android", target_os = "linux"))]
136 NetlinkRoute = libc::NETLINK_ROUTE,
137 #[cfg(any(target_os = "android", target_os = "linux"))]
140 NetlinkUserSock = libc::NETLINK_USERSOCK,
141 #[cfg(any(target_os = "android", target_os = "linux"))]
144 NetlinkSockDiag = libc::NETLINK_SOCK_DIAG,
145 #[cfg(any(target_os = "android", target_os = "linux"))]
148 NetlinkSELinux = libc::NETLINK_SELINUX,
149 #[cfg(any(target_os = "android", target_os = "linux"))]
152 NetlinkISCSI = libc::NETLINK_ISCSI,
153 #[cfg(any(target_os = "android", target_os = "linux"))]
156 NetlinkAudit = libc::NETLINK_AUDIT,
157 #[cfg(any(target_os = "android", target_os = "linux"))]
160 NetlinkFIBLookup = libc::NETLINK_FIB_LOOKUP,
161 #[cfg(any(target_os = "android", target_os = "linux"))]
164 NetlinkNetFilter = libc::NETLINK_NETFILTER,
165 #[cfg(any(target_os = "android", target_os = "linux"))]
168 NetlinkSCSITransport = libc::NETLINK_SCSITRANSPORT,
169 #[cfg(any(target_os = "android", target_os = "linux"))]
172 NetlinkRDMA = libc::NETLINK_RDMA,
173 #[cfg(any(target_os = "android", target_os = "linux"))]
176 NetlinkIPv6Firewall = libc::NETLINK_IP6_FW,
177 #[cfg(any(target_os = "android", target_os = "linux"))]
180 NetlinkDECNetRoutingMessage = libc::NETLINK_DNRTMSG,
181 #[cfg(any(target_os = "android", target_os = "linux"))]
184 NetlinkKObjectUEvent = libc::NETLINK_KOBJECT_UEVENT,
185 #[cfg(any(target_os = "android", target_os = "linux"))]
189 NetlinkCrypto = libc::NETLINK_CRYPTO,
190}
191
192libc_bitflags!{
193 pub struct SockFlag: c_int {
195 #[cfg(any(target_os = "android",
197 target_os = "dragonfly",
198 target_os = "freebsd",
199 target_os = "illumos",
200 target_os = "linux",
201 target_os = "netbsd",
202 target_os = "openbsd"))]
203 SOCK_NONBLOCK;
204 #[cfg(any(target_os = "android",
206 target_os = "dragonfly",
207 target_os = "freebsd",
208 target_os = "illumos",
209 target_os = "linux",
210 target_os = "netbsd",
211 target_os = "openbsd"))]
212 SOCK_CLOEXEC;
213 #[cfg(target_os = "netbsd")]
215 SOCK_NOSIGPIPE;
216 #[cfg(target_os = "openbsd")]
219 SOCK_DNS;
220 }
221}
222
223libc_bitflags!{
224 pub struct MsgFlags: c_int {
226 MSG_OOB;
230 MSG_PEEK;
234 MSG_WAITALL;
238 MSG_DONTWAIT;
249 MSG_CTRUNC;
251 MSG_TRUNC;
260 MSG_EOR;
263 #[cfg(any(target_os = "android", target_os = "linux"))]
267 MSG_ERRQUEUE;
268 #[cfg(any(target_os = "android",
276 target_os = "dragonfly",
277 target_os = "freebsd",
278 target_os = "linux",
279 target_os = "netbsd",
280 target_os = "openbsd"))]
281 MSG_CMSG_CLOEXEC;
282 }
283}
284
285cfg_if! {
286 if #[cfg(any(target_os = "android", target_os = "linux"))] {
287 #[repr(transparent)]
292 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
293 pub struct UnixCredentials(libc::ucred);
294
295 impl UnixCredentials {
296 pub fn new() -> Self {
298 UnixCredentials(libc::ucred {
299 pid: crate::unistd::getpid().as_raw(),
300 uid: crate::unistd::getuid().as_raw(),
301 gid: crate::unistd::getgid().as_raw(),
302 })
303 }
304
305 pub fn pid(&self) -> libc::pid_t {
307 self.0.pid
308 }
309
310 pub fn uid(&self) -> libc::uid_t {
312 self.0.uid
313 }
314
315 pub fn gid(&self) -> libc::gid_t {
317 self.0.gid
318 }
319 }
320
321 impl Default for UnixCredentials {
322 fn default() -> Self {
323 Self::new()
324 }
325 }
326
327 impl From<libc::ucred> for UnixCredentials {
328 fn from(cred: libc::ucred) -> Self {
329 UnixCredentials(cred)
330 }
331 }
332
333 impl From<UnixCredentials> for libc::ucred {
334 fn from(uc: UnixCredentials) -> Self {
335 uc.0
336 }
337 }
338 } else if #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))] {
339 #[repr(transparent)]
343 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
344 pub struct UnixCredentials(libc::cmsgcred);
345
346 impl UnixCredentials {
347 pub fn pid(&self) -> libc::pid_t {
349 self.0.cmcred_pid
350 }
351
352 pub fn uid(&self) -> libc::uid_t {
354 self.0.cmcred_uid
355 }
356
357 pub fn euid(&self) -> libc::uid_t {
359 self.0.cmcred_euid
360 }
361
362 pub fn gid(&self) -> libc::gid_t {
364 self.0.cmcred_gid
365 }
366
367 pub fn groups(&self) -> &[libc::gid_t] {
369 unsafe { slice::from_raw_parts(self.0.cmcred_groups.as_ptr() as *const libc::gid_t, self.0.cmcred_ngroups as _) }
370 }
371 }
372
373 impl From<libc::cmsgcred> for UnixCredentials {
374 fn from(cred: libc::cmsgcred) -> Self {
375 UnixCredentials(cred)
376 }
377 }
378 }
379}
380
381cfg_if!{
382 if #[cfg(any(
383 target_os = "dragonfly",
384 target_os = "freebsd",
385 target_os = "macos",
386 target_os = "ios"
387 ))] {
388 #[repr(transparent)]
390 #[derive(Clone, Copy, Debug, Eq, PartialEq)]
391 pub struct XuCred(libc::xucred);
392
393 impl XuCred {
394 pub fn version(&self) -> u32 {
396 self.0.cr_version
397 }
398
399 pub fn uid(&self) -> libc::uid_t {
401 self.0.cr_uid
402 }
403
404 pub fn groups(&self) -> &[libc::gid_t] {
407 &self.0.cr_groups
408 }
409 }
410 }
411}
412
413#[repr(transparent)]
417#[derive(Clone, Copy, Debug, Eq, PartialEq)]
418pub struct IpMembershipRequest(libc::ip_mreq);
419
420impl IpMembershipRequest {
421 pub fn new(group: Ipv4Addr, interface: Option<Ipv4Addr>) -> Self {
425 IpMembershipRequest(libc::ip_mreq {
426 imr_multiaddr: group.0,
427 imr_interface: interface.unwrap_or_else(Ipv4Addr::any).0,
428 })
429 }
430}
431
432#[repr(transparent)]
436#[derive(Clone, Copy, Debug, Eq, PartialEq)]
437pub struct Ipv6MembershipRequest(libc::ipv6_mreq);
438
439impl Ipv6MembershipRequest {
440 pub const fn new(group: Ipv6Addr) -> Self {
442 Ipv6MembershipRequest(libc::ipv6_mreq {
443 ipv6mr_multiaddr: group.0,
444 ipv6mr_interface: 0,
445 })
446 }
447}
448
449#[macro_export]
472macro_rules! cmsg_space {
473 ( $( $x:ty ),* ) => {
474 {
475 let mut space = 0;
476 $(
477 space += unsafe {
479 $crate::sys::socket::CMSG_SPACE(::std::mem::size_of::<$x>() as $crate::sys::socket::c_uint)
480 } as usize;
481 )*
482 Vec::<u8>::with_capacity(space)
483 }
484 }
485}
486
487#[derive(Clone, Copy, Debug, Eq, PartialEq)]
488pub struct RecvMsg<'a> {
489 pub bytes: usize,
490 cmsghdr: Option<&'a cmsghdr>,
491 pub address: Option<SockAddr>,
492 pub flags: MsgFlags,
493 mhdr: msghdr,
494}
495
496impl<'a> RecvMsg<'a> {
497 pub fn cmsgs(&self) -> CmsgIterator {
500 CmsgIterator {
501 cmsghdr: self.cmsghdr,
502 mhdr: &self.mhdr
503 }
504 }
505}
506
507#[derive(Clone, Copy, Debug, Eq, PartialEq)]
508pub struct CmsgIterator<'a> {
509 cmsghdr: Option<&'a cmsghdr>,
511 mhdr: &'a msghdr
512}
513
514impl<'a> Iterator for CmsgIterator<'a> {
515 type Item = ControlMessageOwned;
516
517 fn next(&mut self) -> Option<ControlMessageOwned> {
518 match self.cmsghdr {
519 None => None, Some(hdr) => {
521 let cm = unsafe { Some(ControlMessageOwned::decode_from(hdr))};
524 self.cmsghdr = unsafe {
527 let p = CMSG_NXTHDR(self.mhdr as *const _, hdr as *const _);
528 p.as_ref()
529 };
530 cm
531 }
532 }
533 }
534}
535
536#[derive(Clone, Debug, Eq, PartialEq)]
547#[non_exhaustive]
548pub enum ControlMessageOwned {
549 ScmRights(Vec<RawFd>),
551 #[cfg(any(target_os = "android", target_os = "linux"))]
553 ScmCredentials(UnixCredentials),
554 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
556 ScmCreds(UnixCredentials),
557 ScmTimestamp(TimeVal),
613 #[cfg(all(target_os = "linux"))]
617 ScmTimestampns(TimeSpec),
618 #[cfg(any(
619 target_os = "android",
620 target_os = "ios",
621 target_os = "linux",
622 target_os = "macos",
623 target_os = "netbsd",
624 ))]
625 Ipv4PacketInfo(libc::in_pktinfo),
626 #[cfg(any(
627 target_os = "android",
628 target_os = "dragonfly",
629 target_os = "freebsd",
630 target_os = "ios",
631 target_os = "linux",
632 target_os = "macos",
633 target_os = "openbsd",
634 target_os = "netbsd",
635 ))]
636 Ipv6PacketInfo(libc::in6_pktinfo),
637 #[cfg(any(
638 target_os = "freebsd",
639 target_os = "ios",
640 target_os = "macos",
641 target_os = "netbsd",
642 target_os = "openbsd",
643 ))]
644 Ipv4RecvIf(libc::sockaddr_dl),
645 #[cfg(any(
646 target_os = "freebsd",
647 target_os = "ios",
648 target_os = "macos",
649 target_os = "netbsd",
650 target_os = "openbsd",
651 ))]
652 Ipv4RecvDstAddr(libc::in_addr),
653
654 #[cfg(target_os = "linux")]
663 UdpGroSegments(u16),
664
665 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
674 RxqOvfl(u32),
675
676 #[cfg(any(target_os = "android", target_os = "linux"))]
678 Ipv4RecvErr(libc::sock_extended_err, Option<sockaddr_in>),
679 #[cfg(any(target_os = "android", target_os = "linux"))]
681 Ipv6RecvErr(libc::sock_extended_err, Option<sockaddr_in6>),
682
683 #[doc(hidden)]
685 Unknown(UnknownCmsg),
686}
687
688impl ControlMessageOwned {
689 #[allow(clippy::cast_ptr_alignment)]
698 unsafe fn decode_from(header: &cmsghdr) -> ControlMessageOwned
699 {
700 let p = CMSG_DATA(header);
701 #[allow(clippy::unnecessary_cast)]
703 let len = header as *const _ as usize + header.cmsg_len as usize
704 - p as usize;
705 match (header.cmsg_level, header.cmsg_type) {
706 (libc::SOL_SOCKET, libc::SCM_RIGHTS) => {
707 let n = len / mem::size_of::<RawFd>();
708 let mut fds = Vec::with_capacity(n);
709 for i in 0..n {
710 let fdp = (p as *const RawFd).add(i);
711 fds.push(ptr::read_unaligned(fdp));
712 }
713 ControlMessageOwned::ScmRights(fds)
714 },
715 #[cfg(any(target_os = "android", target_os = "linux"))]
716 (libc::SOL_SOCKET, libc::SCM_CREDENTIALS) => {
717 let cred: libc::ucred = ptr::read_unaligned(p as *const _);
718 ControlMessageOwned::ScmCredentials(cred.into())
719 }
720 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
721 (libc::SOL_SOCKET, libc::SCM_CREDS) => {
722 let cred: libc::cmsgcred = ptr::read_unaligned(p as *const _);
723 ControlMessageOwned::ScmCreds(cred.into())
724 }
725 (libc::SOL_SOCKET, libc::SCM_TIMESTAMP) => {
726 let tv: libc::timeval = ptr::read_unaligned(p as *const _);
727 ControlMessageOwned::ScmTimestamp(TimeVal::from(tv))
728 },
729 #[cfg(all(target_os = "linux"))]
730 (libc::SOL_SOCKET, libc::SCM_TIMESTAMPNS) => {
731 let ts: libc::timespec = ptr::read_unaligned(p as *const _);
732 ControlMessageOwned::ScmTimestampns(TimeSpec::from(ts))
733 }
734 #[cfg(any(
735 target_os = "android",
736 target_os = "freebsd",
737 target_os = "ios",
738 target_os = "linux",
739 target_os = "macos"
740 ))]
741 (libc::IPPROTO_IPV6, libc::IPV6_PKTINFO) => {
742 let info = ptr::read_unaligned(p as *const libc::in6_pktinfo);
743 ControlMessageOwned::Ipv6PacketInfo(info)
744 }
745 #[cfg(any(
746 target_os = "android",
747 target_os = "ios",
748 target_os = "linux",
749 target_os = "macos",
750 target_os = "netbsd",
751 ))]
752 (libc::IPPROTO_IP, libc::IP_PKTINFO) => {
753 let info = ptr::read_unaligned(p as *const libc::in_pktinfo);
754 ControlMessageOwned::Ipv4PacketInfo(info)
755 }
756 #[cfg(any(
757 target_os = "freebsd",
758 target_os = "ios",
759 target_os = "macos",
760 target_os = "netbsd",
761 target_os = "openbsd",
762 ))]
763 (libc::IPPROTO_IP, libc::IP_RECVIF) => {
764 let dl = ptr::read_unaligned(p as *const libc::sockaddr_dl);
765 ControlMessageOwned::Ipv4RecvIf(dl)
766 },
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 (libc::IPPROTO_IP, libc::IP_RECVDSTADDR) => {
775 let dl = ptr::read_unaligned(p as *const libc::in_addr);
776 ControlMessageOwned::Ipv4RecvDstAddr(dl)
777 },
778 #[cfg(target_os = "linux")]
779 (libc::SOL_UDP, libc::UDP_GRO) => {
780 let gso_size: u16 = ptr::read_unaligned(p as *const _);
781 ControlMessageOwned::UdpGroSegments(gso_size)
782 },
783 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
784 (libc::SOL_SOCKET, libc::SO_RXQ_OVFL) => {
785 let drop_counter = ptr::read_unaligned(p as *const u32);
786 ControlMessageOwned::RxqOvfl(drop_counter)
787 },
788 #[cfg(any(target_os = "android", target_os = "linux"))]
789 (libc::IPPROTO_IP, libc::IP_RECVERR) => {
790 let (err, addr) = Self::recv_err_helper::<sockaddr_in>(p, len);
791 ControlMessageOwned::Ipv4RecvErr(err, addr)
792 },
793 #[cfg(any(target_os = "android", target_os = "linux"))]
794 (libc::IPPROTO_IPV6, libc::IPV6_RECVERR) => {
795 let (err, addr) = Self::recv_err_helper::<sockaddr_in6>(p, len);
796 ControlMessageOwned::Ipv6RecvErr(err, addr)
797 },
798 (_, _) => {
799 let sl = slice::from_raw_parts(p, len);
800 let ucmsg = UnknownCmsg(*header, Vec::<u8>::from(sl));
801 ControlMessageOwned::Unknown(ucmsg)
802 }
803 }
804 }
805
806 #[cfg(any(target_os = "android", target_os = "linux"))]
807 unsafe fn recv_err_helper<T>(p: *mut libc::c_uchar, len: usize) -> (libc::sock_extended_err, Option<T>) {
808 let ee = p as *const libc::sock_extended_err;
809 let err = ptr::read_unaligned(ee);
810
811 let addrp = libc::SO_EE_OFFENDER(ee) as *const T;
816
817 if addrp.offset(1) as usize - (p as usize) > len {
818 (err, None)
819 } else {
820 (err, Some(ptr::read_unaligned(addrp)))
821 }
822 }
823}
824
825#[derive(Clone, Copy, Debug, Eq, PartialEq)]
831#[non_exhaustive]
832pub enum ControlMessage<'a> {
833 ScmRights(&'a [RawFd]),
845 #[cfg(any(target_os = "android", target_os = "linux"))]
856 ScmCredentials(&'a UnixCredentials),
857 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
870 ScmCreds,
871
872 #[cfg(any(
877 target_os = "android",
878 target_os = "linux",
879 ))]
880 AlgSetIv(&'a [u8]),
881 #[cfg(any(
887 target_os = "android",
888 target_os = "linux",
889 ))]
890 AlgSetOp(&'a libc::c_int),
891 #[cfg(any(
897 target_os = "android",
898 target_os = "linux",
899 ))]
900 AlgSetAeadAssoclen(&'a u32),
901
902 #[cfg(target_os = "linux")]
911 UdpGsoSegments(&'a u16),
912
913 #[cfg(any(target_os = "linux",
918 target_os = "macos",
919 target_os = "netbsd",
920 target_os = "android",
921 target_os = "ios",))]
922 Ipv4PacketInfo(&'a libc::in_pktinfo),
923
924 #[cfg(any(target_os = "linux",
929 target_os = "macos",
930 target_os = "netbsd",
931 target_os = "freebsd",
932 target_os = "android",
933 target_os = "ios",))]
934 Ipv6PacketInfo(&'a libc::in6_pktinfo),
935
936 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
942 RxqOvfl(&'a u32),
943}
944
945#[doc(hidden)]
947#[derive(Clone, Debug, Eq, PartialEq)]
948pub struct UnknownCmsg(cmsghdr, Vec<u8>);
949
950impl<'a> ControlMessage<'a> {
951 fn space(&self) -> usize {
954 unsafe{CMSG_SPACE(self.len() as libc::c_uint) as usize}
955 }
956
957 #[cfg(any(target_os = "android",
960 all(target_os = "linux", not(target_env = "musl"))))]
961 fn cmsg_len(&self) -> usize {
962 unsafe{CMSG_LEN(self.len() as libc::c_uint) as usize}
963 }
964
965 #[cfg(not(any(target_os = "android",
966 all(target_os = "linux", not(target_env = "musl")))))]
967 fn cmsg_len(&self) -> libc::c_uint {
968 unsafe{CMSG_LEN(self.len() as libc::c_uint)}
969 }
970
971 fn copy_to_cmsg_data(&self, cmsg_data: *mut u8) {
973 let data_ptr = match *self {
974 ControlMessage::ScmRights(fds) => {
975 fds as *const _ as *const u8
976 },
977 #[cfg(any(target_os = "android", target_os = "linux"))]
978 ControlMessage::ScmCredentials(creds) => {
979 &creds.0 as *const libc::ucred as *const u8
980 }
981 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
982 ControlMessage::ScmCreds => {
983 unsafe { ptr::write_bytes(cmsg_data, 0, self.len()) };
986 return
987 }
988 #[cfg(any(target_os = "android", target_os = "linux"))]
989 ControlMessage::AlgSetIv(iv) => {
990 #[allow(deprecated)] let af_alg_iv = libc::af_alg_iv {
992 ivlen: iv.len() as u32,
993 iv: [0u8; 0],
994 };
995
996 let size = mem::size_of_val(&af_alg_iv);
997
998 unsafe {
999 ptr::copy_nonoverlapping(
1000 &af_alg_iv as *const _ as *const u8,
1001 cmsg_data,
1002 size,
1003 );
1004 ptr::copy_nonoverlapping(
1005 iv.as_ptr(),
1006 cmsg_data.add(size),
1007 iv.len()
1008 );
1009 };
1010
1011 return
1012 },
1013 #[cfg(any(target_os = "android", target_os = "linux"))]
1014 ControlMessage::AlgSetOp(op) => {
1015 op as *const _ as *const u8
1016 },
1017 #[cfg(any(target_os = "android", target_os = "linux"))]
1018 ControlMessage::AlgSetAeadAssoclen(len) => {
1019 len as *const _ as *const u8
1020 },
1021 #[cfg(target_os = "linux")]
1022 ControlMessage::UdpGsoSegments(gso_size) => {
1023 gso_size as *const _ as *const u8
1024 },
1025 #[cfg(any(target_os = "linux", target_os = "macos",
1026 target_os = "netbsd", target_os = "android",
1027 target_os = "ios",))]
1028 ControlMessage::Ipv4PacketInfo(info) => info as *const _ as *const u8,
1029 #[cfg(any(target_os = "linux", target_os = "macos",
1030 target_os = "netbsd", target_os = "freebsd",
1031 target_os = "android", target_os = "ios",))]
1032 ControlMessage::Ipv6PacketInfo(info) => info as *const _ as *const u8,
1033 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1034 ControlMessage::RxqOvfl(drop_count) => {
1035 drop_count as *const _ as *const u8
1036 },
1037 };
1038 unsafe {
1039 ptr::copy_nonoverlapping(
1040 data_ptr,
1041 cmsg_data,
1042 self.len()
1043 )
1044 };
1045 }
1046
1047 fn len(&self) -> usize {
1049 match *self {
1050 ControlMessage::ScmRights(fds) => {
1051 mem::size_of_val(fds)
1052 },
1053 #[cfg(any(target_os = "android", target_os = "linux"))]
1054 ControlMessage::ScmCredentials(creds) => {
1055 mem::size_of_val(creds)
1056 }
1057 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1058 ControlMessage::ScmCreds => {
1059 mem::size_of::<libc::cmsgcred>()
1060 }
1061 #[cfg(any(target_os = "android", target_os = "linux"))]
1062 ControlMessage::AlgSetIv(iv) => {
1063 mem::size_of_val(&iv) + iv.len()
1064 },
1065 #[cfg(any(target_os = "android", target_os = "linux"))]
1066 ControlMessage::AlgSetOp(op) => {
1067 mem::size_of_val(op)
1068 },
1069 #[cfg(any(target_os = "android", target_os = "linux"))]
1070 ControlMessage::AlgSetAeadAssoclen(len) => {
1071 mem::size_of_val(len)
1072 },
1073 #[cfg(target_os = "linux")]
1074 ControlMessage::UdpGsoSegments(gso_size) => {
1075 mem::size_of_val(gso_size)
1076 },
1077 #[cfg(any(target_os = "linux", target_os = "macos",
1078 target_os = "netbsd", target_os = "android",
1079 target_os = "ios",))]
1080 ControlMessage::Ipv4PacketInfo(info) => mem::size_of_val(info),
1081 #[cfg(any(target_os = "linux", target_os = "macos",
1082 target_os = "netbsd", target_os = "freebsd",
1083 target_os = "android", target_os = "ios",))]
1084 ControlMessage::Ipv6PacketInfo(info) => mem::size_of_val(info),
1085 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1086 ControlMessage::RxqOvfl(drop_count) => {
1087 mem::size_of_val(drop_count)
1088 },
1089 }
1090 }
1091
1092 fn cmsg_level(&self) -> libc::c_int {
1094 match *self {
1095 ControlMessage::ScmRights(_) => libc::SOL_SOCKET,
1096 #[cfg(any(target_os = "android", target_os = "linux"))]
1097 ControlMessage::ScmCredentials(_) => libc::SOL_SOCKET,
1098 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1099 ControlMessage::ScmCreds => libc::SOL_SOCKET,
1100 #[cfg(any(target_os = "android", target_os = "linux"))]
1101 ControlMessage::AlgSetIv(_) | ControlMessage::AlgSetOp(_) |
1102 ControlMessage::AlgSetAeadAssoclen(_) => libc::SOL_ALG,
1103 #[cfg(target_os = "linux")]
1104 ControlMessage::UdpGsoSegments(_) => libc::SOL_UDP,
1105 #[cfg(any(target_os = "linux", target_os = "macos",
1106 target_os = "netbsd", target_os = "android",
1107 target_os = "ios",))]
1108 ControlMessage::Ipv4PacketInfo(_) => libc::IPPROTO_IP,
1109 #[cfg(any(target_os = "linux", target_os = "macos",
1110 target_os = "netbsd", target_os = "freebsd",
1111 target_os = "android", target_os = "ios",))]
1112 ControlMessage::Ipv6PacketInfo(_) => libc::IPPROTO_IPV6,
1113 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1114 ControlMessage::RxqOvfl(_) => libc::SOL_SOCKET,
1115 }
1116 }
1117
1118 fn cmsg_type(&self) -> libc::c_int {
1120 match *self {
1121 ControlMessage::ScmRights(_) => libc::SCM_RIGHTS,
1122 #[cfg(any(target_os = "android", target_os = "linux"))]
1123 ControlMessage::ScmCredentials(_) => libc::SCM_CREDENTIALS,
1124 #[cfg(any(target_os = "freebsd", target_os = "dragonfly"))]
1125 ControlMessage::ScmCreds => libc::SCM_CREDS,
1126 #[cfg(any(target_os = "android", target_os = "linux"))]
1127 ControlMessage::AlgSetIv(_) => {
1128 libc::ALG_SET_IV
1129 },
1130 #[cfg(any(target_os = "android", target_os = "linux"))]
1131 ControlMessage::AlgSetOp(_) => {
1132 libc::ALG_SET_OP
1133 },
1134 #[cfg(any(target_os = "android", target_os = "linux"))]
1135 ControlMessage::AlgSetAeadAssoclen(_) => {
1136 libc::ALG_SET_AEAD_ASSOCLEN
1137 },
1138 #[cfg(target_os = "linux")]
1139 ControlMessage::UdpGsoSegments(_) => {
1140 libc::UDP_SEGMENT
1141 },
1142 #[cfg(any(target_os = "linux", target_os = "macos",
1143 target_os = "netbsd", target_os = "android",
1144 target_os = "ios",))]
1145 ControlMessage::Ipv4PacketInfo(_) => libc::IP_PKTINFO,
1146 #[cfg(any(target_os = "linux", target_os = "macos",
1147 target_os = "netbsd", target_os = "freebsd",
1148 target_os = "android", target_os = "ios",))]
1149 ControlMessage::Ipv6PacketInfo(_) => libc::IPV6_PKTINFO,
1150 #[cfg(any(target_os = "android", target_os = "fuchsia", target_os = "linux"))]
1151 ControlMessage::RxqOvfl(_) => {
1152 libc::SO_RXQ_OVFL
1153 },
1154 }
1155 }
1156
1157 unsafe fn encode_into(&self, cmsg: *mut cmsghdr) {
1160 (*cmsg).cmsg_level = self.cmsg_level();
1161 (*cmsg).cmsg_type = self.cmsg_type();
1162 (*cmsg).cmsg_len = self.cmsg_len();
1163 self.copy_to_cmsg_data(CMSG_DATA(cmsg));
1164 }
1165}
1166
1167
1168pub fn sendmsg(fd: RawFd, iov: &[IoVec<&[u8]>], cmsgs: &[ControlMessage],
1174 flags: MsgFlags, addr: Option<&SockAddr>) -> Result<usize>
1175{
1176 let capacity = cmsgs.iter().map(|c| c.space()).sum();
1177
1178 let mut cmsg_buffer = vec![0u8; capacity];
1181
1182 let mhdr = pack_mhdr_to_send(&mut cmsg_buffer[..], iov, cmsgs, addr);
1183
1184 let ret = unsafe { libc::sendmsg(fd, &mhdr, flags.bits()) };
1185
1186 Errno::result(ret).map(|r| r as usize)
1187}
1188
1189#[cfg(any(
1190 target_os = "linux",
1191 target_os = "android",
1192 target_os = "freebsd",
1193 target_os = "netbsd",
1194))]
1195#[derive(Debug)]
1196pub struct SendMmsgData<'a, I, C>
1197 where
1198 I: AsRef<[IoVec<&'a [u8]>]>,
1199 C: AsRef<[ControlMessage<'a>]>
1200{
1201 pub iov: I,
1202 pub cmsgs: C,
1203 pub addr: Option<SockAddr>,
1204 pub _lt: std::marker::PhantomData<&'a I>,
1205}
1206
1207#[cfg(any(
1225 target_os = "linux",
1226 target_os = "android",
1227 target_os = "freebsd",
1228 target_os = "netbsd",
1229))]
1230pub fn sendmmsg<'a, I, C>(
1231 fd: RawFd,
1232 data: impl std::iter::IntoIterator<Item=&'a SendMmsgData<'a, I, C>>,
1233 flags: MsgFlags
1234) -> Result<Vec<usize>>
1235 where
1236 I: AsRef<[IoVec<&'a [u8]>]> + 'a,
1237 C: AsRef<[ControlMessage<'a>]> + 'a,
1238{
1239 let iter = data.into_iter();
1240
1241 let size_hint = iter.size_hint();
1242 let reserve_items = size_hint.1.unwrap_or(size_hint.0);
1243
1244 let mut output = Vec::<libc::mmsghdr>::with_capacity(reserve_items);
1245
1246 let mut cmsgs_buffers = Vec::<Vec<u8>>::with_capacity(reserve_items);
1247
1248 for d in iter {
1249 let capacity: usize = d.cmsgs.as_ref().iter().map(|c| c.space()).sum();
1250 let mut cmsgs_buffer = vec![0u8; capacity];
1251
1252 output.push(libc::mmsghdr {
1253 msg_hdr: pack_mhdr_to_send(
1254 &mut cmsgs_buffer,
1255 &d.iov,
1256 &d.cmsgs,
1257 d.addr.as_ref()
1258 ),
1259 msg_len: 0,
1260 });
1261 cmsgs_buffers.push(cmsgs_buffer);
1262 };
1263
1264 let ret = unsafe { libc::sendmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _) };
1265
1266 let sent_messages = Errno::result(ret)? as usize;
1267 let mut sent_bytes = Vec::with_capacity(sent_messages);
1268
1269 for item in &output {
1270 sent_bytes.push(item.msg_len as usize);
1271 }
1272
1273 Ok(sent_bytes)
1274}
1275
1276
1277#[cfg(any(
1278 target_os = "linux",
1279 target_os = "android",
1280 target_os = "freebsd",
1281 target_os = "netbsd",
1282))]
1283#[derive(Debug)]
1284pub struct RecvMmsgData<'a, I>
1285 where
1286 I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
1287{
1288 pub iov: I,
1289 pub cmsg_buffer: Option<&'a mut Vec<u8>>,
1290}
1291
1292#[cfg(any(
1319 target_os = "linux",
1320 target_os = "android",
1321 target_os = "freebsd",
1322 target_os = "netbsd",
1323))]
1324#[allow(clippy::needless_collect)] pub fn recvmmsg<'a, I>(
1326 fd: RawFd,
1327 data: impl std::iter::IntoIterator<Item=&'a mut RecvMmsgData<'a, I>,
1328 IntoIter=impl ExactSizeIterator + Iterator<Item=&'a mut RecvMmsgData<'a, I>>>,
1329 flags: MsgFlags,
1330 timeout: Option<crate::sys::time::TimeSpec>
1331) -> Result<Vec<RecvMsg<'a>>>
1332 where
1333 I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
1334{
1335 let iter = data.into_iter();
1336
1337 let num_messages = iter.len();
1338
1339 let mut output: Vec<libc::mmsghdr> = Vec::with_capacity(num_messages);
1340
1341 let mut addresses = vec![mem::MaybeUninit::uninit(); num_messages]
1345 .into_boxed_slice();
1346
1347 let results: Vec<_> = iter.enumerate().map(|(i, d)| {
1348 let (msg_controllen, mhdr) = unsafe {
1349 pack_mhdr_to_receive(
1350 d.iov.as_ref(),
1351 &mut d.cmsg_buffer,
1352 addresses[i].as_mut_ptr(),
1353 )
1354 };
1355
1356 output.push(
1357 libc::mmsghdr {
1358 msg_hdr: mhdr,
1359 msg_len: 0,
1360 }
1361 );
1362
1363 (msg_controllen, &mut d.cmsg_buffer)
1364 }).collect();
1365
1366 let timeout = if let Some(mut t) = timeout {
1367 t.as_mut() as *mut libc::timespec
1368 } else {
1369 ptr::null_mut()
1370 };
1371
1372 let ret = unsafe { libc::recvmmsg(fd, output.as_mut_ptr(), output.len() as _, flags.bits() as _, timeout) };
1373
1374 let _ = Errno::result(ret)?;
1375
1376 Ok(output
1377 .into_iter()
1378 .take(ret as usize)
1379 .zip(addresses.iter().map(|addr| unsafe{addr.assume_init()}))
1380 .zip(results.into_iter())
1381 .map(|((mmsghdr, address), (msg_controllen, cmsg_buffer))| {
1382 #[allow(clippy::unnecessary_cast)]
1384 unsafe {
1385 read_mhdr(
1386 mmsghdr.msg_hdr,
1387 mmsghdr.msg_len as isize,
1388 msg_controllen,
1389 address,
1390 cmsg_buffer
1391 )
1392 }
1393 })
1394 .collect())
1395}
1396
1397unsafe fn read_mhdr<'a>(
1398 mhdr: msghdr,
1399 r: isize,
1400 msg_controllen: usize,
1401 address: sockaddr_storage,
1402 cmsg_buffer: &mut Option<&'a mut Vec<u8>>
1403) -> RecvMsg<'a> {
1404 #[allow(clippy::unnecessary_cast)]
1406 let cmsghdr = {
1407 if mhdr.msg_controllen > 0 {
1408 cmsg_buffer
1410 .as_mut()
1411 .unwrap()
1412 .set_len(mhdr.msg_controllen as usize);
1413 debug_assert!(!mhdr.msg_control.is_null());
1414 debug_assert!(msg_controllen >= mhdr.msg_controllen as usize);
1415 CMSG_FIRSTHDR(&mhdr as *const msghdr)
1416 } else {
1417 ptr::null()
1418 }.as_ref()
1419 };
1420
1421 let address = sockaddr_storage_to_addr(
1422 &address ,
1423 mhdr.msg_namelen as usize
1424 ).ok();
1425
1426 RecvMsg {
1427 bytes: r as usize,
1428 cmsghdr,
1429 address,
1430 flags: MsgFlags::from_bits_truncate(mhdr.msg_flags),
1431 mhdr,
1432 }
1433}
1434
1435unsafe fn pack_mhdr_to_receive<'a, I>(
1436 iov: I,
1437 cmsg_buffer: &mut Option<&mut Vec<u8>>,
1438 address: *mut sockaddr_storage,
1439) -> (usize, msghdr)
1440 where
1441 I: AsRef<[IoVec<&'a mut [u8]>]> + 'a,
1442{
1443 let (msg_control, msg_controllen) = cmsg_buffer.as_mut()
1444 .map(|v| (v.as_mut_ptr(), v.capacity()))
1445 .unwrap_or((ptr::null_mut(), 0));
1446
1447 let mhdr = {
1448 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
1451 let p = mhdr.as_mut_ptr();
1452 (*p).msg_name = address as *mut c_void;
1453 (*p).msg_namelen = mem::size_of::<sockaddr_storage>() as socklen_t;
1454 (*p).msg_iov = iov.as_ref().as_ptr() as *mut iovec;
1455 (*p).msg_iovlen = iov.as_ref().len() as _;
1456 (*p).msg_control = msg_control as *mut c_void;
1457 (*p).msg_controllen = msg_controllen as _;
1458 (*p).msg_flags = 0;
1459 mhdr.assume_init()
1460 };
1461
1462 (msg_controllen, mhdr)
1463}
1464
1465fn pack_mhdr_to_send<'a, I, C>(
1466 cmsg_buffer: &mut [u8],
1467 iov: I,
1468 cmsgs: C,
1469 addr: Option<&SockAddr>
1470) -> msghdr
1471 where
1472 I: AsRef<[IoVec<&'a [u8]>]>,
1473 C: AsRef<[ControlMessage<'a>]>
1474{
1475 let capacity = cmsg_buffer.len();
1476
1477 let (name, namelen) = match addr {
1479 Some(addr) => {
1480 let (x, y) = addr.as_ffi_pair();
1481 (x as *const _, y)
1482 },
1483 None => (ptr::null(), 0),
1484 };
1485
1486 let cmsg_ptr = if capacity > 0 {
1488 cmsg_buffer.as_ptr() as *mut c_void
1489 } else {
1490 ptr::null_mut()
1491 };
1492
1493 let mhdr = unsafe {
1494 let mut mhdr = mem::MaybeUninit::<msghdr>::zeroed();
1497 let p = mhdr.as_mut_ptr();
1498 (*p).msg_name = name as *mut _;
1499 (*p).msg_namelen = namelen;
1500 (*p).msg_iov = iov.as_ref().as_ptr() as *mut _;
1503 (*p).msg_iovlen = iov.as_ref().len() as _;
1504 (*p).msg_control = cmsg_ptr;
1505 (*p).msg_controllen = capacity as _;
1506 (*p).msg_flags = 0;
1507 mhdr.assume_init()
1508 };
1509
1510 let mut pmhdr: *mut cmsghdr = unsafe { CMSG_FIRSTHDR(&mhdr as *const msghdr) };
1514 for cmsg in cmsgs.as_ref() {
1515 assert_ne!(pmhdr, ptr::null_mut());
1516 unsafe { cmsg.encode_into(pmhdr) };
1519 pmhdr = unsafe { CMSG_NXTHDR(&mhdr as *const msghdr, pmhdr) };
1521 }
1522
1523 mhdr
1524}
1525
1526pub fn recvmsg<'a>(fd: RawFd, iov: &[IoVec<&mut [u8]>],
1541 mut cmsg_buffer: Option<&'a mut Vec<u8>>,
1542 flags: MsgFlags) -> Result<RecvMsg<'a>>
1543{
1544 let mut address = mem::MaybeUninit::uninit();
1545
1546 let (msg_controllen, mut mhdr) = unsafe {
1547 pack_mhdr_to_receive(iov, &mut cmsg_buffer, address.as_mut_ptr())
1548 };
1549
1550 let ret = unsafe { libc::recvmsg(fd, &mut mhdr, flags.bits()) };
1551
1552 let r = Errno::result(ret)?;
1553
1554 Ok(unsafe { read_mhdr(mhdr, r, msg_controllen, address.assume_init(), &mut cmsg_buffer) })
1555}
1556
1557
1558pub fn socket<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, flags: SockFlag, protocol: T) -> Result<RawFd> {
1569 let protocol = match protocol.into() {
1570 None => 0,
1571 Some(p) => p as c_int,
1572 };
1573
1574 let mut ty = ty as c_int;
1578 ty |= flags.bits();
1579
1580 let res = unsafe { libc::socket(domain as c_int, ty, protocol) };
1581
1582 Errno::result(res)
1583}
1584
1585pub fn socketpair<T: Into<Option<SockProtocol>>>(domain: AddressFamily, ty: SockType, protocol: T,
1589 flags: SockFlag) -> Result<(RawFd, RawFd)> {
1590 let protocol = match protocol.into() {
1591 None => 0,
1592 Some(p) => p as c_int,
1593 };
1594
1595 let mut ty = ty as c_int;
1599 ty |= flags.bits();
1600
1601 let mut fds = [-1, -1];
1602
1603 let res = unsafe { libc::socketpair(domain as c_int, ty, protocol, fds.as_mut_ptr()) };
1604 Errno::result(res)?;
1605
1606 Ok((fds[0], fds[1]))
1607}
1608
1609pub fn listen(sockfd: RawFd, backlog: usize) -> Result<()> {
1613 let res = unsafe { libc::listen(sockfd, backlog as c_int) };
1614
1615 Errno::result(res).map(drop)
1616}
1617
1618pub fn bind(fd: RawFd, addr: &SockAddr) -> Result<()> {
1622 let res = unsafe {
1623 let (ptr, len) = addr.as_ffi_pair();
1624 libc::bind(fd, ptr, len)
1625 };
1626
1627 Errno::result(res).map(drop)
1628}
1629
1630pub fn accept(sockfd: RawFd) -> Result<RawFd> {
1634 let res = unsafe { libc::accept(sockfd, ptr::null_mut(), ptr::null_mut()) };
1635
1636 Errno::result(res)
1637}
1638
1639#[cfg(any(all(
1643 target_os = "android",
1644 any(
1645 target_arch = "aarch64",
1646 target_arch = "x86",
1647 target_arch = "x86_64"
1648 )
1649 ),
1650 target_os = "freebsd",
1651 target_os = "linux",
1652 target_os = "openbsd"))]
1653pub fn accept4(sockfd: RawFd, flags: SockFlag) -> Result<RawFd> {
1654 let res = unsafe { libc::accept4(sockfd, ptr::null_mut(), ptr::null_mut(), flags.bits()) };
1655
1656 Errno::result(res)
1657}
1658
1659pub fn connect(fd: RawFd, addr: &SockAddr) -> Result<()> {
1663 let res = unsafe {
1664 let (ptr, len) = addr.as_ffi_pair();
1665 libc::connect(fd, ptr, len)
1666 };
1667
1668 Errno::result(res).map(drop)
1669}
1670
1671pub fn recv(sockfd: RawFd, buf: &mut [u8], flags: MsgFlags) -> Result<usize> {
1676 unsafe {
1677 let ret = libc::recv(
1678 sockfd,
1679 buf.as_ptr() as *mut c_void,
1680 buf.len() as size_t,
1681 flags.bits());
1682
1683 Errno::result(ret).map(|r| r as usize)
1684 }
1685}
1686
1687pub fn recvfrom(sockfd: RawFd, buf: &mut [u8])
1693 -> Result<(usize, Option<SockAddr>)>
1694{
1695 unsafe {
1696 let mut addr: sockaddr_storage = mem::zeroed();
1697 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
1698
1699 let ret = Errno::result(libc::recvfrom(
1700 sockfd,
1701 buf.as_ptr() as *mut c_void,
1702 buf.len() as size_t,
1703 0,
1704 &mut addr as *mut libc::sockaddr_storage as *mut libc::sockaddr,
1705 &mut len as *mut socklen_t))? as usize;
1706
1707 match sockaddr_storage_to_addr(&addr, len as usize) {
1708 Err(Errno::ENOTCONN) => Ok((ret, None)),
1709 Ok(addr) => Ok((ret, Some(addr))),
1710 Err(e) => Err(e)
1711 }
1712 }
1713}
1714
1715pub fn sendto(fd: RawFd, buf: &[u8], addr: &SockAddr, flags: MsgFlags) -> Result<usize> {
1719 let ret = unsafe {
1720 let (ptr, len) = addr.as_ffi_pair();
1721 libc::sendto(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits(), ptr, len)
1722 };
1723
1724 Errno::result(ret).map(|r| r as usize)
1725}
1726
1727pub fn send(fd: RawFd, buf: &[u8], flags: MsgFlags) -> Result<usize> {
1731 let ret = unsafe {
1732 libc::send(fd, buf.as_ptr() as *const c_void, buf.len() as size_t, flags.bits())
1733 };
1734
1735 Errno::result(ret).map(|r| r as usize)
1736}
1737
1738pub trait GetSockOpt : Copy {
1746 type Val;
1747
1748 fn get(&self, fd: RawFd) -> Result<Self::Val>;
1750}
1751
1752pub trait SetSockOpt : Clone {
1754 type Val;
1755
1756 fn set(&self, fd: RawFd, val: &Self::Val) -> Result<()>;
1758}
1759
1760pub fn getsockopt<O: GetSockOpt>(fd: RawFd, opt: O) -> Result<O::Val> {
1764 opt.get(fd)
1765}
1766
1767pub fn setsockopt<O: SetSockOpt>(fd: RawFd, opt: O, val: &O::Val) -> Result<()> {
1785 opt.set(fd, val)
1786}
1787
1788pub fn getpeername(fd: RawFd) -> Result<SockAddr> {
1792 unsafe {
1793 let mut addr = mem::MaybeUninit::uninit();
1794 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
1795
1796 let ret = libc::getpeername(
1797 fd,
1798 addr.as_mut_ptr() as *mut libc::sockaddr,
1799 &mut len
1800 );
1801
1802 Errno::result(ret)?;
1803
1804 sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
1805 }
1806}
1807
1808pub fn getsockname(fd: RawFd) -> Result<SockAddr> {
1812 unsafe {
1813 let mut addr = mem::MaybeUninit::uninit();
1814 let mut len = mem::size_of::<sockaddr_storage>() as socklen_t;
1815
1816 let ret = libc::getsockname(
1817 fd,
1818 addr.as_mut_ptr() as *mut libc::sockaddr,
1819 &mut len
1820 );
1821
1822 Errno::result(ret)?;
1823
1824 sockaddr_storage_to_addr(&addr.assume_init(), len as usize)
1825 }
1826}
1827
1828pub fn sockaddr_storage_to_addr(
1837 addr: &sockaddr_storage,
1838 len: usize) -> Result<SockAddr> {
1839
1840 assert!(len <= mem::size_of::<sockaddr_storage>());
1841 if len < mem::size_of_val(&addr.ss_family) {
1842 return Err(Errno::ENOTCONN);
1843 }
1844
1845 match c_int::from(addr.ss_family) {
1846 libc::AF_INET => {
1847 assert!(len >= mem::size_of::<sockaddr_in>());
1848 let sin = unsafe {
1849 *(addr as *const sockaddr_storage as *const sockaddr_in)
1850 };
1851 Ok(SockAddr::Inet(InetAddr::V4(sin)))
1852 }
1853 libc::AF_INET6 => {
1854 assert!(len >= mem::size_of::<sockaddr_in6>());
1855 let sin6 = unsafe {
1856 *(addr as *const _ as *const sockaddr_in6)
1857 };
1858 Ok(SockAddr::Inet(InetAddr::V6(sin6)))
1859 }
1860 libc::AF_UNIX => {
1861 let pathlen = len - offset_of!(sockaddr_un, sun_path);
1862 unsafe {
1863 let sun = *(addr as *const _ as *const sockaddr_un);
1864 Ok(SockAddr::Unix(UnixAddr::from_raw_parts(sun, pathlen)))
1865 }
1866 }
1867 #[cfg(any(target_os = "android", target_os = "linux"))]
1868 libc::AF_PACKET => {
1869 use libc::sockaddr_ll;
1870 let sll = unsafe {
1875 *(addr as *const _ as *const sockaddr_ll)
1876 };
1877 Ok(SockAddr::Link(LinkAddr(sll)))
1878 }
1879 #[cfg(any(target_os = "android", target_os = "linux"))]
1880 libc::AF_NETLINK => {
1881 use libc::sockaddr_nl;
1882 let snl = unsafe {
1883 *(addr as *const _ as *const sockaddr_nl)
1884 };
1885 Ok(SockAddr::Netlink(NetlinkAddr(snl)))
1886 }
1887 #[cfg(any(target_os = "android", target_os = "linux"))]
1888 libc::AF_ALG => {
1889 use libc::sockaddr_alg;
1890 let salg = unsafe {
1891 *(addr as *const _ as *const sockaddr_alg)
1892 };
1893 Ok(SockAddr::Alg(AlgAddr(salg)))
1894 }
1895 #[cfg(any(target_os = "android", target_os = "linux"))]
1896 libc::AF_VSOCK => {
1897 use libc::sockaddr_vm;
1898 let svm = unsafe {
1899 *(addr as *const _ as *const sockaddr_vm)
1900 };
1901 Ok(SockAddr::Vsock(VsockAddr(svm)))
1902 }
1903 af => panic!("unexpected address family {}", af),
1904 }
1905}
1906
1907
1908#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
1909pub enum Shutdown {
1910 Read,
1912 Write,
1914 Both,
1916}
1917
1918pub fn shutdown(df: RawFd, how: Shutdown) -> Result<()> {
1922 unsafe {
1923 use libc::shutdown;
1924
1925 let how = match how {
1926 Shutdown::Read => libc::SHUT_RD,
1927 Shutdown::Write => libc::SHUT_WR,
1928 Shutdown::Both => libc::SHUT_RDWR,
1929 };
1930
1931 Errno::result(shutdown(df, how)).map(drop)
1932 }
1933}
1934
1935#[cfg(test)]
1936mod tests {
1937 #[test]
1938 fn can_use_cmsg_space() {
1939 let _ = cmsg_space!(u8);
1940 }
1941}