Skip to content

feat(net): design improvements for TcpOpts #441

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jul 5, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 15 additions & 29 deletions compio-net/src/opts.rs
Original file line number Diff line number Diff line change
@@ -1,92 +1,78 @@
use std::time::Duration;

use crate::Socket;

/// Options for configuring TCP sockets.
/// By default, SO_REUSEADDR is enabled.
#[derive(Copy, Clone)]
#[derive(Default, Debug, Copy, Clone)]
pub struct TcpOpts {
recv_buffer_size: Option<usize>,
send_buffer_size: Option<usize>,
keepalive: bool,
linger: Option<std::time::Duration>,
read_timeout: Option<std::time::Duration>,
write_timeout: Option<std::time::Duration>,
linger: Option<Duration>,
read_timeout: Option<Duration>,
write_timeout: Option<Duration>,
reuse_address: bool,
reuse_port: bool,
no_delay: bool,
}

impl Default for TcpOpts {
fn default() -> Self {
Self {
recv_buffer_size: None,
send_buffer_size: None,
keepalive: false,
linger: None,
read_timeout: None,
write_timeout: None,
reuse_address: true,
reuse_port: false,
no_delay: false,
}
}
}

impl TcpOpts {
/// Creates a new `TcpOpts` with default settings.
pub fn new() -> Self {
TcpOpts::default()
}

/// Sets the receive buffer size for the TCP socket.
pub fn set_recv_buffer_size(mut self, size: usize) -> Self {
pub fn recv_buffer_size(mut self, size: usize) -> Self {
self.recv_buffer_size = Some(size);
self
}

/// Sets the send buffer size for the TCP socket.
pub fn set_send_buffer_size(mut self, size: usize) -> Self {
pub fn send_buffer_size(mut self, size: usize) -> Self {
self.send_buffer_size = Some(size);
self
}

/// Enables or disables the TCP keepalive option.
pub fn set_keepalive(mut self, keepalive: bool) -> Self {
pub fn keepalive(mut self, keepalive: bool) -> Self {
self.keepalive = keepalive;
self
}

/// Sets the linger duration for the TCP socket.
pub fn set_linger(mut self, duration: std::time::Duration) -> Self {
pub fn linger(mut self, duration: Duration) -> Self {
self.linger = Some(duration);
self
}

/// Sets the read timeout for the TCP socket.
pub fn set_read_timeout(mut self, duration: std::time::Duration) -> Self {
pub fn read_timeout(mut self, duration: Duration) -> Self {
self.read_timeout = Some(duration);
self
}

/// Sets the write timeout for the TCP socket.
pub fn set_write_timeout(mut self, duration: std::time::Duration) -> Self {
pub fn write_timeout(mut self, duration: Duration) -> Self {
self.write_timeout = Some(duration);
self
}

/// Sets whether the TCP socket should reuse the address.
pub fn set_reuse_address(mut self, reuse: bool) -> Self {
pub fn reuse_address(mut self, reuse: bool) -> Self {
self.reuse_address = reuse;
self
}

/// Sets whether the TCP socket should reuse the port.
pub fn set_reuse_port(mut self, reuse: bool) -> Self {
pub fn reuse_port(mut self, reuse: bool) -> Self {
self.reuse_port = reuse;
self
}

/// Sets whether the TCP socket should disable Nagle's algorithm (no delay).
pub fn set_no_delay(mut self, no_delay: bool) -> Self {
pub fn no_delay(mut self, no_delay: bool) -> Self {
self.no_delay = no_delay;
self
}
Expand Down
15 changes: 4 additions & 11 deletions compio-net/src/tcp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ impl TcpListener {
/// Binding with a port number of 0 will request that the OS assigns a port
/// to this listener.
pub async fn bind(addr: impl ToSocketAddrsAsync) -> io::Result<Self> {
Self::bind_base(addr, None).await
Self::bind_with_options(addr, TcpOpts::default().reuse_address(true)).await
}

/// Creates a new `TcpListener`, which will be bound to the specified
Expand All @@ -70,14 +70,6 @@ impl TcpListener {
addr: impl ToSocketAddrsAsync,
options: TcpOpts,
) -> io::Result<Self> {
Self::bind_base(addr, Some(options)).await
}

async fn bind_base(
addr: impl ToSocketAddrsAsync,
options: Option<TcpOpts>,
) -> io::Result<Self> {
let options = options.unwrap_or_default();
super::each_addr(addr, |addr| async move {
let sa = SockAddr::from(addr);
let socket = Socket::new(sa.domain(), Type::STREAM, Some(Protocol::TCP)).await?;
Expand Down Expand Up @@ -191,7 +183,6 @@ impl TcpStream {
) -> io::Result<Self> {
use std::net::{Ipv4Addr, Ipv6Addr, SocketAddrV4, SocketAddrV6};

let options = options.unwrap_or_default();
super::each_addr(addr, |addr| async move {
let addr2 = SockAddr::from(addr);
let socket = if cfg!(windows) {
Expand All @@ -209,7 +200,9 @@ impl TcpStream {
} else {
Socket::new(addr2.domain(), Type::STREAM, Some(Protocol::TCP)).await?
};
options.setup_socket(&socket)?;
if let Some(options) = &options {
options.setup_socket(&socket)?;
}
socket.connect_async(&addr2).await?;
Ok(Self { inner: socket })
})
Expand Down
Loading