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
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
// ---------------- [ File: bitcoin-sock/src/wait.rs ]
crate::ix!();
impl Sock {
/// Block until the socket becomes ready for the requested events.
///
/// *Uses `poll(2)` on Linux when `USE_POLL` is enabled, otherwise
/// falls back to a classic `select(2)` implementation that honours
/// the `is_selectable_socket` constraint.*
pub fn wait(
&self,
timeout: Duration,
requested: SockEvent,
occurred: *mut SockEvent,
) -> bool {
#[cfg(all(target_os = "linux", feature = "use_poll"))]
{
use libc::{poll, pollfd, POLLIN, POLLOUT};
let mut fd = pollfd {
fd: self.socket(),
events: 0,
revents: 0,
};
if requested & SOCK_RECV as u8 != 0 {
fd.events |= POLLIN;
}
if requested & SOCK_SEND as u8 != 0 {
fd.events |= POLLOUT;
}
let ms = timeout.as_millis() as libc::c_int;
let ret = unsafe { poll(&mut fd, 1, ms) };
if ret == SOCKET_ERROR {
return false;
}
unsafe {
if !occurred.is_null() {
*occurred = 0;
if fd.revents & POLLIN != 0 {
*occurred |= SOCK_RECV as u8;
}
if fd.revents & POLLOUT != 0 {
*occurred |= SOCK_SEND as u8;
}
}
}
true
}
#[cfg(not(all(target_os = "linux", feature = "use_poll")))]
{
use libc::{
fd_set, select, timeval, FD_ISSET, FD_SET, FD_SETSIZE, FD_ZERO, timeval as TimeVal,
};
if !is_selectable_socket(self.socket()) {
return false;
}
unsafe {
let mut recv_set: fd_set = std::mem::zeroed();
let mut send_set: fd_set = std::mem::zeroed();
FD_ZERO(&mut recv_set);
FD_ZERO(&mut send_set);
if requested & SOCK_RECV as u8 != 0 {
FD_SET(*self.socket(), &mut recv_set);
}
if requested & SOCK_SEND as u8 != 0 {
FD_SET(*self.socket(), &mut send_set);
}
let mut tv = TimeVal {
tv_sec: timeout.as_seconds_f32() as libc::time_t,
tv_usec: (timeout.subsec_microseconds()) as libc::suseconds_t,
};
let ret = select(
*self.socket() + 1,
&mut recv_set,
&mut send_set,
std::ptr::null_mut(),
&mut tv,
);
if ret == SOCKET_ERROR {
return false;
}
if !occurred.is_null() {
*occurred = 0;
if FD_ISSET(*self.socket(), &mut recv_set) {
*occurred |= SOCK_RECV as u8;
}
if FD_ISSET(*self.socket(), &mut send_set) {
*occurred |= SOCK_SEND as u8;
}
}
true
}
}
}
}
// -----------------------------------------------------------------------------
// Specification – edge‑to‑edge readiness tests
// -----------------------------------------------------------------------------
#[cfg(test)]
mod sock_wait_spec {
use super::*;
#[cfg(unix)]
fn make_socket_pair() -> (libc::c_int, libc::c_int) {
let mut sv = [-1; 2];
let ret =
unsafe { libc::socketpair(libc::AF_UNIX, libc::SOCK_STREAM, 0, sv.as_mut_ptr()) };
assert_eq!(ret, 0, "socketpair() failed");
(sv[0], sv[1])
}
#[traced_test]
fn wait_detects_readiness() {
serialize_fds!(); // <— add this
#[cfg(unix)]
{
use std::ptr;
let (a, b) = make_socket_pair();
let sock_a = Sock::from(a);
let sock_b = Sock::from(b);
// Prepare: write a byte so that `sock_a` becomes readable.
let one = b"X";
let sent = sock_b.send(one.as_ptr() as *const _, 1, 0);
assert_eq!(sent, 1);
// Now wait for RECV on `sock_a`.
let mut occurred: SockEvent = 0;
let ok = sock_a.wait(Duration::seconds(1), SOCK_RECV as u8, &mut occurred);
assert!(ok, "wait() should succeed");
assert!(occurred & SOCK_RECV as u8 != 0, "read readiness expected");
}
info!("wait_detects_readiness passed");
}
}