1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
use super::NetWriter;
use super::Transport;
#[cfg(unix)]
use std::os::unix::io::AsRawFd;
impl NetWriter {
/// Return Some(pending_bytes) if supported, None if unsupported, Err on syscall error.
pub(super) fn os_sendq_len(&self) -> Result<Option<usize>, std::io::Error> {
#[cfg(unix)]
{
if let Transport::Tcp(stream) = &self.transport {
let fd = stream.as_raw_fd();
// Linux: ioctl TIOCOUTQ (get number of unsent bytes in socket send queue)
#[cfg(target_os = "linux")]
unsafe {
let mut outq: libc::c_int = 0;
let rc = libc::ioctl(fd, libc::TIOCOUTQ, &mut outq);
if rc == -1 {
return Err(std::io::Error::last_os_error());
}
return Ok(Some(outq as usize));
}
// Darwin/BSD: getsockopt(SOL_SOCKET, SO_NWRITE)
#[cfg(any(
target_os = "macos",
target_os = "ios",
target_os = "freebsd",
target_os = "openbsd",
target_os = "netbsd"
))]
unsafe {
let mut n: libc::c_int = 0;
let mut len: libc::socklen_t = std::mem::size_of::<libc::c_int>() as _;
#[allow(non_upper_case_globals)]
let opt = libc::SO_NWRITE;
let rc = libc::getsockopt(
fd,
libc::SOL_SOCKET,
opt,
&mut n as *mut _ as *mut _,
&mut len,
);
if rc == -1 {
return Err(std::io::Error::last_os_error());
}
return Ok(Some(n as usize));
}
}
}
Ok(None)
}
/// 返回 SO_SNDBUF(内核发送缓冲区大小,字节)。不支持的平台返回 None。
pub(super) fn os_sndbuf_size(&self) -> Result<Option<usize>, std::io::Error> {
#[cfg(unix)]
{
use std::os::unix::io::AsRawFd;
if let Transport::Tcp(stream) = &self.transport {
let fd = stream.as_raw_fd();
unsafe {
let mut n: libc::c_int = 0;
let mut len: libc::socklen_t = std::mem::size_of::<libc::c_int>() as _;
let rc = libc::getsockopt(
fd,
libc::SOL_SOCKET,
libc::SO_SNDBUF,
&mut n as *mut _ as *mut _,
&mut len,
);
if rc == -1 {
return Err(std::io::Error::last_os_error());
}
return Ok(Some(n as usize));
}
}
}
Ok(None)
}
/// 获取(并缓存)SO_SNDBUF;测试可覆写。
pub(super) fn get_cached_sndbuf(&mut self) -> Option<usize> {
#[cfg(test)]
{
if let Some(v) = self.sndbuf_override {
return Some(v);
}
}
if let Some(v) = self.cached_sndbuf {
return Some(v);
}
if let Ok(Some(v)) = self.os_sndbuf_size() {
self.cached_sndbuf = Some(v);
return Some(v);
}
None
}
/// 读取 send-queue 与 sndbuf(测试下支持覆盖)。
pub(super) fn peek_kernel_queues(&mut self) -> (Option<usize>, Option<usize>) {
let pending = {
#[cfg(test)]
{
if let Some(p) = self.pending_override {
Some(p)
} else {
self.os_sendq_len().unwrap_or(None)
}
}
#[cfg(not(test))]
{
self.os_sendq_len().unwrap_or(None)
}
};
#[allow(unused_mut)]
let mut sndbuf = self.get_cached_sndbuf();
#[cfg(test)]
{
if self.sndbuf_override.is_some() {
sndbuf = self.sndbuf_override;
}
}
(pending, sndbuf)
}
}