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
16pub use tcp_info::TcpInfo;
18
19pub 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}