#[cfg(feature = "async-std")]
pub(crate) mod async_std;
#[cfg(feature = "tokio")]
pub(crate) mod tokio;
#[cfg(feature = "smol")]
pub(crate) mod smol;
#[cfg(feature = "rustls")]
pub(crate) mod rustls;
#[cfg(feature = "native-tls")]
pub(crate) mod native_tls;
pub(crate) mod streamops;
pub(crate) mod unimpl_tls;
use crate::network::{
CommonConnectOptions, CommonListenOptions, TcpConnectOptions, TcpListenOptions,
};
use socket2::Socket;
#[cfg(unix)]
use tor_error::warn_report;
const LISTEN_BACKLOG: i32 = u16::MAX as i32;
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub(crate) fn tcp_listen(
addr: &std::net::SocketAddr,
options: &TcpListenOptions,
) -> std::io::Result<std::net::TcpListener> {
use socket2::{Domain, Type};
let TcpListenOptions {
common:
CommonListenOptions {
send_buffer_size,
recv_buffer_size,
},
} = options;
let socket = match addr {
std::net::SocketAddr::V4(_) => Socket::new(Domain::IPV4, Type::STREAM, None)?,
std::net::SocketAddr::V6(_) => {
let socket = Socket::new(Domain::IPV6, Type::STREAM, None)?;
#[cfg(unix)]
if let Err(e) = socket.set_only_v6(true) {
warn_report!(
e,
"Failed to set `IPV6_V6ONLY` on `AF_INET6` socket. \
Please report this bug at https://gitlab.torproject.org/tpo/core/arti/-/issues",
);
}
socket
}
};
socket.set_nonblocking(true)?;
#[cfg(unix)]
socket.set_reuse_address(true)?;
if let Some(send_buffer_size) = send_buffer_size {
socket.set_send_buffer_size(*send_buffer_size)?;
}
if let Some(recv_buffer_size) = recv_buffer_size {
socket.set_recv_buffer_size(*recv_buffer_size)?;
}
socket.bind(&(*addr).into())?;
socket.listen(LISTEN_BACKLOG)?;
Ok(socket.into())
}
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub(crate) fn tcp_listen(
_addr: &std::net::SocketAddr,
_options: &TcpListenOptions,
) -> std::io::Result<std::net::TcpListener> {
Err(std::io::Error::from(std::io::ErrorKind::Unsupported))
}
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub(crate) fn tcp_pre_connect(
addr: &std::net::SocketAddr,
options: &TcpConnectOptions,
) -> std::io::Result<socket2::Socket> {
use socket2::{Domain, Type};
let TcpConnectOptions {
common:
CommonConnectOptions {
send_buffer_size,
recv_buffer_size,
},
} = options;
let domain = match addr {
std::net::SocketAddr::V4(_) => Domain::IPV4,
std::net::SocketAddr::V6(_) => Domain::IPV6,
};
let socket = Socket::new(domain, Type::STREAM, None)?;
socket.set_nonblocking(true)?;
if let Some(send_buffer_size) = send_buffer_size {
socket.set_send_buffer_size(*send_buffer_size)?;
}
if let Some(recv_buffer_size) = recv_buffer_size {
socket.set_recv_buffer_size(*recv_buffer_size)?;
}
Ok(socket)
}
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub(crate) fn tcp_pre_connect(
_addr: &std::net::SocketAddr,
_options: &TcpConnectOptions,
) -> std::io::Result<socket2::Socket> {
Err(std::io::Error::from(std::io::ErrorKind::Unsupported))
}
#[cfg(any(feature = "async-std", feature = "smol"))]
#[cfg(not(all(target_arch = "wasm32", target_os = "unknown")))]
pub(crate) async fn tcp_async_io_connect(
addr: &std::net::SocketAddr,
options: &TcpConnectOptions,
) -> std::io::Result<std::net::TcpStream> {
use async_io::Async;
let socket = tcp_pre_connect(addr, options)?;
match socket.connect(&(*addr).into()) {
Ok(()) => {}
#[cfg(unix)]
Err(e) if e.raw_os_error() == Some(libc::EINPROGRESS) => {}
#[cfg(windows)]
Err(e) if e.kind() == std::io::ErrorKind::WouldBlock => {}
Err(e) => return Err(e),
}
let socket = Async::new_nonblocking(socket)?;
socket.writable().await?;
if let Some(e) = socket.get_ref().take_error()? {
return Err(e);
}
Ok(socket.into_inner()?.into())
}
#[cfg(any(feature = "async-std", feature = "smol"))]
#[cfg(all(target_arch = "wasm32", target_os = "unknown"))]
pub(crate) async fn tcp_async_io_connect(
_addr: &std::net::SocketAddr,
_options: &TcpConnectOptions,
) -> std::io::Result<std::net::TcpStream> {
Err(std::io::Error::from(std::io::ErrorKind::Unsupported))
}
#[cfg(not(unix))]
macro_rules! impl_unix_non_provider {
{ $for_type:ty } => {
#[async_trait]
impl crate::traits::NetStreamProvider<tor_general_addr::unix::SocketAddr> for $for_type {
type Stream = crate::unimpl::FakeStream;
type Listener = crate::unimpl::FakeListener<tor_general_addr::unix::SocketAddr>;
type ConnectOptions = crate::network::UnixConnectOptions;
type ListenOptions = crate::network::UnixListenOptions;
async fn connect(
&self,
_a: &tor_general_addr::unix::SocketAddr,
_options: &Self::ConnectOptions,
) -> IoResult<Self::Stream> {
Err(tor_general_addr::unix::NoAfUnixSocketSupport::default().into())
}
async fn listen(
&self,
_a: &tor_general_addr::unix::SocketAddr,
_options: &Self::ListenOptions,
) -> IoResult<Self::Listener> {
Err(tor_general_addr::unix::NoAfUnixSocketSupport::default().into())
}
}
}
}
#[cfg(not(unix))]
pub(crate) use impl_unix_non_provider;