use std::fmt;
use std::io::{self, Read, Write};
#[cfg(not(target_os = "redox"))]
use std::io::{IoSlice, IoSliceMut};
use std::mem::MaybeUninit;
#[cfg(not(target_os = "nto"))]
use std::net::Ipv6Addr;
use std::net::{self, Ipv4Addr, Shutdown};
#[cfg(unix)]
use std::os::unix::io::{FromRawFd, IntoRawFd};
#[cfg(windows)]
use std::os::windows::io::{FromRawSocket, IntoRawSocket};
use std::time::Duration;
use crate::sys::{self, c_int, getsockopt, setsockopt, Bool};
#[cfg(all(unix, not(target_os = "redox")))]
use crate::MsgHdrMut;
use crate::{Domain, Protocol, SockAddr, TcpKeepalive, Type};
#[cfg(not(target_os = "redox"))]
use crate::{MaybeUninitSlice, MsgHdr, RecvFlags};
pub struct Socket {
inner: Inner,
}
pub(crate) type Inner = std::net::TcpStream;
impl Socket {
pub(crate) fn from_raw(raw: sys::Socket) -> Socket {
Socket {
inner: unsafe {
#[cfg(unix)]
assert!(raw >= 0, "tried to create a `Socket` with an invalid fd");
sys::socket_from_raw(raw)
},
}
}
pub(crate) fn as_raw(&self) -> sys::Socket {
sys::socket_as_raw(&self.inner)
}
pub(crate) fn into_raw(self) -> sys::Socket {
sys::socket_into_raw(self.inner)
}
#[doc = man_links!(socket(2))]
pub fn new(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
let ty = set_common_type(ty);
Socket::new_raw(domain, ty, protocol).and_then(set_common_flags)
}
pub fn new_raw(domain: Domain, ty: Type, protocol: Option<Protocol>) -> io::Result<Socket> {
let protocol = protocol.map_or(0, |p| p.0);
sys::socket(domain.0, ty.0, protocol).map(Socket::from_raw)
}
#[doc = man_links!(unix: socketpair(2))]
#[cfg(all(feature = "all", unix))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
pub fn pair(
domain: Domain,
ty: Type,
protocol: Option<Protocol>,
) -> io::Result<(Socket, Socket)> {
let ty = set_common_type(ty);
let (a, b) = Socket::pair_raw(domain, ty, protocol)?;
let a = set_common_flags(a)?;
let b = set_common_flags(b)?;
Ok((a, b))
}
#[cfg(all(feature = "all", unix))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
pub fn pair_raw(
domain: Domain,
ty: Type,
protocol: Option<Protocol>,
) -> io::Result<(Socket, Socket)> {
let protocol = protocol.map_or(0, |p| p.0);
sys::socketpair(domain.0, ty.0, protocol)
.map(|[a, b]| (Socket::from_raw(a), Socket::from_raw(b)))
}
#[doc = man_links!(bind(2))]
pub fn bind(&self, address: &SockAddr) -> io::Result<()> {
sys::bind(self.as_raw(), address)
}
#[doc = man_links!(connect(2))]
#[allow(rustdoc::broken_intra_doc_links)] pub fn connect(&self, address: &SockAddr) -> io::Result<()> {
sys::connect(self.as_raw(), address)
}
pub fn connect_timeout(&self, addr: &SockAddr, timeout: Duration) -> io::Result<()> {
self.set_nonblocking(true)?;
let res = self.connect(addr);
self.set_nonblocking(false)?;
match res {
Ok(()) => return Ok(()),
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {}
#[cfg(unix)]
Err(ref e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
Err(e) => return Err(e),
}
sys::poll_connect(self, timeout)
}
#[doc = man_links!(listen(2))]
pub fn listen(&self, backlog: c_int) -> io::Result<()> {
sys::listen(self.as_raw(), backlog)
}
#[doc = man_links!(accept(2))]
#[allow(rustdoc::broken_intra_doc_links)] pub fn accept(&self) -> io::Result<(Socket, SockAddr)> {
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
))]
return self._accept4(libc::SOCK_CLOEXEC);
#[cfg(not(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
)))]
{
let (socket, addr) = self.accept_raw()?;
let socket = set_common_flags(socket)?;
#[cfg(windows)]
socket._set_no_inherit(true)?;
Ok((socket, addr))
}
}
pub fn accept_raw(&self) -> io::Result<(Socket, SockAddr)> {
sys::accept(self.as_raw()).map(|(inner, addr)| (Socket::from_raw(inner), addr))
}
#[doc = man_links!(getsockname(2))]
pub fn local_addr(&self) -> io::Result<SockAddr> {
sys::getsockname(self.as_raw())
}
#[doc = man_links!(getpeername(2))]
pub fn peer_addr(&self) -> io::Result<SockAddr> {
sys::getpeername(self.as_raw())
}
pub fn r#type(&self) -> io::Result<Type> {
unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_TYPE).map(Type) }
}
pub fn try_clone(&self) -> io::Result<Socket> {
sys::try_clone(self.as_raw()).map(Socket::from_raw)
}
#[cfg(all(feature = "all", unix))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", unix))))]
pub fn nonblocking(&self) -> io::Result<bool> {
sys::nonblocking(self.as_raw())
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> {
sys::set_nonblocking(self.as_raw(), nonblocking)
}
#[doc = man_links!(shutdown(2))]
pub fn shutdown(&self, how: Shutdown) -> io::Result<()> {
sys::shutdown(self.as_raw(), how)
}
#[doc = man_links!(recv(2))]
pub fn recv(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
self.recv_with_flags(buf, 0)
}
#[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
pub fn recv_out_of_band(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
self.recv_with_flags(buf, sys::MSG_OOB)
}
pub fn recv_with_flags(
&self,
buf: &mut [MaybeUninit<u8>],
flags: sys::c_int,
) -> io::Result<usize> {
sys::recv(self.as_raw(), buf, flags)
}
#[doc = man_links!(recvmsg(2))]
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn recv_vectored(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
) -> io::Result<(usize, RecvFlags)> {
self.recv_vectored_with_flags(bufs, 0)
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn recv_vectored_with_flags(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
flags: c_int,
) -> io::Result<(usize, RecvFlags)> {
sys::recv_vectored(self.as_raw(), bufs, flags)
}
pub fn peek(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<usize> {
self.recv_with_flags(buf, sys::MSG_PEEK)
}
#[doc = man_links!(recvfrom(2))]
pub fn recv_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
self.recv_from_with_flags(buf, 0)
}
pub fn recv_from_with_flags(
&self,
buf: &mut [MaybeUninit<u8>],
flags: c_int,
) -> io::Result<(usize, SockAddr)> {
sys::recv_from(self.as_raw(), buf, flags)
}
#[doc = man_links!(recvmsg(2))]
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn recv_from_vectored(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
) -> io::Result<(usize, RecvFlags, SockAddr)> {
self.recv_from_vectored_with_flags(bufs, 0)
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn recv_from_vectored_with_flags(
&self,
bufs: &mut [MaybeUninitSlice<'_>],
flags: c_int,
) -> io::Result<(usize, RecvFlags, SockAddr)> {
sys::recv_from_vectored(self.as_raw(), bufs, flags)
}
pub fn peek_from(&self, buf: &mut [MaybeUninit<u8>]) -> io::Result<(usize, SockAddr)> {
self.recv_from_with_flags(buf, sys::MSG_PEEK)
}
pub fn peek_sender(&self) -> io::Result<SockAddr> {
sys::peek_sender(self.as_raw())
}
#[doc = man_links!(recvmsg(2))]
#[cfg(all(unix, not(target_os = "redox")))]
#[cfg_attr(docsrs, doc(cfg(all(unix, not(target_os = "redox")))))]
pub fn recvmsg(&self, msg: &mut MsgHdrMut<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
sys::recvmsg(self.as_raw(), msg, flags)
}
#[doc = man_links!(send(2))]
pub fn send(&self, buf: &[u8]) -> io::Result<usize> {
self.send_with_flags(buf, 0)
}
pub fn send_with_flags(&self, buf: &[u8], flags: c_int) -> io::Result<usize> {
sys::send(self.as_raw(), buf, flags)
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn send_vectored(&self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.send_vectored_with_flags(bufs, 0)
}
#[doc = man_links!(sendmsg(2))]
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn send_vectored_with_flags(
&self,
bufs: &[IoSlice<'_>],
flags: c_int,
) -> io::Result<usize> {
sys::send_vectored(self.as_raw(), bufs, flags)
}
#[cfg_attr(target_os = "redox", allow(rustdoc::broken_intra_doc_links))]
pub fn send_out_of_band(&self, buf: &[u8]) -> io::Result<usize> {
self.send_with_flags(buf, sys::MSG_OOB)
}
#[doc = man_links!(sendto(2))]
pub fn send_to(&self, buf: &[u8], addr: &SockAddr) -> io::Result<usize> {
self.send_to_with_flags(buf, addr, 0)
}
pub fn send_to_with_flags(
&self,
buf: &[u8],
addr: &SockAddr,
flags: c_int,
) -> io::Result<usize> {
sys::send_to(self.as_raw(), buf, addr, flags)
}
#[doc = man_links!(sendmsg(2))]
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn send_to_vectored(&self, bufs: &[IoSlice<'_>], addr: &SockAddr) -> io::Result<usize> {
self.send_to_vectored_with_flags(bufs, addr, 0)
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn send_to_vectored_with_flags(
&self,
bufs: &[IoSlice<'_>],
addr: &SockAddr,
flags: c_int,
) -> io::Result<usize> {
sys::send_to_vectored(self.as_raw(), bufs, addr, flags)
}
#[doc = man_links!(sendmsg(2))]
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn sendmsg(&self, msg: &MsgHdr<'_, '_, '_>, flags: sys::c_int) -> io::Result<usize> {
sys::sendmsg(self.as_raw(), msg, flags)
}
}
#[inline(always)]
const fn set_common_type(ty: Type) -> Type {
#[cfg(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "cygwin",
))]
let ty = ty._cloexec();
#[cfg(windows)]
let ty = ty._no_inherit();
ty
}
#[inline(always)]
#[allow(clippy::unnecessary_wraps)]
fn set_common_flags(socket: Socket) -> io::Result<Socket> {
#[cfg(all(
unix,
not(any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "linux",
target_os = "netbsd",
target_os = "openbsd",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
))
))]
socket._set_cloexec(true)?;
#[cfg(any(
target_os = "ios",
target_os = "visionos",
target_os = "macos",
target_os = "tvos",
target_os = "watchos",
))]
socket._set_nosigpipe(true)?;
Ok(socket)
}
#[cfg(not(any(
target_os = "haiku",
target_os = "illumos",
target_os = "netbsd",
target_os = "redox",
target_os = "solaris",
)))]
#[derive(Debug)]
pub enum InterfaceIndexOrAddress {
Index(u32),
Address(Ipv4Addr),
}
impl Socket {
pub fn broadcast(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_BROADCAST)
.map(|broadcast| broadcast != 0)
}
}
pub fn set_broadcast(&self, broadcast: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_BROADCAST,
broadcast as c_int,
)
}
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
match unsafe { getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_ERROR) } {
Ok(0) => Ok(None),
Ok(errno) => Ok(Some(io::Error::from_raw_os_error(errno))),
Err(err) => Err(err),
}
}
pub fn keepalive(&self) -> io::Result<bool> {
unsafe {
getsockopt::<Bool>(self.as_raw(), sys::SOL_SOCKET, sys::SO_KEEPALIVE)
.map(|keepalive| keepalive != 0)
}
}
pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_KEEPALIVE,
keepalive as c_int,
)
}
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
unsafe {
getsockopt::<sys::linger>(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER)
.map(from_linger)
}
}
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
let linger = into_linger(linger);
unsafe { setsockopt(self.as_raw(), sys::SOL_SOCKET, sys::SO_LINGER, linger) }
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn out_of_band_inline(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_OOBINLINE)
.map(|oob_inline| oob_inline != 0)
}
}
#[cfg(not(target_os = "redox"))]
#[cfg_attr(docsrs, doc(cfg(not(target_os = "redox"))))]
pub fn set_out_of_band_inline(&self, oob_inline: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_OOBINLINE,
oob_inline as c_int,
)
}
}
#[cfg(any(target_os = "linux", target_os = "cygwin"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "cygwin"))))]
pub fn passcred(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_PASSCRED)
.map(|passcred| passcred != 0)
}
}
#[cfg(any(target_os = "linux", target_os = "cygwin"))]
#[cfg_attr(docsrs, doc(cfg(any(target_os = "linux", target_os = "cygwin"))))]
pub fn set_passcred(&self, passcred: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_PASSCRED,
passcred as c_int,
)
}
}
pub fn recv_buffer_size(&self) -> io::Result<usize> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVBUF)
.map(|size| size as usize)
}
}
pub fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_RCVBUF,
size as c_int,
)
}
}
pub fn read_timeout(&self) -> io::Result<Option<Duration>> {
sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO)
}
pub fn set_read_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_RCVTIMEO, duration)
}
pub fn reuse_address(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_REUSEADDR)
.map(|reuse| reuse != 0)
}
}
pub fn set_reuse_address(&self, reuse: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_REUSEADDR,
reuse as c_int,
)
}
}
pub fn send_buffer_size(&self) -> io::Result<usize> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDBUF)
.map(|size| size as usize)
}
}
pub fn set_send_buffer_size(&self, size: usize) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::SOL_SOCKET,
sys::SO_SNDBUF,
size as c_int,
)
}
}
pub fn write_timeout(&self) -> io::Result<Option<Duration>> {
sys::timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO)
}
pub fn set_write_timeout(&self, duration: Option<Duration>) -> io::Result<()> {
sys::set_timeout_opt(self.as_raw(), sys::SOL_SOCKET, sys::SO_SNDTIMEO, duration)
}
}
const fn from_linger(linger: sys::linger) -> Option<Duration> {
if linger.l_onoff == 0 {
None
} else {
Some(Duration::from_secs(linger.l_linger as u64))
}
}
const fn into_linger(duration: Option<Duration>) -> sys::linger {
match duration {
Some(duration) => sys::linger {
l_onoff: 1,
l_linger: duration.as_secs() as _,
},
None => sys::linger {
l_onoff: 0,
l_linger: 0,
},
}
}
impl Socket {
#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
)]
#[deprecated = "Use `Socket::header_included_v4` instead"]
pub fn header_included(&self) -> io::Result<bool> {
self.header_included_v4()
}
#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
)]
pub fn header_included_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_HDRINCL)
.map(|included| included != 0)
}
}
#[cfg_attr(
any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
allow(rustdoc::broken_intra_doc_links)
)]
#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
)]
#[deprecated = "Use `Socket::set_header_included_v4` instead"]
pub fn set_header_included(&self, included: bool) -> io::Result<()> {
self.set_header_included_v4(included)
}
#[cfg_attr(
any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
allow(rustdoc::broken_intra_doc_links)
)]
#[cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf"))))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
)]
pub fn set_header_included_v4(&self, included: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_HDRINCL,
included as c_int,
)
}
}
#[cfg(all(feature = "all", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
pub fn ip_transparent(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_TRANSPARENT)
.map(|transparent| transparent != 0)
}
}
#[cfg(all(feature = "all", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
pub fn set_ip_transparent(&self, transparent: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
libc::IP_TRANSPARENT,
transparent as c_int,
)
}
}
pub fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
let mreq = sys::IpMreq {
imr_multiaddr: sys::to_in_addr(multiaddr),
imr_interface: sys::to_in_addr(interface),
};
unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_ADD_MEMBERSHIP, mreq) }
}
pub fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> io::Result<()> {
let mreq = sys::IpMreq {
imr_multiaddr: sys::to_in_addr(multiaddr),
imr_interface: sys::to_in_addr(interface),
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_DROP_MEMBERSHIP,
mreq,
)
}
}
#[cfg(not(any(
target_os = "aix",
target_os = "haiku",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
)))]
pub fn join_multicast_v4_n(
&self,
multiaddr: &Ipv4Addr,
interface: &InterfaceIndexOrAddress,
) -> io::Result<()> {
let mreqn = sys::to_mreqn(multiaddr, interface);
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_ADD_MEMBERSHIP,
mreqn,
)
}
}
#[cfg(not(any(
target_os = "aix",
target_os = "haiku",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
)))]
pub fn leave_multicast_v4_n(
&self,
multiaddr: &Ipv4Addr,
interface: &InterfaceIndexOrAddress,
) -> io::Result<()> {
let mreqn = sys::to_mreqn(multiaddr, interface);
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_DROP_MEMBERSHIP,
mreqn,
)
}
}
#[cfg(not(any(
target_os = "dragonfly",
target_os = "haiku",
target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "fuchsia",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
)))]
pub fn join_ssm_v4(
&self,
source: &Ipv4Addr,
group: &Ipv4Addr,
interface: &Ipv4Addr,
) -> io::Result<()> {
let mreqs = sys::IpMreqSource {
imr_multiaddr: sys::to_in_addr(group),
imr_interface: sys::to_in_addr(interface),
imr_sourceaddr: sys::to_in_addr(source),
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_ADD_SOURCE_MEMBERSHIP,
mreqs,
)
}
}
#[cfg(not(any(
target_os = "dragonfly",
target_os = "haiku",
target_os = "hurd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "fuchsia",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
)))]
pub fn leave_ssm_v4(
&self,
source: &Ipv4Addr,
group: &Ipv4Addr,
interface: &Ipv4Addr,
) -> io::Result<()> {
let mreqs = sys::IpMreqSource {
imr_multiaddr: sys::to_in_addr(group),
imr_interface: sys::to_in_addr(interface),
imr_sourceaddr: sys::to_in_addr(source),
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_DROP_SOURCE_MEMBERSHIP,
mreqs,
)
}
}
#[cfg(all(feature = "all", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
pub fn multicast_all_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, libc::IP_MULTICAST_ALL)
.map(|all| all != 0)
}
}
#[cfg(all(feature = "all", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
pub fn set_multicast_all_v4(&self, all: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
libc::IP_MULTICAST_ALL,
all as c_int,
)
}
}
pub fn multicast_if_v4(&self) -> io::Result<Ipv4Addr> {
unsafe {
getsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_IF).map(sys::from_in_addr)
}
}
pub fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()> {
let interface = sys::to_in_addr(interface);
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_MULTICAST_IF,
interface,
)
}
}
pub fn multicast_loop_v4(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_LOOP)
.map(|loop_v4| loop_v4 != 0)
}
}
pub fn set_multicast_loop_v4(&self, loop_v4: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_MULTICAST_LOOP,
loop_v4 as c_int,
)
}
}
pub fn multicast_ttl_v4(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_MULTICAST_TTL)
.map(|ttl| ttl as u32)
}
}
pub fn set_multicast_ttl_v4(&self, ttl: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_MULTICAST_TTL,
ttl as c_int,
)
}
}
pub fn ttl(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL).map(|ttl| ttl as u32)
}
}
pub fn set_ttl(&self, ttl: u32) -> io::Result<()> {
unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TTL, ttl as c_int) }
}
#[cfg(not(any(
target_os = "fuchsia",
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
)))]
pub fn set_tos(&self, tos: u32) -> io::Result<()> {
unsafe { setsockopt(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS, tos as c_int) }
}
#[cfg(not(any(
target_os = "fuchsia",
target_os = "redox",
target_os = "solaris",
target_os = "illumos",
target_os = "haiku",
)))]
pub fn tos(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_TOS).map(|tos| tos as u32)
}
}
#[cfg(not(any(
target_os = "aix",
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
)))]
pub fn set_recv_tos(&self, recv_tos: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IP,
sys::IP_RECVTOS,
recv_tos as c_int,
)
}
}
#[cfg(not(any(
target_os = "aix",
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "hurd",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "nto",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
)))]
pub fn recv_tos(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IP, sys::IP_RECVTOS)
.map(|recv_tos| recv_tos > 0)
}
}
}
impl Socket {
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd"
))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
)]
pub fn header_included_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IP_HDRINCL)
.map(|included| included != 0)
}
}
#[cfg_attr(
any(target_os = "fuchsia", target_os = "illumos", target_os = "solaris"),
allow(rustdoc::broken_intra_doc_links)
)]
#[cfg(all(
feature = "all",
not(any(
target_os = "redox",
target_os = "espidf",
target_os = "openbsd",
target_os = "freebsd",
target_os = "dragonfly",
target_os = "netbsd"
))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(feature = "all", not(any(target_os = "redox", target_os = "espidf")))))
)]
pub fn set_header_included_v6(&self, included: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IP_HDRINCL,
included as c_int,
)
}
}
#[cfg(not(target_os = "nto"))]
pub fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = sys::Ipv6Mreq {
ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
ipv6mr_interface: interface as _,
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_ADD_MEMBERSHIP,
mreq,
)
}
}
#[cfg(not(target_os = "nto"))]
pub fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) -> io::Result<()> {
let mreq = sys::Ipv6Mreq {
ipv6mr_multiaddr: sys::to_in6_addr(multiaddr),
ipv6mr_interface: interface as _,
};
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_DROP_MEMBERSHIP,
mreq,
)
}
}
pub fn multicast_hops_v6(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_HOPS)
.map(|hops| hops as u32)
}
}
pub fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_MULTICAST_HOPS,
hops as c_int,
)
}
}
#[cfg(all(feature = "all", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
pub fn multicast_all_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, libc::IPV6_MULTICAST_ALL)
.map(|all| all != 0)
}
}
#[cfg(all(feature = "all", target_os = "linux"))]
#[cfg_attr(docsrs, doc(cfg(all(feature = "all", target_os = "linux"))))]
pub fn set_multicast_all_v6(&self, all: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
libc::IPV6_MULTICAST_ALL,
all as c_int,
)
}
}
pub fn multicast_if_v6(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_IF)
.map(|interface| interface as u32)
}
}
pub fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_MULTICAST_IF,
interface as c_int,
)
}
}
pub fn multicast_loop_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_MULTICAST_LOOP)
.map(|loop_v6| loop_v6 != 0)
}
}
pub fn set_multicast_loop_v6(&self, loop_v6: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_MULTICAST_LOOP,
loop_v6 as c_int,
)
}
}
pub fn unicast_hops_v6(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_UNICAST_HOPS)
.map(|hops| hops as u32)
}
}
pub fn set_unicast_hops_v6(&self, hops: u32) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_UNICAST_HOPS,
hops as c_int,
)
}
}
pub fn only_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_V6ONLY)
.map(|only_v6| only_v6 != 0)
}
}
pub fn set_only_v6(&self, only_v6: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_V6ONLY,
only_v6 as c_int,
)
}
}
#[cfg(not(any(
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
)))]
pub fn recv_tclass_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVTCLASS)
.map(|recv_tclass| recv_tclass > 0)
}
}
#[cfg(not(any(
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
)))]
pub fn set_recv_tclass_v6(&self, recv_tclass: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_RECVTCLASS,
recv_tclass as c_int,
)
}
}
#[cfg(all(
feature = "all",
not(any(
windows,
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
))
))]
pub fn recv_hoplimit_v6(&self) -> io::Result<bool> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_IPV6, sys::IPV6_RECVHOPLIMIT)
.map(|recv_hoplimit| recv_hoplimit > 0)
}
}
#[cfg(all(
feature = "all",
not(any(
windows,
target_os = "dragonfly",
target_os = "fuchsia",
target_os = "illumos",
target_os = "netbsd",
target_os = "openbsd",
target_os = "redox",
target_os = "solaris",
target_os = "haiku",
target_os = "hurd",
target_os = "espidf",
target_os = "vita",
target_os = "cygwin",
))
))]
pub fn set_recv_hoplimit_v6(&self, recv_hoplimit: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_IPV6,
sys::IPV6_RECVHOPLIMIT,
recv_hoplimit as c_int,
)
}
}
}
impl Socket {
#[cfg(all(
feature = "all",
not(any(
windows,
target_os = "haiku",
target_os = "openbsd",
target_os = "vita"
))
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
not(any(
windows,
target_os = "haiku",
target_os = "openbsd",
target_os = "vita"
))
)))
)]
pub fn keepalive_time(&self) -> io::Result<Duration> {
sys::keepalive_time(self.as_raw())
}
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "cygwin",
)
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
)
)))
)]
pub fn keepalive_interval(&self) -> io::Result<Duration> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPINTVL)
.map(|secs| Duration::from_secs(secs as u64))
}
}
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
target_os = "cygwin",
)
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "dragonfly",
target_os = "freebsd",
target_os = "fuchsia",
target_os = "illumos",
target_os = "ios",
target_os = "visionos",
target_os = "linux",
target_os = "macos",
target_os = "netbsd",
target_os = "tvos",
target_os = "watchos",
)
)))
)]
pub fn keepalive_retries(&self) -> io::Result<u32> {
unsafe {
getsockopt::<c_int>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_KEEPCNT)
.map(|retries| retries as u32)
}
}
pub fn set_tcp_keepalive(&self, params: &TcpKeepalive) -> io::Result<()> {
self.set_keepalive(true)?;
sys::set_tcp_keepalive(self.as_raw(), params)
}
pub fn nodelay(&self) -> io::Result<bool> {
unsafe {
getsockopt::<Bool>(self.as_raw(), sys::IPPROTO_TCP, sys::TCP_NODELAY)
.map(|nodelay| nodelay != 0)
}
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
unsafe {
setsockopt(
self.as_raw(),
sys::IPPROTO_TCP,
sys::TCP_NODELAY,
nodelay as c_int,
)
}
}
#[cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows",
)
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(
target_os = "android",
target_os = "fuchsia",
target_os = "linux",
target_os = "windows",
)
)))
)]
pub fn original_dst(&self) -> io::Result<SockAddr> {
sys::original_dst(self.as_raw())
}
#[cfg(all(
feature = "all",
any(target_os = "android", target_os = "linux", target_os = "windows")
))]
#[cfg_attr(
docsrs,
doc(cfg(all(
feature = "all",
any(target_os = "android", target_os = "linux", target_os = "windows")
)))
)]
pub fn original_dst_ipv6(&self) -> io::Result<SockAddr> {
sys::original_dst_ipv6(self.as_raw())
}
}
impl Read for Socket {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
self.recv(buf)
}
#[cfg(not(target_os = "redox"))]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
self.recv_vectored(bufs).map(|(n, _)| n)
}
}
impl<'a> Read for &'a Socket {
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
let buf = unsafe { &mut *(buf as *mut [u8] as *mut [MaybeUninit<u8>]) };
self.recv(buf)
}
#[cfg(not(target_os = "redox"))]
fn read_vectored(&mut self, bufs: &mut [IoSliceMut<'_>]) -> io::Result<usize> {
let bufs = unsafe { &mut *(bufs as *mut [IoSliceMut<'_>] as *mut [MaybeUninitSlice<'_>]) };
self.recv_vectored(bufs).map(|(n, _)| n)
}
}
impl Write for Socket {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.send(buf)
}
#[cfg(not(target_os = "redox"))]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.send_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl<'a> Write for &'a Socket {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
self.send(buf)
}
#[cfg(not(target_os = "redox"))]
fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result<usize> {
self.send_vectored(bufs)
}
fn flush(&mut self) -> io::Result<()> {
Ok(())
}
}
impl fmt::Debug for Socket {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("Socket")
.field("raw", &self.as_raw())
.field("local_addr", &self.local_addr().ok())
.field("peer_addr", &self.peer_addr().ok())
.finish()
}
}
from!(net::TcpStream, Socket);
from!(net::TcpListener, Socket);
from!(net::UdpSocket, Socket);
from!(Socket, net::TcpStream);
from!(Socket, net::TcpListener);
from!(Socket, net::UdpSocket);