diff --git a/src/net/tcp/listener.rs b/src/net/tcp/listener.rs index 6a2bab154..8e8f6eeeb 100644 --- a/src/net/tcp/listener.rs +++ b/src/net/tcp/listener.rs @@ -16,7 +16,10 @@ use crate::net::TcpStream; #[cfg(any(unix, target_os = "hermit"))] use crate::sys::tcp::set_reuseaddr; #[cfg(not(target_os = "wasi"))] -use crate::sys::tcp::{bind, listen, new_for_addr}; +use crate::sys::{ + tcp::{bind, listen, new_for_addr}, + LISTEN_BACKLOG_SIZE, +}; use crate::{event, sys, Interest, Registry, Token}; /// A structure representing a socket server @@ -78,7 +81,7 @@ impl TcpListener { set_reuseaddr(&listener.inner, true)?; bind(&listener.inner, addr)?; - listen(&listener.inner, 1024)?; + listen(&listener.inner, LISTEN_BACKLOG_SIZE)?; Ok(listener) } diff --git a/src/sys/mod.rs b/src/sys/mod.rs index 8bfbdd9b8..6ec1e9bf7 100644 --- a/src/sys/mod.rs +++ b/src/sys/mod.rs @@ -80,3 +80,68 @@ cfg_not_os_poll! { pub use self::unix::SourceFd; } } + +/// Define the `listen` backlog parameters as in the standard library. This +/// helps avoid hardcoded unsynchronized values and allows better control of +/// default values depending on the target. +/// +/// Selecting a “valid” default value can be tricky due to: +/// +/// - It often serves only as a hint and may be rounded, trimmed, or ignored by +/// the OS. +/// +/// - It is sometimes provided as a "magic" value, for example, -1. This +/// value is undocumented and not standard, but it is often used to represent +/// the largest possible backlog size. This happens due to signed/unsigned +/// conversion and rounding to the upper bound performed by the OS. +/// +/// - Default values vary depending on the OS and its version. Common defaults +/// include: -1, 128, 1024, and 4096. +/// +// Here is the original code from the standard library +// https://github.com/rust-lang/rust/blob/4f808ba6bf9f1c8dde30d009e73386d984491587/library/std/src/os/unix/net/listener.rs#L72 +// +#[allow(dead_code)] +#[cfg(any( + target_os = "windows", + target_os = "redox", + target_os = "espidf", + target_os = "horizon" +))] +pub(crate) const LISTEN_BACKLOG_SIZE: i32 = 128; + +/// This is a special case for some target(s) supported by `mio`. This value +/// is needed because `libc::SOMAXCON` (used as a fallback for unknown targets) +/// is not implemented for them. Feel free to update this if the `libc` crate +/// changes. +#[allow(dead_code)] +#[cfg(target_os = "hermit")] +pub(crate) const LISTEN_BACKLOG_SIZE: i32 = 1024; + +#[allow(dead_code)] +#[cfg(any( + // Silently capped to `/proc/sys/net/core/somaxconn`. + target_os = "linux", + // Silently capped to `kern.ipc.soacceptqueue`. + target_os = "freebsd", + // Silently capped to `kern.somaxconn sysctl`. + target_os = "openbsd", + // Silently capped to the default 128. + target_vendor = "apple", +))] +pub(crate) const LISTEN_BACKLOG_SIZE: i32 = -1; + +#[allow(dead_code)] +#[cfg(not(any( + target_os = "windows", + target_os = "redox", + target_os = "espidf", + target_os = "horizon", + target_os = "linux", + target_os = "freebsd", + target_os = "openbsd", + target_os = "wasi", + target_os = "hermit", + target_vendor = "apple", +)))] +pub(crate) const LISTEN_BACKLOG_SIZE: i32 = libc::SOMAXCONN; diff --git a/src/sys/shell/tcp.rs b/src/sys/shell/tcp.rs index b61a4ffc9..4f7326ab8 100644 --- a/src/sys/shell/tcp.rs +++ b/src/sys/shell/tcp.rs @@ -17,7 +17,7 @@ pub(crate) fn connect(_: &net::TcpStream, _: SocketAddr) -> io::Result<()> { } #[cfg(not(target_os = "wasi"))] -pub(crate) fn listen(_: &net::TcpListener, _: u32) -> io::Result<()> { +pub(crate) fn listen(_: &net::TcpListener, _: i32) -> io::Result<()> { os_required!(); } diff --git a/src/sys/unix/tcp.rs b/src/sys/unix/tcp.rs index 4dbdb73c5..a3560c225 100644 --- a/src/sys/unix/tcp.rs +++ b/src/sys/unix/tcp.rs @@ -1,4 +1,3 @@ -use std::convert::TryInto; use std::io; use std::mem::{size_of, MaybeUninit}; use std::net::{self, SocketAddr}; @@ -38,8 +37,7 @@ pub(crate) fn connect(socket: &net::TcpStream, addr: SocketAddr) -> io::Result<( } } -pub(crate) fn listen(socket: &net::TcpListener, backlog: u32) -> io::Result<()> { - let backlog = backlog.try_into().unwrap_or(i32::MAX); +pub(crate) fn listen(socket: &net::TcpListener, backlog: i32) -> io::Result<()> { syscall!(listen(socket.as_raw_fd(), backlog))?; Ok(()) } diff --git a/src/sys/unix/uds/listener.rs b/src/sys/unix/uds/listener.rs index 5b4219a29..d3c3eee3b 100644 --- a/src/sys/unix/uds/listener.rs +++ b/src/sys/unix/uds/listener.rs @@ -8,6 +8,7 @@ use std::{io, mem}; use crate::net::UnixStream; use crate::sys::unix::net::new_socket; use crate::sys::unix::uds::{path_offset, unix_addr}; +use crate::sys::LISTEN_BACKLOG_SIZE; pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result { let fd = new_socket(libc::AF_UNIX, libc::SOCK_STREAM)?; @@ -16,7 +17,7 @@ pub(crate) fn bind_addr(address: &SocketAddr) -> io::Result { let (unix_address, addrlen) = unix_addr(address); let sockaddr = &unix_address as *const libc::sockaddr_un as *const libc::sockaddr; syscall!(bind(fd, sockaddr, addrlen))?; - syscall!(listen(fd, 1024))?; + syscall!(listen(fd, LISTEN_BACKLOG_SIZE))?; Ok(socket) } diff --git a/src/sys/windows/tcp.rs b/src/sys/windows/tcp.rs index 4f77d5d6e..a59389676 100644 --- a/src/sys/windows/tcp.rs +++ b/src/sys/windows/tcp.rs @@ -46,11 +46,9 @@ pub(crate) fn connect(socket: &net::TcpStream, addr: SocketAddr) -> io::Result<( } } -pub(crate) fn listen(socket: &net::TcpListener, backlog: u32) -> io::Result<()> { - use std::convert::TryInto; +pub(crate) fn listen(socket: &net::TcpListener, backlog: i32) -> io::Result<()> { use WinSock::listen; - let backlog = backlog.try_into().unwrap_or(i32::MAX); syscall!( listen(socket.as_raw_socket() as _, backlog), PartialEq::eq,