pub mod sock_protocol;
pub mod sock_domain;
pub mod sock_type;
pub mod sock_msg_flags;
pub mod sock_opts;
use std::
{
cmp::{self, min},
ffi::c_void,
io::{self, ErrorKind, IoSlice, IoSliceMut},
mem::{self, MaybeUninit},
net::{Ipv4Addr, Shutdown},
os::fd::{AsFd, AsRawFd, FromRawFd, OwnedFd, RawFd, IntoRawFd},
ptr::{self, null_mut},
time::{Duration, Instant}
};
use libc::{c_uint, cmsghdr, ssize_t};
pub use libc::
{
linger, time_t, suseconds_t, timeval, ip_mreqn, sockaddr_storage, socklen_t, sockaddr, sa_family_t,
sockaddr_un, AF_UNIX, msghdr, sockaddr_in, AF_INET, AF_INET6, in_addr, in6_addr, sockaddr_in6,
SO_SNDTIMEO, SOCK_STREAM, SOCK_DGRAM, SOCK_SEQPACKET, SOCK_RAW, IPPROTO_ICMP, IPPROTO_ICMPV6,
IPPROTO_TCP, IPPROTO_UDP, IPPROTO_SCTP, SO_TIMESTAMP
};
pub use libc::
{
ipv6_mreq, ip_mreq_source, IPPROTO_IPV6, IP_HDRINCL, IPV6_ADD_MEMBERSHIP, IPV6_DROP_MEMBERSHIP,
IPV6_MULTICAST_HOPS, IPV6_MULTICAST_IF, IPV6_MULTICAST_LOOP, IPV6_UNICAST_HOPS, IPV6_V6ONLY,
IPV6_RECVTCLASS
};
pub use libc::
{
POLLIN, IP_MULTICAST_ALL, IP_TRANSPARENT, TCP_NOTSENT_LOWAT, TCP_THIN_LINEAR_TIMEOUTS, TCP_KEEPCNT,
IPV6_RECVHOPLIMIT, IPV6_MULTICAST_ALL, SO_PRIORITY, SO_INCOMING_CPU, SO_DOMAIN, SO_REUSEPORT,
SO_PASSCRED, SO_OOBINLINE, SO_PROTOCOL, SO_RCVTIMEO, SOL_SOCKET, SO_TYPE, SO_BROADCAST, SO_ERROR,
SO_KEEPALIVE, SO_LINGER, SO_RCVBUF, SO_RCVLOWAT, SO_REUSEADDR, SO_DONTROUTE, SO_SNDBUF, SO_SNDLOWAT,
SO_ACCEPTCONN, IP6T_SO_ORIGINAL_DST, SOL_IPV6, SOL_IP, SO_ORIGINAL_DST, TCP_NODELAY, TCP_KEEPINTVL,
TCP_KEEPIDLE,IPPROTO_IP, IP_TTL, IP_TOS, IP_RECVTOS,IP_ADD_MEMBERSHIP, IP_MULTICAST_TTL,
IP_MULTICAST_LOOP, IP_MULTICAST_IF, IP_DROP_MEMBERSHIP, IP_ADD_SOURCE_MEMBERSHIP,
IP_DROP_SOURCE_MEMBERSHIP
};
pub use sock_domain::So9DomainRange;
pub use sock_type::{So9SockDwFlags, So9SockType};
pub(crate) use sock_opts::{getsockopt, setsockopt};
pub use sock_domain::*;
pub use sock_msg_flags::*;
pub use sock_protocol::*;
use uds_fork::UnixSocketAddr;
use crate::
{
LocalFrom, SockTypeFromRaw, Socket9ExtSo, SocketTypeImps, address::{So9AddrIntoRaw, So9SocketAddr}
};
#[derive(Debug, Clone, Copy)]
pub enum So9IfInder
{
Address(Ipv4Addr),
IfInder(u32)
}
impl So9IfInder
{
pub(crate)
fn into_ip_mreqn(&self, multiaddr: &Ipv4Addr) -> ip_mreqn
{
match self
{
Self::Address(ipv4_addr) =>
ip_mreqn
{
imr_multiaddr: <in_addr as LocalFrom<&Ipv4Addr>>::from(multiaddr),
imr_address: <in_addr as LocalFrom<&Ipv4Addr>>::from(ipv4_addr),
imr_ifindex: 0,
},
Self::IfInder(idx) =>
ip_mreqn
{
imr_multiaddr: <in_addr as LocalFrom<&Ipv4Addr>>::from(multiaddr),
imr_address: <in_addr as LocalFrom<&Ipv4Addr>>::from(&Ipv4Addr::UNSPECIFIED),
imr_ifindex: *idx as _,
},
}
}
}
#[derive(Clone,Copy, PartialEq,Eq, Debug)]
#[allow(unused)] pub enum Credentials
{
Effective,
Real,
Custom
{
pid: libc::pid_t,
uid: libc::uid_t,
gid: libc::gid_t
}
}
#[cfg(any(target_os="linux", target_os="android"))]
impl Credentials
{
pub
fn into_ucred(self) -> libc::ucred
{
let mut ucred: libc::ucred = unsafe { std::mem::zeroed() };
match self
{
Credentials::Effective =>
{
unsafe
{
ucred.pid = libc::getpid();
ucred.uid = libc::geteuid();
ucred.gid = libc::getegid();
}
},
Credentials::Real =>
{
unsafe
{
ucred.pid = libc::getpid();
ucred.uid = libc::getuid();
ucred.gid = libc::getgid();
}
},
Credentials::Custom{pid, uid, gid} =>
{
ucred.pid = pid;
ucred.uid = uid;
ucred.gid = gid;
}
}
return ucred;
}
}
impl Socket9ExtSo<Self> for OwnedFd {}
impl SockTypeFromRaw for OwnedFd {}
impl SocketTypeImps for OwnedFd
{
type RawType = RawFd;
fn get_raw(&self) -> Self::RawType
{
self.as_raw_fd()
}
fn new_sock(so_dom: So9SockDomain, so_type: So9SockType, so_proto: So9SockProtocol, dwflags: So9SockDwFlags) -> io::Result<Self>
where
Self: Sized
{
let so_type_comb = so_type.join(dwflags);
let res = unsafe{ libc::socket(so_dom.0, so_type_comb.0, so_proto.0) };
if res > 0
{
return Ok( unsafe{ OwnedFd::from_raw_fd(res) } );
}
return Err(io::Error::last_os_error());
}
fn bind_sock<A: So9AddrIntoRaw>(&self, addr: &A) -> io::Result<()>
{
let addr_raw = addr.into_raw_addr();
let (addr_ptr, addr_sz) = addr_raw.get_sockaddr_ptr();
let res =
unsafe
{
libc::bind(self.as_raw_fd(), addr_ptr, addr_sz)
};
if res == 0
{
return Ok(());
}
return Err(io::Error::last_os_error());
}
fn listen_sock(&self, backlog: i32) -> io::Result<()>
{
let res = unsafe{ libc::listen(self.as_raw_fd(), backlog) };
if res == 0
{
return Ok(());
}
return Err(io::Error::last_os_error());
}
fn accept_with_flags<A, CAST>(&self, flags: i32) -> io::Result<(CAST, A)>
where
Self: Sized,
A: TryFrom<So9SocketAddr, Error = io::Error>,
CAST: SocketTypeImps
{
let mut sa = So9SocketAddr::default();
let res =
unsafe
{
libc::accept4(self.as_raw_fd(), sa.get_sockaddr_ptr(), sa.get_capacity_mut(), flags)
};
if res > -1
{
let a = unsafe{ CAST::from_raw_fd(res) };
return Ok(( a, sa.try_into()? ));
}
return Err(io::Error::last_os_error());
}
fn connect_sock<A>(&self, addr: &A) -> io::Result<()>
where
A: So9AddrIntoRaw
{
let sa = addr.into_raw_addr();
let sa_raw = sa.get_sockaddr_ptr();
loop
{
let res =
unsafe
{
libc::connect(self.as_raw_fd(), sa_raw.0, sa_raw.1)
};
if res > -1
{
return Ok(());
}
let err = io::Error::last_os_error();
if err.raw_os_error() == Some(libc::EISCONN)
{
return Ok(());
}
else if err.raw_os_error() == Some(libc::EINTR)
{
continue
}
return Err(err);
}
}
fn poll_connect_sock(&self, timeout: Duration) -> io::Result<()>
{
self.poll_sock(libc::POLLIN | libc::POLLOUT, timeout)
}
fn poll_sock(&self, ev: i16, timeout: Duration) -> io::Result<()>
{
let mut pollfd =
libc::pollfd {
fd: self.as_raw_fd(),
events: ev,
revents: 0,
};
let start = Instant::now();
while let elapsed = start.elapsed() && elapsed < timeout
{
let timeout =
(timeout - elapsed).as_millis().clamp(1, libc::c_int::MAX as u128) as libc::c_int;
let res = unsafe{ libc::poll(&mut pollfd, 1, timeout) };
if res > 0
{
if (pollfd.revents & libc::POLLHUP) != 0 || (pollfd.revents & libc::POLLERR) != 0
{
let Some(err) = self.get_so_error()
else
{
return Err(
io::Error::new(io::ErrorKind::Other,"POLLHUP without error")
)
};
return Err(err);
}
return Ok(());
}
else if res == 0
{
break;
}
else
{
let last_err = io::Error::last_os_error();
if last_err.kind() == ErrorKind::Interrupted
{
continue;
}
else
{
return Err(last_err);
}
}
}
return Err(
io::Error::new(ErrorKind::TimedOut,
format!("recv/send timeout!"))
);
}
fn get_socket_peer_addr<A>(&self) -> io::Result<A>
where
A: TryFrom<So9SocketAddr, Error = io::Error>
{
let mut sa = So9SocketAddr::default();
let res =
unsafe
{
libc::getpeername(self.as_raw_fd(),sa.get_sockaddr_storage_ptr().cast(), sa.get_capacity_mut())
};
if res == 0
{
return A::try_from(sa);
}
else
{
return Err(std::io::Error::last_os_error());
}
}
fn get_socket_local_addr<A>(&self) -> io::Result<A>
where
A: TryFrom<So9SocketAddr, Error = io::Error>
{
let mut sa = So9SocketAddr::default();
let res =
unsafe
{
libc::getsockname(self.as_raw_fd(),sa.get_sockaddr_storage_ptr().cast(), sa.get_capacity_mut())
};
if res == 0
{
return A::try_from(sa);
}
else
{
return Err(std::io::Error::last_os_error());
}
}
fn get_socket_addr_type(&self) -> io::Result<So9SockDomain>
{
let mut optval: MaybeUninit<libc::sockaddr> = MaybeUninit::zeroed();
let mut len = size_of::<libc::sockaddr>() as libc::socklen_t;
let res =
unsafe
{
libc::getsockname(self.as_raw_fd(),optval.as_mut_ptr().cast(), &mut len)
};
if res == 0
{
return Ok(So9SockDomain::from(unsafe { optval.assume_init() }.sa_family));
}
else
{
return Err(std::io::Error::last_os_error());
}
}
fn get_socket_proto(&self) -> io::Result<Option<<crate::op_sol_socket::SoProtocol as crate::SockOptMarker>::DataType>>
{
#[cfg(any(target_os = "linux", target_os = "freebsd"))]
return
self.get_so_protocol().map(|v| Some(v));
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
return Ok(None);
}
fn send_with_flags(&self, data: &[u8], flags: So9MsgFlags) -> Result<usize, io::Error>
{
let ptr = data.as_ptr() as *const c_void;
let sent = unsafe { libc::send(self.as_raw_fd(), ptr, data.len(), flags.bits()) };
if sent > -1
{
return Ok(sent as usize);
}
return Err(io::Error::last_os_error());
}
fn send_vect_with_flags<A>(&self, slices: &[IoSlice], dest: Option<&A>, snd_flags: i32) -> io::Result<usize>
where
A: So9AddrIntoRaw
{
let mut msg = unsafe{ std::mem::zeroed::<libc::msghdr>() };
if let Some(addr) = dest
{
let raw_addr = addr.into_raw_addr();
msg.msg_name = raw_addr.get_sockaddr_ptr().0.cast_mut().cast();
msg.msg_namelen = raw_addr.get_sockaddr_ptr().1;
}
msg.msg_iov = (*slices).as_ptr() as *mut libc::iovec;
msg.msg_iovlen =
slices.len().try_into()
.map_err(|e|
io::Error::new(ErrorKind::InvalidInput,
format!("iovlen too large {}", e))
)?;
let sent =
unsafe{ libc::sendmsg(self.as_raw_fd(), &msg, snd_flags) };
if sent > -1
{
return Ok(sent as usize);
}
return Err(io::Error::last_os_error());
}
fn send_fd_with_flags(&self, fd_to_send: OwnedFd, snd_flags: i32) -> io::Result<usize>
{
let mut msg = unsafe{ std::mem::zeroed::<libc::msghdr>() };
#[repr(C)]
struct ControlBuf<const N: usize>([cmsghdr; 0],[u8; N]);
let control_buf =
ControlBuf([], [0_u8; unsafe { libc::CMSG_SPACE(mem::size_of::<RawFd>() as c_uint) as usize}] );
assert_eq!(control_buf.0.as_ptr().is_aligned(), true, "control_buf is not aligned on stack");
assert_eq!((control_buf.1.as_ptr() as *const cmsghdr).is_aligned(), true, "control_buf .1 is not aligned on stack");
msg.msg_controllen = control_buf.1.len();
msg.msg_control = control_buf.1.as_ptr() as *mut c_void;
let header_ptr = unsafe{ libc::CMSG_FIRSTHDR(&mut msg) };
assert_eq!(header_ptr.is_null(), false, "CMSG_FIRSTHDR returned unexpected NULL pointer");
#[allow(unused_mut)]
let mut header = unsafe{ &mut*header_ptr };
header.cmsg_level = libc::SOL_SOCKET;
header.cmsg_type = libc::SCM_RIGHTS;
header.cmsg_len =
unsafe{ libc::CMSG_LEN(std::mem::size_of::<RawFd>() as u32) as usize };
unsafe{ *(libc::CMSG_DATA(header) as *mut c_void as *mut RawFd) = fd_to_send.into_raw_fd() };
let sent =
unsafe{ libc::sendmsg(self.as_raw_fd(), &msg, snd_flags) };
if sent > -1
{
return Ok(sent as usize);
}
return Err(io::Error::last_os_error());
}
fn send_cred_with_flags(&self, creds: Credentials, snd_flags: i32) -> io::Result<usize>
{
let mut msg = unsafe{ std::mem::zeroed::<libc::msghdr>() };
let ucred = creds.into_ucred();
#[repr(C)]
struct ControlBuf<const N: usize>([cmsghdr; 0],[u8; N]);
let control_buf =
ControlBuf([], [0_u8; unsafe { libc::CMSG_SPACE(mem::size_of::<libc::ucred>() as c_uint) as usize}] );
assert_eq!(control_buf.0.as_ptr().is_aligned(), true, "control_buf is not aligned on stack");
assert_eq!((control_buf.1.as_ptr() as *const cmsghdr).is_aligned(), true, "control_buf .1 is not aligned on stack");
msg.msg_controllen = control_buf.1.len();
msg.msg_control = control_buf.1.as_ptr() as *mut c_void;
let header_ptr = unsafe{ libc::CMSG_FIRSTHDR(&mut msg) };
assert!(!header_ptr.is_null(), "CMSG_FIRSTHDR returned unexpected NULL pointer");
let header = &mut unsafe{ *header_ptr };
header.cmsg_level = libc::SOL_SOCKET;
header.cmsg_type = libc::SCM_CREDENTIALS;
header.cmsg_len =
unsafe{ libc::CMSG_LEN(std::mem::size_of_val(&ucred) as u32) as usize };
unsafe{ *(libc::CMSG_DATA(header) as *mut c_void as *mut _) = ucred };
let header_ptr = unsafe{ libc::CMSG_NXTHDR(&mut msg, header) };
assert!(!header_ptr.is_null(), "CMSG_NXTHDR returned unexpected NULL pointer");
let sent =
unsafe{ libc::sendmsg(self.as_raw_fd(), &msg, snd_flags) };
if sent > -1
{
return Ok(sent as usize);
}
return Err(io::Error::last_os_error());
}
fn recv_fd(&self, rcv_flags: i32) -> io::Result<(OwnedFd, So9MsgFlags)>
{
let mut msg: libc::msghdr = unsafe { std::mem::zeroed() };
#[repr(C)]
struct ControlBuf<const N: usize>([cmsghdr; 0],[u8; N]);
let mut control_buf =
ControlBuf([], [0_u8; unsafe { libc::CMSG_SPACE(mem::size_of::<RawFd>() as c_uint) as usize}] );
assert_eq!(control_buf.0.as_ptr().is_aligned(), true, "control_buf is not aligned on stack");
assert_eq!((control_buf.1.as_ptr() as *const cmsghdr).is_aligned(), true, "control_buf .1 is not aligned on stack");
msg.msg_control = control_buf.1.as_mut_ptr() as *mut c_void;
msg.msg_controllen = control_buf.1.len();
let received = unsafe{ libc::recvmsg(self.as_raw_fd(), &mut msg, rcv_flags) };
if received == -1
{
return Err(io::Error::last_os_error());
}
let next_msg = unsafe{ libc::CMSG_FIRSTHDR(&msg) };
if next_msg.is_null() == true
{
return Err(
io::Error::new(ErrorKind::Other, "no control message received!")
);
}
let next_msg_ref = unsafe{ next_msg.as_ref() }.unwrap();
if next_msg_ref.cmsg_level == libc::SOL_SOCKET &&
next_msg_ref.cmsg_type == libc::SCM_RIGHTS
{
let fd_ref = unsafe{ libc::CMSG_DATA(next_msg) } as *const c_void;
let fd = unsafe{ OwnedFd::from_raw_fd(*fd_ref.cast::<RawFd>()) };
return Ok(
(
fd,
So9MsgFlags::from_bits_retain(msg.msg_flags)
)
);
}
return Err(
io::Error::new(ErrorKind::Other, "no FD received!")
);
}
fn recv_with_flags(&self, buf: &mut [u8], flags: i32) -> io::Result<usize>
{
let ptr = buf.as_ptr() as *mut c_void;
let received = unsafe { libc::recv(self.as_raw_fd(), ptr, buf.len(), flags) };
if received > -1
{
return Ok(received as usize);
}
return Err(io::Error::last_os_error());
}
fn recv_from<A>(&self, buf: &mut [u8], rcv_flags: i32) -> io::Result<(usize, A)>
where
A: TryFrom<So9SocketAddr, Error = io::Error>
{
let mut sa = So9SocketAddr::default();
let recv =
unsafe
{
libc::recvfrom(
self.as_raw_fd(),
buf.as_mut_ptr().cast(),
min(buf.len(), ssize_t::MAX as usize),
rcv_flags,
sa.get_sockaddr_ptr(),
sa.get_capacity_mut()
)
};
if recv > -1
{
return Ok( (recv as usize, A::try_from(sa)?) );
}
return Err(io::Error::last_os_error());
}
fn recv_addr_from<A>(&self) -> io::Result<A>
where
A: TryFrom<So9SocketAddr, Error = io::Error> {
todo!()
}
#[cfg(unix)]
fn read_vectored(&self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize>
{
let recv =
unsafe
{
libc::readv(
self.as_raw_fd(),
bufs.as_mut_ptr() as *mut libc::iovec as *const libc::iovec,
cmp::min(bufs.len(), libc::UIO_MAXIOV as usize) as libc::c_int,
)
};
if recv > -1
{
return Ok(recv as usize);
}
return Err(io::Error::last_os_error());
}
fn recv_vectored_flags(&self, bufs: &mut [IoSliceMut<'_>], flags: i32) -> io::Result<(usize, So9MsgFlags)>
{
self
.recv_vect_from_flags::<UnixSocketAddr>(bufs, false, flags)
.map(|(sz, fl,_)| (sz, fl))
}
fn recv_vect_from_flags<A>(&self, buffers: &mut[IoSliceMut], recv_from: bool, snd_flags: i32) -> io::Result<(usize, So9MsgFlags, Option<A>)>
where
A: TryFrom<So9SocketAddr, Error = io::Error>
{
let mut opt_sa_addr =
if recv_from == true
{
Some(So9SocketAddr::default())
}
else
{
None
};
let mut msg: libc::msghdr = unsafe { std::mem::zeroed() };
msg.msg_iov = buffers.as_mut_ptr() as *mut libc::iovec;
msg.msg_iovlen =
buffers.len().try_into()
.map_err(|_|
io::Error::new(ErrorKind::InvalidInput, "too many content buffers")
)?;
msg.msg_name = opt_sa_addr.as_mut().map_or(null_mut(), |sa| sa.0.as_mut_ptr() as *mut libc::sockaddr as *mut c_void);
msg.msg_namelen = opt_sa_addr.as_ref().map_or(0, |_| So9SocketAddr::SO9SOCK_LEN);
let received = unsafe{ libc::recvmsg(self.as_raw_fd(), &mut msg, snd_flags) };
if received == -1
{
return Err(io::Error::last_os_error());
}
let ret_sa =
if let Some(mut sa) = opt_sa_addr.take() {
sa.set_length(&msg);
Some(A::try_from(sa)?)
}
else
{
None
};
return Ok(
(
received as usize,
So9MsgFlags::from_bits_retain(msg.msg_flags),
ret_sa
)
);
}
fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize>
{
let sent =
unsafe
{
libc::writev(
self.as_raw_fd(),
bufs.as_ptr() as *const libc::iovec,
cmp::min(bufs.len(), libc::UIO_MAXIOV as usize) as libc::c_int,
)
};
if sent > -1
{
return Ok(sent as usize);
}
return Err(io::Error::last_os_error());
}
fn send_to_sock<A>(&self, addr: &A, buf: &[u8], flags: i32) -> io::Result<usize>
where
A: So9AddrIntoRaw
{
let sa = addr.into_raw_addr();
let sa_raw = sa.get_sockaddr_ptr();
let sent =
unsafe
{
libc::sendto(
self.as_raw_fd(),
buf.as_ptr().cast(),
min(buf.len(), ssize_t::MAX as usize),
flags,
sa_raw.0,
sa_raw.1
)
};
if sent > -1
{
return Ok(sent as usize);
}
return Err(io::Error::last_os_error());
}
fn send_to_sock_vect<A>(&self, addr: &A, bufs: &[IoSlice<'_>], flags: i32) -> io::Result<usize>
where
A: So9AddrIntoRaw
{
self.send_vect_with_flags(bufs, Some(addr), flags)
}
fn try_clone_sock(&self, dwflags: So9SockDwFlags) -> io::Result<Self>
where
Self: Sized
{
self.try_clone()
}
fn is_nonblocking_sock(&self) -> io::Result<bool>
{
let fnres = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_GETFL) };
if fnres > -1
{
return Ok( (fnres & libc::O_NONBLOCK) != 0 );
}
return Err(io::Error::last_os_error());
}
fn set_nonblocking_sock(&self, nonblk: bool) -> io::Result<()>
{
let fnres_prev = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_GETFL) };
if fnres_prev == -1
{
return Err(io::Error::last_os_error());
}
if nonblk == true
{
let fn_new = fnres_prev | libc::O_NONBLOCK;
if fn_new == fnres_prev
{
return Ok(());
}
let fnres = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_SETFL, fn_new) };
if fnres == -1
{
return Err(io::Error::last_os_error());
}
}
else
{
let fn_new = fnres_prev & !libc::O_NONBLOCK;
if fn_new == fnres_prev
{
return Ok(());
}
let fnres = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_SETFL, fn_new) };
if fnres == -1
{
return Err(io::Error::last_os_error());
}
}
return Ok(());
}
fn is_cloexec_sock(&self) -> io::Result<bool>
{
let fnres = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_GETFD) };
if fnres > -1
{
return Ok( (fnres & libc::FD_CLOEXEC) != 0 );
}
return Err(io::Error::last_os_error());
}
fn set_cloexec_sock(&self, cloexec: bool) -> io::Result<()>
{
let fnres_prev = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_GETFD) };
if fnres_prev == -1
{
return Err(io::Error::last_os_error());
}
if cloexec == true
{
let fn_new = fnres_prev | libc::FD_CLOEXEC;
if fn_new == fnres_prev
{
return Ok(());
}
let fnres = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_SETFD, fn_new) };
if fnres == -1
{
return Err(io::Error::last_os_error());
}
}
else
{
let fn_new = fnres_prev & !libc::FD_CLOEXEC;
if fn_new == fnres_prev
{
return Ok(());
}
let fnres = unsafe{ libc::fcntl(self.as_raw_fd(), libc::F_SETFD, fn_new) };
if fnres == -1
{
return Err(io::Error::last_os_error());
}
}
return Ok(());
}
#[cfg(any(
target_os = "ios",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
target_os = "visionos",
))]
fn set_nosigpipe_sock<FD: AsRawFd>(fd: &FD, nosigpipe: bool) -> io::Result<()>
{
use crate::{setsockopt, SoNoSigPipe};
return
setsockopt::<SoNoSigPipe, _>(fd, SoNoSigPipe::from_user(nosigpipe));
}
fn shutdown_sock(&self, how: Shutdown) -> io::Result<()>
{
let res =
match how
{
Shutdown::Write =>
unsafe{ libc::shutdown(self.as_raw_fd(), libc::SHUT_WR) },
Shutdown::Read =>
unsafe{ libc::shutdown(self.as_raw_fd(), libc::SHUT_RD) },
Shutdown::Both =>
unsafe{ libc::shutdown(self.as_raw_fd(), libc::SHUT_RDWR) },
};
if res == -1
{
return Err(io::Error::last_os_error());
}
return Ok(());
}
fn pair(so_dom: So9SockDomain, so_type: So9SockType, so_proto: Option<So9SockProtocol>, dwflags: So9SockDwFlags) -> io::Result<(Self, Self)>
where Self: Sized
{
let mapped_proto = so_proto.map_or(0, |p| p.0);
let so_type_comb = so_type.join(dwflags);
let mut fds = [0, 0];
let res =
unsafe
{
libc::socketpair(so_dom.0, so_type_comb.0, mapped_proto, fds.as_mut_ptr())
};
if res > 0
{
let a = unsafe{ OwnedFd::from_raw_fd(fds[0]) };
let b = unsafe{ OwnedFd::from_raw_fd(fds[1]) };
return Ok( (a, b) );
}
return Err(io::Error::last_os_error());
}
}