Skip to content
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

h3i: extract connection creation to its own function #1868

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
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
86 changes: 85 additions & 1 deletion h3i/src/client/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -38,11 +38,13 @@ use qlog::events::h3::HttpHeader;
use quiche::ConnectionError;

use std::collections::HashMap;
use std::net::SocketAddr;
use std::time::Instant;

use crate::actions::h3::Action;
use crate::actions::h3::StreamEvent;
use crate::actions::h3::StreamEventType;
use crate::config::Config;
use crate::frame::H3iFrame;
use crate::frame::ResetStream;
use crate::frame_parser::FrameParseResult;
Expand All @@ -55,10 +57,92 @@ use qlog::events::h3::Http3Frame;
use qlog::events::EventData;
use qlog::streamer::QlogStreamer;

use quiche;
use quiche::h3::frame::Frame as QFrame;
use quiche::h3::Error;
use quiche::h3::NameValue;
use quiche::Connection;
use quiche::Result;
use quiche::{
self,
};

const MAX_DATAGRAM_SIZE: usize = 1350;
const QUIC_VERSION: u32 = 1;

pub fn build_quiche_connection(
args: Config, peer_addr: SocketAddr, local_addr: SocketAddr,
) -> Result<Connection> {
// We'll only connect to one server.
let connect_url = if !args.omit_sni {
args.host_port.split(':').next()
} else {
None
};

// Create the configuration for the QUIC connection.
let mut config = quiche::Config::new(QUIC_VERSION).unwrap();

config.verify_peer(args.verify_peer);
config.set_application_protos(&[b"h3"]).unwrap();
config.set_max_idle_timeout(args.idle_timeout);
config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_initial_max_data(10_000_000);
config
.set_initial_max_stream_data_bidi_local(args.max_stream_data_bidi_local);
config.set_initial_max_stream_data_bidi_remote(
args.max_stream_data_bidi_remote,
);
config.set_initial_max_stream_data_uni(args.max_stream_data_uni);
config.set_initial_max_streams_bidi(args.max_streams_bidi);
config.set_initial_max_streams_uni(args.max_streams_uni);
config.set_disable_active_migration(true);
config.set_active_connection_id_limit(0);

config.set_max_connection_window(args.max_window);
config.set_max_stream_window(args.max_stream_window);

let mut keylog = None;

if let Some(keylog_path) = std::env::var_os("SSLKEYLOGFILE") {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(keylog_path)
.unwrap();

keylog = Some(file);

config.log_keys();
}

config.grease(false);

// Generate a random source connection ID for the connection.
let mut scid = [0; quiche::MAX_CONN_ID_LEN];
rand::RngCore::fill_bytes(&mut rand::thread_rng(), &mut scid);

let scid = quiche::ConnectionId::from_ref(&scid);

// Create a QUIC connection and initiate handshake.
let mut conn =
quiche::connect(connect_url, &scid, local_addr, peer_addr, &mut config)?;

if let Some(keylog) = &mut keylog {
if let Ok(keylog) = keylog.try_clone() {
conn.set_keylog(Box::new(keylog));
}
}

log::info!(
"connecting to {:} from {:} with scid {:?}",
peer_addr,
local_addr,
scid,
);
evanrittenhouse marked this conversation as resolved.
Show resolved Hide resolved

Ok(conn)
}

fn handle_qlog(
qlog_streamer: Option<&mut QlogStreamer>, qlog_frame: Http3Frame,
Expand Down
92 changes: 8 additions & 84 deletions h3i/src/client/sync_client.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,27 +37,27 @@ use crate::actions::h3::Action;
use crate::actions::h3::StreamEventType;
use crate::actions::h3::WaitType;
use crate::actions::h3::WaitingFor;
use crate::client::build_quiche_connection;
use crate::client::execute_action;
use crate::client::parse_streams;
use crate::client::ClientError;
use crate::client::ClientVariant;
use crate::client::ConnectionCloseDetails;
use crate::client::MAX_DATAGRAM_SIZE;
use crate::config::Config;

use super::ConnectionSummary;
use super::StreamMap;
use super::StreamParserMap;

const MAX_DATAGRAM_SIZE: usize = 1350;

/// Connect to a server and execute provided actions.
///
/// Constructs a socket and [quiche::Connection] based on the provided `args`,
/// then iterates over `actions`.
///
/// Returns a [ConnectionSummary] on success, [ClientError] on failure.
pub fn connect(
args: &Config, actions: &[Action],
args: Config, actions: &[Action],
) -> std::result::Result<ConnectionSummary, ClientError> {
let mut buf = [0; 65535];
let mut out = [0; MAX_DATAGRAM_SIZE];
Expand All @@ -66,13 +66,6 @@ pub fn connect(
let mut poll = mio::Poll::new().unwrap();
let mut events = mio::Events::with_capacity(1024);

// We'll only connect to one server.
let connect_url = if !args.omit_sni {
args.host_port.split(':').next()
} else {
None
};

// Resolve server address.
let peer_addr = if let Some(addr) = &args.connect_to {
evanrittenhouse marked this conversation as resolved.
Show resolved Hide resolved
addr.parse().expect("--connect-to is expected to be a string containing an IPv4 or IPv6 address with a port. E.g. 192.0.2.0:443")
Expand Down Expand Up @@ -102,84 +95,15 @@ pub fn connect(
.register(&mut socket, mio::Token(0), mio::Interest::READABLE)
.unwrap();

// Create the configuration for the QUIC connection.
let mut config = quiche::Config::new(1).unwrap();

config.verify_peer(args.verify_peer);
config.set_application_protos(&[b"h3"]).unwrap();
config.set_max_idle_timeout(args.idle_timeout);
config.set_max_recv_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_max_send_udp_payload_size(MAX_DATAGRAM_SIZE);
config.set_initial_max_data(10_000_000);
config
.set_initial_max_stream_data_bidi_local(args.max_stream_data_bidi_local);
config.set_initial_max_stream_data_bidi_remote(
args.max_stream_data_bidi_remote,
);
config.set_initial_max_stream_data_uni(args.max_stream_data_uni);
config.set_initial_max_streams_bidi(args.max_streams_bidi);
config.set_initial_max_streams_uni(args.max_streams_uni);
config.set_disable_active_migration(true);
config.set_active_connection_id_limit(0);

config.set_max_connection_window(args.max_window);
config.set_max_stream_window(args.max_stream_window);

let mut keylog = None;

if let Some(keylog_path) = std::env::var_os("SSLKEYLOGFILE") {
let file = std::fs::OpenOptions::new()
.create(true)
.append(true)
.open(keylog_path)
.unwrap();

keylog = Some(file);

config.log_keys();
}
let Ok(local_addr) = socket.local_addr() else {
return Err(ClientError::Other("invalid socket".to_string()));
};

config.grease(false);
let mut conn = build_quiche_connection(args, peer_addr, local_addr)
.map_err(|_| ClientError::HandshakeFail)?;

let mut app_proto_selected = false;

// Generate a random source connection ID for the connection.
let mut scid = [0; quiche::MAX_CONN_ID_LEN];
rand::RngCore::fill_bytes(&mut rand::thread_rng(), &mut scid);

let scid = quiche::ConnectionId::from_ref(&scid);

let local_addr = socket.local_addr().unwrap();

// Create a QUIC connection and initiate handshake.
let mut conn =
quiche::connect(connect_url, &scid, local_addr, peer_addr, &mut config)
.unwrap();

if let Some(keylog) = &mut keylog {
if let Ok(keylog) = keylog.try_clone() {
conn.set_keylog(Box::new(keylog));
}
}

if let Some(dir) = std::env::var_os("QLOGDIR") {
let id = format!("{scid:?}");
let writer = make_qlog_writer(&dir, "client", &id);

conn.set_qlog(
std::boxed::Box::new(writer),
"h3i-client qlog".to_string(),
format!("{} id={}", "quiche-client qlog", id),
);
}

log::info!(
"connecting to {:} from {:} with scid {:?}",
peer_addr,
socket.local_addr().unwrap(),
scid,
);

let (write, send_info) = conn.send(&mut out).expect("initial send failed");

while let Err(e) = socket.send_to(&out[..write], send_info.to) {
Expand Down
6 changes: 3 additions & 3 deletions h3i/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ fn main() -> Result<(), ClientError> {
None => prompt_frames(&config),
};

match sync_client(&config, &actions) {
match sync_client(config, &actions) {
Ok(summary) => {
log::debug!(
"received connection_summary: {}",
Expand Down Expand Up @@ -296,9 +296,9 @@ fn config_from_clap() -> std::result::Result<Config, String> {
}

fn sync_client(
config: &Config, actions: &[Action],
config: Config, actions: &[Action],
) -> Result<ConnectionSummary, ClientError> {
h3i::client::sync_client::connect(&config.library_config, actions)
h3i::client::sync_client::connect(config.library_config, actions)
}

fn read_qlog(filename: &str, host_override: Option<&str>) -> Vec<Action> {
Expand Down