Skip to content

Expand ECN support #222

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 28, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .travis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ before_script:
script:
- cargo clean
- cargo build --all-features
- cargo test --all-features
- RUST_BACKTRACE=1 cargo test --all-features
- if [[ "$TRAVIS_RUST_VERSION" == stable ]]; then
cargo fmt -- --check;
fi
Expand Down
2 changes: 1 addition & 1 deletion quinn/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ untrusted = "0.6.2"
webpki = "0.19"
webpki-roots = "0.16"
ct-logs = "0.5"
libc = "0.2.46"
libc = "0.2.49"
mio = "0.6"

[dev-dependencies]
Expand Down
4 changes: 2 additions & 2 deletions quinn/src/platform/cmsg.rs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ impl<'a> Encoder<'a> {
assert!(mem::align_of::<T>() <= mem::align_of::<libc::cmsghdr>());
let space = unsafe { libc::CMSG_SPACE(mem::size_of_val(&value) as _) as usize };
assert!(
self.hdr.msg_controllen >= self.len + space,
self.hdr.msg_controllen as usize >= self.len + space,
"control message buffer too small"
);
let cmsg = self.cmsg.take().expect("no control buffer space remaining");
Expand All @@ -60,7 +60,7 @@ impl<'a> Encoder<'a> {
// by `sendmsg`.
impl<'a> Drop for Encoder<'a> {
fn drop(&mut self) {
self.hdr.msg_controllen = self.len;
self.hdr.msg_controllen = self.len as _;
}
}

Expand Down
10 changes: 4 additions & 6 deletions quinn/src/platform/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,13 @@
use quinn_proto::EcnCodepoint;
use std::{io, net::SocketAddr};

// The Linux code should work for most unixes, but as of this writing nobody's ported the
// CMSG_... macros to the libc crate for any of the BSDs.
#[cfg(target_os = "linux")]
#[cfg(unix)]
mod cmsg;
#[cfg(target_os = "linux")]
mod linux;
#[cfg(unix)]
mod unix;

// No ECN support
#[cfg(not(target_os = "linux"))]
#[cfg(not(unix))]
mod fallback;

pub trait UdpExt {
Expand Down
28 changes: 19 additions & 9 deletions quinn/src/platform/linux.rs → quinn/src/platform/unix.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ use quinn_proto::EcnCodepoint;

use super::cmsg;

#[cfg(target_os = "freebsd")]
type IpTosTy = libc::c_uchar;
#[cfg(not(target_os = "freebsd"))]
type IpTosTy = libc::c_int;

impl super::UdpExt for UdpSocket {
fn init_ext(&self) -> io::Result<()> {
// Safety
Expand All @@ -22,24 +27,26 @@ impl super::UdpExt for UdpSocket {
mem::size_of::<SocketAddrV6>(),
mem::size_of::<libc::sockaddr_in6>()
);
assert_eq!(CMSG_LEN, unsafe {
libc::CMSG_SPACE(mem::size_of::<libc::c_int>() as _) as usize
});
assert!(
CMSG_LEN >= unsafe { libc::CMSG_SPACE(mem::size_of::<libc::c_int>() as _) as usize }
);
assert!(
mem::align_of::<libc::cmsghdr>() <= mem::align_of::<cmsg::Aligned<[u8; 0]>>(),
"control message buffers will be misaligned"
);

let addr = self.local_addr()?;

if addr.is_ipv4() || !self.only_v6()? {
// macos doesn't support IP_RECVTOS on dual-stack sockets :(
if addr.is_ipv4() || (!cfg!(target_os = "macos") && !self.only_v6()?) {
let on: libc::c_int = 1;
let rc = unsafe {
libc::setsockopt(
self.as_raw_fd(),
libc::IPPROTO_IP,
libc::IP_RECVTOS,
&true as *const _ as _,
1,
&on as *const _ as _,
mem::size_of_val(&on) as _,
)
};
if rc == -1 {
Expand All @@ -54,7 +61,7 @@ impl super::UdpExt for UdpSocket {
libc::IPPROTO_IPV6,
libc::IPV6_RECVTCLASS,
&on as *const _ as _,
mem::size_of::<libc::c_int>() as _,
mem::size_of_val(&on) as _,
)
};
if rc == -1 {
Expand Down Expand Up @@ -100,7 +107,7 @@ impl super::UdpExt for UdpSocket {
};
let mut encoder = unsafe { cmsg::Encoder::new(&mut hdr, &mut ctrl.0) };
if is_ipv4 {
encoder.push(libc::IPPROTO_IP, libc::IP_TOS, ecn);
encoder.push(libc::IPPROTO_IP, libc::IP_TOS, ecn as IpTosTy);
} else {
encoder.push(libc::IPPROTO_IPV6, libc::IPV6_TCLASS, ecn);
}
Expand Down Expand Up @@ -148,7 +155,10 @@ impl super::UdpExt for UdpSocket {
};
let ecn_bits = if let Some(cmsg) = unsafe { cmsg::Iter::new(&hdr).next() } {
match (cmsg.cmsg_level, cmsg.cmsg_type) {
(libc::IPPROTO_IP, libc::IP_TOS) => unsafe { cmsg::decode::<u8>(cmsg) },
// FreeBSD uses IP_RECVTOS here, and we can be liberal because cmsgs are opt-in.
(libc::IPPROTO_IP, libc::IP_TOS) | (libc::IPPROTO_IP, libc::IP_RECVTOS) => unsafe {
cmsg::decode::<u8>(cmsg)
},
(libc::IPPROTO_IPV6, libc::IPV6_TCLASS) => unsafe {
cmsg::decode::<libc::c_int>(cmsg) as u8
},
Expand Down
2 changes: 1 addition & 1 deletion quinn/src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@ fn echo_v4() {
}

#[test]
#[cfg(target_os = "linux")] // Dual-stack sockets aren't the default anywhere else.
#[cfg(any(target_os = "linux", target_os = "macos"))] // Dual-stack sockets aren't the default anywhere else.
fn echo_dualstack() {
run_echo(
SocketAddr::new(IpAddr::V6(Ipv6Addr::UNSPECIFIED), 0),
Expand Down