Skip to content

feat: Get tcp_info structure #2615

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions changelog/2615.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Added `TCP_INFO` sockopt to read TCP socket information on _linux_.
11 changes: 11 additions & 0 deletions src/sys/socket/sockopt.rs
Original file line number Diff line number Diff line change
@@ -1268,6 +1268,17 @@ sockopt_impl!(
libc::SO_EXCLBIND,
bool
);
#[cfg(target_os = "linux")]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi there

However, I'd like advice on how to resolve the latter.

If uClibc has that symbol, you can add it to the libc crate. Otherwise, we need to filter it out:

Suggested change
#[cfg(target_os = "linux")]
#[cfg(all(target_os = "linux", not(target_env = "uclibc")))]

Copy link
Author

@b-parikh b-parikh Mar 28, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added tcp_info to the uClibc symbols in libc: rust-lang/libc@4a34937. It looks like the CI still isn't happy though, do you know if that's because the libc change isn't published to crates.io yet?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That PR rust-lang/libc#4347 added it to the main branch, Nix uses the libc-0.2 branch, so you need to ask the maintainer to backport it to this branch.

Once the backport PR gets merged, update the Cargo.toml file to use it from git:

nix/Cargo.toml

Line 31 in ea012be

libc = { version = "0.2.171", features = ["extra_traits"] }

- libc = { version = "0.2.171", features = ["extra_traits"] } 
+ libc = { git = "https://github.com/rust-lang/libc", rev = "the commit includes your libc PR", features = ... }

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it, thanks! I'll update this PR when the change is backported.

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm a bit confused by this comment. The commit was backported to the 0.2 branch: rust-lang/libc@5a1f5f2. Why would pinning the version of the crate in the nix Cargo.toml file be the correct approach? I don't think that should get committed, right?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Emm, I don't think I understand what you mean, could you please elaborate a bit?

#[cfg(feature = "net")]
sockopt_impl!(
#[cfg_attr(docsrs, doc(cfg(feature = "net")))]
/// Get tcp_info structure.
TcpInfo,
GetOnly,
libc::SOL_TCP,
libc::TCP_INFO,
libc::tcp_info
);

#[allow(missing_docs)]
// Not documented by Linux!
17 changes: 17 additions & 0 deletions test/sys/test_sockopt.rs
Original file line number Diff line number Diff line change
@@ -568,6 +568,23 @@ fn test_ipv6_tclass() {
assert_eq!(getsockopt(&fd, sockopt::Ipv6TClass).unwrap(), class);
}

#[test]
#[cfg(target_os = "linux")]
fn test_tcp_info() {
let fd = socket(
AddressFamily::Inet6,
SockType::Stream,
SockFlag::empty(),
SockProtocol::Tcp,
)
.unwrap();
let tcp_info = getsockopt(&fd, sockopt::TcpInfo).unwrap();
// Silly assert for the sake of having one in the test.
// There should be no retransmits because nothing is sent through the
// socket in the first place.
assert_eq!(tcp_info.tcpi_retransmits, 0);
}

#[test]
#[cfg(target_os = "freebsd")]
fn test_receive_timestamp() {
Loading