tcp_info_sys/
lib.rs

1use libc::{c_void, socklen_t};
2use std::mem::MaybeUninit;
3use std::os::fd::AsRawFd;
4
5#[allow(
6    non_camel_case_types,
7    unsafe_op_in_unsafe_fn,
8    clippy::useless_transmute,
9    clippy::missing_safety_doc,
10    clippy::ptr_offset_with_cast
11)]
12mod tcp_info {
13    include!(concat!(env!("OUT_DIR"), "/linux_tcp_info.rs"));
14}
15
16/// The binding to the `tcp_info` struct in the kernel
17pub use tcp_info::TcpInfo;
18
19/// Get TCP_INFO for a socket (with its fd)
20///
21/// ## Examples
22///
23/// ```
24/// use std::io::prelude::*;
25/// use std::net::TcpStream;
26/// use std::os::fd::AsRawFd;
27/// use tcp_info_sys::get_tcp_info;
28///
29/// fn main() -> std::io::Result<()> {
30///     let stream = TcpStream::connect("127.0.0.1:12345")?;
31///     let tcp_info = get_tcp_info(stream.as_raw_fd())?;
32///     println!("TCP Info: {:?}", tcp_info);
33///     Ok(())
34/// }
35/// ```
36pub fn get_tcp_info<T: AsRawFd>(sk_fd: T) -> Result<TcpInfo, std::io::Error> {
37    let mut tcp_info: GetSockOptStruct<TcpInfo> = GetSockOptStruct::uninit();
38    let res = unsafe {
39        libc::getsockopt(
40            sk_fd.as_raw_fd(),
41            libc::SOL_TCP,
42            libc::TCP_INFO,
43            tcp_info.ffi_ptr(),
44            tcp_info.ffi_len(),
45        )
46    };
47    if res == -1 {
48        Err(std::io::Error::last_os_error())
49    } else {
50        let tcp_info = tcp_info.assume_init();
51        Ok(tcp_info)
52    }
53}
54
55struct GetSockOptStruct<T> {
56    len: socklen_t,
57    val: MaybeUninit<T>,
58}
59
60impl<T> GetSockOptStruct<T> {
61    fn uninit() -> Self {
62        GetSockOptStruct {
63            len: std::mem::size_of::<T>() as socklen_t,
64            val: MaybeUninit::uninit(),
65        }
66    }
67
68    fn ffi_ptr(&mut self) -> *mut c_void {
69        self.val.as_mut_ptr() as *mut c_void
70    }
71
72    fn ffi_len(&mut self) -> *mut socklen_t {
73        &mut self.len
74    }
75
76    fn assume_init(self) -> T {
77        assert_eq!(
78            self.len as usize,
79            std::mem::size_of::<T>(),
80            "invalid getsockopt implementation"
81        );
82        unsafe { self.val.assume_init() }
83    }
84}