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