Skip to content

Commit 4358096

Browse files
authored
Extra socket options: SO_ACCEPTCONN, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL (#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.
1 parent d3ae806 commit 4358096

4 files changed

Lines changed: 495 additions & 10 deletions

File tree

src/backend/libc/net/syscalls.rs

Lines changed: 66 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -536,6 +536,10 @@ pub(crate) mod sockopt {
536536
use crate::net::AddressFamily;
537537
use crate::net::{Ipv4Addr, Ipv6Addr, SocketType};
538538
use crate::utils::as_mut_ptr;
539+
#[cfg(apple)]
540+
use c::TCP_KEEPALIVE as TCP_KEEPIDLE;
541+
#[cfg(not(any(apple, target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
542+
use c::TCP_KEEPIDLE;
539543
use core::time::Duration;
540544
#[cfg(windows)]
541545
use windows_sys::Win32::Foundation::BOOL;
@@ -613,6 +617,11 @@ pub(crate) mod sockopt {
613617
)
614618
}
615619

620+
#[inline]
621+
pub(crate) fn get_socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
622+
getsockopt(fd, c::SOL_SOCKET as _, c::SO_REUSEADDR).map(to_bool)
623+
}
624+
616625
#[inline]
617626
pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
618627
setsockopt(
@@ -635,11 +644,7 @@ pub(crate) mod sockopt {
635644
) -> io::Result<()> {
636645
// Convert `linger` to seconds, rounding up.
637646
let l_linger = if let Some(linger) = linger {
638-
let mut l_linger = linger.as_secs();
639-
if linger.subsec_nanos() != 0 {
640-
l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?;
641-
}
642-
l_linger.try_into().map_err(|_e| io::Errno::INVAL)?
647+
duration_to_secs(linger)?
643648
} else {
644649
0
645650
};
@@ -847,6 +852,12 @@ pub(crate) mod sockopt {
847852
))
848853
}
849854

855+
#[inline]
856+
#[cfg(not(apple))] // Apple platforms declare the constant, but do not actually implement it.
857+
pub(crate) fn get_socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
858+
getsockopt(fd, c::SOL_SOCKET as _, c::SO_ACCEPTCONN).map(to_bool)
859+
}
860+
850861
#[inline]
851862
pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
852863
setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl)
@@ -1029,6 +1040,46 @@ pub(crate) mod sockopt {
10291040
getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool)
10301041
}
10311042

1043+
#[inline]
1044+
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
1045+
pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
1046+
setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPCNT, count)
1047+
}
1048+
1049+
#[inline]
1050+
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
1051+
pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
1052+
getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPCNT)
1053+
}
1054+
1055+
#[inline]
1056+
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
1057+
pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
1058+
let secs: c::c_uint = duration_to_secs(duration)?;
1059+
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE, secs)
1060+
}
1061+
1062+
#[inline]
1063+
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
1064+
pub(crate) fn get_tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
1065+
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE)?;
1066+
Ok(Duration::from_secs(secs as u64))
1067+
}
1068+
1069+
#[inline]
1070+
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
1071+
pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
1072+
let secs: c::c_uint = duration_to_secs(duration)?;
1073+
setsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPINTVL, secs)
1074+
}
1075+
1076+
#[inline]
1077+
#[cfg(not(any(target_os = "openbsd", target_os = "haiku", target_os = "nto")))]
1078+
pub(crate) fn get_tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
1079+
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_KEEPINTVL)?;
1080+
Ok(Duration::from_secs(secs as u64))
1081+
}
1082+
10321083
#[inline]
10331084
fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
10341085
c::ip_mreq {
@@ -1089,4 +1140,14 @@ pub(crate) mod sockopt {
10891140
fn to_bool(value: SocketBool) -> bool {
10901141
value.0 != 0
10911142
}
1143+
1144+
/// Convert to seconds, rounding up if necessary.
1145+
#[inline]
1146+
fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
1147+
let mut secs = duration.as_secs();
1148+
if duration.subsec_nanos() != 0 {
1149+
secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
1150+
}
1151+
T::try_from(secs).map_err(|_e| io::Errno::INVAL)
1152+
}
10921153
}

src/backend/linux_raw/net/syscalls.rs

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -929,6 +929,7 @@ pub(crate) mod sockopt {
929929
use c::{SO_RCVTIMEO_NEW, SO_RCVTIMEO_OLD, SO_SNDTIMEO_NEW, SO_SNDTIMEO_OLD};
930930
use core::time::Duration;
931931
use linux_raw_sys::general::{__kernel_timespec, timeval};
932+
use linux_raw_sys::net::{SO_ACCEPTCONN, TCP_KEEPCNT, TCP_KEEPIDLE, TCP_KEEPINTVL};
932933

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

1043+
#[inline]
1044+
pub(crate) fn get_socket_reuseaddr(fd: BorrowedFd<'_>) -> io::Result<bool> {
1045+
getsockopt(fd, c::SOL_SOCKET as _, c::SO_REUSEADDR).map(to_bool)
1046+
}
1047+
10421048
#[inline]
10431049
pub(crate) fn set_socket_broadcast(fd: BorrowedFd<'_>, broadcast: bool) -> io::Result<()> {
10441050
setsockopt(
@@ -1061,11 +1067,7 @@ pub(crate) mod sockopt {
10611067
) -> io::Result<()> {
10621068
// Convert `linger` to seconds, rounding up.
10631069
let l_linger = if let Some(linger) = linger {
1064-
let mut l_linger = linger.as_secs();
1065-
if linger.subsec_nanos() != 0 {
1066-
l_linger = l_linger.checked_add(1).ok_or(io::Errno::INVAL)?;
1067-
}
1068-
l_linger.try_into().map_err(|_e| io::Errno::INVAL)?
1070+
duration_to_secs(linger)?
10691071
} else {
10701072
0
10711073
};
@@ -1284,6 +1286,11 @@ pub(crate) mod sockopt {
12841286
))
12851287
}
12861288

1289+
#[inline]
1290+
pub(crate) fn get_socket_acceptconn(fd: BorrowedFd<'_>) -> io::Result<bool> {
1291+
getsockopt(fd, c::SOL_SOCKET as _, SO_ACCEPTCONN).map(to_bool)
1292+
}
1293+
12871294
#[inline]
12881295
pub(crate) fn set_ip_ttl(fd: BorrowedFd<'_>, ttl: u32) -> io::Result<()> {
12891296
setsockopt(fd, c::IPPROTO_IP as _, c::IP_TTL, ttl)
@@ -1432,6 +1439,40 @@ pub(crate) mod sockopt {
14321439
getsockopt(fd, c::IPPROTO_TCP as _, c::TCP_NODELAY).map(to_bool)
14331440
}
14341441

1442+
#[inline]
1443+
pub(crate) fn set_tcp_keepcnt(fd: BorrowedFd<'_>, count: u32) -> io::Result<()> {
1444+
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPCNT, count)
1445+
}
1446+
1447+
#[inline]
1448+
pub(crate) fn get_tcp_keepcnt(fd: BorrowedFd<'_>) -> io::Result<u32> {
1449+
getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPCNT)
1450+
}
1451+
1452+
#[inline]
1453+
pub(crate) fn set_tcp_keepidle(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
1454+
let secs: c::c_uint = duration_to_secs(duration)?;
1455+
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE, secs)
1456+
}
1457+
1458+
#[inline]
1459+
pub(crate) fn get_tcp_keepidle(fd: BorrowedFd<'_>) -> io::Result<Duration> {
1460+
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPIDLE)?;
1461+
Ok(Duration::from_secs(secs as u64))
1462+
}
1463+
1464+
#[inline]
1465+
pub(crate) fn set_tcp_keepintvl(fd: BorrowedFd<'_>, duration: Duration) -> io::Result<()> {
1466+
let secs: c::c_uint = duration_to_secs(duration)?;
1467+
setsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPINTVL, secs)
1468+
}
1469+
1470+
#[inline]
1471+
pub(crate) fn get_tcp_keepintvl(fd: BorrowedFd<'_>) -> io::Result<Duration> {
1472+
let secs: c::c_uint = getsockopt(fd, c::IPPROTO_TCP as _, TCP_KEEPINTVL)?;
1473+
Ok(Duration::from_secs(secs as u64))
1474+
}
1475+
14351476
#[inline]
14361477
fn to_imr(multiaddr: &Ipv4Addr, interface: &Ipv4Addr) -> c::ip_mreq {
14371478
c::ip_mreq {
@@ -1478,4 +1519,14 @@ pub(crate) mod sockopt {
14781519
fn to_bool(value: c::c_uint) -> bool {
14791520
value != 0
14801521
}
1522+
1523+
/// Convert to seconds, rounding up if necessary.
1524+
#[inline]
1525+
fn duration_to_secs<T: TryFrom<u64>>(duration: Duration) -> io::Result<T> {
1526+
let mut secs = duration.as_secs();
1527+
if duration.subsec_nanos() != 0 {
1528+
secs = secs.checked_add(1).ok_or(io::Errno::INVAL)?;
1529+
}
1530+
T::try_from(secs).map_err(|_e| io::Errno::INVAL)
1531+
}
14811532
}

0 commit comments

Comments
 (0)