tor_rtcompat/impls/
streamops.rs
1use std::io;
4
5#[cfg(target_os = "linux")]
6use {
7 std::mem,
8 std::os::fd::{AsRawFd, RawFd},
9};
10
11use crate::StreamOps;
12#[cfg(not(target_os = "linux"))]
13use crate::UnsupportedStreamOp;
14
15#[derive(Clone, Copy)]
19#[cfg(target_os = "linux")]
20pub(crate) struct TcpSockFd(RawFd);
21
22#[cfg(target_os = "linux")]
23impl AsRawFd for TcpSockFd {
24 fn as_raw_fd(&self) -> RawFd {
25 self.0
26 }
27}
28
29#[cfg(target_os = "linux")]
30impl TcpSockFd {
31 pub(crate) fn from_fd(fd: &impl AsRawFd) -> Self {
33 Self(fd.as_raw_fd())
34 }
35}
36
37#[cfg(target_os = "linux")]
38impl StreamOps for TcpSockFd {
39 fn set_tcp_notsent_lowat(&self, notsent_lowat: u32) -> io::Result<()> {
40 set_tcp_notsent_lowat(self, notsent_lowat)
41 }
42
43 fn new_handle(&self) -> Box<dyn StreamOps + Send + Unpin> {
44 Box::new(*self)
45 }
46}
47
48#[cfg(target_os = "linux")]
52pub(crate) fn set_tcp_notsent_lowat<S: AsRawFd>(sock: &S, notsent_lowat: u32) -> io::Result<()> {
53 let fd = sock.as_raw_fd();
54 let res = unsafe {
55 libc::setsockopt(
56 fd,
57 libc::SOL_TCP,
58 libc::TCP_NOTSENT_LOWAT,
59 ¬sent_lowat as *const _ as *const libc::c_void,
60 mem::size_of_val(¬sent_lowat) as libc::socklen_t,
61 )
62 };
63
64 if res != 0 {
65 return Err(io::Error::last_os_error());
66 }
67
68 Ok(())
69}
70
71#[cfg(not(target_os = "linux"))]
75pub(crate) fn set_tcp_notsent_lowat<S>(_sock: &S, _notsent_lowat: u32) -> io::Result<()> {
76 Err(UnsupportedStreamOp::new(
77 "set_tcp_notsent_lowat",
78 "unsupported on non-linux platforms",
79 )
80 .into())
81}
82
83#[cfg(test)]
84mod tests {
85 #![allow(clippy::bool_assert_comparison)]
87 #![allow(clippy::clone_on_copy)]
88 #![allow(clippy::dbg_macro)]
89 #![allow(clippy::mixed_attributes_style)]
90 #![allow(clippy::print_stderr)]
91 #![allow(clippy::print_stdout)]
92 #![allow(clippy::single_char_pattern)]
93 #![allow(clippy::unwrap_used)]
94 #![allow(clippy::unchecked_duration_subtraction)]
95 #![allow(clippy::useless_vec)]
96 #![allow(clippy::needless_pass_by_value)]
97 use super::*;
99 use std::net::TcpListener;
100
101 #[cfg(target_os = "linux")]
102 pub(crate) fn get_tcp_notsent_lowat<S: AsRawFd>(sock: &S) -> io::Result<u32> {
103 let fd = sock.as_raw_fd();
104 let mut notsent_lowat = 0;
105 let mut socklen: u32 = mem::size_of_val(¬sent_lowat) as libc::socklen_t;
106 let res = unsafe {
107 libc::getsockopt(
108 fd,
109 libc::SOL_TCP,
110 libc::TCP_NOTSENT_LOWAT,
111 &mut notsent_lowat as *mut _ as *mut libc::c_void,
112 &mut socklen as *mut _,
113 )
114 };
115
116 if res != 0 {
117 return Err(io::Error::last_os_error());
118 }
119
120 Ok(notsent_lowat)
121 }
122
123 #[test]
124 #[cfg(target_os = "linux")]
125 #[cfg_attr(miri, ignore)] fn tcp_notsent_lowat() {
127 let sock = TcpListener::bind("127.0.0.1:0").unwrap();
128 set_tcp_notsent_lowat(&sock, 1337).unwrap();
129 let notsent_lowat = get_tcp_notsent_lowat(&sock).unwrap();
130 assert_eq!(1337, notsent_lowat);
131 }
132
133 #[test]
134 #[cfg(not(target_os = "linux"))]
135 #[cfg_attr(miri, ignore)] fn tcp_notsent_lowat() {
137 let sock = TcpListener::bind("127.0.0.1:0").unwrap();
138 assert!(set_tcp_notsent_lowat(&sock, 1337).is_err());
140 }
141}