From 69bde4406c207695d86901aec0ef82ceef407c9d Mon Sep 17 00:00:00 2001 From: SIMO Francklin Date: Mon, 26 Oct 2020 13:49:04 +0000 Subject: [PATCH] Add support for 0RTT-BDP extension --- loglib/qlog.c | 21 ++++ picoquic/logger.c | 21 ++++ picoquic/picoquic.h | 7 ++ picoquic/picoquic_internal.h | 29 ++++- picoquic/tls_api.c | 101 ++++++++++++++++- picoquic/transport.c | 211 +++++++++++++++++++++++++++++++++++ picoquicfirst/picoquicdemo.c | 41 ++++++- 7 files changed, 422 insertions(+), 9 deletions(-) diff --git a/loglib/qlog.c b/loglib/qlog.c index cc782d23c..9c69bd58d 100644 --- a/loglib/qlog.c +++ b/loglib/qlog.c @@ -304,6 +304,27 @@ int qlog_transport_extensions(FILE* f, bytestream* s, size_t tp_length) case picoquic_tp_grease_quic_bit: qlog_boolean_transport_extension(f, "grease_quic_bit", s, extension_length); break; + case picoquic_tp_recon_bytes_in_flight: + qlog_vint_transport_extension(f, "recon_bytes_in_flight", s, extension_length); + break; + case picoquic_tp_recon_min_rtt: + qlog_vint_transport_extension(f, "recon_bytes_min_rtt", s, extension_length); + break; + case picoquic_tp_recon_max_pkt_number: + qlog_vint_transport_extension(f, "recon_max_pkt_number", s, extension_length); + break; + case picoquic_tp_recon_cwin: + qlog_vint_transport_extension(f, "recon_cwin", s, extension_length); + break; + case picoquic_tp_recon_rtt_variant: + qlog_vint_transport_extension(f, "recon_rtt_variant", s, extension_length); + break; + case picoquic_tp_recon_smoothed_rtt: + qlog_vint_transport_extension(f, "recon_smoothed_rtt", s, extension_length); + break; + case picoquic_tp_recon_max_ack_delay: + qlog_vint_transport_extension(f, "recon_max_ack_delay", s, extension_length); + break; default: /* dump unknown extensions */ fprintf(f, "\"%" PRIx64 "\": ", extension_type); diff --git a/picoquic/logger.c b/picoquic/logger.c index 01cb35c0a..598bb3887 100644 --- a/picoquic/logger.c +++ b/picoquic/logger.c @@ -445,6 +445,27 @@ char const* picoquic_log_tp_name(uint64_t tp_number) case picoquic_tp_grease_quic_bit: tp_name = "grease_quic_bit"; break; + case picoquic_tp_recon_bytes_in_flight: + tp_name = "recon_bytes_in_flight"; + break; + case picoquic_tp_recon_min_rtt: + tp_name = "recon_min_rtt"; + break; + case picoquic_tp_recon_max_pkt_number: + tp_name = "recon_max_pkt_number"; + break; + case picoquic_tp_recon_cwin: + tp_name = "recon_cwin"; + break; + case picoquic_tp_recon_rtt_variant: + tp_name = "recon_rtt_variant"; + break; + case picoquic_tp_recon_smoothed_rtt: + tp_name = "recon_smoothed_rtt"; + break; + case picoquic_tp_recon_max_ack_delay: + tp_name = "recon_max_ack_delay"; + break; default: break; } diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h index 101bc1a0a..309f319d0 100644 --- a/picoquic/picoquic.h +++ b/picoquic/picoquic.h @@ -235,6 +235,13 @@ typedef struct st_picoquic_tp_t { int enable_time_stamp; /* (x&1) want, (x&2) can */ uint64_t min_ack_delay; int do_grease_quic_bit; + uint64_t recon_bytes_in_flight; + uint64_t recon_min_rtt; + uint64_t recon_max_pkt_number; + uint64_t recon_cwin; + uint64_t recon_rtt_variant; + uint64_t recon_smoothed_rtt; + uint64_t recon_max_ack_delay; } picoquic_tp_t; /* diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h index 5962167d6..94a30f615 100644 --- a/picoquic/picoquic_internal.h +++ b/picoquic/picoquic_internal.h @@ -98,6 +98,7 @@ extern "C" { #define PICOQUIC_ALPN_NUMBER_MAX 8 + /* * Types of frames */ @@ -465,7 +466,15 @@ typedef enum { picoquic_tp_enable_loss_bit = 0x1057, picoquic_tp_min_ack_delay = 0xDE1A, picoquic_tp_enable_time_stamp = 0x7158, /* x&1 = */ - picoquic_tp_grease_quic_bit = 0x2ab2 + picoquic_tp_grease_quic_bit = 0x2ab2, + picoquic_tp_recon_bytes_in_flight = 0x3ab1, /* draft-kuhn-quic-0rtt-bdp-07 */ + picoquic_tp_recon_min_rtt = 0x3ba1, /* draft-kuhn-quic-0rtt-bdp-07 */ + picoquic_tp_recon_max_pkt_number = 0x3bc1, /* draft-kuhn-quic-0rtt-bdp-07 */ + picoquic_tp_recon_cwin = 0x3cb1, /* draft-kuhn-quic-0rtt-bdp-07 */ + picoquic_tp_recon_rtt_variant = 0x3cd1, /* draft-kuhn-quic-0rtt-bdp-07 */ + picoquic_tp_recon_smoothed_rtt = 0x3dc1, /* draft-kuhn-quic-0rtt-bdp-07 */ + picoquic_tp_recon_max_ack_delay = 0x3de1, /* draft-kuhn-quic-0rtt-bdp-07 */ + } picoquic_tp_enum; /* Callback for converting binary log to quic log at the end of a connection. @@ -522,6 +531,7 @@ typedef struct st_picoquic_quic_t { unsigned int log_pn_dec : 1; /* Log key hashes on key changes to debug crypto */ unsigned int random_initial : 1; /* Randomize the initial PN number */ unsigned int packet_train_mode : 1; /* Tune pacing for sending packet trains */ + unsigned int is_0RTT_BDP_enabled : 1; /* 0-RTT_BDP extension is negociated */ picoquic_stateless_packet_t* pending_stateless_packet; @@ -560,6 +570,9 @@ typedef struct st_picoquic_quic_t { void* fuzz_ctx; int wake_file; int wake_line; + + int bdp_interval; + int bdp_limit; } picoquic_quic_t; picoquic_packet_context_enum picoquic_context_from_epoch(int epoch); @@ -944,7 +957,6 @@ typedef struct st_picoquic_cnx_t { unsigned int quic_bit_greased : 1; /* Indicate whether the quic bit was greased at least once */ unsigned int quic_bit_received_0 : 1; /* Indicate whether the quic bit was received as zero at least once */ unsigned int is_half_open : 1; /* for server side connections, created but not yet complete */ - /* Spin bit policy */ picoquic_spinbit_version_enum spin_policy; /* Idle timeout in microseconds */ @@ -1092,6 +1104,10 @@ typedef struct st_picoquic_cnx_t { uint64_t ack_gap_remote; uint64_t ack_delay_remote; + /* Management the sending of BDP */ + uint64_t bdp_send_time; + uint64_t nb_bdp_sample_sent; + /* Copies of packets received too soon */ picoquic_stateless_packet_t* first_sooner; picoquic_stateless_packet_t* last_sooner; @@ -1452,6 +1468,15 @@ int picoquic_prepare_transport_extensions(picoquic_cnx_t* cnx, int extension_mod int picoquic_receive_transport_extensions(picoquic_cnx_t* cnx, int extension_mode, uint8_t* bytes, size_t bytes_max, size_t* consumed); +int picoquic_prepare_bdp_extensions(picoquic_cnx_t* cnx, int extension_mode, + uint8_t* bytes, size_t bytes_max, size_t* consumed); + +int picoquic_receive_transport_extensions(picoquic_cnx_t* cnx, int extension_mode, + uint8_t* bytes, size_t bytes_max, size_t* consumed); + +int picoquic_receive_bdp_extensions(picoquic_cnx_t* cnx, int extension_mode, + uint8_t* bytes, size_t bytes_max, size_t* consumed); + picoquic_misc_frame_header_t* picoquic_create_misc_frame(const uint8_t* bytes, size_t length, int is_pure_ack); #ifdef __cplusplus diff --git a/picoquic/tls_api.c b/picoquic/tls_api.c index 26813cee9..b09488449 100644 --- a/picoquic/tls_api.c +++ b/picoquic/tls_api.c @@ -75,6 +75,9 @@ #define PICOQUIC_TRANSPORT_PARAMETERS_TLS_EXTENSION 0xFFA5 #define PICOQUIC_TRANSPORT_PARAMETERS_MAX_SIZE 2048 +#define PICOQUIC_BDP_PARAMETERS_TLS_EXTENSION 0xFFA0 +#define PICOQUIC_BDP_PARAMETERS_MAX_SIZE 2048 + #ifdef PTLS_ESNI_NONCE_SIZE #define PICOQUIC_ESNI_NONCE_SIZE PTLS_ESNI_NONCE_SIZE #else @@ -87,13 +90,18 @@ typedef struct st_picoquic_tls_ctx_t { picoquic_cnx_t* cnx; int client_mode; ptls_raw_extension_t ext[2]; + ptls_raw_extension_t bdp_ext[2]; ptls_handshake_properties_t handshake_properties; ptls_iovec_t alpn_vec[PICOQUIC_ALPN_NUMBER_MAX]; int alpn_count; uint8_t ext_data[PICOQUIC_TRANSPORT_PARAMETERS_MAX_SIZE]; + uint8_t bdp_ext_data[PICOQUIC_BDP_PARAMETERS_MAX_SIZE]; uint8_t ext_received[PICOQUIC_TRANSPORT_PARAMETERS_MAX_SIZE]; size_t ext_received_length; int ext_received_return; + uint8_t ext_bdp_received[PICOQUIC_BDP_PARAMETERS_MAX_SIZE]; + size_t ext_bdp_received_length; + int ext_bdp_received_return; uint16_t esni_version; uint8_t esni_nonce[PICOQUIC_ESNI_NONCE_SIZE]; uint8_t app_secret_enc[PTLS_MAX_DIGEST_SIZE]; @@ -924,7 +932,7 @@ int picoquic_tls_collect_extensions_cb(ptls_t* tls, struct st_ptls_handshake_pro UNREFERENCED_PARAMETER(tls); UNREFERENCED_PARAMETER(properties); #endif - return type == PICOQUIC_TRANSPORT_PARAMETERS_TLS_EXTENSION; + return type == PICOQUIC_TRANSPORT_PARAMETERS_TLS_EXTENSION || type == PICOQUIC_BDP_PARAMETERS_TLS_EXTENSION; } void picoquic_tls_set_extensions(picoquic_cnx_t* cnx, picoquic_tls_ctx_t* tls_ctx) @@ -949,6 +957,29 @@ void picoquic_tls_set_extensions(picoquic_cnx_t* cnx, picoquic_tls_ctx_t* tls_ct tls_ctx->handshake_properties.additional_extensions = tls_ctx->ext; } +void picoquic_tls_set_bdp_extensions(picoquic_cnx_t* cnx, picoquic_tls_ctx_t* tls_ctx) +{ + size_t consumed; + int ret = picoquic_prepare_bdp_extensions(cnx, (tls_ctx->client_mode) ? 0 : 1, + tls_ctx->bdp_ext_data, sizeof(tls_ctx->bdp_ext_data), &consumed); + + if (ret == 0) { + tls_ctx->bdp_ext[0].type = PICOQUIC_BDP_PARAMETERS_TLS_EXTENSION; + tls_ctx->bdp_ext[0].data.base = tls_ctx->bdp_ext_data; + tls_ctx->bdp_ext[0].data.len = consumed; + tls_ctx->bdp_ext[1].type = 0xFFFF; + tls_ctx->bdp_ext[1].data.base = NULL; + tls_ctx->bdp_ext[1].data.len = 0; + } else { + tls_ctx->bdp_ext[0].type = 0xFFFF; + tls_ctx->bdp_ext[0].data.base = NULL; + tls_ctx->bdp_ext[0].data.len = 0; + } + + tls_ctx->handshake_properties.nst_extensions = tls_ctx->bdp_ext; +} + + /* * The collected extensions call back is called by the stack upon * reception of a handshake message containing supported extensions. @@ -987,6 +1018,23 @@ int picoquic_tls_collected_extensions_cb(ptls_t* tls, ptls_handshake_properties_ picoquic_tls_set_extensions(ctx->cnx, ctx); } } + if (slots[i_slot].type == PICOQUIC_BDP_PARAMETERS_TLS_EXTENSION) { + size_t copied_length = sizeof(ctx->ext_bdp_received); + + /* Retrieve the bdp metadata parameters from session ticket */ + if (ctx->client_mode == 1 && ctx->cnx->quic->is_0RTT_BDP_enabled == 1) { + ret = picoquic_receive_bdp_extensions(ctx->cnx, 1, + slots[i_slot].data.base, slots[i_slot].data.len, &consumed); + } + + /* Copy the extensions in the local context for further debugging */ + ctx->ext_bdp_received_length = slots[i_slot].data.len; + if (copied_length > ctx->ext_bdp_received_length) + copied_length = ctx->ext_bdp_received_length; + memcpy(ctx->ext_bdp_received, slots[i_slot].data.base, copied_length); + ctx->ext_bdp_received_return = ret; + picoquic_tls_set_extensions(ctx->cnx, ctx); + } } return ret; @@ -1262,7 +1310,6 @@ int picoquic_enable_custom_verify_certificate_callback(picoquic_quic_t* quic) { } } - void picoquic_dispose_verify_certificate_callback(picoquic_quic_t* quic, int custom) { ptls_context_t* ctx = (ptls_context_t*)quic->tls_master_ctx; @@ -2590,6 +2637,56 @@ int picoquic_tls_stream_process(picoquic_cnx_t* cnx) ptls_buffer_dispose(&sendbuf); } + // Send a new session ticket + { + uint64_t current_time = picoquic_get_quic_time(cnx->quic); + if (cnx->bdp_send_time == 0) + cnx->bdp_send_time = current_time; + + if (!cnx->client_mode && ptls_handshake_is_complete(ctx->tls) && (current_time - cnx->bdp_send_time > cnx->quic->bdp_interval * 1000) + && cnx->quic->bdp_limit > cnx->nb_bdp_sample_sent) { + picoquic_tls_set_bdp_extensions(cnx, ctx); + struct st_ptls_buffer_t sendbuf; + size_t send_offset[PICOQUIC_NUMBER_OF_EPOCH_OFFSETS] = { 0, 0, 0, 0, 0 }; + ptls_buffer_init(&sendbuf, "", 0); + + /* Clearing the global error state of openssl before calling handle message. + * This allows detection of errors during processing. */ + picoquic_clear_crypto_errors(); + + ret = ptls_handle_message(ctx->tls, &sendbuf, send_offset, epoch, NULL, 0, &ctx->handshake_properties); + + if ((ret == 0 || ret == PTLS_ERROR_IN_PROGRESS || + ret == PTLS_ERROR_STATELESS_RETRY)) { +#ifdef PTLS_ESNI_NONCE_SIZE + /* Find the ESNI secret if any, and copy key values to picoquic tls context */ + struct st_ptls_esni_secret_t* esni = ptls_get_esni_secret(ctx->tls); + if (esni != NULL) { + ctx->esni_version = esni->version; + memcpy(ctx->esni_nonce, esni->nonce, PTLS_ESNI_NONCE_SIZE); + } +#endif + if (sendbuf.off > 0) { + ret = picoquic_add_to_tls_stream(cnx, sendbuf.base, sendbuf.off, epoch); + if (ret == 0) { + cnx->bdp_send_time = current_time; + cnx->nb_bdp_sample_sent += 1; + } + } + else { + ret = 0; + } + } + else { + picoquic_log_crypto_errors(cnx, ret); + ret = -1; + } + + ptls_buffer_dispose(&sendbuf); + } + } + + if (processed > 0) { if (ret == 0) { switch (cnx->cnx_state) { diff --git a/picoquic/transport.c b/picoquic/transport.c index 9b26f64aa..2b034bdcc 100644 --- a/picoquic/transport.c +++ b/picoquic/transport.c @@ -399,6 +399,41 @@ int picoquic_prepare_transport_extensions(picoquic_cnx_t* cnx, int extension_mod bytes = picoquic_transport_param_type_flag_encode(bytes, bytes_max, picoquic_tp_grease_quic_bit); } + if (cnx->local_parameters.recon_bytes_in_flight > 0 && bytes != NULL) { + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_bytes_in_flight, + cnx->local_parameters.recon_bytes_in_flight); + } + + if (cnx->local_parameters.recon_min_rtt > 0 && bytes != NULL) { + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_min_rtt, + cnx->local_parameters.recon_min_rtt); + } + + if (cnx->local_parameters.recon_max_pkt_number > 0 && bytes != NULL) { + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_max_pkt_number, + cnx->local_parameters.recon_max_pkt_number); + } + + if (cnx->local_parameters.recon_cwin > 0 && bytes != NULL) { + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_cwin, + cnx->local_parameters.recon_cwin); + } + + if (cnx->local_parameters.recon_rtt_variant > 0 && bytes != NULL) { + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_rtt_variant, + cnx->local_parameters.recon_rtt_variant); + } + + if (cnx->local_parameters.recon_smoothed_rtt > 0 && bytes != NULL) { + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_smoothed_rtt, + cnx->local_parameters.recon_smoothed_rtt); + } + + if (cnx->local_parameters.recon_max_ack_delay > 0 && bytes != NULL) { + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_max_ack_delay, + cnx->local_parameters.recon_max_ack_delay); + } + if (bytes == NULL) { *consumed = 0; ret = PICOQUIC_ERROR_EXTENSION_BUFFER_TOO_SMALL; @@ -414,6 +449,50 @@ int picoquic_prepare_transport_extensions(picoquic_cnx_t* cnx, int extension_mod } } + return ret; + +} + +int picoquic_prepare_bdp_extensions(picoquic_cnx_t* cnx, int extension_mode, + uint8_t* bytes, size_t bytes_length, size_t* consumed) +{ + int ret = 0; + uint8_t* bytes_zero = bytes; + uint8_t* bytes_max = bytes + bytes_length; + + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_bytes_in_flight, + cnx->path[0]->bytes_in_transit); + + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_min_rtt, + cnx->path[0]->rtt_min); + + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_max_pkt_number, + 0); + + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_cwin, + cnx->path[0]->cwin); + + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_rtt_variant, + cnx->path[0]->rtt_variant); + + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_smoothed_rtt, + cnx->path[0]->smoothed_rtt); + + bytes = picoquic_transport_param_type_varint_encode(bytes, bytes_max, picoquic_tp_recon_max_ack_delay, + cnx->path[0]->max_ack_delay); + + if (bytes == NULL) { + *consumed = 0; + ret = PICOQUIC_ERROR_EXTENSION_BUFFER_TOO_SMALL; + } + else { + *consumed = bytes - bytes_zero; + if (cnx->quic->F_log) { + picoquic_log_transport_extension(cnx->quic->F_log, cnx, 0, 1, bytes_zero, *consumed); + } + + } + return ret; } @@ -687,6 +766,43 @@ int picoquic_receive_transport_extensions(picoquic_cnx_t* cnx, int extension_mod cnx->remote_parameters.do_grease_quic_bit = 1; } break; + case picoquic_tp_recon_bytes_in_flight: + cnx->remote_parameters.recon_bytes_in_flight = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + cnx->quic->is_0RTT_BDP_enabled = 1; + break; + case picoquic_tp_recon_min_rtt: + cnx->remote_parameters.recon_min_rtt = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + cnx->quic->is_0RTT_BDP_enabled = 1; + break; + case picoquic_tp_recon_max_pkt_number: + cnx->remote_parameters.recon_max_pkt_number = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + cnx->quic->is_0RTT_BDP_enabled = 1; + break; + case picoquic_tp_recon_cwin: + cnx->remote_parameters.recon_cwin = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + cnx->path[0]->cwin = cnx->remote_parameters.recon_cwin; + cnx->quic->is_0RTT_BDP_enabled = 1; + break; + case picoquic_tp_recon_rtt_variant: + cnx->remote_parameters.recon_rtt_variant = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + cnx->quic->is_0RTT_BDP_enabled = 1; + break; + case picoquic_tp_recon_smoothed_rtt: + cnx->remote_parameters.recon_smoothed_rtt = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + cnx->quic->is_0RTT_BDP_enabled = 1; + break; + case picoquic_tp_recon_max_ack_delay: + cnx->remote_parameters.recon_max_ack_delay = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + cnx->quic->is_0RTT_BDP_enabled = 1; + break; + default: /* ignore unknown extensions */ break; @@ -694,6 +810,11 @@ int picoquic_receive_transport_extensions(picoquic_cnx_t* cnx, int extension_mod if (ret == 0) { byte_index += (size_t)extension_length; + if (cnx->quic->is_0RTT_BDP_enabled) { + uint64_t current_time = picoquic_get_quic_time(cnx->quic); + uint64_t recon_smoothed_rtt = cnx->remote_parameters.recon_smoothed_rtt; + picoquic_update_path_rtt(cnx, cnx->path[0], current_time - recon_smoothed_rtt, current_time, 0); + } } } } @@ -834,3 +955,93 @@ int picoquic_receive_transport_extensions(picoquic_cnx_t* cnx, int extension_mod return ret; } + + +int picoquic_receive_bdp_extensions(picoquic_cnx_t* cnx, int extension_mode, + uint8_t* bytes, size_t bytes_max, size_t* consumed) +{ + int ret = 0; + size_t byte_index = 0; + uint64_t present_flag = 0; + + + if (cnx->quic->F_log) { + picoquic_log_transport_extension(cnx->quic->F_log, cnx, 1, 1, bytes, bytes_max); + } + + while (ret == 0 && byte_index < bytes_max) { + size_t ll_type = 0; + size_t ll_length = 0; + uint64_t extension_type = UINT64_MAX; + uint64_t extension_length = 0; + + if (byte_index + 2 > bytes_max) { + ret = picoquic_connection_error(cnx, PICOQUIC_TRANSPORT_PARAMETER_ERROR, 0); + } + else { + ll_type = picoquic_varint_decode(bytes + byte_index, bytes_max - byte_index, &extension_type); + byte_index += ll_type; + ll_length = picoquic_varint_decode(bytes + byte_index, bytes_max - byte_index, &extension_length); + byte_index += ll_length; + + if (ll_type == 0 || ll_length == 0 || byte_index + extension_length > bytes_max) { + ret = picoquic_connection_error(cnx, PICOQUIC_TRANSPORT_PARAMETER_ERROR, 0); + } + else { + if (extension_type < 64) { + if ((present_flag & (1ull << extension_type)) != 0) { + /* Malformed, already present */ + ret = picoquic_connection_error(cnx, PICOQUIC_TRANSPORT_PARAMETER_ERROR, 0); + } + else { + present_flag |= (1ull << extension_type); + } + } + + switch (extension_type) { + case picoquic_tp_recon_bytes_in_flight: + cnx->local_parameters.recon_bytes_in_flight = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + break; + case picoquic_tp_recon_min_rtt: + cnx->local_parameters.recon_min_rtt = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + break; + case picoquic_tp_recon_max_pkt_number: + cnx->local_parameters.recon_max_pkt_number = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + break; + case picoquic_tp_recon_cwin: + cnx->local_parameters.recon_cwin = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + break; + case picoquic_tp_recon_rtt_variant: + cnx->local_parameters.recon_rtt_variant = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + break; + case picoquic_tp_recon_smoothed_rtt: + cnx->local_parameters.recon_smoothed_rtt = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + break; + case picoquic_tp_recon_max_ack_delay: + cnx->local_parameters.recon_max_ack_delay = + picoquic_transport_param_varint_decode(cnx, bytes + byte_index, extension_length, &ret); + break; + + default: + /* ignore unknown extensions */ + break; + } + + if (ret == 0) { + byte_index += (size_t)extension_length; + } + } + } + } + + + *consumed = byte_index; + + return ret; +} diff --git a/picoquicfirst/picoquicdemo.c b/picoquicfirst/picoquicdemo.c index 06dd15c96..9d71c1b67 100644 --- a/picoquicfirst/picoquicdemo.c +++ b/picoquicfirst/picoquicdemo.c @@ -50,6 +50,7 @@ #include #include #include +#include #define SERVER_CERT_FILE "certs/cert.pem" #define SERVER_KEY_FILE "certs/key.pem" @@ -147,7 +148,7 @@ int quic_server(const char* server_name, int server_port, const char* esni_key_file_name, const char* esni_rr_file_name, char const* log_file, char const* bin_dir, char const* qlog_dir, int use_long_log, picoquic_congestion_algorithm_t const* cc_algorithm, char const* web_folder, - int initial_random) + int initial_random, int bdp_interval, int bdp_limit) { /* Start: start the QUIC process with cert and key files */ int ret = 0; @@ -202,6 +203,9 @@ int quic_server(const char* server_name, int server_port, picoquic_set_random_initial(qserver, 1); } + qserver->bdp_interval = bdp_interval; + qserver->bdp_limit = bdp_limit; + picoquic_set_key_log_file_from_env(qserver); if (esni_key_file_name != NULL && esni_rr_file_name != NULL) { @@ -462,7 +466,7 @@ int quic_client(const char* ip_address_text, int server_port, int client_cnx_id_length, char const * client_scenario_text, int no_disk, int use_long_log, picoquic_congestion_algorithm_t const* cc_algorithm, int large_client_hello, char const * out_dir, int cipher_suite_id, - int initial_random) + int initial_random, int enable_zero_rtt_bdp) { /* Start: start the QUIC process with cert and key files */ int ret = 0; @@ -558,6 +562,9 @@ int quic_client(const char* ip_address_text, int server_port, fprintf(stderr, "Could not set cipher suite #%d.\n", cipher_suite_id); } } + if (enable_zero_rtt_bdp) { + qclient->is_0RTT_BDP_enabled = 1; + } } } @@ -636,6 +643,7 @@ int quic_client(const char* ip_address_text, int server_port, ret = picoquic_demo_client_start_streams(cnx_client, &callback_ctx, PICOQUIC_DEMO_STREAM_ID_INITIAL); } } + } } @@ -882,6 +890,9 @@ void usage() fprintf(stderr, " -Q send a large client hello in order to test post quantum\n"); fprintf(stderr, " readiness.\n"); fprintf(stderr, " -R randomize initial packet number\n"); + fprintf(stderr, " -B Enable 0-RTT BDP extension on client\n"); + fprintf(stderr, " -T bdp_interval Delay between bdp samples in milliseconds. Default to 1000ms\n"); + fprintf(stderr, " -M bdp_limit Maximum number of bdp samples to send by server\n"); fprintf(stderr, "\nThe scenario argument specifies the set of files that should be retrieved,\n"); fprintf(stderr, "and their order. The syntax is:\n"); @@ -939,6 +950,9 @@ int main(int argc, char** argv) char default_server_cert_file[512]; char default_server_key_file[512]; char * client_scenario = NULL; + int enable_zero_rtt_bdp = 0; + int bdp_interval = 1000; + int bdp_limit = UINT_MAX; int ret = 0; #ifdef _WINDOWS @@ -948,7 +962,7 @@ int main(int argc, char** argv) /* Get the parameters */ int opt; - while ((opt = getopt(argc, argv, "c:k:K:p:u:v:o:w:f:i:s:e:E:C:l:b:q:m:n:a:t:S:I:G:1rRhzDLQ")) != -1) { + while ((opt = getopt(argc, argv, "c:k:K:p:u:v:o:w:f:i:s:e:E:C:l:b:q:m:n:a:t:S:I:G:T:M:1rRhzDLQB")) != -1) { switch (opt) { case 'c': server_cert_file = optarg; @@ -1083,6 +1097,23 @@ int main(int argc, char** argv) case 'Q': large_client_hello = 1; break; + case 'B': + enable_zero_rtt_bdp = 1; + break; + case 'T': + bdp_interval = atoi(optarg); + if (bdp_interval < 0) { + fprintf(stderr, "Invalid bdp interval: %s\n", optarg); + usage(); + } + break; + case 'M': + bdp_limit = atoi(optarg); + if (bdp_limit < 0) { + fprintf(stderr, "Invalid bdp limit: %s\n", optarg); + usage(); + } + break; case 'h': usage(); break; @@ -1134,7 +1165,7 @@ int main(int argc, char** argv) (cnx_id_cbdata == NULL) ? NULL : (void*)cnx_id_cbdata, (uint8_t*)reset_seed, dest_if, mtu_max, proposed_version, esni_key_file, esni_rr_file, - log_file, bin_dir, qlog_dir, use_long_log, cc_algorithm, www_dir, initial_random); + log_file, bin_dir, qlog_dir, use_long_log, cc_algorithm, www_dir, initial_random, bdp_interval, bdp_limit); printf("Server exit with code = %d\n", ret); } else { /* Run as client */ @@ -1142,7 +1173,7 @@ int main(int argc, char** argv) ret = quic_client(server_name, server_port, sni, esni_rr_file, alpn, root_trust_file, proposed_version, force_zero_share, force_migration, nb_packets_before_update, mtu_max, log_file, bin_dir, qlog_dir, client_cnx_id_length, client_scenario, - no_disk, use_long_log, cc_algorithm, large_client_hello, out_dir, cipher_suite_id, initial_random); + no_disk, use_long_log, cc_algorithm, large_client_hello, out_dir, cipher_suite_id, initial_random, enable_zero_rtt_bdp); printf("Client exit with code = %d\n", ret); }