Skip to content

Commit 5a3ac8d

Browse files
bors[bot]Fensteer
andcommitted
Merge #972
972: Add support of TCP_CONGESTION for setsockopt r=asomers a=Fensteer Implementation proposal for support of TCP_CONGESTION param for `setsockopt`and `getsockopt` with the CString type. Co-authored-by: Fensteer <[email protected]>
2 parents 307cc90 + b75d31d commit 5a3ac8d

File tree

3 files changed

+91
-0
lines changed

3 files changed

+91
-0
lines changed

CHANGELOG.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,11 @@ This project adheres to [Semantic Versioning](http://semver.org/).
55

66
## [Unreleased]
77
### Added
8+
- Added support of CString type in `setsockopt`.
9+
([#972](https://github.com/nix-rust/nix/pull/972))
10+
- Added option `TCP_CONGESTION` in `setsockopt`.
11+
([#972](https://github.com/nix-rust/nix/pull/972))
12+
813
### Changed
914
### Fixed
1015
### Removed

src/sys/socket/sockopt.rs

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,14 @@ use sys::time::TimeVal;
55
use libc::{self, c_int, uint8_t, c_void, socklen_t};
66
use std::mem;
77
use std::os::unix::io::RawFd;
8+
use std::ffi::{OsStr, OsString};
9+
#[cfg(target_family = "unix")]
10+
use std::os::unix::ffi::OsStrExt;
11+
12+
// Constants
13+
// TCP_CA_NAME_MAX isn't defined in user space include files
14+
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
15+
const TCP_CA_NAME_MAX: usize = 16;
816

917
/// Helper for implementing `SetSockOpt` for a given socket option. See
1018
/// [`::sys::socket::SetSockOpt`](sys/socket/trait.SetSockOpt.html).
@@ -152,6 +160,10 @@ macro_rules! sockopt_impl {
152160
sockopt_impl!(Both, $name, $level, $flag, usize, GetUsize, SetUsize);
153161
};
154162

163+
(Both, $name:ident, $level:path, $flag:path, OsString<$array:ty>) => {
164+
sockopt_impl!(Both, $name, $level, $flag, OsString, GetOsString<$array>, SetOsString);
165+
};
166+
155167
/*
156168
* Matchers with generic getter types must be placed at the end, so
157169
* they'll only match _after_ specialized matchers fail
@@ -257,6 +269,8 @@ sockopt_impl!(Both, BindAny, libc::IPPROTO_IP, libc::IP_BINDANY, bool);
257269
sockopt_impl!(Both, Mark, libc::SOL_SOCKET, libc::SO_MARK, u32);
258270
#[cfg(any(target_os = "android", target_os = "linux"))]
259271
sockopt_impl!(Both, PassCred, libc::SOL_SOCKET, libc::SO_PASSCRED, bool);
272+
#[cfg(any(target_os = "freebsd", target_os = "linux"))]
273+
sockopt_impl!(Both, TcpCongestion, libc::IPPROTO_TCP, libc::TCP_CONGESTION, OsString<[u8; TCP_CA_NAME_MAX]>);
260274

261275
/*
262276
*
@@ -478,6 +492,53 @@ unsafe impl<'a> Set<'a, usize> for SetUsize {
478492
}
479493
}
480494

495+
/// Getter for a `OsString` value.
496+
struct GetOsString<T: AsMut<[u8]>> {
497+
len: socklen_t,
498+
val: T,
499+
}
500+
501+
unsafe impl<T: AsMut<[u8]>> Get<OsString> for GetOsString<T> {
502+
unsafe fn blank() -> Self {
503+
GetOsString {
504+
len: mem::size_of::<T>() as socklen_t,
505+
val: mem::zeroed(),
506+
}
507+
}
508+
509+
fn ffi_ptr(&mut self) -> *mut c_void {
510+
&mut self.val as *mut T as *mut c_void
511+
}
512+
513+
fn ffi_len(&mut self) -> *mut socklen_t {
514+
&mut self.len
515+
}
516+
517+
unsafe fn unwrap(mut self) -> OsString {
518+
OsStr::from_bytes(self.val.as_mut()).to_owned()
519+
}
520+
}
521+
522+
/// Setter for a `OsString` value.
523+
struct SetOsString<'a> {
524+
val: &'a OsStr,
525+
}
526+
527+
unsafe impl<'a> Set<'a, OsString> for SetOsString<'a> {
528+
fn new(val: &'a OsString) -> SetOsString {
529+
SetOsString { val: val.as_os_str() }
530+
}
531+
532+
fn ffi_ptr(&self) -> *const c_void {
533+
self.val.as_bytes().as_ptr() as *const c_void
534+
}
535+
536+
fn ffi_len(&self) -> socklen_t {
537+
self.val.len() as socklen_t
538+
}
539+
}
540+
541+
481542
#[cfg(test)]
482543
mod test {
483544
#[cfg(any(target_os = "android", target_os = "linux"))]

test/sys/test_sockopt.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,3 +13,28 @@ fn test_so_buf() {
1313
let actual = getsockopt(fd, sockopt::RcvBuf).unwrap();
1414
assert!(actual >= bufsize);
1515
}
16+
17+
// The CI doesn't supported getsockopt and setsockopt on emulated processors.
18+
// It's beleived that a QEMU issue, the tests run ok on a fully emulated system.
19+
// Current CI just run the binary with QEMU but the Kernel remains the same as the host.
20+
// So the syscall doesn't work properly unless the kernel is also emulated.
21+
#[test]
22+
#[cfg(all(
23+
any(target_arch = "x86", target_arch = "x86_64"),
24+
any(target_os = "freebsd", target_os = "linux")
25+
))]
26+
fn test_tcp_congestion() {
27+
use std::ffi::OsString;
28+
29+
let fd = socket(AddressFamily::Inet, SockType::Stream, SockFlag::empty(), None).unwrap();
30+
31+
let val = getsockopt(fd, sockopt::TcpCongestion).unwrap();
32+
setsockopt(fd, sockopt::TcpCongestion, &val).unwrap();
33+
34+
setsockopt(fd, sockopt::TcpCongestion, &OsString::from("tcp_congestion_does_not_exist")).unwrap_err();
35+
36+
assert_eq!(
37+
getsockopt(fd, sockopt::TcpCongestion).unwrap(),
38+
val
39+
);
40+
}

0 commit comments

Comments
 (0)