diff --git a/demo/demo_client.c b/demo/demo_client.c index 8c8e02bf..b9536a1b 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -171,7 +171,8 @@ typedef struct xqc_demo_cli_quic_config_s { uint8_t mp_version; - uint8_t test_path_status; + uint8_t send_path_standby; + xqc_msec_t path_status_timer_threshold; } xqc_demo_cli_quic_config_t; @@ -397,7 +398,10 @@ typedef struct xqc_demo_cli_user_conn_s { xqc_demo_cli_ctx_t *ctx; xqc_demo_cli_task_t *task; - int send_path_available; + int send_path_standby; + int path_status; /* 0:available 1:standby */ + xqc_msec_t path_status_time; + xqc_msec_t path_status_timer_threshold; } xqc_demo_cli_user_conn_t; static void @@ -958,6 +962,40 @@ xqc_demo_cli_hq_req_write_notify(xqc_hq_request_t *hqr, void *req_user_data) return 0; } +void +xqc_demo_path_status_trigger(xqc_demo_cli_user_conn_t *user_conn) +{ + xqc_msec_t ts_now = xqc_demo_now(), path_status_time = 0; + + if (user_conn->send_path_standby) { + + /* set initial path standby here */ + if (user_conn->path_status == 0 + && xqc_conn_available_paths(user_conn->ctx->engine, &user_conn->cid) >= 2) + { + if (ts_now > user_conn->path_status_time + user_conn->path_status_timer_threshold) { + xqc_conn_mark_path_standby(user_conn->ctx->engine, &user_conn->cid, 0); + user_conn->path_status = 1; /* 1:standby */ + + user_conn->path_status_time = ts_now; + printf("mark_path_standby: path_id=0 path_status=%d now=%"PRIu64" pre=%"PRIu64" threshold=%"PRIu64"\n", + user_conn->path_status, ts_now, user_conn->path_status_time, user_conn->path_status_timer_threshold); + } + + } else if (user_conn->path_status == 1) { + + if (ts_now > user_conn->path_status_time + user_conn->path_status_timer_threshold) { + xqc_conn_mark_path_available(user_conn->ctx->engine, &user_conn->cid, 0); + user_conn->path_status = 0; /* 0:available */ + + user_conn->path_status_time = ts_now; + printf("mark_path_available: path_id=0 path_status=%d now=%"PRIu64" pre=%"PRIu64" threshold=%"PRIu64"\n", + user_conn->path_status, ts_now, user_conn->path_status_time, user_conn->path_status_timer_threshold); + } + } + } +} + int xqc_demo_cli_hq_req_read_notify(xqc_hq_request_t *hqr, void *req_user_data) { @@ -967,6 +1005,8 @@ xqc_demo_cli_hq_req_read_notify(xqc_hq_request_t *hqr, void *req_user_data) char buff[4096] = {0}; size_t buff_size = 4096; + xqc_demo_path_status_trigger(user_stream->user_conn); + ssize_t read = 0; ssize_t read_sum = 0; do { @@ -1074,6 +1114,7 @@ xqc_demo_cli_h3_request_write_notify(xqc_h3_request_t *h3_request, void *user_da return 0; } + int xqc_demo_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_flag_t flag, void *user_data) @@ -1084,6 +1125,9 @@ xqc_demo_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_no xqc_demo_cli_task_ctx_t *ctx = &user_stream->user_conn->ctx->task_ctx; xqc_demo_cli_user_conn_t *user_conn = user_stream->user_conn; uint32_t task_idx = user_conn->task->task_idx; + + xqc_demo_path_status_trigger(user_conn); + // printf("xqc_demo_cli_h3_request_read_notify, h3_request: %p, user_stream: %p\n", h3_request, user_stream); if (flag & XQC_REQ_NOTIFY_READ_HEADER) { xqc_http_headers_t *headers; @@ -1721,7 +1765,7 @@ xqc_demo_cli_usage(int argc, char *argv[]) " -T Throttle recving rate (Bps)\n" " -R Reinjection (1,2,4) \n" " -V Multipath Version (4,5,6)\n" - " -B Set path B standby after 600ms\n" + " -B Set initial path standby after recvd first application data, and set initial path available after X ms\n" " -I Idle interval between requests (ms)\n" " -n Throttling the {1,2,...}xn-th requests\n" " -e NAT rebinding on path 0\n" @@ -1936,8 +1980,9 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args break; case 'B': - printf("option multipath set path status: %s\n", optarg); - args->quic_cfg.test_path_status = 1; + printf("option multipath set path status: %s ms\n", optarg); + args->quic_cfg.send_path_standby = 1; + args->quic_cfg.path_status_timer_threshold = atoi(optarg) * 1000; break; case 'I': @@ -2199,12 +2244,6 @@ xqc_demo_cli_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data) xqc_conn_stats_t stats = xqc_conn_get_stats(user_conn->ctx->engine, &user_conn->cid); printf("0rtt_flag:%d\n", stats.early_data_flag); - if (user_conn->send_path_available) { - /* set initial path available here */ - xqc_conn_mark_path_standby(user_conn->ctx->engine, &user_conn->cid, 0); - xqc_conn_mark_path_available(user_conn->ctx->engine, &user_conn->cid, 0); - } - } void @@ -2391,9 +2430,12 @@ xqc_demo_cli_init_xquic_connection(xqc_demo_cli_user_conn_t *user_conn, if (conn_settings.enable_multipath && conn_settings.multipath_version >= XQC_MULTIPATH_06 - && args->quic_cfg.test_path_status == 1) + && args->quic_cfg.send_path_standby == 1) { - user_conn->send_path_available = 1; + user_conn->send_path_standby = 1; + user_conn->path_status = 0; + user_conn->path_status_timer_threshold = args->quic_cfg.path_status_timer_threshold; + user_conn->path_status_time = 0; } return 0; diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index 970d88c2..cbbf08a2 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -1867,6 +1867,15 @@ XQC_EXPORT_PUBLIC_API xqc_int_t xqc_conn_mark_path_frozen(xqc_engine_t *engine, const xqc_cid_t *cid, uint64_t path_id); +/** + * Calculate how many available paths on the current connection, i.e., paths which finished validation and is marked "available" status. + * @param engine xquic engine ctx + * @param cid scid for connection + * @return number of available paths when success, <0 for error + */ +XQC_EXPORT_PUBLIC_API xqc_int_t xqc_conn_available_paths(xqc_engine_t *engine, const xqc_cid_t *cid); + + XQC_EXPORT_PUBLIC_API xqc_conn_type_t xqc_conn_get_type(xqc_connection_t *conn); diff --git a/scripts/xquic.lds b/scripts/xquic.lds index 17cdd7b2..a971851c 100644 --- a/scripts/xquic.lds +++ b/scripts/xquic.lds @@ -75,6 +75,7 @@ XQUIC_VERS_1.0 { xqc_conn_mark_path_standby; xqc_conn_mark_path_available; xqc_conn_mark_path_frozen; + xqc_conn_available_paths; xqc_dcid_str_by_scid; xqc_h3_ctx_init; xqc_h3_ctx_destroy; diff --git a/src/transport/xqc_conn.c b/src/transport/xqc_conn.c index 488d35d9..4d667961 100644 --- a/src/transport/xqc_conn.c +++ b/src/transport/xqc_conn.c @@ -5595,6 +5595,34 @@ xqc_conn_handle_stateless_reset(xqc_connection_t *conn, } +xqc_int_t +xqc_conn_available_paths(xqc_engine_t *engine, const xqc_cid_t *cid) +{ + xqc_int_t available_paths = 0; + xqc_connection_t *conn = xqc_engine_conns_hash_find(engine, cid, 's'); + if (conn == NULL) { + /* no connection found */ + return available_paths; + } + + xqc_path_ctx_t *path; + xqc_list_head_t *path_pos, *path_next; + + xqc_list_for_each_safe(path_pos, path_next, &conn->conn_paths_list) { + path = xqc_list_entry(path_pos, xqc_path_ctx_t, path_list); + if (path->path_state < XQC_PATH_STATE_VALIDATING) { + continue; + } + if (path->path_state == XQC_PATH_STATE_ACTIVE) { + available_paths++; + } + } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_conn_available_paths|%" PRId32 "|", available_paths); + return available_paths; +} + + #ifdef XQC_COMPAT_GENERATE_SR_PKT xqc_int_t diff --git a/src/transport/xqc_conn.h b/src/transport/xqc_conn.h index 2700a8d6..7fe56dce 100644 --- a/src/transport/xqc_conn.h +++ b/src/transport/xqc_conn.h @@ -666,4 +666,5 @@ void xqc_conn_destroy_ping_notification_list(xqc_connection_t *conn); xqc_int_t xqc_conn_send_ping_internal(xqc_connection_t *conn, void *ping_user_data, xqc_bool_t notify); + #endif /* _XQC_CONN_H_INCLUDED_ */