Skip to content

Commit 3f03778

Browse files
committed
fix(udp): retry send on first EINVAL
Android API level < 26 does not support the `libc::IP_TOS` control message. `sendmsg` calls with `libc::IP_TOS` return `libc::EINVAL`. quinn-rs#1516 added a fallback, not setting `libc::IP_TOS` on consecutive calls to `sendmsg` after a failure with `libc::EINVAL`. The current datagram would be dropped. Consecutive datagrams passed to `sendmsg` would succeed as they would be sent without `libc::IP_TOS` through the fallback. Instead of dropping the first datagram on `libc::EINVAL`, this commit adds a retry for it without `libc::IP_TOS`. This is e.g. relevant for Neqo. When establishing a QUIC connection, dropping the first datagram [delays connection establishment by 100ms](https://github.com/mozilla/neqo/blob/3001a3a56f2274eaafaa956fb394f0817f526ae7/neqo-transport/src/rtt.rs#L28). With the retry introduced in this commit, delay due to unsupported `libc::IP_TOS` should be negligeable. Closes quinn-rs#1975.
1 parent 0dcdd29 commit 3f03778

File tree

2 files changed

+18
-3
lines changed

2 files changed

+18
-3
lines changed

quinn-udp/src/unix.rs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -332,8 +332,20 @@ fn send(
332332

333333
if e.raw_os_error() == Some(libc::EINVAL) {
334334
// Some arguments to `sendmsg` are not supported.
335-
// Switch to fallback mode.
336-
state.set_sendmsg_einval();
335+
if !state.sendmsg_einval() {
336+
// Switch to fallback mode.
337+
state.set_sendmsg_einval();
338+
prepare_msg(
339+
transmit,
340+
&dst_addr,
341+
&mut msg_hdr,
342+
&mut iovec,
343+
&mut cmsgs,
344+
encode_src_ip,
345+
state.sendmsg_einval(),
346+
);
347+
continue;
348+
}
337349
}
338350

339351
// - EMSGSIZE is expected for MTU probes. Future work might be able to avoid

quinn-udp/tests/tests.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -244,7 +244,10 @@ fn test_send_recv(send: &Socket, recv: &Socket, transmit: Transmit) {
244244
}
245245
}
246246

247-
if cfg!(target_os = "android")
247+
if match transmit.destination.ip() {
248+
IpAddr::V4(_) => true,
249+
IpAddr::V6(a) => a.to_ipv4_mapped().is_some(),
250+
} && cfg!(target_os = "android")
248251
&& std::env::var("API_LEVEL")
249252
.ok()
250253
.and_then(|v| v.parse::<u32>().ok())

0 commit comments

Comments
 (0)