cloudflare / quiche

🥧 Savoury implementation of the QUIC transport protocol and HTTP/3
https://docs.quic.tech/quiche/
BSD 2-Clause "Simplified" License
9.4k stars 709 forks source link

Timestamps returned from quiche::Connection::send #1516

Open dawmd opened 1 year ago

dawmd commented 1 year ago

Is it guaranteed that consecutive calls to quiche::Connection::send will return timestamps (the field at in the returned SendInfo) in the non-decreasing order? When implementing pacing, it's significant information.

ljluestc commented 1 month ago

use quiche::Connection;
use std::time::{Duration, Instant};

struct PacingManager {
    last_send_time: Option<Instant>,
    min_interval: Duration, // Minimum interval between sends (for pacing)
}

impl PacingManager {
    fn new(min_interval: Duration) -> Self {
        PacingManager {
            last_send_time: None,
            min_interval,
        }
    }

    fn pace_send(&mut self, conn: &mut Connection) -> Result<(), Box<dyn std::error::Error>> {
        loop {
            let mut out = [0; quiche::MAX_DATAGRAM_SIZE];
            let (write_len, send_info) = match conn.send(&mut out) {
                Ok(res) => res,
                Err(quiche::Error::Done) => break, // No more data to send
                Err(e) => return Err(Box::new(e)),
            };

            // Get the current time based on SendInfo
            let current_time = send_info.time;

            // If pacing is enabled, ensure non-decreasing timestamps and enforce pacing interval
            if let Some(last_time) = self.last_send_time {
                if current_time < last_time {
                    // Adjust to non-decreasing timestamp
                    // Here we assume that current_time should not be smaller, adjust it accordingly
                    println!("Warning: Decreasing timestamp detected. Adjusting...");
                    continue; // Skip the send if we detect a decreasing timestamp
                }

                // Enforce pacing delay (delay between packets)
                let elapsed = current_time.duration_since(last_time);
                if elapsed < self.min_interval {
                    let wait_time = self.min_interval - elapsed;
                    println!("Pacing: Waiting for {:?}", wait_time);
                    std::thread::sleep(wait_time);
                }
            }

            // Send the packet (this could be sending via a real socket in your actual code)
            println!("Sending packet of size {} at {:?}", write_len, current_time);

            // Update the last send time
            self.last_send_time = Some(current_time);
        }

        Ok(())
    }
}

fn main() -> Result<(), Box<dyn std::error::Error>> {
    // Example usage of the pacing manager
    let mut conn = setup_quiche_connection(); // Replace with actual connection setup

    let mut pacing_manager = PacingManager::new(Duration::from_millis(10)); // Minimum 10ms between sends

    // Use the pacing manager to send data with pacing
    pacing_manager.pace_send(&mut conn)?;

    Ok(())
}

// Dummy function for setting up the quiche connection
fn setup_quiche_connection() -> Connection {
    // Implement your actual quiche connection setup here
    unimplemented!()
}