Skip to content

Commit

Permalink
Pacing: Pacing of egress QUIC packets
Browse files Browse the repository at this point in the history
  • Loading branch information
Lohith Bellad committed Dec 11, 2020
1 parent 54806c8 commit 07683ee
Show file tree
Hide file tree
Showing 6 changed files with 341 additions and 5 deletions.
10 changes: 10 additions & 0 deletions include/quiche.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,16 @@ ssize_t quiche_conn_recv(quiche_conn *conn, uint8_t *buf, size_t buf_len);
// Writes a single QUIC packet to be sent to the peer.
ssize_t quiche_conn_send(quiche_conn *conn, uint8_t *out, size_t out_len);

typedef struct {
// Time to send the packet out.
struct timespec send_time;
} send_info;

// Writes a single QUIC packet to be sent to the peer and fills in the send_info
// struct.
ssize_t quiche_conn_send_at(quiche_conn *conn, uint8_t *out, size_t out_len,
struct send_info *out_info);

// Buffer holding data at a specific offset.
typedef struct RangeBuf quiche_rangebuf;

Expand Down
37 changes: 37 additions & 0 deletions src/ffi.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,9 @@ use libc::c_void;
use libc::size_t;
use libc::ssize_t;

#[cfg(unix)]
use libc::timespec;

use crate::*;

#[no_mangle]
Expand Down Expand Up @@ -543,6 +546,40 @@ pub extern fn quiche_conn_send(
}
}

#[cfg(unix)]
#[repr(C)]
pub struct send_info {
pub send_time: timespec,
}

#[no_mangle]
#[cfg(unix)]
pub extern fn quiche_conn_send_with_info(
conn: &mut Connection, out: *mut u8, out_len: size_t,
out_info: &mut send_info,
) -> ssize_t {
if out_len > <ssize_t>::max_value() as usize {
panic!("The provided buffer is too large");
}

let out = unsafe { slice::from_raw_parts_mut(out, out_len) };

match conn.send_with_info(out) {
Ok((v, info)) => {
unsafe {
ptr::copy_nonoverlapping(
&info.send_time as *const _ as *const timespec,
&mut out_info.send_time,
1,
)
};
v as ssize_t
},

Err(e) => e.to_c(),
}
}

#[no_mangle]
pub extern fn quiche_conn_stream_recv(
conn: &mut Connection, stream_id: u64, out: *mut u8, out_len: size_t,
Expand Down
83 changes: 78 additions & 5 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1986,10 +1986,12 @@ impl Connection {
Ok(read)
}

/// Writes a single QUIC packet to be sent to the peer.
/// Writes a single QUIC packet to be sent to the peer along with send_info
/// like to time to send the packet out.
///
/// On success the number of bytes written to the output buffer is
/// returned, or [`Done`] if there was nothing to write.
/// returned along with send_info, or [`Done`] if there was nothing to
/// write.
///
/// The application should call `send()` multiple times until [`Done`] is
/// returned, indicating that there are no more packets to send. It is
Expand Down Expand Up @@ -2019,8 +2021,11 @@ impl Connection {
/// # let scid = [0xba; 16];
/// # let mut conn = quiche::accept(&scid, None, &mut config)?;
/// loop {
/// let write = match conn.send(&mut out) {
/// Ok(v) => v,
/// let write = match conn.send_with_info(&mut out) {
/// Ok((v, send_info)) => {
/// // Use send_info
/// v;
/// },
///
/// Err(quiche::Error::Done) => {
/// // Done writing.
Expand All @@ -2037,7 +2042,9 @@ impl Connection {
/// }
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn send(&mut self, out: &mut [u8]) -> Result<usize> {
pub fn send_with_info(
&mut self, out: &mut [u8],
) -> Result<(usize, SendInfo)> {
let now = time::Instant::now();

if out.is_empty() {
Expand Down Expand Up @@ -2796,6 +2803,10 @@ impl Connection {
&self.trace_id,
);

let out_info = SendInfo {
send_time: self.recovery.get_packet_send_time().unwrap_or(now),
};

qlog_with!(self.qlog_streamer, q, {
let ev = self.recovery.to_qlog();
q.add_event(ev).ok();
Expand Down Expand Up @@ -2828,6 +2839,62 @@ impl Connection {
self.ack_eliciting_sent = true;
}

Ok((written, out_info))
}

/// Writes a single QUIC packet to be sent to the peer.
///
/// On success the number of bytes written to the output buffer is
/// returned, or [`Done`] if there was nothing to write.
///
/// The application should call `send()` multiple times until [`Done`] is
/// returned, indicating that there are no more packets to send. It is
/// recommended that `send()` be called in the following cases:
///
/// * When the application receives QUIC packets from the peer (that is,
/// any time [`recv()`] is also called).
///
/// * When the connection timer expires (that is, any time [`on_timeout()`]
/// is also called).
///
/// * When the application sends data to the peer (for examples, any time
/// [`stream_send()`] or [`stream_shutdown()`] are called).
///
/// [`Done`]: enum.Error.html#variant.Done
/// [`recv()`]: struct.Connection.html#method.recv
/// [`on_timeout()`]: struct.Connection.html#method.on_timeout
/// [`stream_send()`]: struct.Connection.html#method.stream_send
/// [`stream_shutdown()`]: struct.Connection.html#method.stream_shutdown
///
/// ## Examples:
///
/// ```no_run
/// # let mut out = [0; 512];
/// # let socket = std::net::UdpSocket::bind("127.0.0.1:0").unwrap();
/// # let mut config = quiche::Config::new(quiche::PROTOCOL_VERSION)?;
/// # let scid = [0xba; 16];
/// # let mut conn = quiche::accept(&scid, None, &mut config)?;
/// loop {
/// let write = match conn.send_at(&mut out) {
/// Ok(v) => v,
///
/// Err(quiche::Error::Done) => {
/// // Done writing.
/// break;
/// },
///
/// Err(e) => {
/// // An error occurred, handle it.
/// break;
/// },
/// };
///
/// socket.send(&out[..write]).unwrap();
/// }
/// # Ok::<(), quiche::Error>(())
/// ```
pub fn send(&mut self, out: &mut [u8]) -> Result<usize> {
let (written, _) = self.send_with_info(out)?;
Ok(written)
}

Expand Down Expand Up @@ -4381,6 +4448,12 @@ fn drop_pkt_on_err(
Error::Done
}

/// Info send out on every send_with_info call.
pub struct SendInfo {
/// Time to send the packet out.
pub send_time: time::Instant,
}

/// Statistics about the connection.
///
/// A connections's statistics can be collected using the [`stats()`] method.
Expand Down
5 changes: 5 additions & 0 deletions src/recovery/cubic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ pub static CUBIC: CongestionControlOps = CongestionControlOps {
on_packet_acked,
congestion_event,
collapse_cwnd,
has_custom_pacing,
};

/// CUBIC Constants.
Expand Down Expand Up @@ -292,6 +293,10 @@ fn congestion_event(
}
}

fn has_custom_pacing() -> bool {
false
}

#[cfg(test)]
mod tests {
use super::*;
Expand Down
Loading

0 comments on commit 07683ee

Please sign in to comment.