Skip to content

Commit

Permalink
Set and get ECN information.
Browse files Browse the repository at this point in the history
  • Loading branch information
larseggert committed Nov 20, 2023
1 parent 8a3aaa2 commit f8a3d7e
Show file tree
Hide file tree
Showing 13 changed files with 199 additions and 41 deletions.
3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,6 @@ members = [
"neqo-interop",
"test-fixture",
]

[patch.crates-io]
nix = { path = "./../nix" }
2 changes: 2 additions & 0 deletions neqo-client/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,10 @@ neqo-transport = { path = "./../neqo-transport" }
neqo-common = { path="./../neqo-common" }
neqo-http3 = { path = "./../neqo-http3" }
neqo-qpack = { path = "./../neqo-qpack" }
neqo-helper = { path = "./../neqo-helper" }
structopt = "0.3.7"
url = "2.0"
log = {version = "0.4.0", default-features = false}
qlog = "0.9.0"

[features]
Expand Down
27 changes: 11 additions & 16 deletions neqo-client/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ use neqo_transport::{
CongestionControlAlgorithm, Connection, ConnectionId, ConnectionParameters,
EmptyConnectionIdGenerator, Error as TransportError, StreamId, StreamType, Version,
};
use neqo_helper::{bind, emit_datagram, recv_datagram};

use std::{
cell::RefCell,
Expand All @@ -35,7 +36,7 @@ use std::{
process::exit,
rc::Rc,
str::FromStr,
time::{Duration, Instant},
time::{Duration, Instant}, os::fd::AsRawFd,
};

use structopt::StructOpt;
Expand Down Expand Up @@ -330,14 +331,6 @@ impl QuicParameters {
}
}

fn emit_datagram(socket: &UdpSocket, d: Datagram) -> io::Result<()> {
let sent = socket.send_to(&d[..], d.destination())?;
if sent != d.len() {
eprintln!("Unable to send all {} bytes of datagram", d.len());
}
Ok(())
}

fn get_output_file(
url: &Url,
output_dir: &Option<PathBuf>,
Expand Down Expand Up @@ -397,7 +390,7 @@ fn process_loop(
loop {
match client.process_output(Instant::now()) {
Output::Datagram(dgram) => {
if let Err(e) = emit_datagram(socket, dgram) {
if let Err(e) = emit_datagram(socket.as_raw_fd(), dgram) {
eprintln!("UDP write error: {}", e);
client.close(Instant::now(), 0, e.to_string());
exiting = true;
Expand All @@ -421,7 +414,8 @@ fn process_loop(
return Ok(client.state());
}

match socket.recv_from(&mut buf[..]) {
let mut tos = 0;
match recv_datagram(socket.as_raw_fd(), &mut buf[..], &mut tos) {
Err(ref err)
if err.kind() == ErrorKind::WouldBlock || err.kind() == ErrorKind::Interrupted => {}
Err(err) => {
Expand All @@ -434,7 +428,7 @@ fn process_loop(
continue;
}
if sz > 0 {
let d = Datagram::new(remote, *local_addr, &buf[..sz]);
let d = Datagram::new(remote, *local_addr, tos, &buf[..sz]);
client.process_input(d, Instant::now());
handler.maybe_key_update(client)?;
}
Expand Down Expand Up @@ -795,7 +789,7 @@ fn main() -> Res<()> {
SocketAddr::V6(..) => SocketAddr::new(IpAddr::V6(Ipv6Addr::from([0; 16])), 0),
};

let socket = match UdpSocket::bind(local_addr) {
let socket = match bind(local_addr) {
Err(e) => {
eprintln!("Unable to bind UDP socket: {}", e);
exit(1)
Expand Down Expand Up @@ -873,7 +867,7 @@ mod old {
path::PathBuf,
process::exit,
rc::Rc,
time::Instant,
time::Instant, os::fd::AsRawFd,
};

use url::Url;
Expand Down Expand Up @@ -1088,7 +1082,7 @@ mod old {
loop {
match client.process_output(Instant::now()) {
Output::Datagram(dgram) => {
if let Err(e) = emit_datagram(socket, dgram) {
if let Err(e) = emit_datagram(socket.as_raw_fd(), dgram) {
eprintln!("UDP write error: {}", e);
client.close(Instant::now(), 0, e.to_string());
exiting = true;
Expand Down Expand Up @@ -1125,7 +1119,8 @@ mod old {
continue;
}
if sz > 0 {
let d = Datagram::new(addr, *local_addr, &buf[..sz]);
// FIXME: deal with tos
let d = Datagram::new(addr, *local_addr, 0, &buf[..sz]);
client.process_input(d, Instant::now());
handler.maybe_key_update(client)?;
}
Expand Down
9 changes: 8 additions & 1 deletion neqo-common/src/datagram.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,14 +13,16 @@ use crate::hex_with_len;
pub struct Datagram {
src: SocketAddr,
dst: SocketAddr,
tos: u8,
d: Vec<u8>,
}

impl Datagram {
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, d: V) -> Self {
pub fn new<V: Into<Vec<u8>>>(src: SocketAddr, dst: SocketAddr, tos: u8, d: V) -> Self {
Self {
src,
dst,
tos,
d: d.into(),
}
}
Expand All @@ -34,6 +36,11 @@ impl Datagram {
pub fn destination(&self) -> SocketAddr {
self.dst
}

#[must_use]
pub fn tos(&self) -> u8 {
self.tos
}
}

impl Deref for Datagram {
Expand Down
12 changes: 12 additions & 0 deletions neqo-helper/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
[package]
name = "neqo-helper"
version = "0.6.7"
authors = ["Lars Eggert <lars@eggert.org>"]
edition = "2018"
rust-version = "1.65.0"
license = "MIT OR Apache-2.0"

[dependencies]
neqo-common = { path="./../neqo-common" }
nix = { version = "0.27.1", features = ["socket", "net", "uio"] }
log = {version = "0.4.0", default-features = false}
136 changes: 136 additions & 0 deletions neqo-helper/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

use std::{
io::{self, Error, ErrorKind, IoSlice, IoSliceMut},
net::{SocketAddr, UdpSocket},
process::exit,
};

use nix::{
cmsg_space,
errno::Errno::{EAGAIN, EINTR},
sys::socket::{
recvmsg, sendmsg, setsockopt,
sockopt::{IpDontFrag, IpRecvTos, IpTos, Ipv6DontFrag, Ipv6RecvTClass, Ipv6TClass},
AddressFamily, ControlMessage, ControlMessageOwned, MsgFlags, SockaddrLike,
SockaddrStorage,
},
};

use neqo_common::{Datagram, qdebug};

// Bind a UDPO socket and set some default socket options.
pub fn bind(local_addr: SocketAddr) -> io::Result<UdpSocket> {
let socket = match UdpSocket::bind(local_addr) {
Err(e) => {
eprintln!("Unable to bind UDP socket: {}", e);
exit(1)
}
Ok(s) => {
// Don't let the host stack or network path fragment our IP packets
// (RFC9000, Section 14).
let res = match local_addr {
SocketAddr::V4(..) => setsockopt(&s, IpDontFrag, &true),
SocketAddr::V6(..) => setsockopt(&s, Ipv6DontFrag, &true),
};
assert!(res.is_ok());

// Mark all outgoing IP packets with ECT(0). This is a kludge until proper ECN
// validation is supported (RFC9000, Section 13.4.2).
let res = match local_addr {
SocketAddr::V4(..) => setsockopt(&s, IpTos, &0b00000010),
SocketAddr::V6(..) => setsockopt(&s, Ipv6TClass, &0b00000010),
};
assert!(res.is_ok());

let res = match local_addr {
SocketAddr::V4(..) => setsockopt(&s, IpRecvTos, &true),
SocketAddr::V6(..) => setsockopt(&s, Ipv6RecvTClass, &true),
};
assert!(res.is_ok());

// let res = match local_addr {
// SocketAddr::V4(..) => setsockopt(&s, IpRecvTtl, &true),
// SocketAddr::V6(..) => setsockopt(&s, Ipv6HopLimit, &true),
// };
// assert!(res.is_ok());
s
}
};
Ok(socket)
}

fn to_sockaddr(addr: SocketAddr) -> SockaddrStorage {
SockaddrStorage::from(addr)
}

pub fn emit_datagram(fd: i32, d: Datagram) -> io::Result<()> {
let iov = [IoSlice::new(&d[..])];
let tos = d.tos();
let cmsg = ControlMessage::IpTos(&tos);
let sent = sendmsg(
fd,
&iov,
&[cmsg],
MsgFlags::empty(),
Some(&to_sockaddr(d.destination())),
)
.unwrap();
if sent != d.len() {
eprintln!("Unable to send all {} bytes of datagram", d.len());
}
qdebug!("TX TOS {:#04x}", tos);
Ok(())
}

fn to_socket_addr(addr: &SockaddrStorage) -> SocketAddr {
let fam = addr.family().unwrap();

let port = match fam {
AddressFamily::Inet => addr.as_sockaddr_in().unwrap().port(),
AddressFamily::Inet6 => addr.as_sockaddr_in6().unwrap().port(),
_ => todo!(),
};

match fam {
AddressFamily::Inet => SocketAddr::new(
std::net::IpAddr::V4(addr.as_sockaddr_in().unwrap().ip()),
port,
),
AddressFamily::Inet6 => SocketAddr::new(
std::net::IpAddr::V6(addr.as_sockaddr_in6().unwrap().ip()),
port,
),
_ => todo!(),
}
}

pub fn recv_datagram(fd: i32, buf: &mut [u8], tos: &mut u8) -> io::Result<(usize, SocketAddr)> {
let mut iov = [IoSliceMut::new(buf)];
let mut cmsg = cmsg_space!(IpTos, Ipv6TClass);
let flags = MsgFlags::empty();

match recvmsg::<SockaddrStorage>(fd, &mut iov, Some(&mut cmsg), flags) {
Err(e) if e == EAGAIN => Err(Error::new(ErrorKind::WouldBlock, e)),
Err(e) if e == EINTR => Err(Error::new(ErrorKind::Interrupted, e)),
Err(e) => {
eprintln!("UDP error: {}", e);
exit(1)
}
Ok(res) => {
for cmsg in res.cmsgs() {
*tos = match cmsg {
ControlMessageOwned::IpTos(t) => t,
ControlMessageOwned::Ipv6TClass(t) => t,
_ => todo!(),
};
}
qdebug!("RX TOS {:#04x}", tos);
Ok((res.bytes, to_socket_addr(&res.address.unwrap())))
}
}
}
9 changes: 6 additions & 3 deletions neqo-interop/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -148,7 +148,8 @@ fn process_loop(
continue;
}
if sz > 0 {
let received = Datagram::new(nctx.remote_addr, nctx.local_addr, &buf[..sz]);
// FIXME: deal with tos
let received = Datagram::new(nctx.remote_addr, nctx.local_addr, 0, &buf[..sz]);
client.process_input(received, Instant::now());
}
}
Expand Down Expand Up @@ -309,7 +310,8 @@ fn process_loop_h3(
continue;
}
if sz > 0 {
let received = Datagram::new(nctx.remote_addr, nctx.local_addr, &buf[..sz]);
// FIXME: deal with tos
let received = Datagram::new(nctx.remote_addr, nctx.local_addr, 0, &buf[..sz]);
handler.h3.process_input(received, Instant::now());
}
}
Expand Down Expand Up @@ -682,7 +684,8 @@ impl Handler for VnHandler {
fn rewrite_out(&mut self, d: &Datagram) -> Option<Datagram> {
let mut payload = d[..].to_vec();
payload[1] = 0x1a;
Some(Datagram::new(d.source(), d.destination(), payload))
// FIXME: deal with tos
Some(Datagram::new(d.source(), d.destination(), 0, payload))
}
}

Expand Down
1 change: 1 addition & 0 deletions neqo-server/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ neqo-transport = { path = "./../neqo-transport" }
neqo-common = { path="./../neqo-common" }
neqo-http3 = { path = "./../neqo-http3" }
neqo-qpack = { path = "./../neqo-qpack" }
neqo-helper = { path = "./../neqo-helper" }
structopt = "0.3.7"
regex = "1"
mio = "0.6.17"
Expand Down
Loading

0 comments on commit f8a3d7e

Please sign in to comment.