Skip to content

Commit

Permalink
Add TCP_KEEPCNT, TCP_KEEPIDLE and TCP_KEEPINTVL
Browse files Browse the repository at this point in the history
  • Loading branch information
badeend committed Sep 17, 2023
1 parent 0cdf0cc commit ebf5682
Show file tree
Hide file tree
Showing 4 changed files with 388 additions and 11 deletions.
54 changes: 49 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(apple))]
use c::TCP_KEEPIDLE;
use core::time::Duration;
#[cfg(windows)]
use windows_sys::Win32::Foundation::BOOL;
Expand Down Expand Up @@ -640,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 @@ -1039,6 +1039,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 _, c::TCP_KEEPCNT, count)
}

#[inline]
pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
getsockopt(fd, c::IPPROTO_TCP as _, c::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 _, c::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 _, 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 @@ -1099,4 +1133,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)
}
}
52 changes: 46 additions & 6 deletions src/backend/linux_raw/net/syscalls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -929,7 +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;
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 @@ -1067,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 @@ -1443,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 @@ -1489,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 ebf5682

Please sign in to comment.