use core::mem::ManuallyDrop;
use std::io;
use std::net::SocketAddr;
use std::time::Duration;
use super::opt;
use crate::io::raw::{Owned, Raw};
use crate::io::source::Kind;
use crate::io::{Handle, sys};
pub struct TcpSocket {
socket: Owned,
nonblocking: bool,
}
super::sockopt::socket_options!(TcpSocket);
impl TcpSocket {
pub fn new_v4() -> io::Result<TcpSocket> {
Self::new(false)
}
pub fn new_v6() -> io::Result<TcpSocket> {
Self::new(true)
}
fn new(v6: bool) -> io::Result<TcpSocket> {
Ok(TcpSocket {
socket: super::tcp::new_socket(v6)?,
nonblocking: true,
})
}
pub(super) fn raw(&self) -> Raw {
raw_of(&self.socket)
}
fn as_std(&self) -> ManuallyDrop<std::net::TcpStream> {
ManuallyDrop::new(unsafe { std_from_raw(self.raw()) })
}
pub fn set_keepalive(&self, keepalive: bool) -> io::Result<()> {
opt::set_flag(self.raw(), opt::SOL_SOCKET, opt::SO_KEEPALIVE, keepalive)
}
pub fn keepalive(&self) -> io::Result<bool> {
opt::flag(self.raw(), opt::SOL_SOCKET, opt::SO_KEEPALIVE)
}
pub fn set_linger(&self, linger: Option<Duration>) -> io::Result<()> {
opt::set_linger_time(self.raw(), linger)
}
pub fn set_zero_linger(&self) -> io::Result<()> {
opt::set_linger_time(self.raw(), Some(Duration::ZERO))
}
pub fn linger(&self) -> io::Result<Option<Duration>> {
opt::linger_time(self.raw())
}
pub fn set_nodelay(&self, nodelay: bool) -> io::Result<()> {
self.as_std().set_nodelay(nodelay)
}
pub fn nodelay(&self) -> io::Result<bool> {
self.as_std().nodelay()
}
pub fn local_addr(&self) -> io::Result<SocketAddr> {
self.as_std().local_addr()
}
pub fn take_error(&self) -> io::Result<Option<io::Error>> {
self.as_std().take_error()
}
pub fn bind(&self, addr: SocketAddr) -> io::Result<()> {
sys::bind_inet(self.raw(), &addr)
}
pub async fn connect(self, addr: SocketAddr) -> io::Result<super::TcpStream> {
let TcpSocket {
socket,
nonblocking,
} = self;
super::tcp::connect_socket(socket, nonblocking, addr).await
}
pub fn listen(self, backlog: u32) -> io::Result<super::TcpListener> {
sys::listen(self.raw(), backlog)?;
let listener = std::net::TcpListener::from(self.socket);
if self.nonblocking {
Ok(Handle::from_nonblocking(listener, Kind::TcpListener))
} else {
Handle::adopt(listener, Kind::TcpListener)
}
}
pub fn from_std_stream(stream: std::net::TcpStream) -> TcpSocket {
TcpSocket {
socket: Owned::from(stream),
nonblocking: false,
}
}
}
impl core::fmt::Debug for TcpSocket {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_struct("TcpSocket")
.field("socket", &self.raw())
.finish_non_exhaustive()
}
}
#[cfg(unix)]
pub(super) fn raw_of(socket: &Owned) -> Raw {
use std::os::fd::AsRawFd;
socket.as_raw_fd()
}
#[cfg(windows)]
pub(super) fn raw_of(socket: &Owned) -> Raw {
use std::os::windows::io::AsRawSocket;
socket.as_raw_socket()
}
#[cfg(unix)]
pub(super) unsafe fn std_from_raw<T>(raw: Raw) -> T
where
T: std::os::fd::FromRawFd,
{
unsafe { T::from_raw_fd(raw) }
}
#[cfg(windows)]
pub(super) unsafe fn std_from_raw<T>(raw: Raw) -> T
where
T: std::os::windows::io::FromRawSocket,
{
unsafe { T::from_raw_socket(raw) }
}
#[cfg(unix)]
mod fd {
use std::os::fd::{AsFd, AsRawFd, BorrowedFd, FromRawFd, IntoRawFd, OwnedFd, RawFd};
use super::TcpSocket;
impl AsRawFd for TcpSocket {
fn as_raw_fd(&self) -> RawFd {
self.socket.as_raw_fd()
}
}
impl AsFd for TcpSocket {
fn as_fd(&self) -> BorrowedFd<'_> {
self.socket.as_fd()
}
}
impl FromRawFd for TcpSocket {
unsafe fn from_raw_fd(fd: RawFd) -> TcpSocket {
TcpSocket {
socket: unsafe { OwnedFd::from_raw_fd(fd) },
nonblocking: false,
}
}
}
impl IntoRawFd for TcpSocket {
fn into_raw_fd(self) -> RawFd {
self.socket.into_raw_fd()
}
}
}
#[cfg(windows)]
mod raw_socket {
use std::os::windows::io::{
AsRawSocket, AsSocket, BorrowedSocket, FromRawSocket, IntoRawSocket, OwnedSocket, RawSocket,
};
use super::TcpSocket;
impl AsRawSocket for TcpSocket {
fn as_raw_socket(&self) -> RawSocket {
self.socket.as_raw_socket()
}
}
impl AsSocket for TcpSocket {
fn as_socket(&self) -> BorrowedSocket<'_> {
self.socket.as_socket()
}
}
impl FromRawSocket for TcpSocket {
unsafe fn from_raw_socket(socket: RawSocket) -> TcpSocket {
TcpSocket {
socket: unsafe { OwnedSocket::from_raw_socket(socket) },
nonblocking: false,
}
}
}
impl IntoRawSocket for TcpSocket {
fn into_raw_socket(self) -> RawSocket {
self.socket.into_raw_socket()
}
}
}