Skip to content

Commit e988f5d

Browse files
authored
Merge pull request #2 from ssrlive/mywin
fix issues that always timeout in windows
2 parents f5778a4 + ec65bb9 commit e988f5d

File tree

7 files changed

+331
-369
lines changed

7 files changed

+331
-369
lines changed

Cargo.toml

-1
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@ ctrlc2 = { version = "3.5", features = ["termination"] }
1919
env_logger = "0.10"
2020
log = { version = "0.4", features = ["std"] }
2121
mio = { version = "0.8", features = ["log", "os-poll", "net"] }
22-
nix = { version = "0.27", features = ["net"] }
2322
serde = { version = "1.0", features = ["derive"] }
2423
serde_json = "1.0"
2524
simple-error = "0.3"

src/args.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -92,12 +92,12 @@ pub struct Args {
9292

9393
/// send buffer, in bytes (only supported on some platforms;
9494
/// if set too small, a 'resource unavailable' error may occur;
95-
/// affects TCP window-size)
95+
/// affects UDP and TCP window-size)
9696
#[arg(long, default_value = "0", value_name = "bytes", conflicts_with = "server")]
9797
pub send_buffer: usize,
9898

9999
/// receive buffer, in bytes (only supported on some platforms;
100-
/// if set too small, a 'resource unavailable' error may occur; affects TCP window-size)
100+
/// if set too small, a 'resource unavailable' error may occur; affects UDP)
101101
#[arg(long, default_value = "0", value_name = "bytes", conflicts_with = "server")]
102102
pub receive_buffer: usize,
103103

src/client.rs

+13-26
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,16 @@
2121
use crate::{
2222
args,
2323
protocol::{
24-
communication::{receive, send, KEEPALIVE_DURATION},
24+
communication::{receive, send},
2525
messaging::{prepare_begin, prepare_download_configuration, prepare_end, prepare_upload_configuration},
2626
results::{ClientDoneResult, ClientFailedResult},
2727
results::{IntervalResultBox, IntervalResultKind, TcpTestResults, TestResults, UdpTestResults},
2828
},
2929
stream::{tcp, udp, TestStream},
3030
BoxResult,
3131
};
32-
use mio::net::TcpStream;
3332
use std::{
34-
net::{IpAddr, Shutdown, ToSocketAddrs},
33+
net::{IpAddr, Shutdown, TcpStream, ToSocketAddrs},
3534
sync::{
3635
atomic::{AtomicBool, Ordering},
3736
mpsc::channel,
@@ -63,23 +62,16 @@ fn connect_to_server(address: &str, port: &u16) -> BoxResult<TcpStream> {
6362
Err(e) => return Err(Box::new(simple_error::simple_error!("unable to connect: {}", e))),
6463
};
6564

66-
let stream = {
67-
let socket: socket2::Socket = socket2::Socket::from(stream);
68-
let keepalive = socket2::TcpKeepalive::new()
69-
.with_time(KEEPALIVE_DURATION)
70-
.with_interval(KEEPALIVE_DURATION);
71-
cfg_if::cfg_if! {
72-
if #[cfg(unix)] {
73-
let keepalive = keepalive.with_retries(4);
74-
}
75-
}
76-
socket.set_tcp_keepalive(&keepalive)?;
77-
socket.set_nodelay(true)?;
78-
79-
let stream: std::net::TcpStream = socket.into();
65+
log::debug!("connected TCP control-channel to {}", destination);
66+
stream.set_nodelay(true).expect("cannot disable Nagle's algorithm");
8067

81-
TcpStream::from_std(stream)
82-
};
68+
#[cfg(unix)]
69+
{
70+
use crate::protocol::communication::KEEPALIVE_DURATION;
71+
let keepalive_parameters = socket2::TcpKeepalive::new().with_time(KEEPALIVE_DURATION);
72+
let raw_socket = socket2::SockRef::from(&stream);
73+
raw_socket.set_tcp_keepalive(&keepalive_parameters)?;
74+
}
8375

8476
log::info!("connected to server");
8577

@@ -222,13 +214,8 @@ pub fn execute(args: &args::Args) -> BoxResult<()> {
222214
let test_definition = tcp::TcpTestDefinition::new(&download_config)?;
223215
for stream_idx in 0..stream_count {
224216
log::debug!("preparing TCP-receiver for stream {}...", stream_idx);
225-
let test = tcp::receiver::TcpReceiver::new(
226-
test_definition.clone(),
227-
&(stream_idx as u8),
228-
&mut tcp_port_pool,
229-
&server_addr.ip(),
230-
&(download_config["receive_buffer"].as_i64().unwrap() as usize),
231-
)?;
217+
let test =
218+
tcp::receiver::TcpReceiver::new(test_definition.clone(), &(stream_idx as u8), &mut tcp_port_pool, &server_addr.ip())?;
232219
stream_ports.push(test.get_port()?);
233220
parallel_streams.push(Arc::new(Mutex::new(test)));
234221
}

src/protocol/communication.rs

+97-95
Original file line numberDiff line numberDiff line change
@@ -19,22 +19,26 @@
1919
*/
2020

2121
use std::io::{self, Read, Write};
22-
use std::time::Duration;
23-
24-
use mio::net::TcpStream;
25-
use mio::{Events, Interest, Poll};
22+
use std::net::TcpStream;
23+
use std::time::{Duration, Instant};
2624

2725
use crate::BoxResult;
2826

2927
/// how long to wait for keepalive events
3028
/// the communications channels typically exchange data every second, so 2s is reasonable to avoid excess noise
31-
pub const KEEPALIVE_DURATION: Duration = Duration::from_secs(2);
29+
#[cfg(unix)]
30+
pub const KEEPALIVE_DURATION: Duration = Duration::from_secs(3);
3231

3332
/// how long to block on polling operations
3433
const POLL_TIMEOUT: Duration = Duration::from_millis(50);
3534

35+
/// how long to allow for send-operations to complete
36+
const SEND_TIMEOUT: Duration = Duration::from_secs(5);
37+
3638
/// sends JSON data over a client-server communications stream
3739
pub fn send(stream: &mut TcpStream, message: &serde_json::Value) -> BoxResult<()> {
40+
stream.set_write_timeout(Some(POLL_TIMEOUT))?;
41+
3842
let serialised_message = serde_json::to_vec(message)?;
3943

4044
log::debug!(
@@ -46,61 +50,72 @@ pub fn send(stream: &mut TcpStream, message: &serde_json::Value) -> BoxResult<()
4650
let mut output_buffer = vec![0_u8; serialised_message.len() + 2];
4751
output_buffer[..2].copy_from_slice(&(serialised_message.len() as u16).to_be_bytes());
4852
output_buffer[2..].copy_from_slice(serialised_message.as_slice());
49-
Ok(stream.write_all(&output_buffer)?)
53+
54+
let start = Instant::now();
55+
let mut total_bytes_written: usize = 0;
56+
57+
while start.elapsed() < SEND_TIMEOUT {
58+
match stream.write(&output_buffer[total_bytes_written..]) {
59+
Ok(bytes_written) => {
60+
total_bytes_written += bytes_written;
61+
if total_bytes_written == output_buffer.len() {
62+
return Ok(());
63+
}
64+
}
65+
Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock || e.kind() == std::io::ErrorKind::TimedOut => {
66+
// unable to write at the moment; keep trying until the full timeout is reached
67+
continue;
68+
}
69+
Err(e) => {
70+
return Err(Box::new(e));
71+
}
72+
}
73+
}
74+
Err(Box::new(simple_error::simple_error!(
75+
"timed out while attempting to send status-message to {}",
76+
stream.peer_addr()?
77+
)))
5078
}
5179

5280
/// receives the length-count of a pending message over a client-server communications stream
5381
fn receive_length(stream: &mut TcpStream, alive_check: fn() -> bool, results_handler: &mut dyn FnMut() -> BoxResult<()>) -> BoxResult<u16> {
54-
let mio_token = crate::get_global_token();
55-
let mut poll = Poll::new()?;
56-
poll.registry().register(stream, mio_token, Interest::READABLE)?;
57-
let mut events = Events::with_capacity(1); //only interacting with one stream
82+
stream.set_read_timeout(Some(POLL_TIMEOUT)).expect("unable to set TCP read-timeout");
5883

5984
let mut length_bytes_read = 0;
6085
let mut length_spec: [u8; 2] = [0; 2];
61-
let result: BoxResult<u16> = 'exiting: loop {
62-
if !alive_check() {
63-
break 'exiting Ok(0);
64-
}
86+
while alive_check() {
6587
//waiting to find out how long the next message is
6688
results_handler()?; //send any outstanding results between cycles
67-
poll.poll(&mut events, Some(POLL_TIMEOUT))?;
68-
for event in events.iter() {
69-
event.token();
70-
loop {
71-
let size = match stream.read(&mut length_spec[length_bytes_read..]) {
72-
Ok(size) => size,
73-
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
74-
//nothing left to process
75-
break;
76-
}
77-
Err(e) => {
78-
break 'exiting Err(Box::new(e));
79-
}
80-
};
81-
82-
if size == 0 {
83-
if alive_check() {
84-
break 'exiting Err(Box::new(simple_error::simple_error!("connection lost")));
85-
} else {
86-
//shutting down; a disconnect is expected
87-
break 'exiting Err(Box::new(simple_error::simple_error!("local shutdown requested")));
88-
}
89-
}
9089

91-
length_bytes_read += size;
92-
if length_bytes_read == 2 {
93-
let length = u16::from_be_bytes(length_spec);
94-
log::debug!("received length-spec of {} from {}", length, stream.peer_addr()?);
95-
break 'exiting Ok(length);
96-
} else {
97-
log::debug!("received partial length-spec from {}", stream.peer_addr()?);
98-
}
90+
let size = match stream.read(&mut length_spec[length_bytes_read..]) {
91+
Ok(size) => size,
92+
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock || e.kind() == std::io::ErrorKind::TimedOut => {
93+
// nothing available to process
94+
continue;
95+
}
96+
Err(e) => {
97+
return Err(Box::new(e));
98+
}
99+
};
100+
if size == 0 {
101+
if alive_check() {
102+
return Err(Box::new(simple_error::simple_error!("connection lost")));
103+
} else {
104+
// shutting down; a disconnect is expected
105+
return Err(Box::new(simple_error::simple_error!("local shutdown requested")));
99106
}
100107
}
101-
};
102-
poll.registry().deregister(stream)?;
103-
result
108+
109+
length_bytes_read += size;
110+
if length_bytes_read == 2 {
111+
let length = u16::from_be_bytes(length_spec);
112+
log::debug!("received length-spec of {} from {}", length, stream.peer_addr()?);
113+
return Ok(length);
114+
} else {
115+
log::debug!("received partial length-spec from {}", stream.peer_addr()?);
116+
}
117+
}
118+
Err(Box::new(simple_error::simple_error!("system shutting down")))
104119
}
105120

106121
/// receives the data-value of a pending message over a client-server communications stream
@@ -110,62 +125,49 @@ fn receive_payload(
110125
results_handler: &mut dyn FnMut() -> BoxResult<()>,
111126
length: u16,
112127
) -> BoxResult<serde_json::Value> {
113-
let mio_token = crate::get_global_token();
114-
let mut poll = Poll::new()?;
115-
poll.registry().register(stream, mio_token, Interest::READABLE)?;
116-
let mut events = Events::with_capacity(1); //only interacting with one stream
128+
stream.set_read_timeout(Some(POLL_TIMEOUT)).expect("unable to set TCP read-timeout");
117129

118130
let mut bytes_read = 0;
119131
let mut buffer = vec![0_u8; length.into()];
120-
let result: BoxResult<serde_json::Value> = 'exiting: loop {
121-
if !alive_check() {
122-
break 'exiting Ok(serde_json::from_slice(&buffer[0..0])?);
123-
}
132+
while alive_check() {
124133
//waiting to receive the payload
125134
results_handler()?; //send any outstanding results between cycles
126-
poll.poll(&mut events, Some(POLL_TIMEOUT))?;
127-
for event in events.iter() {
128-
event.token();
129-
loop {
130-
let size = match stream.read(&mut buffer[bytes_read..]) {
131-
Ok(size) => size,
132-
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock => {
133-
// nothing left to process
134-
break;
135-
}
136-
Err(e) => {
137-
break 'exiting Err(Box::new(e));
138-
}
139-
};
140-
141-
if size == 0 {
142-
if alive_check() {
143-
break 'exiting Err(Box::new(simple_error::simple_error!("connection lost")));
144-
} else {
145-
// shutting down; a disconnect is expected
146-
break 'exiting Err(Box::new(simple_error::simple_error!("local shutdown requested")));
147-
}
148-
}
149135

150-
bytes_read += size;
151-
if bytes_read == length as usize {
152-
match serde_json::from_slice(&buffer) {
153-
Ok(v) => {
154-
log::debug!("received {:?} from {}", v, stream.peer_addr()?);
155-
break 'exiting Ok(v);
156-
}
157-
Err(e) => {
158-
break 'exiting Err(Box::new(e));
159-
}
160-
}
161-
} else {
162-
log::debug!("received partial payload from {}", stream.peer_addr()?);
136+
let size = match stream.read(&mut buffer[bytes_read..]) {
137+
Ok(size) => size,
138+
Err(ref e) if e.kind() == io::ErrorKind::WouldBlock || e.kind() == std::io::ErrorKind::TimedOut => {
139+
// nothing available to process
140+
continue;
141+
}
142+
Err(e) => {
143+
return Err(Box::new(e));
144+
}
145+
};
146+
if size == 0 {
147+
if alive_check() {
148+
return Err(Box::new(simple_error::simple_error!("connection lost")));
149+
} else {
150+
//shutting down; a disconnect is expected
151+
return Err(Box::new(simple_error::simple_error!("local shutdown requested")));
152+
}
153+
}
154+
155+
bytes_read += size;
156+
if bytes_read == length as usize {
157+
match serde_json::from_slice(&buffer) {
158+
Ok(v) => {
159+
log::debug!("received {:?} from {}", v, stream.peer_addr()?);
160+
return Ok(v);
161+
}
162+
Err(e) => {
163+
return Err(Box::new(e));
163164
}
164165
}
166+
} else {
167+
log::debug!("received partial payload from {}", stream.peer_addr()?);
165168
}
166-
};
167-
poll.registry().deregister(stream)?;
168-
result
169+
}
170+
Err(Box::new(simple_error::simple_error!("system shutting down")))
169171
}
170172

171173
/// handles the full process of retrieving a message from a client-server communications stream

0 commit comments

Comments
 (0)