use std::net::SocketAddr;
use std::{io::Result, os::raw::c_int};
#[cfg(unix)]
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, RawFd};
#[cfg(windows)]
use std::os::windows::io::{AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, RawSocket};
use crate::buf::{BufResult, IoBuf, IoBufMut, IoVectoredBuf, IoVectoredBufMut};
use crate::driver::helpers::attached_handle::AttachedHandle;
#[cfg(target_os = "linux")]
use crate::driver::ops::MultiOp;
use crate::driver::ops::Op;
#[cfg(target_os = "linux")]
use crate::driver::ops::accept_multi::AcceptMulti;
#[cfg(target_os = "linux")]
use crate::io::Stream;
#[derive(Clone, Debug)]
pub(crate) struct Socket {
pub(crate) handle: AttachedHandle<socket2::Socket>,
}
fn configure_async_socket(socket: &socket2::Socket) -> Result<()> {
socket.set_nonblocking(true)?;
#[cfg(any(
target_os = "macos",
target_os = "freebsd",
target_os = "netbsd",
target_os = "openbsd",
target_os = "dragonfly"
))]
{
socket.set_cloexec(true)?;
}
#[cfg(target_vendor = "apple")]
{
let is_unix = socket
.local_addr()
.map(|a| i32::from(a.family()) == libc::AF_UNIX)
.unwrap_or(false);
if !is_unix {
socket.set_nosigpipe(true)?;
}
}
Ok(())
}
impl Socket {
fn attach(socket: socket2::Socket) -> Result<AttachedHandle<socket2::Socket>> {
#[cfg(windows)]
{
AttachedHandle::new_socket(socket)
}
#[cfg(unix)]
{
AttachedHandle::new(socket)
}
}
pub(crate) fn set_async_flags(&self) -> Result<()> {
configure_async_socket(&self.handle)
}
pub(crate) fn new(socket_addr: SocketAddr, socket_type: socket2::Type) -> Result<Self> {
let socket = socket2::Socket::new(socket2::Domain::for_address(socket_addr), socket_type, None)?;
configure_async_socket(&socket)?;
Ok(Self {
handle: Self::attach(socket)?,
})
}
#[cfg(unix)]
pub(crate) fn new_unix(socket_type: c_int) -> Result<Self> {
let socket = socket2::Socket::new(socket2::Domain::UNIX, socket_type.into(), None)?;
configure_async_socket(&socket)?;
Ok(Self {
handle: Self::attach(socket)?,
})
}
pub(crate) fn bind(socket_addr: SocketAddr, socket_type: socket2::Type) -> Result<Self> {
Self::bind_internal(
socket_addr.into(),
socket2::Domain::for_address(socket_addr),
socket_type,
)
}
#[cfg(unix)]
pub(crate) fn bind_unix<P: AsRef<std::path::Path>>(path: P, socket_type: c_int) -> Result<Self> {
let addr = socket2::SockAddr::unix(path.as_ref())?;
Self::bind_internal(addr, socket2::Domain::UNIX, socket_type.into())
}
fn bind_internal(
socket_addr: socket2::SockAddr,
domain: socket2::Domain,
socket_type: socket2::Type,
) -> Result<Socket> {
let socket = socket2::Socket::new(domain, socket_type, None)?;
socket.set_reuse_address(true)?;
#[cfg(unix)]
socket.set_reuse_port(true)?;
configure_async_socket(&socket)?;
socket.bind(&socket_addr)?;
Ok(Self {
handle: Self::attach(socket)?,
})
}
pub(crate) fn from_socket(socket: socket2::Socket) -> Result<Self> {
Ok(Self {
handle: Self::attach(socket)?,
})
}
pub(crate) async fn connect(&self, socket_addr: socket2::SockAddr) -> Result<()> {
let op = Op::connect(&self.handle, socket_addr)?;
op.await
}
pub(crate) async fn accept(&self) -> Result<(Self, Option<SocketAddr>)> {
let op = Op::accept(&self.handle)?;
op.await
}
#[cfg(target_os = "linux")]
pub(crate) fn incoming(&self) -> Result<Incoming> {
Ok(Incoming {
inner: MultiOp::accept_multi(&self.handle)?,
})
}
pub(crate) fn listen(&self, backlog: c_int) -> Result<()> {
self.handle.listen(backlog)
}
pub fn shutdown(&self, how: std::net::Shutdown) -> Result<()> {
self.handle.shutdown(how)
}
pub(crate) async fn close(self) -> Result<()> {
self.handle.into_inner().close().await
}
pub fn set_nodelay(&self, nodelay: bool) -> Result<()> {
self.handle.set_tcp_nodelay(nodelay)
}
pub(crate) async fn recv<B: IoBufMut>(&self, buf: B) -> BufResult<usize, B> {
let op = match Op::recv(&self.handle, buf) {
Ok(op) => op,
Err((error, buf)) => return BufResult(Err(error), buf),
};
op.await
}
#[cfg(target_os = "linux")]
pub(crate) async fn recv_managed(&self, len: usize) -> Result<Option<crate::buf::PooledBuf>> {
let op = Op::recv_managed(&self.handle, len)?;
op.await
}
#[cfg(target_os = "linux")]
pub(crate) fn recv_multi(&self) -> Result<MultiOp<crate::driver::ops::recv_multi::RecvMulti>> {
MultiOp::recv_multi(&self.handle)
}
#[cfg(target_os = "linux")]
pub(crate) async fn recv_datagram_managed(
&self,
len: usize,
capture_peer: bool,
) -> Result<crate::net::udp::RecvDatagram> {
let op = Op::recv_datagram_managed(&self.handle, len, capture_peer)?;
op.await
}
#[cfg(target_os = "linux")]
pub(crate) fn recv_datagram_multi(
&self,
capture_peer: bool,
) -> Result<MultiOp<crate::driver::ops::recv_from_multi::RecvFromMulti>> {
MultiOp::recv_datagram_multi(&self.handle, capture_peer)
}
#[cfg(target_os = "linux")]
pub(crate) async fn recv_from_managed(&self, len: usize) -> Result<crate::net::udp::RecvDatagram> {
self.recv_datagram_managed(len, true).await
}
#[cfg(target_os = "linux")]
pub(crate) fn recv_from_multi(&self) -> Result<MultiOp<crate::driver::ops::recv_from_multi::RecvFromMulti>> {
self.recv_datagram_multi(true)
}
pub(crate) async fn recv_from<B: IoBufMut>(&self, buf: B) -> BufResult<(usize, SocketAddr), B> {
let op = match Op::recv_from(&self.handle, buf) {
Ok(op) => op,
Err((error, buf)) => return BufResult(Err(error), buf),
};
op.await
}
pub(crate) async fn recvmsg<V: IoVectoredBufMut>(&self, buf: V) -> BufResult<(usize, SocketAddr), V> {
let op = match Op::recvmsg(&self.handle, buf) {
Ok(op) => op,
Err((error, buf)) => return BufResult(Err(error), buf),
};
op.await
}
pub(crate) async fn send<B: IoBuf>(&self, buf: B) -> BufResult<usize, B> {
let op = match Op::send(&self.handle, buf) {
Ok(op) => op,
Err((error, buf)) => return BufResult(Err(error), buf),
};
op.await
}
pub(crate) async fn send_to<B: IoBuf>(&self, buf: B, socket_addr: SocketAddr) -> BufResult<usize, B> {
let op = match Op::send_to(&self.handle, buf, socket_addr) {
Ok(op) => op,
Err((error, buf)) => return BufResult(Err(error), buf),
};
op.await
}
pub(crate) async fn sendmsg<V: IoVectoredBuf, C: IoBuf>(
&self,
io_slices: V,
socket_addr: Option<SocketAddr>,
control: Option<C>,
) -> BufResult<(usize, Option<C>), V> {
let op = match Op::sendmsg(&self.handle, io_slices, control, socket_addr) {
Ok(op) => op,
Err((error, io_slices)) => return BufResult(Err(error), io_slices),
};
op.await
}
}
#[cfg(unix)]
impl AsRawFd for Socket {
fn as_raw_fd(&self) -> RawFd {
self.handle.raw_fd()
}
}
#[cfg(unix)]
impl AsFd for Socket {
fn as_fd(&self) -> BorrowedFd<'_> {
self.handle.as_fd()
}
}
#[cfg(windows)]
impl AsSocket for Socket {
fn as_socket(&self) -> BorrowedSocket<'_> {
unsafe { BorrowedSocket::borrow_raw(self.handle.raw_socket()) }
}
}
#[cfg(windows)]
impl AsRawSocket for Socket {
fn as_raw_socket(&self) -> RawSocket {
self.handle.raw_socket()
}
}
impl From<AttachedHandle<socket2::Socket>> for Socket {
fn from(value: AttachedHandle<socket2::Socket>) -> Self {
Self { handle: value }
}
}
#[cfg(target_os = "linux")]
pub(crate) struct Incoming {
inner: MultiOp<AcceptMulti>,
}
#[cfg(target_os = "linux")]
impl Stream for Incoming {
type Item = Result<(Socket, Option<SocketAddr>)>;
async fn next(&mut self) -> Option<Self::Item> {
let accepted = self.inner.next().await?;
Some(match accepted {
Ok(socket) => match socket.handle.peer_addr() {
Ok(addr) => Ok((socket, addr.as_socket())),
Err(err) => Err(err),
},
Err(err) => Err(err),
})
}
}
#[cfg(unix)]
impl FromRawFd for Socket {
unsafe fn from_raw_fd(fd: RawFd) -> Self {
Self {
handle: unsafe { AttachedHandle::new_unchecked(socket2::Socket::from_raw_fd(fd)) },
}
}
}
#[cfg(windows)]
impl FromRawSocket for Socket {
unsafe fn from_raw_socket(socket: RawSocket) -> Self {
Self {
handle: unsafe { AttachedHandle::new_unchecked(socket2::Socket::from_raw_socket(socket)) },
}
}
}