diff --git a/CMakeLists.txt b/CMakeLists.txt index a08b763da..2d0a2d2e2 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -8,7 +8,7 @@ else() endif() project(picoquic - VERSION 1.1.32.0 + VERSION 1.1.33.0 DESCRIPTION "picoquic library" LANGUAGES C CXX) @@ -102,6 +102,7 @@ set(PICOQUIC_LIBRARY_FILES picoquic/port_blocking.c picoquic/prague.c picoquic/quicctx.c + picoquic/register_all_cc_algorithms.c picoquic/sacks.c picoquic/sender.c picoquic/sim_link.c @@ -126,6 +127,12 @@ set(PICOQUIC_CORE_HEADERS picoquic/picoquic_binlog.h picoquic/picoquic_config.h picoquic/picoquic_lb.h + picoquic/picoquic_newreno.h + picoquic/picoquic_cubic.h + picoquic/picoquic_bbr.h + picoquic/picoquic_bbr1.h + picoquic/picoquic_fastcc.h + picoquic/picoquic_prague.h picoquic/siphash.h) set(LOGLIB_LIBRARY_FILES diff --git a/picoquic/bbr.c b/picoquic/bbr.c index c7c14a45a..c51c5ee28 100644 --- a/picoquic/bbr.c +++ b/picoquic/bbr.c @@ -26,7 +26,7 @@ #include "picoquic_utils.h" #ifdef BBRExperiment -#define BBRExpGate(ctx, test, action) { if (ctx->exp_flags.test) action; } +#define BBRExpGate(ctx, test, action) { if (!ctx->exp_flags.test) action; } #define BBRExpTest(ctx, test) ( (ctx)->exp_flags.test ) #else #define BBRExpGate(ctx, test, action) {} @@ -141,6 +141,22 @@ typedef enum { #define BBRExcessiveEcnCE 0.2 +/* Temporary code, do define a set of BBR flags that +* turn on and off individual extensions. We want to use that +* to do "before/after" measurements. + */ +#define BBRExperiment on +#ifdef BBRExperiment + /* Control flags for BBR improvements */ +typedef struct st_bbr_exp { + unsigned int do_early_exit : 1; + unsigned int do_rapid_start : 1; + unsigned int do_handle_suspension : 1; + unsigned int do_control_lost : 1; + unsigned int do_exit_probeBW_up_on_delay : 1; + unsigned int do_enter_probeBW_after_limited : 1; +} bbr_exp; +#endif typedef struct st_picoquic_bbr_state_t { /* Algorithm state: */ picoquic_bbr_alg_state_t state; @@ -260,13 +276,13 @@ typedef struct st_picoquic_bbr_state_t { unsigned int probe_bdp_seed; /* Experimental extensions, may or maynot be a good idea. */ + char const* option_string; uint64_t wifi_shadow_rtt; /* Shadow RTT used for wifi connections. */ double quantum_ratio; /* allow application to use a different default than 0.1% of bandwidth (or 1ms of traffic) */ #ifdef BBRExperiment /* Control flags for BBR improvements */ bbr_exp exp_flags; #endif - } picoquic_bbr_state_t; /* BBR v3 assumes that there is state associated with the acknowledgements. @@ -422,13 +438,132 @@ static void BBRInitFullPipe(picoquic_bbr_state_t* bbr_state) bbr_state->full_bw_count = 0; } +/* Initialization of optional variables defined in text string +* Syntax: +* - Single letter options that control the "BBR Experiment" +* E: do_early_exit +* R: do_rapid_start +* H: do_handle_suspension +* L: do_control_lost +* D: do_exit_probeBW_up_on_delay +* A: do_enter_probeBW_after_limited +* - Complex options, ends with ':' +* T999999999: wifi_shadow_rtt, microseconds +* Q99999.999: quantum_ratio, % +* +* The "BBR Experiment" is an attempt to improve behavior of BBR for +* realtime support on some networks, mostly Wi-Fi. The experiment was a +* success, and the corresponding support is on by default, The individual +* option flags can be used to turn off some parts of the experiment, +* for example when doing before/after measurements. +*/ +static void BBRSetOptions(picoquic_bbr_state_t* bbr_state) +{ + const char* x = bbr_state->option_string; +#ifdef BBRExperiment + bbr_state->exp_flags.do_early_exit = 1; + bbr_state->exp_flags.do_rapid_start = 1; + bbr_state->exp_flags.do_handle_suspension = 1; + bbr_state->exp_flags.do_control_lost = 1; + bbr_state->exp_flags.do_exit_probeBW_up_on_delay = 1; + bbr_state->exp_flags.do_enter_probeBW_after_limited = 1; +#endif + + if (x != NULL) { + char c; + while ((c = *x) != 0) { + x++; + switch (c) { +#ifdef BBRExperiment + case 'E': + bbr_state->exp_flags.do_early_exit = 0; + break; + case 'R': + bbr_state->exp_flags.do_rapid_start = 0; + break; + case 'H': + bbr_state->exp_flags.do_handle_suspension = 0; + break; + case 'L': + bbr_state->exp_flags.do_control_lost = 0; + break; + case 'D': + bbr_state->exp_flags.do_exit_probeBW_up_on_delay = 0; + break; + case 'A': + bbr_state->exp_flags.do_enter_probeBW_after_limited = 0; + break; +#endif + case 'T': { + /* Reading digits into an uint64_t */ + uint64_t u = 0; + while ((c = *x) != 0) { + if (c >= '0' && c <= '9') { + u *= 10; + u += c - '0'; + x++; + } + else { + break; + } + } + bbr_state->wifi_shadow_rtt = u; + break; + } + case 'Q': { + /* Reading digits ad one dot into a double */ + while ((c = *x) != 0) { + double d = 0; + double div = 1.0; + int dotted = 0; + while ((c = *x) != 0) { + if (c >= '0' && c <= '9') { + if (!dotted) { + d *= 10; + d += c - '0'; + } + else { + div /= 10.0; + d += div * (c - '0'); + } + x++; + } + else if (c == '.') { + if (dotted) { + break; + } + else { + dotted = 1; + x++; + } + } + else { + break; + } + } + bbr_state->quantum_ratio = d; + break; + } + } + case ':': + /* Ignore */ + break; + default: + break; + } + } + } +} + /* Initialization of the BBR state */ -static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, uint64_t current_time) +static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, uint64_t current_time, char const * option_string) { /* TODO: init_windowed_max_filter(filter = BBR.MaxBwFilter, value = 0, time = 0) */ memset(bbr_state, 0, sizeof(picoquic_bbr_state_t)); + bbr_state->option_string = option_string; + BBRInitRandom(bbr_state, path_x, current_time); /* If RTT was already sampled, use it, other wise set min RTT to infinity */ if (path_x->smoothed_rtt == PICOQUIC_INITIAL_RTT @@ -446,15 +581,8 @@ static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, bbr_state->min_rtt_stamp = current_time; bbr_state->extra_acked_interval_start = current_time; bbr_state->extra_acked_delivered = 0; - /* Support for the wifi_shadow_rtt hack */ - bbr_state->wifi_shadow_rtt = path_x->cnx->quic->wifi_shadow_rtt; - -#ifdef BBRExperiment - /* Support for BBR Experiment */ - bbr_state->exp_flags = path_x->cnx->quic->bbr_exp_flags; -#endif - /* Support for experimenting with the send_quantum ratio */ - bbr_state->quantum_ratio = path_x->cnx->quic->bbr_quantum_ratio; + /* Support for the experimental options */ + BBRSetOptions(bbr_state); if (bbr_state->quantum_ratio == 0) { bbr_state->quantum_ratio = 0.001; } @@ -469,17 +597,17 @@ static void BBROnInit(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, static void picoquic_bbr_reset(picoquic_bbr_state_t* bbr_state, picoquic_path_t* path_x, uint64_t current_time) { - BBROnInit(bbr_state, path_x, current_time); + BBROnInit(bbr_state, path_x, current_time, bbr_state->option_string); } -static void picoquic_bbr_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, uint64_t current_time) +static void picoquic_bbr_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const* option_string, uint64_t current_time) { /* Initialize the state of the congestion control algorithm */ picoquic_bbr_state_t* bbr_state = (picoquic_bbr_state_t*)malloc(sizeof(picoquic_bbr_state_t)); path_x->congestion_alg_state = (void*)bbr_state; if (bbr_state != NULL) { - BBROnInit(bbr_state, path_x, current_time); + BBROnInit(bbr_state, path_x, current_time, option_string); } } diff --git a/picoquic/bbr1.c b/picoquic/bbr1.c index 6ff8271e5..b1e6b0f73 100644 --- a/picoquic/bbr1.c +++ b/picoquic/bbr1.c @@ -278,6 +278,7 @@ typedef struct st_picoquic_bbr1_state_t { uint64_t congestion_sequence; /* sequence number after congestion notification */ uint64_t cwin_before_suspension; /* So it can be restored if suspension stops. */ + const char* option_string; uint64_t wifi_shadow_rtt; /* Shadow RTT used for wifi connections. */ double quantum_ratio; @@ -368,13 +369,89 @@ void BBR1UpdateTargetCwnd(picoquic_bbr1_state_t* bbr1_state) bbr1_state->target_cwnd = BBR1Inflight(bbr1_state, bbr1_state->cwnd_gain); } -static void picoquic_bbr1_reset(picoquic_bbr1_state_t* bbr1_state, picoquic_path_t* path_x, uint64_t current_time, uint64_t wifi_shadow_rtt) + +/* Initialization of optional variables defined in text string +* Syntax: +* T999999999: wifi_shadow_rtt, microseconds +* Q99999.999: quantum_ratio, +* +*/ +static void picoquic_bbr1_set_options(picoquic_bbr1_state_t* bbr1_state) +{ + const char* x = bbr1_state->option_string; + + if (x != NULL) { + char c; + while ((c = *x) != 0) { + x++; + switch (c) { + case 'T': { + /* Reading digits into an uint64_t */ + uint64_t u = 0; + while ((c = *x) != 0) { + if (c >= '0' && c <= '9') { + u *= 10; + u += c - '0'; + x++; + } + else { + break; + } + } + bbr1_state->wifi_shadow_rtt = u; + break; + } + case 'Q': { + /* Reading digits ad one dot into a double */ + while ((c = *x) != 0) { + double d = 0; + double div = 1.0; + int dotted = 0; + while ((c = *x) != 0) { + if (c >= '0' && c <= '9') { + if (!dotted) { + d *= 10; + d += c - '0'; + } + else { + div /= 10.0; + d += div * (c - '0'); + } + x++; + } + else if (c == '.') { + if (dotted) { + break; + } + else { + dotted = 1; + x++; + } + } + else { + break; + } + } + bbr1_state->quantum_ratio = d; + break; + } + } + case ':': + /* Ignore */ + break; + default: + break; + } + } + } +} + +static void picoquic_bbr1_reset(picoquic_bbr1_state_t* bbr1_state, picoquic_path_t* path_x, uint64_t current_time) { memset(bbr1_state, 0, sizeof(picoquic_bbr1_state_t)); path_x->cwin = PICOQUIC_CWIN_INITIAL; - bbr1_state->rt_prop = UINT64_MAX; - bbr1_state->wifi_shadow_rtt = path_x->cnx->quic->wifi_shadow_rtt; - bbr1_state->quantum_ratio = path_x->cnx->quic->bbr_quantum_ratio; + bbr1_state->rt_prop = UINT64_MAX; + picoquic_bbr1_set_options(bbr1_state); if (bbr1_state->quantum_ratio == 0) { bbr1_state->quantum_ratio = 0.001; } @@ -389,14 +466,15 @@ static void picoquic_bbr1_reset(picoquic_bbr1_state_t* bbr1_state, picoquic_path BBR1UpdateTargetCwnd(bbr1_state); } -static void picoquic_bbr1_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, uint64_t current_time) +static void picoquic_bbr1_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const* option_string, uint64_t current_time) { /* Initialize the state of the congestion control algorithm */ picoquic_bbr1_state_t* bbr1_state = (picoquic_bbr1_state_t*)malloc(sizeof(picoquic_bbr1_state_t)); path_x->congestion_alg_state = (void*)bbr1_state; if (bbr1_state != NULL) { - picoquic_bbr1_reset(bbr1_state, path_x, current_time, cnx->quic->wifi_shadow_rtt); + bbr1_state->option_string = option_string; + picoquic_bbr1_reset(bbr1_state, path_x, current_time); } } @@ -1210,7 +1288,7 @@ static void picoquic_bbr1_notify( case picoquic_congestion_notification_cwin_blocked: break; case picoquic_congestion_notification_reset: - picoquic_bbr1_reset(bbr1_state, path_x, current_time, cnx->quic->wifi_shadow_rtt); + picoquic_bbr1_reset(bbr1_state, path_x, current_time); break; case picoquic_congestion_notification_seed_cwin: if (bbr1_state->state == picoquic_bbr1_alg_startup_long_rtt) { diff --git a/picoquic/config.c b/picoquic/config.c index e8e5a9571..99ba0187f 100644 --- a/picoquic/config.c +++ b/picoquic/config.c @@ -34,6 +34,7 @@ #include "picoquic_unified_log.h" #include "tls_api.h" #include "picoquic_config.h" +#include "picoquic_bbr.h" typedef struct st_option_param_t { char const * param; @@ -64,7 +65,8 @@ static option_table_line_t option_table[] = { { picoquic_option_DisablePortBlocking, 'X', "disable_block", 0, "", "Disable the check for blocked ports"}, { picoquic_option_SOLUTION_DIR, 'S', "solution_dir", 1, "folder", "Set the path to the source files to find the default files" }, { picoquic_option_CC_ALGO, 'G', "cc_algo", 1, "cc_algorithm", - "Use the specified congestion control algorithm: reno, cubic, bbr or fast. Defaults to bbr." }, + "Use the specified congestion control algorithm. Defaults to bbr. Supported values are:" }, + { picoquic_option_CC_OPTION, 'H', "cco", 1, "option", "Set option string if required by congestion control algorithm."}, { picoquic_option_SPINBIT, 'P', "spinbit", 1, "number", "Set the default spinbit policy" }, { picoquic_option_LOSSBIT, 'O', "lossbit", 1, "number", "Set the default lossbit policy" }, { picoquic_option_MULTIPATH, 'M', "multipath", 0, "", "Enable QUIC multipath extension" }, @@ -291,6 +293,9 @@ static int config_set_option(option_table_line_t* option_desc, option_param_t* p case picoquic_option_CC_ALGO: ret = config_set_string_param(&config->cc_algo_id, params, nb_params, 0); break; + case picoquic_option_CC_OPTION: + ret = config_set_string_param(&config->cc_algo_option_string, params, nb_params, 0); + break; case picoquic_option_SPINBIT: { int v = config_atoi(params, nb_params, 0, &ret); if (ret != 0 || v < 0 || v > (int)picoquic_spinbit_on) { @@ -482,6 +487,22 @@ void picoquic_config_usage_file(FILE* F) putc(' ', F); } fprintf(F, " %s\n", option_table[i].option_help); + if (option_table[i].option_num == picoquic_option_CC_ALGO){ + if (picoquic_congestion_control_algorithms != NULL && + picoquic_nb_congestion_control_algorithms > 0) { + /* Add a line with supported values. */ + for (size_t j = 0; j < 18; j++) { + putc(' ', F); + } + for (size_t k = 0; k < picoquic_nb_congestion_control_algorithms; k++) { + if (k != 0) { + fprintf(F, ", "); + } + fprintf(F, "%s", picoquic_congestion_control_algorithms[k]->congestion_algorithm_id); + } + fprintf(F, ".\n"); + } + } } } @@ -790,7 +811,7 @@ picoquic_quic_t* picoquic_create_and_configure(picoquic_quic_config_t* config, cc_algo = picoquic_bbr_algorithm; } - picoquic_set_default_congestion_algorithm(quic, cc_algo); + picoquic_set_default_congestion_algorithm_ex(quic, cc_algo, config->cc_algo_option_string); picoquic_set_default_spinbit_policy(quic, config->spinbit_policy); picoquic_set_default_lossbit_policy(quic, config->lossbit_policy); @@ -933,6 +954,10 @@ void picoquic_config_clear(picoquic_quic_config_t* config) { free((void*)config->cc_algo_id); } + if (config->cc_algo_option_string != NULL) + { + free((void*)config->cc_algo_option_string); + } if (config->cnx_id_cbdata != NULL) { free((void*)config->cnx_id_cbdata); diff --git a/picoquic/cubic.c b/picoquic/cubic.c index 7bc3fddd3..7331c5d8f 100644 --- a/picoquic/cubic.c +++ b/picoquic/cubic.c @@ -61,12 +61,13 @@ static void cubic_reset(picoquic_cubic_state_t* cubic_state, picoquic_path_t* pa path_x->cwin = PICOQUIC_CWIN_INITIAL; } -static void cubic_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, uint64_t current_time) +static void cubic_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const* option_string, uint64_t current_time) { /* Initialize the state of the congestion control algorithm */ picoquic_cubic_state_t* cubic_state = (picoquic_cubic_state_t*)malloc(sizeof(picoquic_cubic_state_t)); #ifdef _WINDOWS UNREFERENCED_PARAMETER(cnx); + UNREFERENCED_PARAMETER(option_string); #endif path_x->congestion_alg_state = (void*)cubic_state; if (cubic_state != NULL) { diff --git a/picoquic/fastcc.c b/picoquic/fastcc.c index 4c26839f7..4c7646d18 100644 --- a/picoquic/fastcc.c +++ b/picoquic/fastcc.c @@ -91,12 +91,13 @@ void picoquic_fastcc_seed_cwin(picoquic_fastcc_state_t* fastcc_state, picoquic_p } } -void picoquic_fastcc_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, uint64_t current_time) +void picoquic_fastcc_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const* option_string, uint64_t current_time) { /* Initialize the state of the congestion control algorithm */ picoquic_fastcc_state_t* fastcc_state = path_x->congestion_alg_state; #ifdef _WINDOWS UNREFERENCED_PARAMETER(cnx); + UNREFERENCED_PARAMETER(option_string); #endif if (fastcc_state == NULL) { diff --git a/picoquic/newreno.c b/picoquic/newreno.c index 842c76e52..a1a0f5a1f 100644 --- a/picoquic/newreno.c +++ b/picoquic/newreno.c @@ -186,12 +186,13 @@ static void picoquic_newreno_reset(picoquic_newreno_state_t* nr_state, picoquic_ path_x->cwin = nr_state->nrss.cwin; } -static void picoquic_newreno_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, uint64_t current_time) +static void picoquic_newreno_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const *option_string, uint64_t current_time) { /* Initialize the state of the congestion control algorithm */ picoquic_newreno_state_t* nr_state = (picoquic_newreno_state_t*)malloc(sizeof(picoquic_newreno_state_t)); #ifdef _WINDOWS UNREFERENCED_PARAMETER(current_time); + UNREFERENCED_PARAMETER(option_string); UNREFERENCED_PARAMETER(cnx); #endif diff --git a/picoquic/picoquic.h b/picoquic/picoquic.h index f785fd29e..e97239fcf 100644 --- a/picoquic/picoquic.h +++ b/picoquic/picoquic.h @@ -40,7 +40,7 @@ extern "C" { #endif -#define PICOQUIC_VERSION "1.1.32.0" +#define PICOQUIC_VERSION "1.1.33.0" #define PICOQUIC_ERROR_CLASS 0x400 #define PICOQUIC_ERROR_DUPLICATE (PICOQUIC_ERROR_CLASS + 1) #define PICOQUIC_ERROR_AEAD_CHECK (PICOQUIC_ERROR_CLASS + 3) @@ -1545,7 +1545,7 @@ typedef struct st_picoquic_per_ack_state_t { unsigned int is_cwnd_limited: 1; /* path marked CWIN limited after packet was sent. */ } picoquic_per_ack_state_t; -typedef void (*picoquic_congestion_algorithm_init)(picoquic_cnx_t* cnx, picoquic_path_t* path_x, uint64_t current_time); +typedef void (*picoquic_congestion_algorithm_init)(picoquic_cnx_t* cnx, picoquic_path_t* path_x, char const * option_string, uint64_t current_time); typedef void (*picoquic_congestion_algorithm_notify)( picoquic_cnx_t* cnx, picoquic_path_t* path_x, @@ -1565,66 +1565,27 @@ typedef struct st_picoquic_congestion_algorithm_t { picoquic_congestion_algorithm_observe alg_observe; } picoquic_congestion_algorithm_t; -extern picoquic_congestion_algorithm_t* picoquic_newreno_algorithm; -extern picoquic_congestion_algorithm_t* picoquic_cubic_algorithm; -extern picoquic_congestion_algorithm_t* picoquic_dcubic_algorithm; -extern picoquic_congestion_algorithm_t* picoquic_fastcc_algorithm; -extern picoquic_congestion_algorithm_t* picoquic_bbr_algorithm; -extern picoquic_congestion_algorithm_t* picoquic_prague_algorithm; -extern picoquic_congestion_algorithm_t* picoquic_bbr1_algorithm; - #define PICOQUIC_DEFAULT_CONGESTION_ALGORITHM picoquic_newreno_algorithm; -picoquic_congestion_algorithm_t const* picoquic_get_congestion_algorithm(char const* alg_name); + +extern picoquic_congestion_algorithm_t const** picoquic_congestion_control_algorithms; +extern size_t picoquic_nb_congestion_control_algorithms; +/* Register a custom table of congestion control algorithms */ +void picoquic_register_congestion_control_algorithms(picoquic_congestion_algorithm_t const** alg, size_t nb_algorithms); +/* Register a full list of congestion control algorithms */ +void picoquic_register_all_congestion_control_algorithms(); + +picoquic_congestion_algorithm_t const* picoquic_get_congestion_algorithm(char const* alg_id); + void picoquic_set_default_congestion_algorithm(picoquic_quic_t* quic, picoquic_congestion_algorithm_t const* algo); +void picoquic_set_default_congestion_algorithm_ex(picoquic_quic_t* quic, picoquic_congestion_algorithm_t const* alg, char const* alg_option_string); void picoquic_set_default_congestion_algorithm_by_name(picoquic_quic_t* quic, char const* alg_name); void picoquic_set_congestion_algorithm(picoquic_cnx_t* cnx, picoquic_congestion_algorithm_t const* algo); +void picoquic_set_congestion_algorithm_ex(picoquic_cnx_t* cnx, picoquic_congestion_algorithm_t const* alg, char const* alg_option_string); -/* Special code for Wi-Fi network. These networks are subject to occasional - * "suspension", for power saving reasons. If the suspension is too long, - * it causes transmission to stop after cngestion control credits are - * exhausted. We expect that the effects of suspension are not so bad if - * the congestion control parameters allow for transmission through the - * suspension. The "wifi shadow RTT" parameter tells the congestion control - * algorithm BBR to set the CWIN large enough to sustain transmission through - * that duration. The value is in microseconds. - * - * This parameter should be set before the first connections are started. - * Changing the settings will not affect existing connections. - */ -void picoquic_set_default_wifi_shadow_rtt(picoquic_quic_t* quic, uint64_t wifi_shadow_rtt); - -/* The experimental API `picoquic_set_default_bbr_quantum_ratio` -* allows application to change the "quantum ratio" parameter of the BBR -* algorithm. The default value is 0.001 (1/1000th of the pacing rate -* in bytes per second). Larger values like 0.01 would increase the -* size of the "leaky bucket" used by the pacing algorithms. Whether -* that's a good idea or not is debatable, probably depends on the -* application. -*/ -void picoquic_set_default_bbr_quantum_ratio(picoquic_quic_t* quic, double quantum_ratio); - -/* Temporary code, do define a set of BBR flags that -* turn on and off individual extensions. We want to use that -* to do "before/after" measurements. - */ -#define BBRExperiment on -#ifdef BBRExperiment -/* Control flags for BBR improvements */ -typedef struct st_bbr_exp { - unsigned int do_early_exit : 1; - unsigned int do_rapid_start : 1; - unsigned int do_handle_suspension : 1; - unsigned int do_control_lost : 1; - unsigned int do_exit_probeBW_up_on_delay : 1; - unsigned int do_enter_probeBW_after_limited : 1; -} bbr_exp; - -void picoquic_set_bbr_exp(picoquic_quic_t * quic, bbr_exp* exp); -#endif /* The experimental API 'picoquic_set_priority_limit_for_bypass' * instruct the stack to send the high priority streams or datagrams * immediately, even if congestion control would normally prevent it. diff --git a/picoquic/picoquic.vcxproj b/picoquic/picoquic.vcxproj index 6c52a45b3..a19db9382 100644 --- a/picoquic/picoquic.vcxproj +++ b/picoquic/picoquic.vcxproj @@ -171,6 +171,7 @@ + diff --git a/picoquic/picoquic.vcxproj.filters b/picoquic/picoquic.vcxproj.filters index ddb243a6e..ed86629b7 100644 --- a/picoquic/picoquic.vcxproj.filters +++ b/picoquic/picoquic.vcxproj.filters @@ -141,6 +141,9 @@ Source Files + + Source Files + diff --git a/picoquic/picoquic_bbr.h b/picoquic/picoquic_bbr.h new file mode 100644 index 000000000..508e8b6e2 --- /dev/null +++ b/picoquic/picoquic_bbr.h @@ -0,0 +1,36 @@ +/* +* Author: Christian Huitema +* Copyright (c) 2025, Private Octopus, Inc. +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL Private Octopus, Inc. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PICOQUIC_BBR_H +#define PICOQUIC_BBR_H + +#include "picoquic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern picoquic_congestion_algorithm_t* picoquic_bbr_algorithm; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/picoquic/picoquic_bbr1.h b/picoquic/picoquic_bbr1.h new file mode 100644 index 000000000..f42f08cc1 --- /dev/null +++ b/picoquic/picoquic_bbr1.h @@ -0,0 +1,29 @@ +/* +* Author: Christian Huitema +* Copyright (c) 2025, Private Octopus, Inc. +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL Private Octopus, Inc. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PICOQUIC_BBR1_H +#define PICOQUIC_BBR1_H + +#include "picoquic.h" + +extern picoquic_congestion_algorithm_t* picoquic_bbr1_algorithm; + +#endif diff --git a/picoquic/picoquic_config.h b/picoquic/picoquic_config.h index a5fe09d85..f3669fbc5 100644 --- a/picoquic/picoquic_config.h +++ b/picoquic/picoquic_config.h @@ -44,6 +44,7 @@ typedef enum { picoquic_option_DisablePortBlocking, picoquic_option_SOLUTION_DIR, picoquic_option_CC_ALGO, + picoquic_option_CC_OPTION, picoquic_option_SPINBIT, picoquic_option_LOSSBIT, picoquic_option_MULTIPATH, @@ -93,6 +94,7 @@ typedef struct st_picoquic_quic_config_t { int idle_timeout; int socket_buffer_size; char const* cc_algo_id; + char const* cc_algo_option_string; char const * cnx_id_cbdata; /* TODO: control key logging */ picoquic_spinbit_version_enum spinbit_policy; /* control spin bit */ diff --git a/picoquic/picoquic_cubic.h b/picoquic/picoquic_cubic.h new file mode 100644 index 000000000..acf409393 --- /dev/null +++ b/picoquic/picoquic_cubic.h @@ -0,0 +1,37 @@ +/* +* Author: Christian Huitema +* Copyright (c) 2025, Private Octopus, Inc. +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL Private Octopus, Inc. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PICOQUIC_CUBIC_H +#define PICOQUIC_CUBIC_H + +#include "picoquic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern picoquic_congestion_algorithm_t* picoquic_cubic_algorithm; +extern picoquic_congestion_algorithm_t* picoquic_dcubic_algorithm; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/picoquic/picoquic_fastcc.h b/picoquic/picoquic_fastcc.h new file mode 100644 index 000000000..4da9a9413 --- /dev/null +++ b/picoquic/picoquic_fastcc.h @@ -0,0 +1,30 @@ +/* +* Author: Christian Huitema +* Copyright (c) 2017, Private Octopus, Inc. +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL Private Octopus, Inc. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PICOQUIC_FASTCC_H +#define PICOQUIC_FASTCC_H + +#include "picoquic.h" + + +extern picoquic_congestion_algorithm_t* picoquic_fastcc_algorithm; + +#endif diff --git a/picoquic/picoquic_internal.h b/picoquic/picoquic_internal.h index 4d0f59ba6..a3bd575e9 100644 --- a/picoquic/picoquic_internal.h +++ b/picoquic/picoquic_internal.h @@ -671,8 +671,7 @@ typedef struct st_picoquic_quic_t { picoquic_stateless_packet_t* pending_stateless_packet; picoquic_congestion_algorithm_t const* default_congestion_alg; - uint64_t wifi_shadow_rtt; - double bbr_quantum_ratio; + char const* default_congestion_alg_option_string; struct st_picoquic_cnx_t* cnx_list; struct st_picoquic_cnx_t* cnx_last; @@ -1432,6 +1431,7 @@ typedef struct st_picoquic_cnx_t { unsigned int stream_blocked : 1; /* Congestion algorithm */ picoquic_congestion_algorithm_t const* congestion_alg; + char const* congestion_alg_option_string; /* Management of quality signalling updates */ uint64_t rtt_update_delta; uint64_t pacing_rate_update_delta; diff --git a/picoquic/picoquic_newreno.h b/picoquic/picoquic_newreno.h new file mode 100644 index 000000000..48a83a980 --- /dev/null +++ b/picoquic/picoquic_newreno.h @@ -0,0 +1,36 @@ +/* +* Author: Christian Huitema +* Copyright (c) 2025, Private Octopus, Inc. +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL Private Octopus, Inc. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PICOQUIC_NEWRENO_H +#define PICOQUIC_NEWRENO_H + +#include "picoquic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern picoquic_congestion_algorithm_t* picoquic_newreno_algorithm; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/picoquic/picoquic_prague.h b/picoquic/picoquic_prague.h new file mode 100644 index 000000000..a8aed9683 --- /dev/null +++ b/picoquic/picoquic_prague.h @@ -0,0 +1,36 @@ +/* +* Author: Christian Huitema +* Copyright (c) 2025, Private Octopus, Inc. +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL Private Octopus, Inc. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ + +#ifndef PICOQUIC_PRAGUE_H +#define PICOQUIC_PRAGUE_H + +#include "picoquic.h" + +#ifdef __cplusplus +extern "C" { +#endif + +extern picoquic_congestion_algorithm_t* picoquic_prague_algorithm; + +#ifdef __cplusplus +} +#endif +#endif diff --git a/picoquic/prague.c b/picoquic/prague.c index 4a3fd016a..f5f865823 100644 --- a/picoquic/prague.c +++ b/picoquic/prague.c @@ -121,12 +121,13 @@ static void picoquic_prague_init_reno(picoquic_prague_state_t* pr_state, picoqui path_x->cwin = PICOQUIC_CWIN_INITIAL; } -void picoquic_prague_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, uint64_t current_time) +void picoquic_prague_init(picoquic_cnx_t * cnx, picoquic_path_t* path_x, char const* option_string, uint64_t current_time) { /* Initialize the state of the congestion control algorithm */ picoquic_prague_state_t* pr_state = (picoquic_prague_state_t*)malloc(sizeof(picoquic_prague_state_t)); #ifdef _WINDOWS UNREFERENCED_PARAMETER(cnx); + UNREFERENCED_PARAMETER(option_string); #endif if (pr_state != NULL) { diff --git a/picoquic/quicctx.c b/picoquic/quicctx.c index 5a87411c5..a05dad994 100644 --- a/picoquic/quicctx.c +++ b/picoquic/quicctx.c @@ -32,7 +32,7 @@ #include #include #endif - +#include "picoquic_newreno.h" /* * Supported versions. Specific versions may mandate different processing of different @@ -1928,7 +1928,7 @@ void picoquic_promote_path_to_default(picoquic_cnx_t* cnx, int path_index, uint6 /* Set the congestion algorithm for the new path */ if (cnx->congestion_alg != NULL) { - cnx->congestion_alg->alg_init(cnx, path_x, current_time); + cnx->congestion_alg->alg_init(cnx, path_x, cnx->congestion_alg_option_string, current_time); } /* Mark old path as demoted */ @@ -4011,8 +4011,9 @@ picoquic_cnx_t* picoquic_create_cnx(picoquic_quic_t* quic, picosplay_init_tree(&cnx->stream_tree, picoquic_stream_node_compare, picoquic_stream_node_create, picoquic_stream_node_delete, picoquic_stream_node_value); cnx->congestion_alg = cnx->quic->default_congestion_alg; + cnx->congestion_alg_option_string = cnx->quic->default_congestion_alg_option_string; if (cnx->congestion_alg != NULL) { - cnx->congestion_alg->alg_init(cnx, cnx->path[0], start_time); + cnx->congestion_alg->alg_init(cnx, cnx->path[0], cnx->congestion_alg_option_string, start_time); } } @@ -4909,54 +4910,59 @@ picoquic_cnx_t* picoquic_cnx_by_secret(picoquic_quic_t* quic, const uint8_t* res return ret; } -/* Get congestion control algorithm by name - * TODO: if we want to minimize code size, we should not require linking a whole library - * of congestion control algorithms. Intead, the application should have a list of - * configured algorithms, and the configuration program should select from that list. +/* Management of congestion control algorithms + * We want to minimize code size, and thus we do not want to require loading the + * entire list of congestion control algorithms in every executable. + * Instead, we require applications to provide a list of the congestion + * control algorithms that they support. */ + +picoquic_congestion_algorithm_t const** picoquic_congestion_control_algorithms = NULL; +size_t picoquic_nb_congestion_control_algorithms = 0; + +/* Register a list of congestion control algorithm */ +void picoquic_register_congestion_control_algorithms(picoquic_congestion_algorithm_t const** alg, size_t nb_algorithms) +{ + picoquic_congestion_control_algorithms = alg; + picoquic_nb_congestion_control_algorithms = nb_algorithms; +} + picoquic_congestion_algorithm_t const* picoquic_get_congestion_algorithm(char const* alg_name) { picoquic_congestion_algorithm_t const* alg = NULL; - if (alg_name != NULL) { - if (strcmp(alg_name, "reno") == 0) { - alg = picoquic_newreno_algorithm; - } - else if (strcmp(alg_name, "cubic") == 0) { - alg = picoquic_cubic_algorithm; - } - else if (strcmp(alg_name, "dcubic") == 0) { - alg = picoquic_dcubic_algorithm; - } - else if (strcmp(alg_name, "fast") == 0) { - alg = picoquic_fastcc_algorithm; - } - else if (strcmp(alg_name, "bbr") == 0) { - alg = picoquic_bbr_algorithm; - } - else if (strcmp(alg_name, "prague") == 0) { - alg = picoquic_prague_algorithm; - } - else if (strcmp(alg_name, "bbr1") == 0) { - alg = picoquic_bbr1_algorithm; + + if (alg_name != NULL && picoquic_congestion_control_algorithms != NULL) { + for (size_t i = 0; i < picoquic_nb_congestion_control_algorithms; i++) { + if (strcmp(alg_name, picoquic_congestion_control_algorithms[i]->congestion_algorithm_id) == 0) { + alg = picoquic_congestion_control_algorithms[i]; + break; + } } - else { - alg = NULL; + if (alg == NULL && strcmp(alg_name, "reno") == 0) { + alg = picoquic_get_congestion_algorithm("newreno"); } } return alg; } + /* * Set or reset the congestion control algorithm */ -void picoquic_set_default_congestion_algorithm(picoquic_quic_t* quic, picoquic_congestion_algorithm_t const* alg) +void picoquic_set_default_congestion_algorithm_ex(picoquic_quic_t* quic, picoquic_congestion_algorithm_t const* alg, char const * alg_option_string) { quic->default_congestion_alg = alg; + quic->default_congestion_alg_option_string = alg_option_string; +} + +void picoquic_set_default_congestion_algorithm(picoquic_quic_t* quic, picoquic_congestion_algorithm_t const* alg) +{ + picoquic_set_default_congestion_algorithm_ex(quic, alg, NULL); } void picoquic_set_default_congestion_algorithm_by_name(picoquic_quic_t* quic, char const * alg_name) { - quic->default_congestion_alg = picoquic_get_congestion_algorithm(alg_name); + picoquic_set_default_congestion_algorithm_ex(quic, picoquic_get_congestion_algorithm(alg_name), NULL); } /* @@ -4978,7 +4984,7 @@ void picoquic_set_preemptive_repeat_per_cnx(picoquic_cnx_t* cnx, int do_repeat) cnx->is_preemptive_repeat_enabled = (do_repeat) ? 1 : 0; } -void picoquic_set_congestion_algorithm(picoquic_cnx_t* cnx, picoquic_congestion_algorithm_t const* alg) +void picoquic_set_congestion_algorithm_ex(picoquic_cnx_t* cnx, picoquic_congestion_algorithm_t const* alg, char const* alg_option_string) { if (cnx->congestion_alg != NULL) { if (cnx->path != NULL) { @@ -4989,32 +4995,22 @@ void picoquic_set_congestion_algorithm(picoquic_cnx_t* cnx, picoquic_congestion_ } cnx->congestion_alg = alg; + cnx->congestion_alg_option_string = alg_option_string; if (cnx->congestion_alg != NULL) { if (cnx->path != NULL) { for (int i = 0; i < cnx->nb_paths; i++) { - cnx->congestion_alg->alg_init(cnx, cnx->path[i], picoquic_get_quic_time(cnx->quic)); + cnx->congestion_alg->alg_init(cnx, cnx->path[i], alg_option_string, picoquic_get_quic_time(cnx->quic)); } } } } -void picoquic_set_default_wifi_shadow_rtt(picoquic_quic_t* quic, uint64_t wifi_shadow_rtt) -{ - quic->wifi_shadow_rtt = wifi_shadow_rtt; -} - -void picoquic_set_default_bbr_quantum_ratio(picoquic_quic_t* quic, double quantum_ratio) +void picoquic_set_congestion_algorithm(picoquic_cnx_t* cnx, picoquic_congestion_algorithm_t const* alg) { - quic->bbr_quantum_ratio = quantum_ratio; + picoquic_set_congestion_algorithm_ex(cnx, alg, NULL); } -#ifdef BBRExperiment -void picoquic_set_bbr_exp(picoquic_quic_t* quic, bbr_exp* exp) -{ - quic->bbr_exp_flags = *exp; -} -#endif void picoquic_set_priority_limit_for_bypass(picoquic_cnx_t* cnx, uint8_t priority_limit) { cnx->priority_limit_for_bypass = priority_limit; diff --git a/picoquic/register_all_cc_algorithms.c b/picoquic/register_all_cc_algorithms.c new file mode 100644 index 000000000..678de18ac --- /dev/null +++ b/picoquic/register_all_cc_algorithms.c @@ -0,0 +1,49 @@ +/* +* Author: Christian Huitema +* Copyright (c) 2025, Private Octopus, Inc. +* All rights reserved. +* +* Permission to use, copy, modify, and distribute this software for any +* purpose with or without fee is hereby granted, provided that the above +* copyright notice and this permission notice appear in all copies. +* +* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +* DISCLAIMED. IN NO EVENT SHALL Private Octopus, Inc. BE LIABLE FOR ANY +* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +*/ +#include "picoquic.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" +#include "picoquic_prague.h" + + +/* Register a complete list of congestion control algorithms, which +* can then be used by calls to picoquic_get_congestion_algorithm() +* and picoquic_create_and_configure(). + */ + +picoquic_congestion_algorithm_t const* getter_test_cc_algo_list[7] = { + NULL, NULL, NULL, NULL, NULL, NULL, NULL +}; + +void picoquic_register_all_congestion_control_algorithms() +{ + getter_test_cc_algo_list[0] = picoquic_newreno_algorithm; + getter_test_cc_algo_list[1] = picoquic_cubic_algorithm; + getter_test_cc_algo_list[2] = picoquic_dcubic_algorithm; + getter_test_cc_algo_list[3] = picoquic_fastcc_algorithm; + getter_test_cc_algo_list[4] = picoquic_bbr_algorithm; + getter_test_cc_algo_list[5] = picoquic_prague_algorithm; + getter_test_cc_algo_list[6] = picoquic_bbr1_algorithm; + picoquic_register_congestion_control_algorithms(getter_test_cc_algo_list, 7); +} \ No newline at end of file diff --git a/picoquic/sender.c b/picoquic/sender.c index 2d7eba164..d86c9fb7e 100644 --- a/picoquic/sender.c +++ b/picoquic/sender.c @@ -4112,7 +4112,7 @@ static int picoquic_select_next_path_mp(picoquic_cnx_t* cnx, uint64_t current_ti int is_new_priority = 0; /* Set the congestion algorithm for the new path */ if (cnx->congestion_alg != NULL && cnx->path[i]->congestion_alg_state == NULL) { - cnx->congestion_alg->alg_init(cnx, cnx->path[i], current_time); + cnx->congestion_alg->alg_init(cnx, cnx->path[i], cnx->congestion_alg_option_string, current_time); } if (path_priority > highest_priority) { diff --git a/picoquicfirst/picoquicdemo.c b/picoquicfirst/picoquicdemo.c index 5ed146276..77cb3a634 100644 --- a/picoquicfirst/picoquicdemo.c +++ b/picoquicfirst/picoquicdemo.c @@ -1317,6 +1317,7 @@ int main(int argc, char** argv) WSADATA wsaData = { 0 }; (void)WSA_START(MAKEWORD(2, 2), &wsaData); #endif + picoquic_register_all_congestion_control_algorithms(); picoquic_config_init(&config); memcpy(option_string, "A:u:f:1", 7); ret = picoquic_config_option_letters(option_string + 7, sizeof(option_string) - 7, NULL); diff --git a/picoquictest/ack_frequency_test.c b/picoquictest/ack_frequency_test.c index 6097fae0a..9914af7ed 100644 --- a/picoquictest/ack_frequency_test.c +++ b/picoquictest/ack_frequency_test.c @@ -29,6 +29,12 @@ #include "logreader.h" #include "qlog.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" + /* Verify that the ack frequency is correctly set. */ diff --git a/picoquictest/app_limited.c b/picoquictest/app_limited.c index 95b3e5fb1..1c6af006a 100644 --- a/picoquictest/app_limited.c +++ b/picoquictest/app_limited.c @@ -29,6 +29,11 @@ #include "picoquic_binlog.h" #include "logreader.h" #include "qlog.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" /* Add a series of tests to study the behavior of rate limited * clients, such as those sending at a sustained rate lower diff --git a/picoquictest/cc_compete_test.c b/picoquictest/cc_compete_test.c index 04e0d370a..fd022cf82 100644 --- a/picoquictest/cc_compete_test.c +++ b/picoquictest/cc_compete_test.c @@ -24,6 +24,12 @@ #include #include #include "picoquic_ns.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" +#include "picoquic_prague.h" /* Congestion compete test. * These tests measure what happens when multiple connections fight for the same diff --git a/picoquictest/config_test.c b/picoquictest/config_test.c index 60ecac93e..f9bc179ab 100644 --- a/picoquictest/config_test.c +++ b/picoquictest/config_test.c @@ -27,11 +27,14 @@ #include "picoquic_utils.h" #include "picoquic_config.h" #include "picoquictest_internal.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" #ifdef PICOQUIC_WITHOUT_SSLKEYLOG -static char* ref_option_text = "c:k:p:v:o:w:x:rR:s:XS:G:P:O:Me:C:i:l:Lb:q:m:n:a:t:zI:d:DQT:N:B:F:VU:0j:W:J:h"; +static char* ref_option_text = "c:k:p:v:o:w:x:rR:s:XS:G:H:P:O:Me:C:i:l:Lb:q:m:n:a:t:zI:d:DQT:N:B:F:VU:0j:W:J:h"; #else -static char* ref_option_text = "c:k:p:v:o:w:x:rR:s:XS:G:P:O:Me:C:i:l:Lb:q:m:n:a:t:zI:d:DQT:N:B:F:VU:0j:W:8J:h"; +static char* ref_option_text = "c:k:p:v:o:w:x:rR:s:XS:G:H:P:O:Me:C:i:l:Lb:q:m:n:a:t:zI:d:DQT:N:B:F:VU:0j:W:8J:h"; #endif int config_option_letters_test() { @@ -66,7 +69,8 @@ static picoquic_quic_config_t param1 = { -1, /* int cnx_id_length; */ PICOQUIC_MICROSEC_HANDSHAKE_MAX/1000, /* int idle_timeout */ 655360, /* Socket buffer size */ - "cubic", /* const picoquic_congestion_algorithm_t* cc_algorithm; */ + "bbr", /* const picoquic_congestion_algorithm_t* cc_algorithm; */ + "T250000", /* BBR option */ "0N8C-000123", /* char const* cnx_id_cbdata; */ 3, /* spin bit policy */ 2, /* loss bit policy */ @@ -119,7 +123,8 @@ static char const* config_argv1[] = { "-p", "4433", "-e", "1", "-m", "1536", - "-G", "cubic", + "-G", "bbr", + "-H", "T250000", "-P", "3", "-O", "2", "-M", @@ -154,6 +159,7 @@ static picoquic_quic_config_t param2 = { 1234567, /* int idle_timeout */ 0, /* socket_buffer_size */ NULL, /* const picoquic_congestion_algorithm_t* cc_algorithm; */ + NULL, /* option string */ NULL, /* char const* cnx_id_cbdata; */ 0, /* spin bit policy */ 0, /* loss bit policy */ @@ -285,6 +291,23 @@ static config_error_test_t config_errors[] = { static size_t nb_config_errors = sizeof(config_errors) / sizeof(config_error_test_t); + +/* Register a small and stable list of congestion control algorithms, +* sufficient to test the cc algorithm configuration functions. + */ + +static picoquic_congestion_algorithm_t const* config_test_cc_algo_list[3] = { + NULL, NULL, NULL +}; + +static void config_test_register_cc_algorithms() +{ + config_test_cc_algo_list[0] = picoquic_newreno_algorithm; + config_test_cc_algo_list[1] = picoquic_cubic_algorithm; + config_test_cc_algo_list[2] = picoquic_bbr_algorithm; + picoquic_register_congestion_control_algorithms(config_test_cc_algo_list, 3); +} + int config_test_compare_string(const char* title, const char* expected, const char* actual) { int ret = 0; @@ -623,6 +646,11 @@ int config_quic_test_one(picoquic_quic_config_t* config) memcmp(quic->reset_seed, config->reset_seed, sizeof(config->reset_seed)) != 0) { ret = -1; } + if (config->cc_algo_id != NULL && + (quic->default_congestion_alg == NULL || + strcmp(quic->default_congestion_alg->congestion_algorithm_id, config->cc_algo_id) != 0)) { + ret = -1; + } picoquic_free(quic); } @@ -642,6 +670,8 @@ int config_quic_test_one(picoquic_quic_config_t* config) int config_quic_test() { int ret = 0; + config_test_register_cc_algorithms(); + if (config_quic_test_one(¶m1) != 0 || config_quic_test_one(¶m2) != 0) { ret = -1; @@ -659,6 +689,8 @@ int config_usage_test() char config_usage_ref[512]; int ret = picoquic_get_input_path(config_usage_ref, sizeof(config_usage_ref), picoquic_solution_dir, CONFIG_USAGE_REF); + config_test_register_cc_algorithms(); + if (ret == 0 && (F = picoquic_file_open(CONFIG_USAGE_TXT, "wt")) != NULL){ picoquic_config_usage_file(F); F = picoquic_file_close(F); diff --git a/picoquictest/config_usage_ref.txt b/picoquictest/config_usage_ref.txt index 0f8bf1ba3..40e642891 100644 --- a/picoquictest/config_usage_ref.txt +++ b/picoquictest/config_usage_ref.txt @@ -11,7 +11,9 @@ Picoquic options: -s <32 hex chars> Reset seed -X Disable the check for blocked ports -S folder Set the path to the source files to find the default files - -G cc_algorithm Use the specified congestion control algorithm: reno, cubic, bbr or fast. Defaults to bbr. + -G cc_algorithm Use the specified congestion control algorithm. Defaults to bbr. Supported values are: + newreno, cubic, bbr. + -H option Set option string if required by congestion control algorithm. -P number Set the default spinbit policy -O number Set the default lossbit policy -M Enable QUIC multipath extension diff --git a/picoquictest/congestion_test.c b/picoquictest/congestion_test.c index a8ad02654..992cc0283 100644 --- a/picoquictest/congestion_test.c +++ b/picoquictest/congestion_test.c @@ -30,6 +30,13 @@ #include "picoquic_logger.h" #include "qlog.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" +#include "picoquic_prague.h" + static test_api_stream_desc_t test_scenario_congestion[] = { { 4, 0, 257, 1000000 }, { 8, 4, 257, 1000000 }, diff --git a/picoquictest/cpu_limited.c b/picoquictest/cpu_limited.c index 884b36672..7162ceb81 100644 --- a/picoquictest/cpu_limited.c +++ b/picoquictest/cpu_limited.c @@ -30,6 +30,14 @@ #include "logreader.h" #include "qlog.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" +#include "picoquic_prague.h" + + /* Add a series of tests to study the behavior of cpu-limited clients. * This requires simulating clients that have cpu limitations, such * as only being able to proceed a set number of messages per second. diff --git a/picoquictest/datagram_tests.c b/picoquictest/datagram_tests.c index 7defa7a71..8a625f747 100644 --- a/picoquictest/datagram_tests.c +++ b/picoquictest/datagram_tests.c @@ -42,7 +42,7 @@ #include "picoquic_logger.h" #include "performance_log.h" #include "picoquictest.h" - +#include "picoquic_bbr.h" /* * Test whether datagrams are sent and received properly */ diff --git a/picoquictest/delay_tolerant_test.c b/picoquictest/delay_tolerant_test.c index 4e02d5fd4..4bae7b316 100644 --- a/picoquictest/delay_tolerant_test.c +++ b/picoquictest/delay_tolerant_test.c @@ -37,6 +37,7 @@ #include "picoquic_logger.h" #include "performance_log.h" #include "picoquictest.h" +#include "picoquic_newreno.h" /* Delay tolerant networking tests. diff --git a/picoquictest/getter_test.c b/picoquictest/getter_test.c index 14a911998..35d1795e0 100644 --- a/picoquictest/getter_test.c +++ b/picoquictest/getter_test.c @@ -26,6 +26,12 @@ #include "picoquic_utils.h" #include "picoquictest_internal.h" #include "picoquic.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" +#include "picoquic_prague.h" /* Verify that the getter/setter functions work as expected */ @@ -229,10 +235,13 @@ int getter_test() ret = -1; } } - + /* set the algorithm list to the complete value before the alogorithm set/get test + * Hopefully, nobody is going to call their algorithm "wuovipfwds". + */ + picoquic_register_all_congestion_control_algorithms(); if (ret == 0) { char const* alg_name[] = { - "reno", "cubic", "dcubic", "fast", "bbr", "prague", "bbr1", "abracadabra", NULL + "reno", "cubic", "dcubic", "fast", "bbr", "prague", "bbr1", "wuovipfwds", NULL }; picoquic_congestion_algorithm_t const* alg[] = { picoquic_newreno_algorithm, picoquic_cubic_algorithm, picoquic_dcubic_algorithm, diff --git a/picoquictest/h3zerotest.c b/picoquictest/h3zerotest.c index a313a0179..48665c074 100644 --- a/picoquictest/h3zerotest.c +++ b/picoquictest/h3zerotest.c @@ -44,7 +44,7 @@ #endif #include "autoqlog.h" #include "picoquic_binlog.h" -#include "picoquic_utils.h" +#include "picoquic_bbr.h" /* * Test of the prefixed integer encoding diff --git a/picoquictest/high_latency_test.c b/picoquictest/high_latency_test.c index 9489a07da..e8ed73acb 100644 --- a/picoquictest/high_latency_test.c +++ b/picoquictest/high_latency_test.c @@ -37,7 +37,9 @@ #include "picoquic_logger.h" #include "performance_log.h" #include "picoquictest.h" - +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" /* Very high latency test. This requires relaxing the handshake timer, so that it covers * at least one rtt. diff --git a/picoquictest/l4s_test.c b/picoquictest/l4s_test.c index 557c2d43a..fb717e55a 100644 --- a/picoquictest/l4s_test.c +++ b/picoquictest/l4s_test.c @@ -30,6 +30,10 @@ #include "picoquic_binlog.h" #include "logreader.h" #include "qlog.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_prague.h" static test_api_stream_desc_t test_scenario_l4s[] = { { 4, 0, 257, 1000000 }, diff --git a/picoquictest/mediatest.c b/picoquictest/mediatest.c index cedb8fd2d..592fb185e 100644 --- a/picoquictest/mediatest.c +++ b/picoquictest/mediatest.c @@ -27,6 +27,8 @@ #include "picoquic_utils.h" #include "picoquictest_internal.h" #include "picoquic_binlog.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" /* Media tests: simulate media transmission, include cases in which * the media bandwidth is much lower than the available bandwidth on diff --git a/picoquictest/multipath_test.c b/picoquictest/multipath_test.c index f3ad8f5a9..a851be4fe 100644 --- a/picoquictest/multipath_test.c +++ b/picoquictest/multipath_test.c @@ -28,6 +28,7 @@ #include "picoquic_binlog.h" #include "logreader.h" #include "qlog.h" +#include "picoquic_bbr.h" /* Add the additional links for multipath scenario */ static int multipath_test_add_links(picoquic_test_tls_api_ctx_t* test_ctx, int mtu_drop) diff --git a/picoquictest/netperf_test.c b/picoquictest/netperf_test.c index c80c42f64..6a97385ba 100644 --- a/picoquictest/netperf_test.c +++ b/picoquictest/netperf_test.c @@ -29,6 +29,7 @@ #include "picoquic_internal.h" #include "tls_api.h" #include "picoquictest_internal.h" +#include "picoquic_bbr.h" #ifdef _WINDOWS #include "wincompat.h" #else diff --git a/picoquictest/pacing_test.c b/picoquictest/pacing_test.c index 73815f50e..f856edf26 100644 --- a/picoquictest/pacing_test.c +++ b/picoquictest/pacing_test.c @@ -29,6 +29,12 @@ #include "picoquic_binlog.h" #include "picoquic_logger.h" #include "qlog.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_fastcc.h" +#include "picoquic_prague.h" /* Test of the pacing functions. */ diff --git a/picoquictest/satellite_test.c b/picoquictest/satellite_test.c index d4a3949ce..ad8331f0a 100644 --- a/picoquictest/satellite_test.c +++ b/picoquictest/satellite_test.c @@ -37,6 +37,10 @@ #include "picoquic_logger.h" #include "performance_log.h" #include "picoquictest.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" +#include "picoquic_prague.h" /* This is similar to the long rtt test, but operating at a higher speed. diff --git a/picoquictest/tls_api_test.c b/picoquictest/tls_api_test.c index 1c67af239..a95cb8340 100644 --- a/picoquictest/tls_api_test.c +++ b/picoquictest/tls_api_test.c @@ -38,6 +38,11 @@ #include "picoquic_logger.h" #include "performance_log.h" #include "picoquictest.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_fastcc.h" +#include "picoquic_prague.h" static const uint8_t test_ticket_encrypt_key[32] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, @@ -12302,4 +12307,4 @@ int get_tls_errors_test() } return ret; -} \ No newline at end of file +} diff --git a/picoquictest/warptest.c b/picoquictest/warptest.c index 5499fe5d6..64c579f1c 100644 --- a/picoquictest/warptest.c +++ b/picoquictest/warptest.c @@ -27,6 +27,7 @@ #include "picoquic_utils.h" #include "picoquictest_internal.h" #include "autoqlog.h" +#include "picoquic_bbr.h" /* Warp tests: * These tests are very similar to the "media tests", with one twist. diff --git a/picoquictest/wifitest.c b/picoquictest/wifitest.c index 0a58d05a9..4a7f3d889 100644 --- a/picoquictest/wifitest.c +++ b/picoquictest/wifitest.c @@ -28,6 +28,10 @@ #include "picoquictest_internal.h" #include "autoqlog.h" #include "picoquic_binlog.h" +#include "picoquic_newreno.h" +#include "picoquic_cubic.h" +#include "picoquic_bbr.h" +#include "picoquic_bbr1.h" /* Wifi test: explore the behavior of QUIC over Wi-Fi links. * @@ -79,9 +83,9 @@ typedef struct st_wifi_test_spec_t { uint64_t latency; wifi_test_suspension_t * suspension; picoquic_congestion_algorithm_t* ccalgo; + const char* cc_algo_option; uint64_t target_time; int simulate_receive_block; - uint64_t wifi_shadow_rtt; uint64_t queue_max_delay; } wifi_test_spec_t; @@ -108,13 +112,8 @@ static int wifi_test_one(wifi_test_enum test_id, wifi_test_spec_t * spec) } if (ret == 0) { - if (spec->wifi_shadow_rtt > 0) { - picoquic_set_default_wifi_shadow_rtt(test_ctx->qserver, spec->wifi_shadow_rtt); - picoquic_set_default_wifi_shadow_rtt(test_ctx->qclient, spec->wifi_shadow_rtt); - } - - picoquic_set_default_congestion_algorithm(test_ctx->qserver, spec->ccalgo); - picoquic_set_congestion_algorithm(test_ctx->cnx_client, spec->ccalgo); + picoquic_set_default_congestion_algorithm_ex(test_ctx->qserver, spec->ccalgo, spec->cc_algo_option); + picoquic_set_congestion_algorithm_ex(test_ctx->cnx_client, spec->ccalgo, spec->cc_algo_option); test_ctx->c_to_s_link->microsec_latency = spec->latency; test_ctx->s_to_c_link->microsec_latency = spec->latency; @@ -214,7 +213,6 @@ void wifi_test_set_default_spec(wifi_test_spec_t* spec, picoquic_congestion_algo spec->ccalgo = ccalgo; spec->target_time = target_time; spec->simulate_receive_block = 0; - spec->wifi_shadow_rtt = 0; spec->queue_max_delay = 260000; } @@ -273,6 +271,7 @@ int wifi_bbr_hard_test() 3000, suspension_hard, picoquic_bbr_algorithm, + NULL, 4060000, 0 }; int ret = wifi_test_one(wifi_test_bbr_hard, &spec); @@ -287,6 +286,7 @@ int wifi_bbr1_hard_test() 3000, suspension_hard, picoquic_bbr1_algorithm, + NULL, 4060000, 0 }; int ret = wifi_test_one(wifi_test_bbr1_hard, &spec); @@ -301,6 +301,7 @@ int wifi_cubic_hard_test() 3000, suspension_hard, picoquic_cubic_algorithm, + NULL, 4700000, 0 }; int ret = wifi_test_one(wifi_test_cubic_hard, &spec); @@ -315,6 +316,7 @@ int wifi_reno_hard_test() 3000, suspension_hard, picoquic_newreno_algorithm, + NULL, 4250000, 0 }; int ret = wifi_test_one(wifi_test_reno_hard, &spec); @@ -329,6 +331,7 @@ int wifi_bbr_long_test() 50000, suspension_basic, picoquic_bbr_algorithm, + NULL, 3400000, 1 }; int ret = wifi_test_one(wifi_test_bbr_long, &spec); @@ -343,6 +346,7 @@ int wifi_bbr1_long_test() 50000, suspension_basic, picoquic_bbr1_algorithm, + NULL, 3400000, 1 }; int ret = wifi_test_one(wifi_test_bbr1_long, &spec); @@ -377,7 +381,7 @@ int wifi_bbr_shadow_test() { wifi_test_spec_t spec; wifi_test_set_default_spec(&spec, picoquic_bbr_algorithm, 2750000); - spec.wifi_shadow_rtt = 250000; + spec.cc_algo_option = "T250000"; spec.queue_max_delay = 600000; spec.simulate_receive_block = 1; @@ -404,6 +408,7 @@ int wifi_bbr_many_test() 3000, suspension_many, picoquic_bbr_algorithm, + NULL, 4070000, 0 }; int ret = wifi_test_one(wifi_test_bbr_many, &spec); diff --git a/quicwind/quicwind_proc.c b/quicwind/quicwind_proc.c index e62c24b51..8c46696e4 100644 --- a/quicwind/quicwind_proc.c +++ b/quicwind/quicwind_proc.c @@ -19,6 +19,7 @@ #include "democlient.h" #include "quicwind.h" #include "autoqlog.h" +#include "picoquic_cubic.h" #ifndef SOCKET_TYPE #define SOCKET_TYPE SOCKET diff --git a/sample/sample_background.c b/sample/sample_background.c index 6aa1f496b..b64203286 100644 --- a/sample/sample_background.c +++ b/sample/sample_background.c @@ -47,6 +47,7 @@ #include #include #include "picoquic_sample.h" +#include "picoquic_bbr.h" /* Background thread management: * diff --git a/sample/sample_client.c b/sample/sample_client.c index 639ff3e56..656e4418c 100644 --- a/sample/sample_client.c +++ b/sample/sample_client.c @@ -47,6 +47,7 @@ #include #include #include "picoquic_sample.h" +#include "picoquic_bbr.h" /* Client context and callback management: * diff --git a/sample/sample_server.c b/sample/sample_server.c index 1bf4058d7..26057dcf6 100644 --- a/sample/sample_server.c +++ b/sample/sample_server.c @@ -47,6 +47,7 @@ #include #include "picoquic_sample.h" #include "picoquic_packet_loop.h" +#include "picoquic_bbr.h" /* Server context and callback management: *