Skip to content

Commit

Permalink
Extra socket options: SO_ACCEPTCONN, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_K…
Browse files Browse the repository at this point in the history
…EEPINTVL (#830)

* Add get_socket_reuseaddr

* Add function for SO_ACCEPTCONN

* Add TCP_KEEPCNT, TCP_KEEPIDLE and TCP_KEEPINTVL

* Add conditional compilation to SO_ACCEPTCONN
Apple platforms declare the constant, but do not actually implement it.
  • Loading branch information
badeend authored Sep 19, 2023
1 parent d3ae806 commit 4358096
Show file tree
Hide file tree
Showing 4 changed files with 495 additions and 10 deletions.
71 changes: 66 additions & 5 deletions src/backend/libc/net/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -536,6 +536,10 @@ pub(crate) mod sockopt {
use crate::net::AddressFamily;
use crate::net::{Ipv4Addr, Ipv6Addr, SocketType};
use crate::utils::as_mut_ptr;
#[cfg(apple)]
use c::TCP_KEEPALIVE as TCP_KEEPIDLE;
#[cfg(not(any(apple, target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
use c::TCP_KEEPIDLE;
use core::time::Duration;
#[cfg(windows)]
use windows_sys::Win32::Foundation::BOOL;
Expand Down Expand Up @@ -613,6 +617,11 @@ pub(crate) mod sockopt {
)
}

#[inline]
pub(crate) fn get_socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
getsockopt(fd, c::SOL_SOCKET as _, c::SO_REUSEADDR).map(to_bool)
}

#[inline]
pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
setsockopt(
Expand All @@ -635,11 +644,7 @@ pub(crate) mod sockopt {
) -> io::Result<()> {
// Convert `linger` to seconds, rounding up.
let l_linger = if let Some(linger) = linger {
let mut l_linger = linger.as_secs();
if linger.subsec_nanos() != 0 {
l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?;
}
l_linger.try_into().map_err(|_e| io::Errno::INVAL)?
duration_to_secs(linger)?
} else {
0
};
Expand Down Expand Up @@ -847,6 +852,12 @@ pub(crate) mod sockopt {
))
}

#[inline]
#[cfg(not(apple))] // Apple platforms declare the constant, but do not actually implement it.
pub(crate) fn get_socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
getsockopt(fd, c::SOL_SOCKET as _, c::SO_ACCEPTCONN).map(to_bool)
}

#[inline]
pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl)
Expand Down Expand Up @@ -1029,6 +1040,46 @@ pub(crate) mod sockopt {
getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool)
}

#[inline]
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPCNT, count)
}

#[inline]
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPCNT)
}

#[inline]
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
let secs: c::c_uint = duration_to_secs(duration)?;
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE, secs)
}

#[inline]
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
pub(crate) fn get_tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE)?;
Ok(Duration::from_secs(secs as u64))
}

#[inline]
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
let secs: c::c_uint = duration_to_secs(duration)?;
setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPINTVL, secs)
}

#[inline]
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
pub(crate) fn get_tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPINTVL)?;
Ok(Duration::from_secs(secs as u64))
}

#[inline]
fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
c::ip_mreq {
Expand Down Expand Up @@ -1089,4 +1140,14 @@ pub(crate) mod sockopt {
fn to_bool(value: SocketBool) -> bool {
value.0 != 0
}

/// Convert to seconds, rounding up if necessary.
#[inline]
fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
let mut secs = duration.as_secs();
if duration.subsec_nanos() != 0 {
secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
}
T::try_from(secs).map_err(|_e| io::Errno::INVAL)
}
}
61 changes: 56 additions & 5 deletions src/backend/linux_raw/net/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,6 +929,7 @@ pub(crate) mod sockopt {
use c::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD};
use core::time::Duration;
use linux_raw_sys::general::{__kernel_timespec, timeval};
use linux_raw_sys::net::{SO_ACCEPTCONN, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL};

#[inline]
fn getsockopt<T: Copy>(fd: BorrowedFd<'_>, level: u32, optname: u32) -> io::Result<T> {
Expand Down Expand Up @@ -1039,6 +1040,11 @@ pub(crate) mod sockopt {
)
}

#[inline]
pub(crate) fn get_socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
getsockopt(fd, c::SOL_SOCKET as _, c::SO_REUSEADDR).map(to_bool)
}

#[inline]
pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
setsockopt(
Expand All @@ -1061,11 +1067,7 @@ pub(crate) mod sockopt {
) -> io::Result<()> {
// Convert `linger` to seconds, rounding up.
let l_linger = if let Some(linger) = linger {
let mut l_linger = linger.as_secs();
if linger.subsec_nanos() != 0 {
l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?;
}
l_linger.try_into().map_err(|_e| io::Errno::INVAL)?
duration_to_secs(linger)?
} else {
0
};
Expand Down Expand Up @@ -1284,6 +1286,11 @@ pub(crate) mod sockopt {
))
}

#[inline]
pub(crate) fn get_socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
getsockopt(fd, c::SOL_SOCKET as _, SO_ACCEPTCONN).map(to_bool)
}

#[inline]
pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl)
Expand Down Expand Up @@ -1432,6 +1439,40 @@ pub(crate) mod sockopt {
getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool)
}

#[inline]
pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPCNT, count)
}

#[inline]
pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPCNT)
}

#[inline]
pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
let secs: c::c_uint = duration_to_secs(duration)?;
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE, secs)
}

#[inline]
pub(crate) fn get_tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE)?;
Ok(Duration::from_secs(secs as u64))
}

#[inline]
pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
let secs: c::c_uint = duration_to_secs(duration)?;
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPINTVL, secs)
}

#[inline]
pub(crate) fn get_tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPINTVL)?;
Ok(Duration::from_secs(secs as u64))
}

#[inline]
fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
c::ip_mreq {
Expand Down Expand Up @@ -1478,4 +1519,14 @@ pub(crate) mod sockopt {
fn to_bool(value: c::c_uint) -> bool {
value != 0
}

/// Convert to seconds, rounding up if necessary.
#[inline]
fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
let mut secs = duration.as_secs();
if duration.subsec_nanos() != 0 {
secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
}
T::try_from(secs).map_err(|_e| io::Errno::INVAL)
}
}
Loading

0 comments on commit 4358096

Please sign in to comment.