use crate::{FromInner, HandleTrait, Inner, IntoInner, ToHandle};
use std::convert::{TryFrom, TryInto};
use std::net::SocketAddr;
use uv::{
uv_tcp_bind, uv_tcp_close_reset, uv_tcp_connect, uv_tcp_getpeername, uv_tcp_getsockname,
uv_tcp_init, uv_tcp_init_ex, uv_tcp_keepalive, uv_tcp_nodelay, uv_tcp_simultaneous_accepts,
uv_tcp_t, AF_INET, AF_INET6, AF_UNSPEC,
};
bitflags! {
pub struct TcpFlags: u32 {
const AF_INET = AF_INET as _;
const AF_INET6 = AF_INET6 as _;
const AF_UNSPEC = AF_UNSPEC as _;
}
}
bitflags! {
pub struct TcpBindFlags: u32 {
const IPV6ONLY = uv::uv_tcp_flags_UV_TCP_IPV6ONLY as _;
}
}
#[derive(Clone, Copy)]
pub struct TcpHandle {
handle: *mut uv_tcp_t,
}
impl TcpHandle {
pub fn new(r#loop: &crate::Loop) -> crate::Result<TcpHandle> {
let layout = std::alloc::Layout::new::<uv_tcp_t>();
let handle = unsafe { std::alloc::alloc(layout) as *mut uv_tcp_t };
if handle.is_null() {
return Err(crate::Error::ENOMEM);
}
let ret = unsafe { uv_tcp_init(r#loop.into_inner(), handle) };
if ret < 0 {
unsafe { std::alloc::dealloc(handle as _, layout) };
return Err(crate::Error::from_inner(ret as uv::uv_errno_t));
}
crate::StreamHandle::initialize_data(uv_handle!(handle), super::NoAddlStreamData);
Ok(TcpHandle { handle })
}
pub fn new_ex(r#loop: &crate::Loop, flags: TcpFlags) -> crate::Result<TcpHandle> {
let layout = std::alloc::Layout::new::<uv_tcp_t>();
let handle = unsafe { std::alloc::alloc(layout) as *mut uv_tcp_t };
if handle.is_null() {
return Err(crate::Error::ENOMEM);
}
let ret = unsafe { uv_tcp_init_ex(r#loop.into_inner(), handle, flags.bits()) };
if ret < 0 {
unsafe { std::alloc::dealloc(handle as _, layout) };
return Err(crate::Error::from_inner(ret as uv::uv_errno_t));
}
crate::StreamHandle::initialize_data(uv_handle!(handle), super::NoAddlStreamData);
Ok(TcpHandle { handle })
}
pub fn nodelay(&mut self, enable: bool) -> crate::Result<()> {
crate::uvret(unsafe { uv_tcp_nodelay(self.handle, if enable { 1 } else { 0 }) })
}
pub fn keepalive(&mut self, enable: bool, delay: u32) -> crate::Result<()> {
crate::uvret(unsafe { uv_tcp_keepalive(self.handle, if enable { 1 } else { 0 }, delay) })
}
pub fn simultaneous_accepts(&mut self, enable: bool) -> crate::Result<()> {
crate::uvret(unsafe {
uv_tcp_simultaneous_accepts(self.handle, if enable { 1 } else { 0 })
})
}
pub fn bind(
&mut self,
addr: &SocketAddr,
flags: TcpBindFlags,
) -> Result<(), Box<dyn std::error::Error>> {
let mut sockaddr: uv::sockaddr = unsafe { std::mem::zeroed() };
crate::fill_sockaddr(&mut sockaddr, addr)?;
crate::uvret(unsafe { uv_tcp_bind(self.handle, &sockaddr as _, flags.bits()) })
.map_err(|e| Box::new(e) as _)
}
pub fn getsockname(&self) -> Result<SocketAddr, Box<dyn std::error::Error>> {
let mut sockaddr: uv::sockaddr_storage = unsafe { std::mem::zeroed() };
let mut sockaddr_len: std::os::raw::c_int =
std::mem::size_of::<uv::sockaddr_storage>() as _;
crate::uvret(unsafe {
uv_tcp_getsockname(
self.handle,
uv_handle!(&mut sockaddr),
&mut sockaddr_len as _,
)
})?;
crate::build_socketaddr(uv_handle!(&sockaddr))
}
pub fn getpeername(&self) -> Result<SocketAddr, Box<dyn std::error::Error>> {
let mut sockaddr: uv::sockaddr_storage = unsafe { std::mem::zeroed() };
let mut sockaddr_len: std::os::raw::c_int =
std::mem::size_of::<uv::sockaddr_storage>() as _;
crate::uvret(unsafe {
uv_tcp_getpeername(
self.handle,
uv_handle!(&mut sockaddr),
&mut sockaddr_len as _,
)
})?;
crate::build_socketaddr(uv_handle!(&sockaddr))
}
pub fn connect<CB: Into<crate::ConnectCB<'static>>>(
&mut self,
addr: &SocketAddr,
cb: CB,
) -> Result<crate::ConnectReq, Box<dyn std::error::Error>> {
let mut req = crate::ConnectReq::new(cb)?;
let mut sockaddr: uv::sockaddr = unsafe { std::mem::zeroed() };
crate::fill_sockaddr(&mut sockaddr, addr)?;
let result = crate::uvret(unsafe {
uv_tcp_connect(
req.inner(),
self.handle,
&sockaddr as _,
Some(crate::uv_connect_cb),
)
});
if result.is_err() {
req.destroy();
}
result.map(|_| req).map_err(|e| Box::new(e) as _)
}
pub fn close_reset<CB: Into<crate::CloseCB<'static>>>(&mut self, cb: CB) -> crate::Result<()> {
let cb = cb.into();
let dataptr = crate::Handle::get_data(uv_handle!(self.handle));
if !dataptr.is_null() {
unsafe { (*dataptr).close_cb = cb };
}
crate::uvret(unsafe { uv_tcp_close_reset(self.handle, Some(crate::uv_close_cb)) })
}
}
impl FromInner<*mut uv_tcp_t> for TcpHandle {
fn from_inner(handle: *mut uv_tcp_t) -> TcpHandle {
TcpHandle { handle }
}
}
impl Inner<*mut uv_tcp_t> for TcpHandle {
fn inner(&self) -> *mut uv_tcp_t {
return self.handle;
}
}
impl Inner<*mut uv::uv_stream_t> for TcpHandle {
fn inner(&self) -> *mut uv::uv_stream_t {
uv_handle!(self.handle)
}
}
impl Inner<*mut uv::uv_handle_t> for TcpHandle {
fn inner(&self) -> *mut uv::uv_handle_t {
uv_handle!(self.handle)
}
}
impl From<TcpHandle> for crate::StreamHandle {
fn from(tcp: TcpHandle) -> crate::StreamHandle {
crate::StreamHandle::from_inner(Inner::<*mut uv::uv_stream_t>::inner(&tcp))
}
}
impl From<TcpHandle> for crate::Handle {
fn from(tcp: TcpHandle) -> crate::Handle {
crate::Handle::from_inner(Inner::<*mut uv::uv_handle_t>::inner(&tcp))
}
}
impl crate::ToStream for TcpHandle {
fn to_stream(&self) -> crate::StreamHandle {
crate::StreamHandle::from_inner(Inner::<*mut uv::uv_stream_t>::inner(self))
}
}
impl ToHandle for TcpHandle {
fn to_handle(&self) -> crate::Handle {
crate::Handle::from_inner(Inner::<*mut uv::uv_handle_t>::inner(self))
}
}
impl TryFrom<crate::Handle> for TcpHandle {
type Error = crate::ConversionError;
fn try_from(handle: crate::Handle) -> Result<Self, Self::Error> {
let t = handle.get_type();
if t != crate::HandleType::TCP {
Err(crate::ConversionError::new(t, crate::HandleType::TCP))
} else {
Ok((handle.inner() as *mut uv_tcp_t).into_inner())
}
}
}
impl TryFrom<crate::StreamHandle> for TcpHandle {
type Error = crate::ConversionError;
fn try_from(stream: crate::StreamHandle) -> Result<Self, Self::Error> {
stream.to_handle().try_into()
}
}
impl crate::StreamTrait for TcpHandle {}
impl HandleTrait for TcpHandle {}
impl crate::Loop {
pub fn tcp(&self) -> crate::Result<TcpHandle> {
TcpHandle::new(self)
}
}