Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| b2be4c2cb7 |
Generated
+1
-1
@@ -436,7 +436,7 @@ dependencies = [
|
||||
|
||||
[[package]]
|
||||
name = "dosh"
|
||||
version = "1.0.0-rc21"
|
||||
version = "1.0.0-rc22"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"base64",
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "dosh"
|
||||
version = "1.0.0-rc21"
|
||||
version = "1.0.0-rc22"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
|
||||
|
||||
+39
-2
@@ -19,7 +19,7 @@ use crate::protocol::{
|
||||
self, CLIENT_TO_SERVER, PacketKind, ReplayWindow, SERVER_TO_CLIENT, StreamClose, StreamData,
|
||||
StreamOpen, StreamOpenOk, StreamOpenReject, StreamWindowAdjust,
|
||||
};
|
||||
use crate::udp::is_transient_udp_send_error;
|
||||
use crate::udp::{is_transient_udp_error, is_transient_udp_send_error};
|
||||
use anyhow::{Result, anyhow, bail};
|
||||
use std::collections::{BTreeMap, HashMap, HashSet, VecDeque};
|
||||
use std::net::SocketAddr;
|
||||
@@ -852,7 +852,11 @@ impl DoshTransport {
|
||||
pub async fn recv(&mut self) -> Result<SessionEvent> {
|
||||
let mut buf = vec![0u8; 65535];
|
||||
loop {
|
||||
let (n, peer) = self.socket.recv_from(&mut buf).await?;
|
||||
let (n, peer) = match self.socket.recv_from(&mut buf).await {
|
||||
Ok(value) => value,
|
||||
Err(err) if transport_recv_error_is_retryable(&err) => continue,
|
||||
Err(err) => return Err(err.into()),
|
||||
};
|
||||
let packet = match protocol::decode(&buf[..n]) {
|
||||
Ok(packet) => packet,
|
||||
Err(_) => continue,
|
||||
@@ -984,6 +988,10 @@ impl DoshTransport {
|
||||
}
|
||||
}
|
||||
|
||||
fn transport_recv_error_is_retryable(err: &std::io::Error) -> bool {
|
||||
is_transient_udp_error(err)
|
||||
}
|
||||
|
||||
fn initial_stream_id(role: SessionRole) -> u64 {
|
||||
match role {
|
||||
SessionRole::Client => 1,
|
||||
@@ -1033,6 +1041,35 @@ mod tests {
|
||||
assert!(service_target("../bad").is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn transport_recv_retries_network_churn_errors() {
|
||||
for kind in [
|
||||
std::io::ErrorKind::Interrupted,
|
||||
std::io::ErrorKind::TimedOut,
|
||||
std::io::ErrorKind::WouldBlock,
|
||||
] {
|
||||
let err = std::io::Error::from(kind);
|
||||
assert!(transport_recv_error_is_retryable(&err));
|
||||
}
|
||||
assert!(!transport_recv_error_is_retryable(&std::io::Error::from(
|
||||
std::io::ErrorKind::PermissionDenied,
|
||||
)));
|
||||
|
||||
#[cfg(unix)]
|
||||
for code in [libc::ENETUNREACH, libc::EHOSTUNREACH, libc::ECONNRESET] {
|
||||
assert!(transport_recv_error_is_retryable(
|
||||
&std::io::Error::from_raw_os_error(code)
|
||||
));
|
||||
}
|
||||
|
||||
#[cfg(windows)]
|
||||
for code in [10051, 10054, 10065] {
|
||||
assert!(transport_recv_error_is_retryable(
|
||||
&std::io::Error::from_raw_os_error(code)
|
||||
));
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn service_registry_matches_registered_service_opens() {
|
||||
let mut registry = ServiceRegistry::new();
|
||||
|
||||
Reference in New Issue
Block a user