From b4571159f33da0d94b994a910712fd658df1ff24 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Thu, 24 Oct 2024 16:01:30 +0800 Subject: [PATCH 01/12] Update version 1.8.1 --- demo/demo_client.c | 131 +- demo/demo_server.c | 18 +- demo/xqc_hq_request.c | 3 - include/xquic/xqc_errno.h | 5 +- include/xquic/xqc_http3.h | 12 + include/xquic/xquic.h | 82 +- include/xquic/xquic_typedef.h | 26 +- scripts/case_test.sh | 108 +- src/common/xqc_log.c | 11 +- src/common/xqc_log_event_callback.c | 4 +- src/common/xqc_priority_q.h | 124 +- src/common/xqc_time.c | 6 +- src/congestion_control/xqc_bbr.c | 18 +- src/congestion_control/xqc_bbr.h | 2 + src/http3/xqc_h3_request.c | 39 +- src/http3/xqc_h3_request.h | 9 +- src/http3/xqc_h3_stream.c | 64 +- src/tls/babassl/xqc_ssl_if_impl.c | 7 +- src/tls/boringssl/xqc_ssl_if_impl.c | 1 + src/tls/xqc_tls.c | 11 +- .../fec_schemes/xqc_galois_calculation.c | 32 +- .../fec_schemes/xqc_galois_calculation.h | 6 +- src/transport/fec_schemes/xqc_packet_mask.c | 291 ++++ src/transport/fec_schemes/xqc_packet_mask.h | 31 + .../fec_schemes/xqc_packet_mask_value.h | 639 ++++++++ src/transport/fec_schemes/xqc_reed_solomon.c | 185 ++- src/transport/fec_schemes/xqc_reed_solomon.h | 9 +- src/transport/fec_schemes/xqc_xor.c | 130 +- src/transport/fec_schemes/xqc_xor.h | 14 +- .../reinjection_control/xqc_reinj_deadline.c | 1 - .../reinjection_control/xqc_reinj_default.c | 1 - .../reinjection_control/xqc_reinj_dgram.c | 1 - .../scheduler/xqc_scheduler_backup.c | 14 +- .../scheduler/xqc_scheduler_backup.h | 2 +- .../scheduler/xqc_scheduler_backup_fec.c | 243 +++ .../scheduler/xqc_scheduler_backup_fec.h | 13 + .../scheduler/xqc_scheduler_common.h | 2 +- .../scheduler/xqc_scheduler_interop.c | 3 +- .../scheduler/xqc_scheduler_interop.h | 2 +- .../scheduler/xqc_scheduler_minrtt.c | 11 +- .../scheduler/xqc_scheduler_minrtt.h | 2 +- src/transport/scheduler/xqc_scheduler_rap.h | 2 +- src/transport/xqc_cid.c | 348 +++-- src/transport/xqc_cid.h | 102 +- src/transport/xqc_client.c | 12 +- src/transport/xqc_conn.c | 920 ++++++----- src/transport/xqc_conn.h | 41 +- src/transport/xqc_datagram.c | 18 +- src/transport/xqc_engine.c | 438 +++--- src/transport/xqc_engine.h | 16 +- src/transport/xqc_fec.c | 1358 +++++++++++++---- src/transport/xqc_fec.h | 164 +- src/transport/xqc_fec_scheme.c | 275 ++-- src/transport/xqc_fec_scheme.h | 12 +- src/transport/xqc_frame.c | 643 +++++--- src/transport/xqc_frame.h | 80 +- src/transport/xqc_frame_parser.c | 782 ++++++---- src/transport/xqc_frame_parser.h | 62 +- src/transport/xqc_multipath.c | 217 ++- src/transport/xqc_multipath.h | 27 +- src/transport/xqc_packet_out.c | 392 +++-- src/transport/xqc_packet_out.h | 20 +- src/transport/xqc_packet_parser.c | 50 +- src/transport/xqc_recv_record.h | 2 +- src/transport/xqc_reinjection.c | 1 - src/transport/xqc_send_ctl.c | 27 +- src/transport/xqc_send_ctl.h | 4 + src/transport/xqc_send_queue.c | 10 +- src/transport/xqc_stream.c | 87 +- src/transport/xqc_stream.h | 8 + src/transport/xqc_timer.c | 82 +- src/transport/xqc_transport_params.c | 99 +- src/transport/xqc_transport_params.h | 21 +- src/transport/xqc_utils.c | 28 +- src/transport/xqc_utils.h | 8 +- src/transport/xqc_wakeup_pq.h | 235 --- tests/platform.h | 6 +- tests/test_client.c | 65 +- tests/test_server.c | 18 +- tests/unittest/main.c | 2 - tests/unittest/xqc_cid_test.c | 40 +- tests/unittest/xqc_fec_scheme_test.c | 197 ++- tests/unittest/xqc_fec_scheme_test.h | 3 +- tests/unittest/xqc_fec_test.c | 123 +- tests/unittest/xqc_fec_test.h | 2 +- tests/unittest/xqc_pq_test.c | 12 +- tests/unittest/xqc_wakeup_pq_test.c | 49 - tests/unittest/xqc_wakeup_pq_test.h | 10 - xqc_configure.h.in | 3 +- 89 files changed, 6413 insertions(+), 3021 deletions(-) create mode 100644 src/transport/fec_schemes/xqc_packet_mask.c create mode 100644 src/transport/fec_schemes/xqc_packet_mask.h create mode 100644 src/transport/fec_schemes/xqc_packet_mask_value.h create mode 100644 src/transport/scheduler/xqc_scheduler_backup_fec.c create mode 100644 src/transport/scheduler/xqc_scheduler_backup_fec.h delete mode 100644 src/transport/xqc_wakeup_pq.h delete mode 100644 tests/unittest/xqc_wakeup_pq_test.c delete mode 100644 tests/unittest/xqc_wakeup_pq_test.h diff --git a/demo/demo_client.c b/demo/demo_client.c index b0257bf31..11992da1e 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -26,6 +26,7 @@ #pragma comment(lib,"event.lib") #pragma comment(lib, "Iphlpapi.lib") #pragma comment(lib, "Bcrypt.lib") +#pragma comment(lib, "crypt32") #include "../tests/getopt.h" #else #include @@ -181,6 +182,8 @@ typedef struct xqc_demo_cli_quic_config_s { uint8_t mp_version; + uint64_t init_max_path_id; + /* support interop test */ int is_interop_mode; @@ -189,6 +192,9 @@ typedef struct xqc_demo_cli_quic_config_s { uint64_t least_available_cid_count; + uint64_t idle_timeout; + uint8_t remove_path_flag; + size_t max_pkt_sz; char co_str[XQC_CO_STR_MAX_LEN]; @@ -235,7 +241,7 @@ typedef struct xqc_demo_cli_env_config_s { * ============================================================================ */ -#define MAX_REQUEST_CNT 2048 /* client might deal MAX_REQUEST_CNT requests once */ +#define MAX_REQUEST_CNT 20480 /* client might deal MAX_REQUEST_CNT requests once */ #define MAX_REQUEST_LEN 256 /* the max length of a request */ #define g_host "" @@ -253,7 +259,6 @@ typedef struct xqc_demo_cli_request_s { /* request bundle args */ typedef struct xqc_demo_cli_requests_s { /* requests */ - char urls[MAX_REQUEST_CNT * MAX_REQUEST_LEN]; int request_cnt; /* requests cnt in urls */ xqc_demo_cli_request_t reqs[MAX_REQUEST_CNT]; @@ -270,6 +275,9 @@ typedef struct xqc_demo_cli_requests_s { int throttled_req; + int ext_reqn; + int batch_cnt; + } xqc_demo_cli_requests_t; @@ -421,6 +429,11 @@ typedef struct xqc_demo_cli_user_conn_s { int path_status; /* 0:available 1:standby */ xqc_msec_t path_status_time; xqc_msec_t path_status_timer_threshold; + + + xqc_msec_t path_create_time; + xqc_flag_t remove_path_flag; + xqc_msec_t idle_timeout; } xqc_demo_cli_user_conn_t; static void @@ -847,8 +860,10 @@ xqc_demo_cli_conn_create_path(const xqc_cid_t *cid, void *conn_user_data) uint64_t path_id; int ret; int backup = 0; + printf("ready to create path notify\n"); + if (user_conn->total_path_cnt < ctx->args->net_cfg.ifcnt - && user_conn->total_path_cnt < MAX_PATH_CNT) + && user_conn->total_path_cnt < ctx->args->quic_cfg.init_max_path_id) { if (user_conn->total_path_cnt == 1 && ctx->args->quic_cfg.mp_backup) { @@ -871,6 +886,8 @@ xqc_demo_cli_conn_create_path(const xqc_cid_t *cid, void *conn_user_data) return; } + user_conn->path_create_time = xqc_now(); + if (user_conn->total_path_cnt == 2 && ctx->args->quic_cfg.mp_backup) { printf("set No.%d path (id = %"PRIu64") to STANDBY state\n", 1, path_id); xqc_conn_mark_path_standby(ctx->engine, &(user_conn->cid), path_id); @@ -1241,7 +1258,8 @@ xqc_demo_cli_h3_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_no // xqc_demo_cli_on_stream_fin(user_stream); task_idx = user_stream->user_conn->task->task_idx; if (ctx->schedule.schedule_info[task_idx].req_create_cnt - < ctx->tasks[task_idx].user_conn->task->req_cnt) + < ctx->tasks[task_idx].user_conn->task->req_cnt + && user_conn->ctx->args->req_cfg.serial) { if (user_conn->ctx->args->req_cfg.idle_gap) { @@ -1478,12 +1496,28 @@ static void xqc_demo_cli_delayed_req_start(int fd, short what, void *arg) { xqc_demo_cli_user_conn_t *user_conn = (xqc_demo_cli_user_conn_t *) arg; + int batch_cnt = user_conn->ctx->args->req_cfg.batch_cnt; int req_cnt = user_conn->task->req_cnt; - if (user_conn->ctx->args->req_cfg.serial) { - req_cnt = req_cnt > 1 ? 1 : req_cnt; + if (batch_cnt) { + req_cnt = req_cnt > batch_cnt ? batch_cnt : req_cnt; } xqc_demo_cli_send_requests(user_conn, user_conn->ctx->args, user_conn->task->reqs, req_cnt); + + if (req_cnt > user_conn->ctx->task_ctx.schedule.schedule_info[user_conn->task->task_idx].req_create_cnt + && user_conn->ctx->args->req_cfg.idle_gap + && user_conn->ctx->args->req_cfg.batch_cnt) + { + + user_conn->ev_idle_restart = event_new(user_conn->ctx->eb, -1, 0, + xqc_demo_cli_delayed_idle_restart, + user_conn); + struct timeval tv = { + .tv_sec = user_conn->ctx->args->req_cfg.idle_gap / 1000, + .tv_usec = (user_conn->ctx->args->req_cfg.idle_gap % 1000) * 1000, + }; + event_add(user_conn->ev_idle_restart, &tv); + } } static void @@ -1660,6 +1694,7 @@ xqc_demo_cli_init_conneciton_settings(xqc_conn_settings_t* settings, settings->is_interop_mode = args->quic_cfg.is_interop_mode; settings->max_pkt_out_size = args->quic_cfg.max_pkt_sz; settings->adaptive_ack_frequency = 1; + settings->init_max_path_id = args->quic_cfg.init_max_path_id; if (args->req_cfg.throttled_req != -1) { settings->enable_stream_rate_limit = 1; settings->recv_rate_bytes_per_sec = 0; @@ -1688,8 +1723,9 @@ xqc_demo_cli_init_args(xqc_demo_cli_client_args_t *args) args->quic_cfg.alpn_type = ALPN_HQ; strncpy(args->quic_cfg.alpn, "hq-interop", sizeof(args->quic_cfg.alpn)); args->quic_cfg.keyupdate_pkt_threshold = UINT64_MAX; - /* default 04 */ - args->quic_cfg.mp_version = XQC_MULTIPATH_04; + /* default 10 */ + args->quic_cfg.mp_version = XQC_MULTIPATH_10; + args->quic_cfg.init_max_path_id = 2; args->quic_cfg.max_pkt_sz = 1200; args->req_cfg.throttled_req = -1; @@ -1812,6 +1848,11 @@ xqc_demo_cli_usage(int argc, char *argv[]) " -E NAT rebinding on path 1\n" " -F MTU size (default: 1200)\n" " -G Google connection options (e.g. CBBR,TBBR)\n" + " -x Extend the number of requests to X\n" + " -r Send X requests per batch\n" + " -y cid rotation after x ms\n" + " -Y cid retirement after x ms\n" + " -f max path id\n" , prog); } @@ -1819,7 +1860,7 @@ void xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args) { int ch = 0; - while ((ch = getopt(argc, argv, "a:p:c:Ct:S:0m:A:D:l:L:k:K:U:u:dMoi:w:Ps:bZ:NQT:R:V:B:I:n:eEF:G:")) != -1) { + while ((ch = getopt(argc, argv, "a:p:c:Ct:S:0m:A:D:l:L:k:K:U:u:dMoi:w:Ps:bZ:NQT:R:V:B:I:n:eEF:G:r:x:y:Y:f:")) != -1) { switch (ch) { /* server ip */ case 'a': @@ -2064,12 +2105,45 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args strncpy(args->quic_cfg.co_str, optarg, XQC_CO_STR_MAX_LEN); break; + case 'r': + printf("Request batch: %s\n", optarg); + args->req_cfg.batch_cnt = atoi(optarg); + break; + + case 'x': + printf("Extend request number: %s\n", optarg); + args->req_cfg.ext_reqn = atoi(optarg); + break; + + case 'f': + printf("max concurrent paths: %s\n", optarg); + args->quic_cfg.init_max_path_id = atoi(optarg); + break; + default: printf("other option :%c\n", ch); xqc_demo_cli_usage(argc, argv); exit(0); } } + + if (args->req_cfg.ext_reqn + && args->req_cfg.request_cnt < args->req_cfg.ext_reqn) + { + for (ch = args->req_cfg.request_cnt; + ch < args->req_cfg.ext_reqn; ch++) + { + memcpy(&args->req_cfg.reqs[ch], + &args->req_cfg.reqs[ch - 1], + sizeof(xqc_demo_cli_request_t)); + } + args->req_cfg.request_cnt = args->req_cfg.ext_reqn; + } + + if (args->req_cfg.serial) { + args->req_cfg.batch_cnt = 1; + } + } #define MAX_REQ_BUF_LEN 1500 @@ -2248,12 +2322,24 @@ xqc_demo_cli_continue_send_reqs(xqc_demo_cli_user_conn_t *user_conn) int task_idx = user_conn->task->task_idx; int req_create_cnt = ctx->task_ctx.schedule.schedule_info[task_idx].req_create_cnt; int req_cnt = user_conn->task->req_cnt - req_create_cnt; - if (ctx->args->req_cfg.serial) { - req_cnt = req_cnt > 1 ? 1 : req_cnt; + if (ctx->args->req_cfg.batch_cnt) { + req_cnt = req_cnt > ctx->args->req_cfg.batch_cnt ? ctx->args->req_cfg.batch_cnt : req_cnt; } if (req_cnt > 0) { xqc_demo_cli_request_t *reqs = user_conn->task->reqs + req_create_cnt; xqc_demo_cli_send_requests(user_conn, ctx->args, reqs, req_cnt); + + if (user_conn->task->req_cnt > req_create_cnt + && ctx->args->req_cfg.idle_gap + && ctx->args->req_cfg.batch_cnt + && !ctx->args->req_cfg.serial) + { + struct timeval tv = { + .tv_sec = ctx->args->req_cfg.idle_gap / 1000, + .tv_usec = (ctx->args->req_cfg.idle_gap % 1000) * 1000, + }; + event_add(user_conn->ev_idle_restart, &tv); + } } } @@ -2492,7 +2578,7 @@ 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 + && conn_settings.multipath_version >= XQC_MULTIPATH_10 && args->quic_cfg.send_path_standby == 1) { user_conn->send_path_standby = 1; @@ -2573,13 +2659,28 @@ xqc_demo_cli_start(xqc_demo_cli_user_conn_t *user_conn, xqc_demo_cli_client_args } else { /* TODO: fix MAX_STREAMS bug */ - if (args->req_cfg.serial) { - xqc_demo_cli_send_requests(user_conn, args, reqs, req_cnt > 1 ? 1 : req_cnt); + if (args->req_cfg.batch_cnt) { + xqc_demo_cli_send_requests(user_conn, args, reqs, req_cnt > args->req_cfg.batch_cnt ? args->req_cfg.batch_cnt : req_cnt); } else { xqc_demo_cli_send_requests(user_conn, args, reqs, req_cnt); } - + + if (req_cnt > user_conn->ctx->task_ctx.schedule.schedule_info[user_conn->task->task_idx].req_create_cnt + && args->req_cfg.idle_gap + && args->req_cfg.batch_cnt + && !args->req_cfg.serial) + { + + user_conn->ev_idle_restart = event_new(user_conn->ctx->eb, -1, 0, + xqc_demo_cli_delayed_idle_restart, + user_conn); + struct timeval tv = { + .tv_sec = args->req_cfg.idle_gap / 1000, + .tv_usec = (args->req_cfg.idle_gap % 1000) * 1000, + }; + event_add(user_conn->ev_idle_restart, &tv); + } } } diff --git a/demo/demo_server.c b/demo/demo_server.c index 4a14062bc..4ce2ad4ae 100644 --- a/demo/demo_server.c +++ b/demo/demo_server.c @@ -26,6 +26,7 @@ #pragma comment(lib,"event.lib") #pragma comment(lib, "Iphlpapi.lib") #pragma comment(lib, "Bcrypt.lib") +#pragma comment(lib, "crypt32") #endif @@ -101,6 +102,8 @@ typedef struct xqc_demo_svr_quic_config_s { /* multipath version */ int multipath_version; + + int max_initial_paths; /* support interop test */ int is_interop_mode; @@ -1277,7 +1280,7 @@ void xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) { int ch = 0; - while ((ch = getopt(argc, argv, "p:c:CD:l:L:6k:rdMiPs:R:u:a:F:")) != -1) { + while ((ch = getopt(argc, argv, "p:c:CD:l:L:6k:rdMiPs:R:u:a:F:f:")) != -1) { switch (ch) { /* listen port */ case 'p': @@ -1365,11 +1368,6 @@ xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) args->quic_cfg.multipath = 1; break; - case 'V': - printf("option multipath version: %s\n", optarg); - args->quic_cfg.multipath_version = atoi(optarg); - break; - case 'P': printf("option ACK_MP on any path enabled\n"); args->quic_cfg.mp_ack_on_any_path = 1; @@ -1400,6 +1398,11 @@ xqc_demo_svr_parse_args(int argc, char *argv[], xqc_demo_svr_args_t *args) args->quic_cfg.max_pkt_sz = atoi(optarg); break; + case 'f': + printf("option init_max_path_id: %s\n", optarg); + args->quic_cfg.max_initial_paths = atoi(optarg); + break; + default: printf("other option :%c\n", ch); xqc_demo_svr_usage(argc, argv); @@ -1514,7 +1517,7 @@ xqc_demo_svr_init_conn_settings(xqc_engine_t *engine, xqc_demo_svr_args_t *args) .spurious_loss_detect_on = 1, .init_idle_time_out = 60000, .enable_multipath = args->quic_cfg.multipath, - .multipath_version = args->quic_cfg.multipath_version, + .init_max_path_id = args->quic_cfg.max_initial_paths, .mp_ack_on_any_path = args->quic_cfg.mp_ack_on_any_path, .scheduler_callback = sched, .reinj_ctl_callback = xqc_deadline_reinj_ctl_cb, @@ -1525,7 +1528,6 @@ xqc_demo_svr_init_conn_settings(xqc_engine_t *engine, xqc_demo_svr_args_t *args) .is_interop_mode = args->quic_cfg.is_interop_mode, .max_pkt_out_size = args->quic_cfg.max_pkt_sz, .adaptive_ack_frequency = 1, - .anti_amplification_limit = 4, }; xqc_server_set_conn_settings(engine, &conn_settings); diff --git a/demo/xqc_hq_request.c b/demo/xqc_hq_request.c index 3eede95a6..8b0454ac5 100644 --- a/demo/xqc_hq_request.c +++ b/demo/xqc_hq_request.c @@ -317,9 +317,6 @@ xqc_hq_request_recv_req(xqc_hq_request_t *hqr, char *res_buf, size_t buf_sz, uin read = (ssize_t)strncpy(res_buf, hqr->resource_buf, buf_sz); hqr->resource_read_offset += read; *fin = (hqr->fin || req_fin); - - } else { - read = 0; } return read; diff --git a/include/xquic/xqc_errno.h b/include/xquic/xqc_errno.h index e314d6338..b8cd7ad66 100644 --- a/include/xquic/xqc_errno.h +++ b/include/xquic/xqc_errno.h @@ -33,8 +33,7 @@ typedef enum { * Multipath error codes */ typedef enum { - TRA_MP_PROTOCOL_VIOLATION_04 = 0xba01, - TRA_MP_PROTOCOL_VIOLATION_05 = 0x1001d76d3ded42f3, + TRA_MP_PROTOCOL_VIOLATION = 0x1001d76d3ded42f3 } xqc_mp_err_code_t; @@ -130,10 +129,12 @@ typedef enum { XQC_EMP_SCHEDULE_PATH = 655, /* Multipath - fail to schedule path for sending */ XQC_EMP_NO_ACTIVE_PATH = 656, /* Multipath - no another active path */ XQC_EMP_INVALID_MP_VERTION = 657, /* Multipath - the multipath version value is invalid */ + XQC_EMP_NO_AVAILABLE_CID_FOR_PATH = 658, /* Multipath - there's no available unused cid for this path */ XQC_EFEC_NOT_SUPPORT_FEC = 660, /* FEC - fec not supported */ XQC_EFEC_SCHEME_ERROR = 661, /* FEC - no available scheme */ XQC_EFEC_SYMBOL_ERROR = 662, /* FEC - symbol value error */ + XQC_EFEC_TOLERABLE_ERROR = 663, /* FEC - tolerable error */ XQC_EENCRYPT_LB_CID = 670, /* load balance connection ID encryption error */ XQC_EENCRYPT_AES_128_ECB = 671, /* aes_128_ecb algorithm error */ diff --git a/include/xquic/xqc_http3.h b/include/xquic/xqc_http3.h index 0c1f783f9..9f42073c3 100644 --- a/include/xquic/xqc_http3.h +++ b/include/xquic/xqc_http3.h @@ -180,6 +180,15 @@ typedef struct xqc_request_stats_s { xqc_usec_t stream_fst_pkt_snd_time; xqc_usec_t stream_fst_pkt_rcv_time; + uint32_t sent_pkt_cnt; + uint8_t max_pto_backoff; + + /** + * @brief the number of lost/delayed packets recovered by fec module; + */ + uint32_t fec_recov_cnt; + + uint8_t is_fec_protected; } xqc_request_stats_t; /** @@ -760,6 +769,9 @@ xqc_stream_id_t xqc_h3_stream_id(xqc_h3_request_t *h3_request); /** * @brief RFC 9218 HTTP Priority */ +XQC_EXPORT_PUBLIC_API +void xqc_h3_priority_init(xqc_h3_priority_t *prio); + XQC_EXPORT_PUBLIC_API size_t xqc_write_http_priority(xqc_h3_priority_t *prio, uint8_t *dst, size_t dstcap); diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index da8510f5b..0c5ea0f46 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -843,6 +843,7 @@ typedef struct xqc_cc_params_s { uint32_t expect_bw; uint32_t max_expect_bw; uint8_t bbr_enable_lt_bw; + uint8_t bbr_ignore_app_limit; uint32_t cc_optimization_flags; /* 0 < delta <= delta_max, default 0.05, ->0 = more throughput-oriented */ double copa_delta_base; @@ -866,25 +867,30 @@ typedef struct xqc_scheduler_params_u { typedef enum { XQC_REED_SOLOMON_CODE = 8, - XQC_XOR_CODE = 11, /* 测试用,没有在IANA登记过*/ - XQC_PACKET_MASK = 12, + XQC_XOR_CODE = 11, + XQC_PACKET_MASK_CODE = 12, } xqc_fec_schemes_e; +typedef enum { + XQC_FEC_MP_DEFAULT, + XQC_FEC_MP_USE_STB, +} xqc_fec_mp_mode_e; + typedef struct xqc_fec_params_s { float fec_code_rate; /* code rate represents the source symbol percents in total symbols */ xqc_int_t fec_ele_bit_size; /* element bit size of current fec finite filed */ uint64_t fec_protected_frames; /* frame type that should be protected by fec */ uint64_t fec_max_window_size; /* maximum number of block that current host can store */ - uint64_t fec_max_symbol_size; /* (E) maximum symbol size of each symbol */ uint64_t fec_max_symbol_num_per_block; /* (B) maximum symbol number of each block */ - + xqc_fec_mp_mode_e fec_mp_mode; + xqc_int_t fec_encoder_schemes_num; xqc_int_t fec_decoder_schemes_num; xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; /* fec schemes supported by current host as encoder */ xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; /* fec schemes supported by current host as decoder */ - xqc_int_t fec_encoder_scheme; /* final fec scheme as encoder after negotiation */ - xqc_int_t fec_decoder_scheme; /* final fec scheme as decoder after negotiation */ + xqc_fec_schemes_e fec_encoder_scheme; /* final fec scheme as encoder after negotiation */ + xqc_fec_schemes_e fec_decoder_scheme; /* final fec scheme as decoder after negotiation */ } xqc_fec_params_t; typedef struct xqc_congestion_control_callback_s { @@ -974,6 +980,7 @@ typedef struct xqc_scheduler_callback_s { XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_minrtt_scheduler_cb; XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_backup_scheduler_cb; +XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_backup_fec_scheduler_cb; XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_rap_scheduler_cb; #ifdef XQC_ENABLE_MP_INTEROP XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_scheduler_callback_t xqc_interop_scheduler_cb; @@ -1005,13 +1012,17 @@ XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_reinj_ctl_callback_t xqc_dgram_reinj_ typedef struct xqc_fec_code_callback_s { void (*xqc_fec_init)(xqc_connection_t *conn); - xqc_int_t (*xqc_fec_encode)(xqc_connection_t *conn, unsigned char *unit_data, unsigned char **outputs); - xqc_int_t (*xqc_fec_decode)(xqc_connection_t *conn, unsigned char **recovered_symbols_buff, xqc_int_t block_idx, - xqc_int_t *loss_symbols_idx, xqc_int_t loss_symbols_len); + xqc_int_t (*xqc_fec_encode)(xqc_connection_t *conn, unsigned char *unit_data, size_t un_size, unsigned char **outputs, + uint8_t fec_bm_mode); + xqc_int_t (*xqc_fec_decode)(xqc_connection_t *conn, unsigned char **recovered_symbols_buff, size_t *size, xqc_int_t block_idx); + xqc_int_t (*xqc_fec_decode_one)(xqc_connection_t *conn, unsigned char *recovered_symbols_buff, + xqc_int_t block_id, xqc_int_t symbol_idx); + void (*xqc_fec_init_one)(xqc_connection_t *conn, uint8_t bm_idx); } xqc_fec_code_callback_t; XQC_EXPORT_PUBLIC_API extern const xqc_fec_code_callback_t xqc_xor_code_cb; XQC_EXPORT_PUBLIC_API extern const xqc_fec_code_callback_t xqc_reed_solomon_code_cb; +XQC_EXPORT_PUBLIC_API extern const xqc_fec_code_callback_t xqc_packet_mask_code_cb; /** * @struct xqc_config_t @@ -1086,10 +1097,11 @@ typedef struct xqc_config_s { uint8_t enable_h3_ext; /** - * @brief disable or enable logging (default: 0, enable) + * @brief manually call mainlogic after stream/request send * */ - xqc_bool_t log_disable; + uint8_t manually_triggered_send; + } xqc_config_t; @@ -1184,14 +1196,12 @@ typedef struct xqc_linger_s { typedef enum { XQC_ERR_MULTIPATH_VERSION = 0x00, - XQC_MULTIPATH_04 = 0x04, - XQC_MULTIPATH_05 = 0x05, - XQC_MULTIPATH_06 = 0x06, + XQC_MULTIPATH_10 = 0x0a, } xqc_multipath_version_t; typedef enum { XQC_ERR_FEC_VERSION = 0x00, - XQC_FEC_01 = 0x01, + XQC_FEC_02 = 0x02, } xqc_fec_version_t; typedef struct xqc_conn_settings_s { @@ -1210,9 +1220,10 @@ typedef struct xqc_conn_settings_s { xqc_msec_t init_idle_time_out; /* initial idle timeout interval, effective before handshake completion */ xqc_msec_t idle_time_out; /* idle timeout interval, effective after handshake completion */ int32_t spurious_loss_detect_on; - uint32_t anti_amplification_limit; /* limit of anti-amplification, default 5 */ + uint32_t anti_amplification_limit; /* limit of anti-amplification, default 3 */ uint64_t keyupdate_pkt_threshold; /* packet limit of a single 1-rtt key, 0 for unlimited */ size_t max_pkt_out_size; + size_t probing_pkt_out_size; /* * datgram option @@ -1231,6 +1242,7 @@ typedef struct xqc_conn_settings_s { */ uint64_t enable_multipath; xqc_multipath_version_t multipath_version; + uint64_t init_max_path_id; uint64_t least_available_cid_count; /* @@ -1352,11 +1364,22 @@ typedef struct xqc_conn_settings_s { uint64_t enable_encode_fec; uint64_t enable_decode_fec; xqc_fec_params_t fec_params; + xqc_fec_code_callback_t fec_callback; xqc_fec_code_callback_t fec_encode_callback; xqc_fec_code_callback_t fec_decode_callback; xqc_dgram_red_setting_e close_dgram_redundancy; + /** + * @brief disable batch sending on the connection (default:0, not disable) + */ + uint8_t disable_send_mmsg; + + /** + * @brief control PTO value + */ + uint8_t control_pto_value; + } xqc_conn_settings_t; @@ -1427,12 +1450,19 @@ typedef struct xqc_conn_stats_s { char conn_info[XQC_CONN_INFO_LEN]; char alpn[XQC_MAX_ALPN_BUF_LEN]; + + uint32_t send_fec_cnt; + + uint8_t enable_fec; + /* only accounts for stream and datagram packets */ + uint64_t total_app_bytes; + uint64_t standby_path_app_bytes; } xqc_conn_stats_t; typedef struct xqc_conn_qos_stats_s { - xqc_usec_t srtt; /* smoothed SRTT at present: initial value = 250000 */ - xqc_usec_t min_rtt; /* minimum RTT until now: initial value = 0xFFFFFFFF */ - uint64_t inflight_bytes; /* initial value = 0 */ + xqc_usec_t srtt; /* smoothed SRTT at present: initial value = 250000 */ + xqc_usec_t min_rtt; /* minimum RTT until now: initial value = 0xFFFFFFFF */ + uint64_t inflight_bytes; /* initial value = 0 */ } xqc_conn_qos_stats_t; /************************************************************* @@ -1580,11 +1610,12 @@ void xqc_engine_set_log_level(xqc_engine_t *engine, xqc_log_level_t log_level); /** * @brief enable/disable the log module of xquic + * @note This function is not thread-safe. * * @param enable XQC_TRUE for disable, XQC_FALSE for enable */ XQC_EXPORT_PUBLIC_API -void xqc_log_disable(xqc_engine_t *engine, xqc_bool_t disable); +void xqc_log_disable(xqc_bool_t disable); /** @@ -1594,6 +1625,17 @@ void xqc_log_disable(xqc_engine_t *engine, xqc_bool_t disable); XQC_EXPORT_PUBLIC_API void xqc_engine_finish_recv(xqc_engine_t *engine); + +/** + * @brief only useful for manually triggered send mode + * + * @param engine + * @return XQC_EXPORT_PUBLIC_API + */ +XQC_EXPORT_PUBLIC_API +void xqc_engine_finish_send(xqc_engine_t *engine); + + XQC_EXPORT_PUBLIC_API xqc_connection_t *xqc_engine_get_conn_by_scid(xqc_engine_t *engine, const xqc_cid_t *cid); diff --git a/include/xquic/xquic_typedef.h b/include/xquic/xquic_typedef.h index ce45eb1a8..313880250 100644 --- a/include/xquic/xquic_typedef.h +++ b/include/xquic/xquic_typedef.h @@ -41,7 +41,7 @@ #if defined(XQC_SYS_WINDOWS) && !defined(XQC_ON_MINGW) # undef XQC_EXTERN -# define XQC_EXTERN +# define XQC_EXTERN extern #ifdef XQC_SYS_WIN64 typedef __int64 ssize_t; @@ -126,6 +126,7 @@ typedef struct xqc_cid_s { uint8_t cid_buf[XQC_MAX_CID_LEN]; uint64_t cid_seq_num; uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN]; + uint64_t path_id; /* preallocate for multi-path */ } xqc_cid_t; typedef enum xqc_log_level_s { @@ -192,6 +193,14 @@ typedef enum { XQC_STREAM_UNI } xqc_stream_direction_t; +typedef enum { + XQC_DEFAULT_SIZE_REQ, + XQC_SLIM_SIZE_REQ, + XQC_NORMAL_SIZE_REQ, + XQC_MIDDLE_SIZE_REQ, + XQC_LARGE_SIZE_REQ +} xqc_stream_size_type_t; + #define XQC_DEFAULT_HTTP_PRIORITY_URGENCY 3 #define XQC_HIGHEST_HTTP_PRIORITY_URGENCY 0 #define XQC_LOWEST_HTTP_PRIORITY_URGENCY 7 @@ -201,6 +210,7 @@ typedef struct xqc_http_priority_s { uint8_t incremental; uint8_t schedule; uint8_t reinject; + uint32_t fec; } xqc_h3_priority_t; /* ALPN definition */ @@ -288,4 +298,18 @@ typedef enum xqc_conn_option_e { XQC_CO_SL10 = XQC_CO_TAG('S', 'L', '1', '0'), // Set the STARTUP loss rate threshold to 0.05 } xqc_conn_option_t; +/* application layer path status */ +typedef enum { + /* max */ + XQC_APP_PATH_STATUS_NONE, + /* suggest that no traffic should be sent on that path if another path is available */ + XQC_APP_PATH_STATUS_STANDBY = 1, + /* allow the peer to use its own logic to split traffic among available paths */ + XQC_APP_PATH_STATUS_AVAILABLE = 2, + /* freeze a path */ + XQC_APP_PATH_STATUS_FROZEN = 3, + /* max */ + XQC_APP_PATH_STATUS_MAX, +} xqc_app_path_status_t; + #endif /*_XQUIC_TYPEDEF_H_INCLUDED_*/ diff --git a/scripts/case_test.sh b/scripts/case_test.sh index 6fd575260..db930b43e 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -47,7 +47,7 @@ clear_log echo -e "log switch off ...\c" ${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 44 >> stdlog log_size=`wc -l clog | awk -F ' ' '{print $1}'` -if [ $log_size -eq 1 ]; then +if [ $log_size -eq 0 ]; then echo ">>>>>>>> pass:1" case_print_result "log_switch_off" "pass" else @@ -1621,28 +1621,15 @@ sleep 1 clear_log -echo -e "send 1M data on multiple paths with multipath vertion 04" -sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo -i lo -E -v 4 > stdlog -cli_result=`grep "multipath version negotiation succeed on multipath 04" clog` +echo -e "send 1M data on multiple paths with multipath version 10" +sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo -i lo -E -v 10 > stdlog +cli_result=`grep "multipath version negotiation succeed on multipath 010" clog` if [ -n "$cli_result" ]; then echo ">>>>>>>> pass:1" - case_print_result "MPNS_send_data_with_multipath_04" "pass" + case_print_result "MPNS_send_data_with_multipath_10" "pass" else echo ">>>>>>>> pass:0" - case_print_result "MPNS_send_data_with_multipath_04" "fail" -fi -rm -f test_session tp_localhost xqc_token - -clear_log -echo -e "send 1M data on multiple paths with multipath vertion 05" -sudo ${CLIENT_BIN} -s 1024000 -l d -t 1 -M -i lo -i lo -E -v 5 > stdlog -cli_result=`grep "multipath version negotiation succeed on multipath 05" clog` -if [ -n "$cli_result" ]; then - echo ">>>>>>>> pass:1" - case_print_result "MPNS_send_data_with_multipath_05" "pass" -else - echo ">>>>>>>> pass:0" - case_print_result "MPNS_send_data_with_multipath_05" "fail" + case_print_result "MPNS_send_data_with_multipath_10" "fail" fi rm -f test_session tp_localhost xqc_token @@ -1769,6 +1756,7 @@ fi if [ -f stdlog ]; then rm -f stdlog fi + ${SERVER_BIN} -l d -Q 9000 > /dev/null & sleep 1 clear_log @@ -4424,17 +4412,16 @@ else case_print_result "h3_engine_set_settings_api_h3_ext_more" "fail" fi -rm -rf tp_localhost test_session xqc_token +sudo rm -rf tp_localhost test_session xqc_token clog slog killall test_server 2> /dev/null ${SERVER_BIN} -l d -e -f > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token -clear_log echo -e "negotiate_encoder_fec_schemes ...\c" sudo ${CLIENT_BIN} -l d -g > stdlog -clog_res1=`grep "|client set final encoder fec scheme: " clog` -slog_res1=`grep "|server set final encoder fec scheme: " slog` +clog_res1=`grep "|xqc_negotiate_fec_schemes|set final encoder fec scheme: XOR" clog` +slog_res1=`grep "|xqc_negotiate_fec_schemes|set final encoder fec scheme: XOR" slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$clog_res1" ] && [ -n "$slog_res1" ]; then echo ">>>>>>>> pass:1" @@ -4446,11 +4433,10 @@ fi rm -rf tp_localhost test_session xqc_token -clear_log echo -e "negotiate_decoder_fec_schemes ...\c" sudo ${CLIENT_BIN} -l d -g > stdlog -clog_res2=`grep "|client set final decoder fec scheme: " clog` -slog_res2=`grep "|server set final decoder fec scheme: " slog` +clog_res2=`grep "|xqc_negotiate_fec_schemes|set final decoder fec scheme: XOR" clog` +slog_res2=`grep "|xqc_negotiate_fec_schemes|set final decoder fec scheme: XOR" slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$clog_res2" ] && [ -n "$slog_res2" ]; then echo ">>>>>>>> pass:1" @@ -4461,59 +4447,62 @@ else fi -rm -rf tp_localhost test_session xqc_token clear_log -echo -e "negotiate_fec_schemes_fail ...\c" -sudo ${CLIENT_BIN} -l d -g --fec_encoder 12 --fec_decoder 12 > stdlog -clog_res2=`grep "|invalid fec schemes, negotiation on final encoder scheme failed.|" clog` -clog_res2=`grep "|invalid fec schemes, negotiation on final decoder scheme failed." clog` -slog_res2=`grep "|negotiation on final encoder scheme failed.|" slog` -slog_res2=`grep "|negotiation on final decoder scheme failed.|" slog` +killall test_server 2> /dev/null +stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & +sleep 1 + +rm -rf tp_localhost test_session xqc_token +echo -e "check fec recovery function of stream using XOR ...\c" +sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo > stdlog +slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ -n "$clog_res2" ] && [ -n "$slog_res2" ]; then +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then echo ">>>>>>>> pass:1" - case_print_result "negotiate_fec_schemes_fail" "pass" + case_print_result "fec_recovered_function_of_stream_xor" "pass" else echo ">>>>>>>> pass:0" - case_print_result "negotiate_fec_schemes_fail" "fail" + case_print_result "fec_recovered_function_of_stream_xor" "fail" fi - +clear_log killall test_server 2> /dev/null stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token -clear_log -echo -e "check fec recovery function of stream ...\c" -sudo ${CLIENT_BIN} -s 10240000 -l e -E -d 30 -g -M -i lo -i lo > stdlog +echo -e "check fec recovery function of stream using RSC ...\c" +sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 8 --fec_decoder 8 > stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then echo ">>>>>>>> pass:1" - case_print_result "fec_recovered_function_of_stream" "pass" + case_print_result "fec_recovered_function_of_stream_rsc" "pass" else echo ">>>>>>>> pass:0" - case_print_result "fec_recovered_function_of_stream" "fail" + case_print_result "fec_recovered_function_of_stream_rsc" "fail" fi +clear_log killall test_server 2> /dev/null stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token -clear_log -echo -e "test repair_num_is_zero ...\c" -sudo ${CLIENT_BIN} -s 3000 -l e -E -d 30 -g -M -i lo -i lo -x 80 > stdlog -clog_res1=`grep '|xqc_process_fec_protected_packet|xqc_is_fec_params_valid|fec params invalid|' clog` -if [ -n "$clog_res1" ]; then +echo -e "check fec recovery function of stream using PM ...\c" +sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 > stdlog +slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then echo ">>>>>>>> pass:1" - case_print_result "repair_num_is_zero" "pass" + case_print_result "fec_recovered_function_of_stream_pm" "pass" else echo ">>>>>>>> pass:0" - case_print_result "repair_num_is_zero" "fail" + case_print_result "fec_recovered_function_of_stream_pm" "fail" fi + + killall test_server 2> /dev/null ${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 --dgram_qos 3 -f > /dev/null & sleep 1 @@ -4522,7 +4511,7 @@ rm -rf tp_localhost test_session xqc_token clear_log echo -e "check fec recovery function of datagram with XOR fec scheme ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 8 > stdlog +sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g > stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4535,7 +4524,7 @@ fi clear_log echo -e "check fec recovery function of datagram with RSC fec scheme ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 11 --fec_decoder 11 > stdlog +sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 8 > stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4546,9 +4535,22 @@ else case_print_result "fec_recovered_function_of_datagram_rsc" "fail" fi +clear_log +echo -e "check fec recovery function of datagram with Packet Mask scheme ...\c" +sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 12 --fec_decoder 12 > stdlog +slog_res1=`grep '|process packet of block 0 successfully' slog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "fec_recovered_function_of_datagram_pm" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_pm" "fail" +fi + clear_log echo -e "check fec recovery function of datagram with XOR(encoder) and RSC(decoder) fec schemes ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 11 --fec_decoder 11 > stdlog +sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 11 > stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4562,7 +4564,7 @@ fi clear_log echo -e "check fec recovery function of datagram with XOR(decoder) and RSC(encoder) fec schemes ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 3000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 11 --fec_decoder 11 > stdlog +sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 11 --fec_decoder 8 > stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then diff --git a/src/common/xqc_log.c b/src/common/xqc_log.c index 2b7b00177..8aca1315f 100644 --- a/src/common/xqc_log.c +++ b/src/common/xqc_log.c @@ -9,11 +9,12 @@ FILE *g_malloc_info_fp; #endif +static xqc_bool_t log_disable = XQC_FALSE; + void -xqc_log_disable(xqc_engine_t *engine, xqc_bool_t disable) +xqc_log_disable(xqc_bool_t disable) { - engine->log_disable = disable; - xqc_log(engine->log, XQC_LOG_DEBUG, "|log_disable:%d|", disable); + log_disable = disable; } void @@ -266,7 +267,7 @@ void xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...) { /* do nothing if switch is off */ - if (log->engine && log->engine->log_disable) { + if (log_disable) { return; } @@ -326,7 +327,7 @@ void xqc_qlog_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...) { /* do nothing if switch is off */ - if (log->engine && log->engine->log_disable) { + if (log_disable) { return; } diff --git a/src/common/xqc_log_event_callback.c b/src/common/xqc_log_event_callback.c index b420478e1..8b2c60134 100644 --- a/src/common/xqc_log_event_callback.c +++ b/src/common/xqc_log_event_callback.c @@ -757,9 +757,9 @@ xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stre void xqc_log_HTTP_PRIORITY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_h3_priority_t *prio, xqc_h3_stream_t *h3s) { - xqc_qlog_implement(log, HTTP_PRIORITY_UPDATED, func, "|urgency:%ui|incremental:%ui|schedule:%ui|reinject:%ui|" + xqc_qlog_implement(log, HTTP_PRIORITY_UPDATED, func, "|urgency:%ui|incremental:%ui|schedule:%ui|reinject:%ui|fec_bm_mode:%ui|" "stream_id:%ui|conn:%p|", - prio->urgency, prio->incremental, prio->schedule, prio->reinject, + prio->urgency, prio->incremental, prio->schedule, prio->reinject, h3s->stream->stream_fec_blk_mode, h3s->stream_id, h3s->h3c->conn); } diff --git a/src/common/xqc_priority_q.h b/src/common/xqc_priority_q.h index ff2234740..69bfce64e 100644 --- a/src/common/xqc_priority_q.h +++ b/src/common/xqc_priority_q.h @@ -9,18 +9,21 @@ #include #include "src/common/xqc_malloc.h" +#include "src/common/xqc_str.h" /* Priority Queue based on Binary Heap * * Interfaces: - * xqc_pq_init(), xqc_pq_init_default(capacity=xqc_pq_default_capacity) + * xqc_pq_init() * xqc_pq_push() * xqc_pq_pop() * xqc_pq_top() * xqc_pq_empty() + * xqc_pq_remove() */ typedef uint64_t xqc_pq_key_t; +typedef struct xqc_priority_queue_s xqc_pq_t; typedef struct xqc_priority_queue_element_s { xqc_pq_key_t key; @@ -29,6 +32,7 @@ typedef struct xqc_priority_queue_element_s { /* element compare function */ typedef int (*xqc_pq_compare_ptr)(xqc_pq_key_t a, xqc_pq_key_t b); +typedef int (*xqc_pq_element_op_t)(xqc_pq_t *pq, xqc_pq_element_t *e); /* default element compare function, priority: a < b */ static inline int @@ -51,14 +55,25 @@ typedef struct xqc_priority_queue_s { size_t capacity; /* capacity */ xqc_allocator_t a; /* memory allocator */ xqc_pq_compare_ptr cmp; /* compare function */ + xqc_pq_element_op_t eop; /* callback function to operate element */ } xqc_pq_t; #define xqc_pq_element(pq, index) ((xqc_pq_element_t *)&(pq)->elements[(index) * (pq)->element_size]) -#define xqc_pq_element_copy(pq, dst, src) memcpy(xqc_pq_element((pq), (dst)), xqc_pq_element((pq), (src)), (pq)->element_size) +#define xqc_pq_element_index(pq, elem) ((((char*)elem) - pq->elements) / pq->element_size) +#define xqc_pq_element_copy(pq, dst, src) (xqc_memcpy(xqc_pq_element((pq), (dst)), xqc_pq_element((pq), (src)), (pq)->element_size)) +#define xqc_pq_element_init(pq, elem, key, data) \ + xqc_memzero(elem, pq->element_size); \ + elem->key = key; \ + if (data != NULL) { \ + xqc_memcpy(elem->data, (char*)data, pq->element_size - sizeof(elem->key)); \ + } + #define xqc_pq_default_capacity 16 static inline int -xqc_pq_init(xqc_pq_t *pq, size_t element_size, size_t capacity, xqc_allocator_t a, xqc_pq_compare_ptr cmp) +xqc_pq_init(xqc_pq_t *pq, size_t element_size, + size_t capacity, xqc_allocator_t a, xqc_pq_compare_ptr cmp, + xqc_pq_element_op_t eop) { if (element_size < sizeof(xqc_pq_element_t) || capacity == 0) { return -1; @@ -74,16 +89,11 @@ xqc_pq_init(xqc_pq_t *pq, size_t element_size, size_t capacity, xqc_allocator_t pq->capacity = capacity; pq->a = a; pq->cmp = cmp; + pq->eop = eop; return 0; } -static inline int -xqc_pq_init_default(xqc_pq_t *pq, size_t element_size, xqc_allocator_t a, xqc_pq_compare_ptr cmp) -{ - return xqc_pq_init(pq, element_size, xqc_pq_default_capacity, a, cmp); -} - static inline void xqc_pq_destroy(xqc_pq_t *pq) { @@ -92,6 +102,8 @@ xqc_pq_destroy(xqc_pq_t *pq) pq->element_size = 0; pq->count = 0; pq->capacity = 0; + pq->cmp = NULL; + pq->eop = NULL; } static inline void @@ -106,10 +118,52 @@ xqc_pq_element_swap(xqc_pq_t *pq, size_t i, size_t j) memcpy(buf, xqc_pq_element(pq, j), pq->element_size); memcpy(xqc_pq_element(pq, j), xqc_pq_element(pq, i), pq->element_size); memcpy(xqc_pq_element(pq, i), buf, pq->element_size); + + if (pq->eop) { + pq->eop(pq, xqc_pq_element(pq, i)); + pq->eop(pq, xqc_pq_element(pq, j)); + } +} + +static inline uint32_t +xqc_pq_move_towards_top(xqc_pq_t *pq, uint32_t i) +{ + uint32_t j; + while (i != 0) { + j = (i - 1) / 2; + + if (!pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, i)->key)) + break; + + xqc_pq_element_swap(pq, i, j); + + i = j; + } + return i; +} + +static inline void +xqc_pq_move_towards_bottom(xqc_pq_t *pq, uint32_t i) +{ + uint32_t j = 2 * i + 1; + while (j <= pq->count - 1) { + if (j < pq->count - 1 && pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, j+1)->key)) { + ++j; + } + + if (!pq->cmp(xqc_pq_element(pq, i)->key, xqc_pq_element(pq, j)->key)) { + break; + } + + xqc_pq_element_swap(pq, i, j); + + i = j; + j = 2 * i + 1; + } } static inline xqc_pq_element_t * -xqc_pq_push(xqc_pq_t *pq, xqc_pq_key_t key) +xqc_pq_push(xqc_pq_t *pq, xqc_pq_key_t key, const void *data) { if (pq->count == pq->capacity) { size_t capacity = pq->capacity * 2; @@ -126,19 +180,15 @@ xqc_pq_push(xqc_pq_t *pq, xqc_pq_key_t key) } xqc_pq_element_t *p = xqc_pq_element(pq, pq->count); - p->key = key; - - size_t i = pq->count++; - while (i != 0) { - int j = (i - 1) / 2; - if (!pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, i)->key)) - break; + xqc_pq_element_init(pq, p, key, data); - xqc_pq_element_swap(pq, i, j); - - i = j; + if (pq->eop) { + pq->eop(pq, p); } + size_t i = pq->count++; + i = xqc_pq_move_towards_top(pq, i); + return xqc_pq_element(pq, i); } @@ -165,25 +215,31 @@ xqc_pq_pop(xqc_pq_t *pq) } xqc_pq_element_copy(pq, 0, pq->count); + + if (pq->eop) { + pq->eop(pq, xqc_pq_element(pq, 0)); + } - int i = 0, j = 2 * i + 1; - while (j <= pq->count - 1) { - if (j < pq->count - 1 && pq->cmp(xqc_pq_element(pq, j)->key, xqc_pq_element(pq, j+1)->key)) { - ++j; - } + xqc_pq_move_towards_bottom(pq, 0); +} - if (!pq->cmp(xqc_pq_element(pq, i)->key, xqc_pq_element(pq, j)->key)) { - break; - } - xqc_pq_element_swap(pq, i, j); +static inline void +xqc_pq_remove(xqc_pq_t *pq, uint32_t index) +{ + if (index >= pq->count || pq->count == 0 || --pq->count == 0) { + return; + } - i = j; - j = 2 * i + 1; + xqc_pq_element_copy(pq, index, pq->count); + xqc_pq_element_t *p = xqc_pq_element(pq, index); + + if (pq->eop) { + pq->eop(pq, p); } -} -#undef xqc_pq_element -#undef xqc_pq_element_copy + xqc_pq_move_towards_bottom(pq, index); + xqc_pq_move_towards_top(pq, index); +} #endif /*_NGX_H_PRIORITY_Q_INCLUDED_*/ diff --git a/src/common/xqc_time.c b/src/common/xqc_time.c index c9d90c5f6..be210a77a 100644 --- a/src/common/xqc_time.c +++ b/src/common/xqc_time.c @@ -6,7 +6,6 @@ #ifdef XQC_SYS_WINDOWS #ifndef _GETTIMEOFDAY_DEFINED -#define DELTA_EPOCH_IN_TICKS 116444736000000000ULL struct timezone { int tz_minuteswest; /* minutes west of Greenwich */ @@ -23,8 +22,9 @@ gettimeofday(struct timeval *tv, struct timezone *tz) GetSystemTimeAsFileTime(&ft); tmpres = ((uint64_t) ft.dwHighDateTime << 32) | (ft.dwLowDateTime); - tmpres -= DELTA_EPOCH_IN_TICKS; - tv->tv_sec = tmpres / 10000000; + tmpres /= 10; /* Convert from 100-nanosecond intervals to microseconds */ + tmpres -= 11644473600000000ULL; /* Convert from Windows epoch (1601-01-01) to Unix epoch (1970-01-01) */ + tv->tv_sec = tmpres / 1000000; tv->tv_usec = tmpres % 1000000; } diff --git a/src/congestion_control/xqc_bbr.c b/src/congestion_control/xqc_bbr.c index 928801882..6392c7520 100644 --- a/src/congestion_control/xqc_bbr.c +++ b/src/congestion_control/xqc_bbr.c @@ -283,6 +283,7 @@ xqc_bbr_init(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params) bbr->full_bandwidth_cnt = 0; bbr->full_bandwidth_reached = FALSE; bbr->lt_bw_enabled = XQC_FALSE; + bbr->ignore_app_limit = XQC_FALSE; if (cc_params.customize_on) { cc_params.init_cwnd *= XQC_BBR_MAX_DATAGRAMSIZE; @@ -306,6 +307,9 @@ xqc_bbr_init(void *cong_ctl, xqc_sample_t *sampler, xqc_cc_params_t cc_params) if (cc_params.bbr_enable_lt_bw) { bbr->lt_bw_enabled = XQC_TRUE; } + if (cc_params.bbr_ignore_app_limit) { + bbr->ignore_app_limit = XQC_TRUE; + } } bbr->congestion_window = bbr->initial_congestion_window; @@ -364,8 +368,12 @@ xqc_bbr_update_bandwidth(xqc_bbr_t *bbr, xqc_sample_t *sampler) if (bbr->enable_max_expect_bw && bandwidth >= bbr->max_expect_bw) { bandwidth = bbr->max_expect_bw; } - - if (!sampler->is_app_limited || bandwidth >= xqc_bbr_max_bw(bbr)) { + + /* + * In a live video scenario, the applimit state often occurs, + * causing the detection bandwidth increases but does not decrease. + */ + if (bbr->ignore_app_limit || !sampler->is_app_limited || bandwidth >= xqc_bbr_max_bw(bbr)) { xqc_win_filter_max(&bbr->bandwidth, xqc_bbr_bw_win_size, bbr->round_cnt, bandwidth); xqc_log(sampler->send_ctl->ctl_conn->log, XQC_LOG_DEBUG, @@ -536,8 +544,12 @@ xqc_bbr_check_full_bw_reached(xqc_bbr_t *bbr, xqc_sample_t *sampler) * Otherwise, startup may end too early due to multiple ACKs arrive in a RTT. */ if (!bbr->round_start || bbr->full_bandwidth_reached - || sampler->is_app_limited) + || (!bbr->ignore_app_limit && sampler->is_app_limited)) { + /* + * In a live video scenario, the applimit state often occurs, + * causing the startup state to persist for a long time. + */ return; } diff --git a/src/congestion_control/xqc_bbr.h b/src/congestion_control/xqc_bbr.h index fdc55e989..7c1a89408 100644 --- a/src/congestion_control/xqc_bbr.h +++ b/src/congestion_control/xqc_bbr.h @@ -153,6 +153,8 @@ typedef struct xqc_bbr_s { xqc_bool_t lt_is_sampling; xqc_bool_t lt_use_bw; uint16_t lt_rtt_cnt; + + xqc_bool_t ignore_app_limit; } xqc_bbr_t; extern const xqc_cong_ctrl_callback_t xqc_bbr_cb; diff --git a/src/http3/xqc_h3_request.c b/src/http3/xqc_h3_request.c index a7e6dd541..d9bb2b28d 100644 --- a/src/http3/xqc_h3_request.c +++ b/src/http3/xqc_h3_request.c @@ -62,7 +62,9 @@ xqc_h3_request_destroy(xqc_h3_request_t *h3_request) "|mp_state:%d|path_info:%s|comp_hdr_s:%uz|comp_hdr_r:%uz|fst_fin_snd:%ui|" "sched_blk:%ud|sched_blk_time:%ui|" "cwnd_blk:%ud|cwnd_blk_time:%ui|" - "pacing_blk:%ud|pacing_blk_time:%ui|begin_state:%s|end_state:%s|", + "pacing_blk:%ud|pacing_blk_time:%ui|begin_state:%s|end_state:%s|" + "is_fec_protected:%ud|fec_reco_pkt_cnt:%ud|fec_block_size_mode:%ud|" + "fst_rpr_ts:%ui|last_rpr_ts:%ui|", h3s->stream_id, stats.stream_close_msg ? stats.stream_close_msg : "", stats.stream_err, stats.recv_body_size, stats.send_body_size, stats.recv_header_size, stats.send_header_size, @@ -90,7 +92,10 @@ xqc_h3_request_destroy(xqc_h3_request_t *h3_request) h3_request->send_pacing_blk_cnt, h3_request->send_pacing_blk_duration / 1000, h3s->begin_trans_state, - h3s->end_trans_state); + h3s->end_trans_state, + stats.is_fec_protected, stats.fec_recov_cnt, h3_request->block_size_mode, + h3_request->fst_rpr_time, h3_request->last_rpr_time + ); if (h3_request->request_if->h3_request_close_notify) { h3_request->request_if->h3_request_close_notify(h3_request, h3_request->user_data); @@ -213,6 +218,7 @@ xqc_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats) int i; int flag = 0; char mp_settings[XQC_MP_SETTINGS_STR_LEN] = {0}; + xqc_usec_t hsk_time; if (h3c->conn->handshake_complete_time > 0) { flag = 1; @@ -222,12 +228,17 @@ xqc_stream_info_print(xqc_h3_stream_t *h3_stream, xqc_request_stats_t *stats) flag |= 1 << 1; } + hsk_time = (h3c->conn->handshake_complete_time > h3c->conn->conn_create_time) ? + (h3c->conn->handshake_complete_time - h3c->conn->conn_create_time) : + 0; + xqc_conn_encode_mp_settings(h3c->conn, mp_settings, XQC_MP_SETTINGS_STR_LEN); - ret = snprintf(buff, buff_size, "(%d,%"PRIu64",%s,%"PRIu64",%"PRIu64",%"PRIu64",%u)#", + ret = snprintf(buff, buff_size, "(%d,%"PRIu64",%s,%"PRIu64",%"PRIu64",%"PRIu64",%u,%"PRIu64")#", flag, h3_stream->recv_rate_limit, mp_settings, h3_stream->send_offset, h3_stream->recv_offset, - stats->cwnd_blocked_ms, stats->retrans_cnt); + stats->cwnd_blocked_ms, stats->retrans_cnt, + hsk_time / 1000); cursor += ret; @@ -323,7 +334,10 @@ xqc_h3_request_get_stats(xqc_h3_request_t *h3_request) stats.retrans_cnt = h3_request->retrans_pkt_cnt; stats.stream_fst_pkt_snd_time = h3_request->stream_fst_pkt_snd_time; stats.stream_fst_pkt_rcv_time = h3_request->stream_fst_pkt_rcv_time; - + stats.sent_pkt_cnt = h3_request->sent_pkt_cnt; + stats.max_pto_backoff = h3_request->max_pto_backoff; + stats.fec_recov_cnt = h3_request->recov_pkt_cnt; + stats.is_fec_protected = h3_request->block_size_mode != XQC_SLIM_SIZE_REQ && h3_request->h3_stream->h3c->conn->conn_settings.fec_params.fec_encoder_scheme != 0 ? 1 : 0; xqc_h3_stream_get_path_info(h3_request->h3_stream); xqc_request_path_metrics_print(h3_request->h3_stream->h3c->conn, h3_request->h3_stream, &stats); @@ -896,6 +910,9 @@ xqc_h3_request_closing(xqc_h3_request_t *h3r, xqc_int_t err) #define XQC_PRIORITY_REINJECT ", r=" #define XQC_PRIORITY_REINJECT_LEN 4 +#define XQC_PRIORITY_FEC ", f=" +#define XQC_PRIORITY_FEC_LEN 4 + void xqc_h3_priority_init(xqc_h3_priority_t *prio) { @@ -903,6 +920,7 @@ xqc_h3_priority_init(xqc_h3_priority_t *prio) prio->incremental = XQC_FALSE; prio->schedule = 0; prio->reinject = 0; + prio->fec = XQC_DEFAULT_SIZE_REQ; } size_t @@ -914,7 +932,8 @@ xqc_write_http_priority(xqc_h3_priority_t *prio, size_t need = XQC_PRIORITY_URGENCY_LEN + 1 + XQC_PRIORITY_INCREMENTAL_LEN + XQC_PRIORITY_SCHEDULE_LEN + 1 - + XQC_PRIORITY_REINJECT_LEN + 1; + + XQC_PRIORITY_REINJECT_LEN + 1 + + XQC_PRIORITY_FEC_LEN + 4; if (need > dstcap) { return -XQC_H3_BUFFER_EXCEED; } @@ -936,6 +955,11 @@ xqc_write_http_priority(xqc_h3_priority_t *prio, dst += XQC_PRIORITY_REINJECT_LEN; *dst++ = '0' + prio->reinject; + xqc_memcpy(dst, XQC_PRIORITY_FEC, XQC_PRIORITY_FEC_LEN); + dst += XQC_PRIORITY_FEC_LEN; + xqc_memcpy(dst, &prio->fec, 4); + dst += 4; + return dst - begin; } @@ -986,6 +1010,9 @@ xqc_parse_http_priority(xqc_h3_priority_t *dst, p += xqc_lengthof("r="); prio.reinject = strtoul(p, NULL, 10); + } else if (strncmp(p, "f=", xqc_lengthof("f=")) == 0) { + p += xqc_lengthof("f="); + prio.fec = *p | *(p + 1) << 8 | *(p + 2) << 16 | *(p + 3) << 24; } p = strchr(p, ','); diff --git a/src/http3/xqc_h3_request.h b/src/http3/xqc_h3_request.h index d8824d495..18916df19 100644 --- a/src/http3/xqc_h3_request.h +++ b/src/http3/xqc_h3_request.h @@ -74,7 +74,14 @@ typedef struct xqc_h3_request_s { xqc_usec_t send_pacing_blk_duration; uint32_t retrans_pkt_cnt; - + uint32_t sent_pkt_cnt; + uint8_t max_pto_backoff; + + /* fec */ + uint32_t recov_pkt_cnt; + uint8_t block_size_mode; + xqc_usec_t fst_rpr_time; + xqc_usec_t last_rpr_time; } xqc_h3_request_t; xqc_h3_request_t *xqc_h3_request_create_inner(xqc_h3_conn_t *h3_conn, xqc_h3_stream_t *h3_stream, diff --git a/src/http3/xqc_h3_stream.c b/src/http3/xqc_h3_stream.c index 8abd92ff6..0c184e53c 100644 --- a/src/http3/xqc_h3_stream.c +++ b/src/http3/xqc_h3_stream.c @@ -86,6 +86,7 @@ xqc_h3_stream_destroy(xqc_h3_stream_t *h3s) } if (h3s->h3r && h3s->type == XQC_H3_STREAM_TYPE_REQUEST) { + xqc_h3_stream_update_stats(h3s); xqc_h3_request_destroy(h3s->h3r); } @@ -392,8 +393,10 @@ xqc_h3_stream_send_headers(xqc_h3_stream_t *h3s, xqc_http_headers_t *headers, ui h3s->flags &= ~XQC_HTTP3_STREAM_NEED_WRITE_NOTIFY; - xqc_engine_main_logic_internal(h3c->conn->engine); - + if (!h3c->conn->engine->config->manually_triggered_send) { + xqc_engine_conn_logic(h3c->conn->engine, h3c->conn); + } + return write; } @@ -526,7 +529,9 @@ xqc_h3_stream_send_data(xqc_h3_stream_t *h3s, unsigned char *data, size_t data_s xqc_log(h3s->log, XQC_LOG_DEBUG, "|stream_id:%ui|data_size:%uz|write:%z|fin:%ud|conn:%p|", h3s->stream_id, data_size, write, (unsigned int)fin, h3s->h3c->conn); - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + if (!h3s->h3c->conn->engine->config->manually_triggered_send) { + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); + } return write; } @@ -570,7 +575,7 @@ xqc_h3_stream_send_finish(xqc_h3_stream_t *h3s) return ret; } - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); return XQC_OK; } @@ -630,7 +635,7 @@ xqc_h3_stream_send_goaway(xqc_h3_stream_t *h3s, uint64_t push_id, uint8_t fin) return ret; } - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); return XQC_OK; } @@ -644,7 +649,7 @@ xqc_h3_stream_send_bidi_stream_type(xqc_h3_stream_t *h3s, return ret; } - xqc_engine_main_logic_internal(h3s->h3c->conn->engine); + xqc_engine_conn_logic(h3s->h3c->conn->engine, h3s->h3c->conn); return XQC_OK; } @@ -765,6 +770,12 @@ xqc_h3_stream_process_control(xqc_h3_stream_t *h3s, unsigned char *data, size_t break; case XQC_H3_FRM_GOAWAY: + + if (!(h3s->h3c->flags & XQC_H3_CONN_FLAG_GOAWAY_RECVD)) { + h3c->goaway_stream_id = pl->goaway.stream_id.vi; + h3s->h3c->flags |= XQC_H3_CONN_FLAG_GOAWAY_RECVD; + } + if (h3c->goaway_stream_id > pl->goaway.stream_id.vi) { h3c->goaway_stream_id = pl->goaway.stream_id.vi; @@ -773,9 +784,11 @@ xqc_h3_stream_process_control(xqc_h3_stream_t *h3s, unsigned char *data, size_t " receive bigger push id|push_id:%ui|", pl->goaway.stream_id.vi); } - h3s->h3c->flags |= XQC_H3_CONN_FLAG_GOAWAY_RECVD; + xqc_log(h3c->log, XQC_LOG_DEBUG, "|H3_GOAWAY|stream_id:%ui|", pl->goaway.stream_id.vi); + break; + case XQC_H3_FRM_MAX_PUSH_ID: /* PUSH related is not implemented yet */ h3c->max_stream_id_recvd = pl->max_push_id.push_id.vi; @@ -1540,6 +1553,10 @@ xqc_h3_stream_get_buf(xqc_h3_stream_t *h3s, xqc_list_head_t *head, size_t expect { xqc_var_buf_t *buf = NULL; + if (head->prev == NULL || head->next == NULL) { + return NULL; + } + if (!xqc_list_empty(head)) { /* the last in list */ xqc_list_buf_t *list_buf = xqc_list_entry(head->prev, xqc_list_buf_t, list_head); @@ -1901,6 +1918,11 @@ xqc_h3_stream_update_stats(xqc_h3_stream_t *h3s) h3s->h3r->retrans_pkt_cnt = h3s->stream->stream_stats.retrans_pkt_cnt; h3s->h3r->stream_fst_pkt_snd_time = h3s->stream->stream_stats.first_snd_time; h3s->h3r->stream_fst_pkt_rcv_time = h3s->stream->stream_stats.first_rcv_time; + h3s->h3r->sent_pkt_cnt = h3s->stream->stream_stats.sent_pkt_cnt; + h3s->h3r->max_pto_backoff = h3s->stream->stream_stats.max_pto_backoff; + h3s->h3r->recov_pkt_cnt = h3s->stream->stream_stats.recov_pkt_cnt; + h3s->h3r->fst_rpr_time = h3s->stream->stream_stats.fst_rpr_time; + h3s->h3r->last_rpr_time = h3s->stream->stream_stats.last_rpr_time; } h3s->send_offset = h3s->stream->stream_send_offset; @@ -1915,6 +1937,11 @@ xqc_h3_stream_update_stats(xqc_h3_stream_t *h3s) if (conn == NULL) { return; } + + if (h3s->type == XQC_H3_STREAM_TYPE_REQUEST) { + h3s->stream->stream_stats.max_pto_backoff = xqc_max(h3s->stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(conn, 1)); + h3s->h3r->max_pto_backoff = h3s->stream->stream_stats.max_pto_backoff; + } if (h3s->stream->stream_flag & XQC_STREAM_FLAG_HAS_0RTT) { if (conn->conn_flag & XQC_CONN_FLAG_0RTT_OK) { @@ -2051,6 +2078,26 @@ xqc_h3_stream_get_path_info(xqc_h3_stream_t *h3s) } } +uint8_t +xqc_set_stream_fec_block_mode(uint32_t fec_size) +{ + if (fec_size == 0) { + return XQC_DEFAULT_SIZE_REQ; + + } else if (fec_size <= 2 * 1024) { + return XQC_SLIM_SIZE_REQ; + + } else if (fec_size <= 4 * 1024) { + return XQC_NORMAL_SIZE_REQ; + + } else if (fec_size <= 20 * 1024) { + return XQC_MIDDLE_SIZE_REQ; + + } else { + return XQC_LARGE_SIZE_REQ; + } +} + void xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) { @@ -2061,6 +2108,7 @@ xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) h3s->priority.incremental = prio->incremental; h3s->priority.schedule = prio->schedule; h3s->priority.reinject = prio->reinject; + h3s->priority.fec = prio->fec; if (h3s->stream == NULL) { xqc_log(h3s->log, XQC_LOG_ERROR, "|transport stream was NULL|stream_id:%ui|", h3s->stream_id); @@ -2068,5 +2116,7 @@ xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) } xqc_stream_set_multipath_usage(h3s->stream, h3s->priority.schedule, h3s->priority.reinject); + h3s->stream->stream_fec_blk_mode = xqc_set_stream_fec_block_mode(h3s->priority.fec); + h3s->h3r->block_size_mode = h3s->stream->stream_fec_blk_mode; } } diff --git a/src/tls/babassl/xqc_ssl_if_impl.c b/src/tls/babassl/xqc_ssl_if_impl.c index d4959b89e..28672a336 100644 --- a/src/tls/babassl/xqc_ssl_if_impl.c +++ b/src/tls/babassl/xqc_ssl_if_impl.c @@ -120,9 +120,10 @@ xqc_ssl_do_handshake(SSL *ssl, xqc_connection_t *conn, xqc_log_t *log) int rv = SSL_do_handshake(ssl); xqc_log(log, XQC_LOG_DEBUG, "|ssl_do_handshake|SSL_quic_read_level:%d|SSL_quic_write_level:%d|rv:%d|", - (int) SSL_quic_read_level(ssl), - (int) SSL_quic_write_level(ssl), - rv); + (int) SSL_quic_read_level(ssl), + (int) SSL_quic_write_level(ssl), + rv); + /* check if client hello is received completely */ if (SSL_quic_read_level(ssl) > 0 && conn != NULL diff --git a/src/tls/boringssl/xqc_ssl_if_impl.c b/src/tls/boringssl/xqc_ssl_if_impl.c index 938fbf9f6..558df1387 100644 --- a/src/tls/boringssl/xqc_ssl_if_impl.c +++ b/src/tls/boringssl/xqc_ssl_if_impl.c @@ -99,6 +99,7 @@ xqc_ssl_do_handshake(SSL *ssl, xqc_connection_t *conn, xqc_log_t *log) { conn->conn_flag |= XQC_CONN_FLAG_TLS_CH_RECVD; } + xqc_log(log, XQC_LOG_DEBUG, "|ssl_do_handshake|SSL_quic_read_level:%d|SSL_quic_write_level:%d|rv:%d|", (int) SSL_quic_read_level(ssl), (int) SSL_quic_write_level(ssl), diff --git a/src/tls/xqc_tls.c b/src/tls/xqc_tls.c index 3f8bb6a6a..66c3256ca 100644 --- a/src/tls/xqc_tls.c +++ b/src/tls/xqc_tls.c @@ -392,6 +392,7 @@ xqc_int_t xqc_tls_do_handshake(xqc_tls_t *tls) { xqc_ssl_handshake_res_t res = xqc_ssl_do_handshake(tls->ssl, tls->user_data, tls->log); + xqc_log(tls->log, XQC_LOG_DEBUG, "|TLS handshake|ret:%d|", res); if (res == XQC_SSL_HSK_RES_FAIL) { @@ -690,7 +691,7 @@ xqc_tls_is_key_ready(xqc_tls_t *tls, xqc_encrypt_level_t level, xqc_key_type_t k } uint32_t -xqc_tls_get_cipher_id(SSL *ssl, xqc_encrypt_level_t level, xqc_bool_t no_crypto) +xqc_tls_get_cipher_id(SSL *ssl, const SSL_CIPHER *cipher, xqc_encrypt_level_t level, xqc_bool_t no_crypto) { if (no_crypto == XQC_TRUE && (level == XQC_ENC_LEV_0RTT || level == XQC_ENC_LEV_1RTT)) @@ -698,6 +699,10 @@ xqc_tls_get_cipher_id(SSL *ssl, xqc_encrypt_level_t level, xqc_bool_t no_crypto) return NID_undef; } + if (cipher != NULL) { + return SSL_CIPHER_get_id(cipher); + } + return SSL_CIPHER_get_id(SSL_get_current_cipher(ssl)); } @@ -1158,7 +1163,7 @@ xqc_tls_set_read_secret(SSL *ssl, enum ssl_encryption_level_t level, /* create crypto instance if not created */ if (NULL == tls->crypto[level]) { tls->crypto[level] = xqc_crypto_create( - xqc_tls_get_cipher_id(ssl, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); + xqc_tls_get_cipher_id(ssl, cipher, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); if (NULL == tls->crypto[level]) { xqc_log(tls->log, XQC_LOG_ERROR, "|create crypto error"); return XQC_SSL_FAIL; @@ -1201,7 +1206,7 @@ xqc_tls_set_write_secret(SSL *ssl, enum ssl_encryption_level_t level, /* create crypto instance if not created */ if (NULL == tls->crypto[level]) { tls->crypto[level] = xqc_crypto_create( - xqc_tls_get_cipher_id(ssl, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); + xqc_tls_get_cipher_id(ssl, cipher, (xqc_encrypt_level_t)level, tls->no_crypto), tls->log); if (NULL == tls->crypto[level]) { xqc_log(tls->log, XQC_LOG_ERROR, "|create crypto error"); return XQC_SSL_FAIL; diff --git a/src/transport/fec_schemes/xqc_galois_calculation.c b/src/transport/fec_schemes/xqc_galois_calculation.c index ced2cec10..8ee0aabaf 100644 --- a/src/transport/fec_schemes/xqc_galois_calculation.c +++ b/src/transport/fec_schemes/xqc_galois_calculation.c @@ -68,7 +68,7 @@ xqc_galois_divide(unsigned char a, unsigned char b, unsigned char *res) unsigned char xqc_galois_inversion(unsigned char a) { - uint16_t i = 0; + int i = 0; if (a == 0) { return 0; } @@ -82,14 +82,14 @@ xqc_galois_inversion(unsigned char a) void -xqc_submatrix(uint16_t row_min, uint16_t row_max, - uint16_t col_min, uint16_t col_max, - uint16_t col_max_sub, uint16_t col_max_matrix, +xqc_submatrix(int row_min, int row_max, + int col_min, int col_max, + int col_max_sub, int col_max_matrix, unsigned char *submatrix, unsigned char *matrix) { xqc_memset(submatrix, 0, col_max_sub * row_max); - for (uint16_t row_i = row_min; row_i < row_max; row_i++) { - for (uint16_t col_i = col_min; col_i < col_max; col_i++) { + for (int row_i = row_min; row_i < row_max; row_i++) { + for (int col_i = col_min; col_i < col_max; col_i++) { *(submatrix + (row_i - row_min) * col_max_sub + col_i - col_min) = *(matrix + row_i * col_max_matrix + col_i); } } @@ -99,8 +99,8 @@ void xqc_build_vandermonde_matrix(unsigned char rows, unsigned char cols, unsigned char (*Vandermonde)[XQC_MAX_MT_ROW]) { - for (unsigned char i = 0; i < rows; i++) { - for (unsigned char j = 0; j < cols; j++) { + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { Vandermonde[i][j] = (unsigned char)xqc_galois_exp(i, j); } } @@ -112,7 +112,7 @@ xqc_build_vandermonde_matrix(unsigned char rows, unsigned char cols, xqc_int_t xqc_identity_matrix(unsigned char size, unsigned char (*output)[XQC_MAX_MT_ROW]) { - for (unsigned char i = 0; i < size; i++) { + for (int i = 0; i < size; i++) { xqc_memset(output[i], 0, XQC_MAX_MT_ROW); output[i][i] = 1; } @@ -130,11 +130,11 @@ xqc_concatenate_matrix(unsigned char (*left)[XQC_MAX_MT_ROW], unsigned char (*ri return -XQC_EPARAM; } - for (unsigned char row_i = 0; row_i < left_rows; row_i++) { - for (unsigned char col_i = 0; col_i < left_cols; col_i++) { + for (int row_i = 0; row_i < left_rows; row_i++) { + for (int col_i = 0; col_i < left_cols; col_i++) { output[row_i][col_i] = left[row_i][col_i]; } - for (unsigned char col_i = 0; col_i < right_cols; col_i++) { + for (int col_i = 0; col_i < right_cols; col_i++) { output[row_i][left_cols + col_i] = right[row_i][col_i]; } } @@ -146,7 +146,7 @@ xqc_int_t xqc_gaussian_elimination(unsigned char rows, unsigned char cols, unsigned char (*output)[2*XQC_MAX_MT_ROW]) { - uint16_t row_i, col_i, max_row, i, tmp, inv, row_above; + int row_i, col_i, max_row, i, tmp, inv, row_above; unsigned char ratio = 0; for (row_i = 0; row_i < rows; row_i++) { max_row = row_i; @@ -234,10 +234,10 @@ xqc_matrix_time(unsigned char left_row, unsigned char left_col, /* invalid matrix multiplication. */ return -XQC_EPARAM; } - for (unsigned char row_i = 0; row_i < left_row; row_i++) { - for(unsigned char col_i = 0; col_i < right_col; col_i++) { + for (int row_i = 0; row_i < left_row; row_i++) { + for(int col_i = 0; col_i < right_col; col_i++) { value = 0; - for (unsigned char i = 0; i < left_col; i++) { + for (int i = 0; i < left_col; i++) { value ^= xqc_galois_multiply(left[row_i][i], right[i][col_i]); } output[row_i][col_i] = value; diff --git a/src/transport/fec_schemes/xqc_galois_calculation.h b/src/transport/fec_schemes/xqc_galois_calculation.h index 070eee4a8..06cb47953 100644 --- a/src/transport/fec_schemes/xqc_galois_calculation.h +++ b/src/transport/fec_schemes/xqc_galois_calculation.h @@ -131,9 +131,9 @@ xqc_int_t xqc_galois_divide(unsigned char a, unsigned char b, unsigned char *res void xqc_build_vandermonde_matrix(unsigned char rows, unsigned char cols, unsigned char (*Vandermonde)[XQC_MAX_MT_ROW]); -void xqc_submatrix(uint16_t row_min, uint16_t row_max, - uint16_t col_min, uint16_t col_max, - uint16_t col_max_sub, uint16_t col_max_matrix, +void xqc_submatrix(int row_min, int row_max, + int col_min, int col_max, + int row_max_sub, int row_max_matrix, unsigned char *submatrix, unsigned char *matrix); xqc_int_t xqc_matrix_time(unsigned char left_row, unsigned char left_col, diff --git a/src/transport/fec_schemes/xqc_packet_mask.c b/src/transport/fec_schemes/xqc_packet_mask.c new file mode 100644 index 000000000..2b8bdc103 --- /dev/null +++ b/src/transport/fec_schemes/xqc_packet_mask.c @@ -0,0 +1,291 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited +*/ + +#include "src/transport/fec_schemes/xqc_packet_mask.h" +#include "src/transport/fec_schemes/xqc_xor.h" +#include "src/transport/fec_schemes/xqc_packet_mask_value.h" +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_conn.h" + + +void +xqc_lookup_pkm(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t rpr_symbol_num, uint8_t *output) +{ + const uint8_t *table = xqc_rnd_pm_tbl, *mask_entry = NULL; + uint8_t increment, count; + uint16_t tbl_len; + if (src_symbol_num > XQC_MAX_LOOKUP_MASK_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|invalid symbol number for constant mask tbl|src num:%d|rpr num:%d", src_symbol_num, rpr_symbol_num); + return; + } + + tbl_len = table[0]; + increment = 2; + mask_entry = &table[1]; + + // skip entries before src_symbol_num'th one; + for (uint32_t i = 0; i < src_symbol_num - 1; i++) { + count = mask_entry[0]; + mask_entry = &mask_entry[1]; + for (uint32_t j = 0; j < count; j++) { + mask_entry += increment * (j + 1); + } + } + + count = mask_entry[0]; + mask_entry = &mask_entry[1]; + // skip entries before repair_num; + for (uint32_t i = 0; i < rpr_symbol_num - 1; i++) { + mask_entry += increment * (i + 1); + } + + xqc_memcpy(output, mask_entry, increment * rpr_symbol_num); +} + +void +xqc_get_packet_mask(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t rpr_symbol_num, uint8_t *tbl) +{ + size_t tbl_size, increment; + uint32_t i, j; + + xqc_memset(tbl, 0, XQC_MAX_PM_SIZE); + if (src_symbol_num <= XQC_MAX_LOOKUP_MASK_SIZE) { + xqc_lookup_pkm(conn, src_symbol_num, rpr_symbol_num, tbl); + return; + } + + tbl_size = src_symbol_num; + increment = src_symbol_num > 16 ? 6 : 2; + for(i = 0; i < rpr_symbol_num; i++) { + for (j = 0; j < increment; j++) { + tbl[i * increment + j] = + ((j * 8) % rpr_symbol_num == i && (j * 8) < src_symbol_num ? 0x80: 0x00) | + ((j * 8 + 1) % rpr_symbol_num == i && (j * 8 + 1) < src_symbol_num ? 0x40: 0x00) | + ((j * 8 + 2) % rpr_symbol_num == i && (j * 8 + 2) < src_symbol_num ? 0x20: 0x00) | + ((j * 8 + 3) % rpr_symbol_num == i && (j * 8 + 3) < src_symbol_num ? 0x10: 0x00) | + ((j * 8 + 4) % rpr_symbol_num == i && (j * 8 + 4) < src_symbol_num ? 0x08: 0x00) | + ((j * 8 + 5) % rpr_symbol_num == i && (j * 8 + 5) < src_symbol_num ? 0x04: 0x00) | + ((j * 8 + 6) % rpr_symbol_num == i && (j * 8 + 6) < src_symbol_num ? 0x02: 0x00) | + ((j * 8 + 7) % rpr_symbol_num == i && (j * 8 + 7) < src_symbol_num ? 0x01: 0x00); + } + } +} + +void +xqc_packet_mask_init_one(xqc_connection_t *conn, uint8_t bm_idx) +{ + // init packet mask with default block size and code rate + uint8_t k, *output = NULL, table[XQC_MAX_PM_SIZE]; + uint16_t repair_num, increment; + const uint8_t *tbl_p = table; + + repair_num = conn->fec_ctl->fec_send_required_repair_num[bm_idx]; + k = xqc_get_fec_blk_size(conn, bm_idx); + increment = k > 16 ? 6 : 2; + + if (k > 48 || repair_num <= 0 || repair_num > xqc_min(k, XQC_REPAIR_LEN)) { + conn->conn_settings.enable_encode_fec = 0; + conn->local_settings.enable_encode_fec = 0; + return; + } + + xqc_get_packet_mask(conn, k, repair_num, table); + + for (uint32_t j = 0; j < repair_num; j++) { + output = conn->fec_ctl->fec_send_decode_matrix[bm_idx][j]; + xqc_memset(output, 0, increment); + xqc_memcpy(output, tbl_p, increment); + tbl_p += increment; + } + + return; +} + +void +xqc_packet_mask_init(xqc_connection_t *conn) +{ + // init packet mask with default block size and code rate + uint8_t i, k, *output = NULL, table[XQC_MAX_PM_SIZE]; + uint16_t repair_num, increment; + const uint8_t *tbl_p = table; + + for (i = 0; i < XQC_BLOCK_MODE_LEN; i++) { + if (i == XQC_SLIM_SIZE_REQ) { + continue; + } + repair_num = conn->fec_ctl->fec_send_required_repair_num[i]; + k = xqc_get_fec_blk_size(conn, i); + increment = k > 16 ? 6 : 2; + + if (k > 48 || repair_num <= 0 || repair_num > xqc_min(k, XQC_REPAIR_LEN)) { + conn->conn_settings.enable_encode_fec = 0; + conn->local_settings.enable_encode_fec = 0; + return; + } + + xqc_get_packet_mask(conn, k, repair_num, table); + tbl_p = table; + + for (uint32_t j = 0; j < repair_num; j++) { + output = conn->fec_ctl->fec_send_decode_matrix[i][j]; + xqc_memset(output, 0, increment); + xqc_memcpy(output, tbl_p, increment); + tbl_p += increment; + } + } + + return; +} + +xqc_int_t +xqc_pm_code_symbols(xqc_connection_t *conn, unsigned char *input, size_t in_size, unsigned char **outputs, + uint8_t fec_bm_mode) +{ + size_t tmp_size; + uint32_t src_syb_num, repair_num, symbol_idx; + unsigned char pm_size, pm_offset, symbol_flag, *output_p = NULL, *pm_p = NULL, *rpr_key_p = NULL; + xqc_int_t ret = XQC_OK; + + src_syb_num = xqc_get_fec_blk_size(conn, fec_bm_mode); + repair_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + symbol_idx = conn->fec_ctl->fec_send_symbol_num[fec_bm_mode]; + symbol_flag = 1 << (7 - symbol_idx % 8); + pm_offset = symbol_idx / 8; + pm_size = src_syb_num > 16 ? 6 : 2; + + if (repair_num > XQC_REPAIR_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair number exceeds buff size"); + return -XQC_EPARAM; + } + + if (pm_offset >= pm_size) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid symbol index"); + return -XQC_EPARAM; + } + + for (uint32_t i = 0; i < repair_num; i++) { + pm_p = conn->fec_ctl->fec_send_decode_matrix[fec_bm_mode][i]; + rpr_key_p = conn->fec_ctl->fec_send_repair_key[fec_bm_mode][i].payload; + if (*(rpr_key_p + pm_offset) & symbol_flag) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|source symbol already been calculated"); + + } else if (symbol_flag & *(pm_p + pm_offset)) { + output_p = outputs[i]; + ret = xqc_xor_code_one_symbol(input, output_p, in_size); + // set validation and payload size of fec_send_repair_symbols_buff object + tmp_size = xqc_max(in_size, conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i].payload_size); + if (tmp_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair symbol payload exceeds the buffer size"); + ret = -XQC_EFEC_SCHEME_ERROR; + } + // have to set fec_send_repair_symbols_buff, otherwise the payload won't be set to 0 after encode process + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i], 1, output_p, + tmp_size); + if (ret == XQC_OK) { + // update repair key value with symbol flag + *(rpr_key_p + pm_offset) |= symbol_flag; + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_key[fec_bm_mode][i], 1, rpr_key_p, pm_size); + } + } + } + return ret; +} + +/** + * TODOfec: maybe need a function to update block size/ code rate, + * for packet mask can be changed according to network conditions; + */ + + + +xqc_int_t +xqc_packet_mask_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode) +{ + xqc_int_t ret; + if (st_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_packet_mask_encode|invalid input size:%d|", st_size); + return -XQC_EFEC_SYMBOL_ERROR; + } + + ret = xqc_pm_code_symbols(conn, stream, st_size, outputs, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_packet_mask_encode|code symbols failed with errno: %d|", ret); + return -XQC_EFEC_SCHEME_ERROR; + } + + return ret; +} + +xqc_int_t +xqc_packet_mask_decode_one(xqc_connection_t *conn, unsigned char *recovered_symbols_buff, + xqc_int_t block_id, xqc_int_t symbol_idx) +{ + xqc_int_t ret, src_block_id, src_symbol_idx, src_mask_offset; + xqc_list_head_t *pos, *next, *src_list, *rpr_list; + xqc_fec_rpr_syb_t *rpr_symbol; + + if (recovered_symbols_buff == NULL) { + return -XQC_EPARAM; + } + + src_list = &conn->fec_ctl->fec_recv_src_syb_list; + rpr_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + rpr_symbol = xqc_get_rpr_symbol(rpr_list, block_id, symbol_idx); + if (rpr_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|no such repair symbol|"); + return -XQC_EPARAM; + } + + if (rpr_symbol->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|pkm decoder can't process rpr symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(rpr_symbol->payload, recovered_symbols_buff, rpr_symbol->payload_size); + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|packet_mask calculate xor error"); + return -XQC_EFEC_SCHEME_ERROR; + } + + xqc_list_for_each_safe(pos, next, src_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + + if (src_symbol->block_id > block_id) { + break; + } + src_block_id = src_symbol->block_id; + src_symbol_idx = src_symbol->symbol_idx; + src_mask_offset = src_symbol_idx / 8; + if (src_mask_offset >= XQC_MAX_RPR_KEY_SIZE) { + return -XQC_EFEC_SCHEME_ERROR; + } + + if (src_block_id == block_id + && *(rpr_symbol->recv_mask + src_mask_offset) & (1 << (7 - src_symbol_idx % 8))) + { + if (src_symbol->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|pkm decoder can't process src symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(src_symbol->payload, recovered_symbols_buff, src_symbol->payload_size); + + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|packet_mask calculate xor error"); + return -XQC_EFEC_SCHEME_ERROR; + } + } + } + + return ret; +} + +const xqc_fec_code_callback_t xqc_packet_mask_code_cb = { + .xqc_fec_init = xqc_packet_mask_init, + .xqc_fec_init_one = xqc_packet_mask_init_one, + .xqc_fec_encode = xqc_packet_mask_encode, + .xqc_fec_decode_one = xqc_packet_mask_decode_one + // .destroy = xqc_rs_destroy, +}; \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_packet_mask.h b/src/transport/fec_schemes/xqc_packet_mask.h new file mode 100644 index 000000000..8d3afa532 --- /dev/null +++ b/src/transport/fec_schemes/xqc_packet_mask.h @@ -0,0 +1,31 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_PACKET_MASK_H_ +#define _XQC_FEC_PACKET_MASK_H_ + +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include +#include +#include + +// TODOfec: might needed change according to the draft +#define XQC_MAX_MASK_SIZE 48 +#define XQC_MAX_LOOKUP_MASK_SIZE 12 + +extern const xqc_fec_code_callback_t xqc_packet_mask_code_cb; + +void xqc_packet_mask_init(xqc_connection_t *conn); + +void +xqc_packet_mask_init_one(xqc_connection_t *conn, uint8_t bm_idx); + +xqc_int_t xqc_packet_mask_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode); + +xqc_int_t xqc_packet_mask_decode_one(xqc_connection_t *conn, unsigned char *recovered_symbols_buff, + xqc_int_t block_id, xqc_int_t symbol_idx); +#endif \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_packet_mask_value.h b/src/transport/fec_schemes/xqc_packet_mask_value.h new file mode 100644 index 000000000..46f280d95 --- /dev/null +++ b/src/transport/fec_schemes/xqc_packet_mask_value.h @@ -0,0 +1,639 @@ +#define RandomMask1_1 \ + 0x80, 0x00 + +#define RandomMask2_1 \ + 0xc0, 0x00 + +#define RandomMask2_2 \ + 0xc0, 0x00, \ + 0x80, 0x00 + +#define RandomMask3_1 \ + 0xe0, 0x00 + +#define RandomMask3_2 \ + 0xc0, 0x00, \ + 0xa0, 0x00 + +#define RandomMask3_3 \ + 0xc0, 0x00, \ + 0xa0, 0x00, \ + 0x60, 0x00 + +#define RandomMask4_1 \ + 0xf0, 0x00 + +#define RandomMask4_2 \ + 0xc0, 0x00, \ + 0xb0, 0x00 + +#define RandomMask4_3 \ + 0xc0, 0x00, \ + 0xb0, 0x00, \ + 0x60, 0x00 + +#define RandomMask4_4 \ + 0xc0, 0x00, \ + 0xa0, 0x00, \ + 0x30, 0x00, \ + 0x50, 0x00 + +#define RandomMask5_1 \ + 0xf8, 0x00 + +#define RandomMask5_2 \ + 0xa8, 0x00, \ + 0xd0, 0x00 + +#define RandomMask5_3 \ + 0xb0, 0x00, \ + 0xc8, 0x00, \ + 0x50, 0x00 + +#define RandomMask5_4 \ + 0xc8, 0x00, \ + 0xb0, 0x00, \ + 0x50, 0x00, \ + 0x28, 0x00 + +#define RandomMask5_5 \ + 0xc0, 0x00, \ + 0x30, 0x00, \ + 0x18, 0x00, \ + 0xa0, 0x00, \ + 0x48, 0x00 + +#define RandomMask6_1 \ + 0xfc, 0x00 + +#define RandomMask6_2 \ + 0xa8, 0x00, \ + 0xd4, 0x00 + +#define RandomMask6_3 \ + 0xd0, 0x00, \ + 0x68, 0x00, \ + 0xa4, 0x00 + +#define RandomMask6_4 \ + 0xa8, 0x00, \ + 0x58, 0x00, \ + 0x64, 0x00, \ + 0x94, 0x00 + +#define RandomMask6_5 \ + 0xa8, 0x00, \ + 0x84, 0x00, \ + 0x64, 0x00, \ + 0x90, 0x00, \ + 0x58, 0x00 + +#define RandomMask6_6 \ + 0x98, 0x00, \ + 0x64, 0x00, \ + 0x50, 0x00, \ + 0x14, 0x00, \ + 0xa8, 0x00, \ + 0xe0, 0x00 + +#define RandomMask7_1 \ + 0xfe, 0x00 + +#define RandomMask7_2 \ + 0xd4, 0x00, \ + 0xaa, 0x00 + +#define RandomMask7_3 \ + 0xd0, 0x00, \ + 0xaa, 0x00, \ + 0x64, 0x00 + +#define RandomMask7_4 \ + 0xd0, 0x00, \ + 0xaa, 0x00, \ + 0x64, 0x00, \ + 0x1c, 0x00 + +#define RandomMask7_5 \ + 0x0c, 0x00, \ + 0xb0, 0x00, \ + 0x1a, 0x00, \ + 0xc4, 0x00, \ + 0x62, 0x00 + +#define RandomMask7_6 \ + 0x8c, 0x00, \ + 0x4a, 0x00, \ + 0x64, 0x00, \ + 0xd0, 0x00, \ + 0xa0, 0x00, \ + 0x32, 0x00 + +#define RandomMask7_7 \ + 0x4a, 0x00, \ + 0x94, 0x00, \ + 0x1a, 0x00, \ + 0xc4, 0x00, \ + 0x28, 0x00, \ + 0xc2, 0x00, \ + 0x34, 0x00 + +#define RandomMask8_1 \ + 0xff, 0x00 + +#define RandomMask8_2 \ + 0xaa, 0x00, \ + 0xd5, 0x00 + +#define RandomMask8_3 \ + 0xc5, 0x00, \ + 0x92, 0x00, \ + 0x6a, 0x00 + +#define RandomMask8_4 \ + 0x45, 0x00, \ + 0xb4, 0x00, \ + 0x6a, 0x00, \ + 0x89, 0x00 + +#define RandomMask8_5 \ + 0x8c, 0x00, \ + 0x92, 0x00, \ + 0x2b, 0x00, \ + 0x51, 0x00, \ + 0x64, 0x00 + +#define RandomMask8_6 \ + 0xa1, 0x00, \ + 0x52, 0x00, \ + 0x91, 0x00, \ + 0x2a, 0x00, \ + 0xc4, 0x00, \ + 0x4c, 0x00 + +#define RandomMask8_7 \ + 0x15, 0x00, \ + 0xc2, 0x00, \ + 0x25, 0x00, \ + 0x62, 0x00, \ + 0x58, 0x00, \ + 0x8c, 0x00, \ + 0xa3, 0x00 + +#define RandomMask8_8 \ + 0x25, 0x00, \ + 0x8a, 0x00, \ + 0x91, 0x00, \ + 0x68, 0x00, \ + 0x32, 0x00, \ + 0x43, 0x00, \ + 0xc4, 0x00, \ + 0x1c, 0x00 + +#define RandomMask9_1 \ + 0xff, 0x80 + +#define RandomMask9_2 \ + 0xaa, 0x80, \ + 0xd5, 0x00 + +#define RandomMask9_3 \ + 0xa5, 0x00, \ + 0xc8, 0x00, \ + 0x52, 0x80 + +#define RandomMask9_4 \ + 0xa2, 0x00, \ + 0xc9, 0x00, \ + 0x52, 0x80, \ + 0x24, 0x80 + +#define RandomMask9_5 \ + 0x8c, 0x00, \ + 0x25, 0x00, \ + 0x92, 0x80, \ + 0x41, 0x80, \ + 0x58, 0x00 + +#define RandomMask9_6 \ + 0x84, 0x80, \ + 0x27, 0x00, \ + 0x51, 0x80, \ + 0x1a, 0x00, \ + 0x68, 0x00, \ + 0x89, 0x00 + +#define RandomMask9_7 \ + 0x8c, 0x00, \ + 0x47, 0x00, \ + 0x81, 0x80, \ + 0x12, 0x80, \ + 0x58, 0x00, \ + 0x28, 0x80, \ + 0xb4, 0x00 + +#define RandomMask9_8 \ + 0x2c, 0x00, \ + 0x91, 0x00, \ + 0x40, 0x80, \ + 0x06, 0x80, \ + 0xc8, 0x00, \ + 0x45, 0x00, \ + 0x30, 0x80, \ + 0xa2, 0x00 + +#define RandomMask9_9 \ + 0x4c, 0x00, \ + 0x62, 0x00, \ + 0x91, 0x00, \ + 0x42, 0x80, \ + 0xa4, 0x00, \ + 0x13, 0x00, \ + 0x30, 0x80, \ + 0x88, 0x80, \ + 0x09, 0x00 + +#define RandomMask10_1 \ + 0xff, 0xc0 + +#define RandomMask10_10 \ + 0x4c, 0x00, \ + 0x51, 0x00, \ + 0xa0, 0x40, \ + 0x04, 0xc0, \ + 0x03, 0x80, \ + 0x86, 0x00, \ + 0x29, 0x00, \ + 0x42, 0x40, \ + 0x98, 0x00, \ + 0x30, 0x80 + +#define RandomMask10_2 \ + 0xaa, 0x80, \ + 0xd5, 0x40 + +#define RandomMask10_3 \ + 0xa4, 0x40, \ + 0xc9, 0x00, \ + 0x52, 0x80 + +#define RandomMask10_4 \ + 0xca, 0x00, \ + 0x32, 0x80, \ + 0xa1, 0x40, \ + 0x55, 0x00 + +#define RandomMask10_5 \ + 0xca, 0x00, \ + 0x32, 0x80, \ + 0xa1, 0x40, \ + 0x55, 0x00, \ + 0x08, 0xc0 + +#define RandomMask10_6 \ + 0x0e, 0x00, \ + 0x33, 0x00, \ + 0x10, 0xc0, \ + 0x45, 0x40, \ + 0x88, 0x80, \ + 0xe0, 0x00 + +#define RandomMask10_7 \ + 0x46, 0x00, \ + 0x33, 0x00, \ + 0x80, 0xc0, \ + 0x0c, 0x40, \ + 0x28, 0x80, \ + 0x94, 0x00, \ + 0xc1, 0x00 + +#define RandomMask10_8 \ + 0x2c, 0x00, \ + 0x81, 0x80, \ + 0xa0, 0x40, \ + 0x05, 0x40, \ + 0x18, 0x80, \ + 0xc2, 0x00, \ + 0x22, 0x80, \ + 0x50, 0x40 + +#define RandomMask10_9 \ + 0x4c, 0x00, \ + 0x23, 0x00, \ + 0x88, 0xc0, \ + 0x21, 0x40, \ + 0x52, 0x80, \ + 0x94, 0x00, \ + 0x26, 0x00, \ + 0x48, 0x40, \ + 0x91, 0x80 + +#define RandomMask11_1 \ + 0xff, 0xe0 + +#define RandomMask11_10 \ + 0x64, 0x40, \ + 0x51, 0x40, \ + 0xa9, 0x00, \ + 0x04, 0xc0, \ + 0xd0, 0x00, \ + 0x82, 0x40, \ + 0x21, 0x20, \ + 0x0c, 0x20, \ + 0x4a, 0x00, \ + 0x12, 0xa0 + +#define RandomMask11_11 \ + 0x46, 0x40, \ + 0x33, 0x20, \ + 0x99, 0x00, \ + 0x05, 0x80, \ + 0x80, 0xa0, \ + 0x84, 0x40, \ + 0x40, 0x60, \ + 0x0a, 0x80, \ + 0x68, 0x00, \ + 0x10, 0x20, \ + 0x30, 0x40 + +#define RandomMask11_2 \ + 0xec, 0xc0, \ + 0x9b, 0xa0 + +#define RandomMask11_3 \ + 0xca, 0xc0, \ + 0xf1, 0x40, \ + 0xb6, 0x20 + +#define RandomMask11_4 \ + 0xc4, 0xc0, \ + 0x31, 0x60, \ + 0x4b, 0x20, \ + 0x2c, 0xa0 + +#define RandomMask11_5 \ + 0x86, 0x80, \ + 0x23, 0x20, \ + 0x16, 0x20, \ + 0x4c, 0x20, \ + 0x41, 0xc0 + +#define RandomMask11_6 \ + 0x64, 0x40, \ + 0x51, 0x40, \ + 0x0c, 0xa0, \ + 0xa1, 0x20, \ + 0x12, 0xa0, \ + 0x8a, 0x40 + +#define RandomMask11_7 \ + 0x46, 0x40, \ + 0x33, 0x20, \ + 0x91, 0x80, \ + 0xa4, 0x20, \ + 0x50, 0xa0, \ + 0x84, 0xc0, \ + 0x09, 0x60 + +#define RandomMask11_8 \ + 0x0c, 0x80, \ + 0x80, 0x60, \ + 0xa0, 0x80, \ + 0x05, 0x40, \ + 0x43, 0x00, \ + 0x1a, 0x00, \ + 0x60, 0x20, \ + 0x14, 0x20 + +#define RandomMask11_9 \ + 0x46, 0x40, \ + 0x62, 0x60, \ + 0x8c, 0x00, \ + 0x01, 0x60, \ + 0x07, 0x80, \ + 0xa0, 0x80, \ + 0x18, 0xa0, \ + 0x91, 0x00, \ + 0x78, 0x00 + +#define RandomMask12_1 \ + 0xff, 0xf0 + +#define RandomMask12_10 \ + 0x51, 0x40, \ + 0x45, 0x10, \ + 0x80, 0xd0, \ + 0x24, 0x20, \ + 0x0a, 0x20, \ + 0x00, 0xe0, \ + 0xb8, 0x00, \ + 0x09, 0x10, \ + 0x56, 0x00, \ + 0xa2, 0x80 + +#define RandomMask12_11 \ + 0x53, 0x60, \ + 0x21, 0x30, \ + 0x10, 0x90, \ + 0x00, 0x70, \ + 0x0c, 0x10, \ + 0x40, 0xc0, \ + 0x6a, 0x00, \ + 0x86, 0x00, \ + 0x24, 0x80, \ + 0x89, 0x00, \ + 0xc0, 0x20 + +#define RandomMask12_12 \ + 0x10, 0x60, \ + 0x02, 0x30, \ + 0x40, 0x50, \ + 0x21, 0x80, \ + 0x81, 0x10, \ + 0x14, 0x80, \ + 0x98, 0x00, \ + 0x08, 0x90, \ + 0x62, 0x00, \ + 0x24, 0x20, \ + 0x8a, 0x00, \ + 0x84, 0x40 + +#define RandomMask12_2 \ + 0xec, 0xc0, \ + 0x93, 0xb0 + +#define RandomMask12_3 \ + 0x9b, 0x80, \ + 0x4f, 0x10, \ + 0x3c, 0x60 + +#define RandomMask12_4 \ + 0x8b, 0x20, \ + 0x14, 0xb0, \ + 0x22, 0xd0, \ + 0x45, 0x50 + +#define RandomMask12_5 \ + 0x53, 0x60, \ + 0x64, 0x20, \ + 0x0c, 0xc0, \ + 0x82, 0xa0, \ + 0x09, 0x30 + +#define RandomMask12_6 \ + 0x51, 0x40, \ + 0xc5, 0x10, \ + 0x21, 0x80, \ + 0x12, 0x30, \ + 0x08, 0xe0, \ + 0x2e, 0x00 + +#define RandomMask12_7 \ + 0x53, 0x60, \ + 0x21, 0x30, \ + 0x90, 0x90, \ + 0x02, 0x50, \ + 0x06, 0xa0, \ + 0x2c, 0x00, \ + 0x88, 0x60 + +#define RandomMask12_8 \ + 0x20, 0x60, \ + 0x80, 0x30, \ + 0x42, 0x40, \ + 0x01, 0x90, \ + 0x14, 0x10, \ + 0x0a, 0x80, \ + 0x38, 0x00, \ + 0xc5, 0x00 + +#define RandomMask12_9 \ + 0x53, 0x60, \ + 0xe4, 0x20, \ + 0x24, 0x40, \ + 0xa1, 0x10, \ + 0x18, 0x30, \ + 0x03, 0x90, \ + 0x8a, 0x10, \ + 0x04, 0x90, \ + 0x00, 0xe0 + +// choose second idx of packet mask according to n-k value (repair number) +#define RandomPacketMask1 1, \ + RandomMask1_1 + +#define RandomPacketMask2 2, \ + RandomMask2_1, \ + RandomMask2_2 + +#define RandomPacketMask3 3, \ + RandomMask3_1, \ + RandomMask3_2, \ + RandomMask3_3 + +#define RandomPacketMask4 4, \ + RandomMask4_1, \ + RandomMask4_2, \ + RandomMask4_3, \ + RandomMask4_4 + +#define RandomPacketMask5 5, \ + RandomMask5_1, \ + RandomMask5_2, \ + RandomMask5_3, \ + RandomMask5_4, \ + RandomMask5_5 + +#define RandomPacketMask6 6, \ + RandomMask6_1, \ + RandomMask6_2, \ + RandomMask6_3, \ + RandomMask6_4, \ + RandomMask6_5, \ + RandomMask6_6 + +#define RandomPacketMask7 7, \ + RandomMask7_1, \ + RandomMask7_2, \ + RandomMask7_3, \ + RandomMask7_4, \ + RandomMask7_5, \ + RandomMask7_6, \ + RandomMask7_7 + +#define RandomPacketMask8 8, \ + RandomMask8_1, \ + RandomMask8_2, \ + RandomMask8_3, \ + RandomMask8_4, \ + RandomMask8_5, \ + RandomMask8_6, \ + RandomMask8_7, \ + RandomMask8_8 + +#define RandomPacketMask9 9, \ + RandomMask9_1, \ + RandomMask9_2, \ + RandomMask9_3, \ + RandomMask9_4, \ + RandomMask9_5, \ + RandomMask9_6, \ + RandomMask9_7, \ + RandomMask9_8, \ + RandomMask9_9 + +#define RandomPacketMask10 10, \ + RandomMask10_1, \ + RandomMask10_2, \ + RandomMask10_3, \ + RandomMask10_4, \ + RandomMask10_5, \ + RandomMask10_6, \ + RandomMask10_7, \ + RandomMask10_8, \ + RandomMask10_9, \ + RandomMask10_10 + +#define RandomPacketMask11 11, \ + RandomMask11_1, \ + RandomMask11_2, \ + RandomMask11_3, \ + RandomMask11_4, \ + RandomMask11_5, \ + RandomMask11_6, \ + RandomMask11_7, \ + RandomMask11_8, \ + RandomMask11_9, \ + RandomMask11_10, \ + RandomMask11_11 + +#define RandomPacketMask12 12, \ + RandomMask12_1, \ + RandomMask12_2, \ + RandomMask12_3, \ + RandomMask12_4, \ + RandomMask12_5, \ + RandomMask12_6, \ + RandomMask12_7, \ + RandomMask12_8, \ + RandomMask12_9, \ + RandomMask12_10, \ + RandomMask12_11, \ + RandomMask12_12 + +// choose first idx of packet mask according to k value (source number) +const uint8_t xqc_rnd_pm_tbl[] = { + 12, + RandomPacketMask1, // 2 byte entries. + RandomPacketMask2, + RandomPacketMask3, + RandomPacketMask4, + RandomPacketMask5, + RandomPacketMask6, + RandomPacketMask7, + RandomPacketMask8, + RandomPacketMask9, + RandomPacketMask10, + RandomPacketMask11, + RandomPacketMask12, +}; diff --git a/src/transport/fec_schemes/xqc_reed_solomon.c b/src/transport/fec_schemes/xqc_reed_solomon.c index 7eaff5994..1c1c874c2 100644 --- a/src/transport/fec_schemes/xqc_reed_solomon.c +++ b/src/transport/fec_schemes/xqc_reed_solomon.c @@ -26,10 +26,38 @@ xqc_build_generator_matrix(unsigned char src_symbol_num, unsigned char total_sym total_symbol_num, src_symbol_num, GM); } +void +xqc_reed_solomon_init_one(xqc_connection_t *conn, uint8_t bm_idx) +{ + return; +} + void xqc_reed_solomon_init(xqc_connection_t *conn) { - xqc_build_generator_matrix(XQC_FEC_MAX_SYMBOL_NUM_PBLOCK - XQC_REPAIR_LEN, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, conn->fec_ctl->LC_GM); + xqc_int_t i, j, ret, max_src_symbol_num, repair_symbol_num, symbol_idx; + unsigned char *key_p; + + max_src_symbol_num = xqc_get_fec_blk_size(conn, XQC_DEFAULT_SIZE_REQ); + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ]; + + if (max_src_symbol_num > XQC_REPAIR_LEN) { + conn->conn_settings.enable_encode_fec = 0; + conn->local_settings.enable_encode_fec = 0; + return; + } + /* If it's the last symbol in block, save it's key; */ + for (i = 0 ; i < repair_symbol_num; i++) { + key_p = conn->fec_ctl->fec_send_repair_key[XQC_DEFAULT_SIZE_REQ][i].payload; + if (key_p == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_reed_solomon_encode|malloc key failed"); + return; + } + xqc_memset(key_p, 0, max_src_symbol_num); + xqc_memcpy(key_p, conn->fec_ctl->decode_matrix + max_src_symbol_num + i, max_src_symbol_num); + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_key[XQC_DEFAULT_SIZE_REQ][i], 1, key_p, max_src_symbol_num); + } + } xqc_int_t @@ -89,78 +117,82 @@ xqc_rs_code_symbols(unsigned char (*GM_rows)[XQC_MAX_MT_ROW], unsigned char **in } xqc_int_t -xqc_reed_solomon_encode(xqc_connection_t *conn, unsigned char *stream, unsigned char **outputs) +xqc_reed_solomon_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode) { - size_t stream_size; - xqc_int_t i, ret, max_src_symbol_num, repair_symbol_num, total_symbol_num, symbol_idx; - unsigned char *key_p; + size_t tmp_size; + xqc_int_t i, ret, max_src_symbol_num, repair_symbol_num, symbol_idx; + unsigned char *key_p, *output_p; /* Record multiplication result in galois field. */ - repair_symbol_num = conn->fec_ctl->fec_send_repair_symbols_num; - max_src_symbol_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block * conn->conn_settings.fec_params.fec_code_rate; - total_symbol_num = max_src_symbol_num + repair_symbol_num; - symbol_idx = conn->fec_ctl->fec_send_src_symbols_num % max_src_symbol_num; - stream_size = conn->conn_settings.fec_params.fec_max_symbol_size; - - ret = xqc_rs_code_one_symbol(conn->fec_ctl->LC_GM + max_src_symbol_num, stream, outputs, - repair_symbol_num, stream_size, symbol_idx); + max_src_symbol_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block; + symbol_idx = conn->fec_ctl->fec_send_symbol_num[fec_bm_mode]; + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + + ret = xqc_rs_code_one_symbol(conn->fec_ctl->decode_matrix + max_src_symbol_num, stream, outputs, + repair_symbol_num, st_size, symbol_idx); + for (i = 0; i < repair_symbol_num; i++) { + // set validation and payload size of fec_send_repair_symbols_buff object + tmp_size = xqc_max(st_size, conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i].payload_size); + if (tmp_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair symbol payload exceeds the buffer size"); + ret = -XQC_EFEC_SCHEME_ERROR; + } + output_p = outputs[i]; + // have to set fec_send_repair_symbols_buff, otherwise the payload won't be set to 0 after encode process + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i], 1, output_p, + tmp_size); + } if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_reed_solomon_encode|xqc_rs_code_one_symbol failed"); return -XQC_EFEC_SCHEME_ERROR; } - /* If it's the last symbol in block, save it's key; */ - if (symbol_idx == max_src_symbol_num - 1) { - for (i = 0 ; i < repair_symbol_num; i++) { - key_p = conn->fec_ctl->fec_send_repair_key[i].payload; - if (key_p == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_reed_solomon_encode|malloc key failed"); - return -XQC_EMALLOC; - } - xqc_memset(key_p, 0, max_src_symbol_num); - xqc_memcpy(key_p, conn->fec_ctl->LC_GM + max_src_symbol_num + i, max_src_symbol_num); - xqc_set_object_value(&conn->fec_ctl->fec_send_repair_key[i], 1, key_p, max_src_symbol_num); - } - } - return XQC_OK; } void -xqc_gen_invert_GM(xqc_connection_t *conn, unsigned char (*GM)[XQC_MAX_MT_ROW], xqc_int_t block_idx) +xqc_gen_invert_GM(xqc_connection_t *conn, unsigned char (*GM)[XQC_MAX_MT_ROW], xqc_int_t block_idx, xqc_int_t symbol_flag) { - xqc_int_t i, j, k, symbol_num, repair_symbol_num, symbol_idx; - symbol_num = conn->fec_ctl->fec_recv_symbols_num[block_idx]; - repair_symbol_num = conn->fec_ctl->fec_recv_repair_symbols_num[block_idx]; + xqc_int_t i, j, k, symbol_num, repair_symbol_num, src_symbol_num, symbol_idx, ret; + xqc_list_head_t *pos, *next; + xqc_fec_rpr_syb_t *rpr_symbol; + + src_symbol_num = xqc_cnt_src_symbols_num(conn->fec_ctl, block_idx); + repair_symbol_num = xqc_cnt_rpr_symbols_num(conn->fec_ctl, block_idx); + symbol_num = src_symbol_num + repair_symbol_num; symbol_idx = 0; + rpr_symbol = NULL; xqc_memset(GM, 0, XQC_MAX_MT_ROW * XQC_MAX_MT_ROW); - for (i = 0, j = 0; i < symbol_num; i++) { - if (i < symbol_num - repair_symbol_num) { - for (k = symbol_idx; k < symbol_num; k++) { - if (conn->fec_ctl->fec_recv_symbols_flag[block_idx] & (1 << k)) { - symbol_idx = k; - GM[i][symbol_idx] = 1; - symbol_idx++; - break; - } - } - } else { - if (!conn->fec_ctl->fec_recv_repair_key[block_idx][j].is_valid) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_gen_invert_GM|repair key is null"); - return; + for (i = 0; i < src_symbol_num; i++) { + for (k = symbol_idx; k < symbol_num; k++) { + if (symbol_flag & (1 << k)) { + symbol_idx = k; + GM[i][symbol_idx] = 1; + symbol_idx++; + break; } - xqc_memcpy(GM[i], conn->fec_ctl->fec_recv_repair_key[block_idx][j].payload, conn->remote_settings.fec_max_symbols_num); - j++; } } + + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_idx) { + break; + } + if (rpr_symbol->block_id == block_idx) { + xqc_memcpy(GM[i], rpr_symbol->repair_key, rpr_symbol->repair_key_size); + i++; + } + } + xqc_invert_matrix(symbol_num, symbol_num, GM); } xqc_int_t -xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, xqc_int_t block_idx, - xqc_int_t *loss_symbols_idx, xqc_int_t loss_symbols_len) +xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx) { /** * 根据fec_recv_symbols_buff和fec_recv_repair_key复原丢失的srcsymbol: @@ -168,30 +200,38 @@ xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, xqc_int * 2. 将recv symbols格式化 * 3. 逆矩阵 * recv symbols */ - uint64_t symbol_size; - xqc_int_t i, j, ret, recv_symbols_num, recv_repair_symbols_num; - unsigned char GM[XQC_MAX_MT_ROW][XQC_MAX_MT_ROW], *recv_symbols_buff[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK - XQC_REPAIR_LEN], *recovered_symbols_buff[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK]; - + xqc_int_t i, j, ret, recv_symbols_num, recv_repair_symbols_num, symbol_flag, max_src_symbol_num, loss_src_num; + unsigned char GM[XQC_MAX_MT_ROW][XQC_MAX_MT_ROW], *recv_symbols_buff[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK], *recovered_symbols_buff[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK]; + xqc_int_t loss_symbol_idx[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK] = {-1}; + + *output_size = loss_src_num = 0; + recv_repair_symbols_num = xqc_cnt_rpr_symbols_num(conn->fec_ctl, block_idx); + recv_symbols_num = xqc_cnt_src_symbols_num(conn->fec_ctl, block_idx) + recv_repair_symbols_num; + symbol_flag = xqc_get_symbol_flag(conn, block_idx); + max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; + for (i = 0; i < XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; i++) { - if (i < XQC_FEC_MAX_SYMBOL_NUM_PBLOCK - XQC_REPAIR_LEN) { - recv_symbols_buff[i] = NULL; + if (i < recv_symbols_num) { + recv_symbols_buff[i] = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); } - recovered_symbols_buff[i] = xqc_calloc(1, XQC_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_HEADER_SPACE - XQC_FEC_SPACE); - } - - recv_symbols_num = conn->fec_ctl->fec_recv_symbols_num[block_idx]; - recv_repair_symbols_num = conn->fec_ctl->fec_recv_repair_symbols_num[block_idx]; - symbol_size = conn->remote_settings.fec_max_symbol_size; - xqc_gen_invert_GM(conn, GM, block_idx); - /* 将收到的symbol整顿为矩阵 */ - for (i = 0, j = 0; i < recv_symbols_num && j < recv_symbols_num + recv_repair_symbols_num; j++) { - if (conn->fec_ctl->fec_recv_symbols_flag[block_idx] & (1 << j) - && conn->fec_ctl->fec_recv_symbols_buff[block_idx][j].is_valid) - { - recv_symbols_buff[i] = conn->fec_ctl->fec_recv_symbols_buff[block_idx][j].payload; - i++; + recovered_symbols_buff[i] = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + } + + for (i = 0; i < max_src_symbol_num; i++) { + if ((symbol_flag & (1 << i)) == 0) { + loss_symbol_idx[loss_src_num] = i; + loss_src_num++; } } + + xqc_gen_invert_GM(conn, GM, block_idx, symbol_flag); + + // get symbols and make them into matrix according to block idx; + i = xqc_get_symbols_buff(recv_symbols_buff, conn->fec_ctl, block_idx, output_size); + if (i < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_get_symbols_buff|recv invalid symbols"); + return -XQC_EFEC_SCHEME_ERROR; + } if (i != recv_symbols_num) { xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_reed_solomon_decode|recv symbols not enouph to recover lost symbols"); return -XQC_EFEC_SCHEME_ERROR; @@ -199,14 +239,14 @@ xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, xqc_int ret = xqc_rs_code_symbols(GM, recv_symbols_buff, recv_symbols_num, recovered_symbols_buff, recv_symbols_num, - symbol_size); + *output_size); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_reed_solomon_decode|reed solomon decode symbols failed"); } - for (i = 0; i < loss_symbols_len; i++) { - xqc_fec_ctl_save_symbol(&outputs[i], recovered_symbols_buff[loss_symbols_idx[i]], symbol_size); + for (i = 0; i < loss_src_num; i++) { + xqc_fec_ctl_save_symbol(&outputs[i], recovered_symbols_buff[loss_symbol_idx[i]], *output_size); } for (i = 0; i < recv_symbols_num; i++) { @@ -221,6 +261,7 @@ xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, xqc_int const xqc_fec_code_callback_t xqc_reed_solomon_code_cb = { .xqc_fec_init = xqc_reed_solomon_init, + .xqc_fec_init_one = xqc_reed_solomon_init_one, .xqc_fec_decode = xqc_reed_solomon_decode, .xqc_fec_encode = xqc_reed_solomon_encode, // .destroy = xqc_rs_destroy, diff --git a/src/transport/fec_schemes/xqc_reed_solomon.h b/src/transport/fec_schemes/xqc_reed_solomon.h index 865a25693..505fb2124 100644 --- a/src/transport/fec_schemes/xqc_reed_solomon.h +++ b/src/transport/fec_schemes/xqc_reed_solomon.h @@ -23,9 +23,10 @@ void xqc_build_generator_matrix(unsigned char src_symbol_num, unsigned char tota xqc_int_t xqc_rs_code_symbols(unsigned char (*GM_rows)[XQC_MAX_MT_ROW], unsigned char **inputs, xqc_int_t inputs_rows_num, unsigned char **outputs, xqc_int_t outputs_rows_num, xqc_int_t item_size); -void xqc_reed_solomon_init(); -xqc_int_t xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **recovered_symbols_buff, xqc_int_t block_idx, - xqc_int_t *loss_symbols_idx, xqc_int_t loss_symbols_len); -xqc_int_t xqc_reed_solomon_encode(xqc_connection_t *conn, unsigned char *stream, unsigned char **outputs); +void xqc_reed_solomon_init(xqc_connection_t *conn); +void xqc_reed_solomon_init_one(xqc_connection_t *conn, uint8_t bm_idx); +xqc_int_t xqc_reed_solomon_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx); +xqc_int_t xqc_reed_solomon_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode); #endif \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_xor.c b/src/transport/fec_schemes/xqc_xor.c index 7ceb457b8..f8619dd71 100644 --- a/src/transport/fec_schemes/xqc_xor.c +++ b/src/transport/fec_schemes/xqc_xor.c @@ -9,22 +9,33 @@ void xqc_xor_init(xqc_connection_t *conn) +{ + if (conn->fec_ctl == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fail to malloc space for fec_ctl"); + return; + } + conn->fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ] = 1; + return; +} + +void +xqc_xor_init_one(xqc_connection_t *conn, uint8_t bm_idx) { return; } xqc_int_t -xqc_xor_code_one_symbol(unsigned char *input, unsigned char **outputs, +xqc_xor_code_one_symbol(unsigned char *input, unsigned char *outputs, xqc_int_t item_size) { xqc_int_t i; unsigned char *output_p; - if (*outputs == NULL) { + if (outputs == NULL) { return -XQC_EMALLOC; } - output_p = *outputs; + output_p = outputs; for (i = 0; i < item_size; i++) { *(output_p + i) ^= *(input + i); } @@ -33,57 +44,57 @@ xqc_xor_code_one_symbol(unsigned char *input, unsigned char **outputs, } xqc_int_t -xqc_xor_code_symbols(unsigned char **inputs, xqc_int_t inputs_rows_num, unsigned char **outputs, - xqc_int_t outputs_rows_num, xqc_int_t item_size) +xqc_xor_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx) { - xqc_int_t input_i, output_i, ret; - unsigned char *input_p, *output_p; - if (outputs_rows_num != 1) { - return -XQC_EFEC_SYMBOL_ERROR; - } - - for (input_i = 0; input_i < inputs_rows_num; input_i++) { - input_p = inputs[input_i]; - ret = xqc_xor_code_one_symbol(input_p, &outputs[0], item_size); - if (ret != XQC_OK) { - return ret; + xqc_int_t i, j, ret, recv_repair_symbols_num, output_len; + xqc_list_head_t *pos, *next, *fec_recv_src_syb_list, *fec_recv_rpr_syb_list; + + *output_size = 0; + ret = -XQC_EFEC_SYMBOL_ERROR; + fec_recv_src_syb_list = &conn->fec_ctl->fec_recv_src_syb_list; + fec_recv_rpr_syb_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + + xqc_list_for_each_safe(pos, next, fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_syb = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_syb->block_id < block_idx) { + continue; } - } - - return XQC_OK; -} - -xqc_int_t -xqc_xor_decode(xqc_connection_t *conn, unsigned char **outputs, xqc_int_t block_idx, - xqc_int_t *loss_symbols_idx, xqc_int_t loss_symbols_len) -{ - xqc_int_t i, j, ret, recv_symbols_num, recv_repair_symbols_num, output_len; - unsigned char *recv_symbols_buff[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK - XQC_REPAIR_LEN]; - - /* TODOfec: 对xor来说,若XQC_FEC_MAX_SYMBOL_NUM_PBLOCK - XQC_REPAIR_LEN != 1, 不该通过协商*/ - - recv_symbols_num = conn->fec_ctl->fec_recv_symbols_num[block_idx]; - recv_repair_symbols_num = conn->fec_ctl->fec_recv_repair_symbols_num[block_idx]; - output_len = 1; - - /* 将收到的symbol整顿为矩阵 */ - for (i = 0, j = 0; i < recv_symbols_num && j < recv_symbols_num + recv_repair_symbols_num; j++) { - if (conn->fec_ctl->fec_recv_symbols_flag[block_idx] & (1 << j) - && conn->fec_ctl->fec_recv_symbols_buff[block_idx][j].is_valid) - { - recv_symbols_buff[i] = conn->fec_ctl->fec_recv_symbols_buff[block_idx][j].payload; - i++; + if (rpr_syb->block_id == block_idx) { + if (rpr_syb->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xor decoder can't process rpr symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(rpr_syb->payload, outputs[0], rpr_syb->payload_size); + if (ret != XQC_OK) { + return ret; + } + *output_size = rpr_syb->payload_size; + break; + } + if (rpr_syb->block_id > block_idx) { + return -XQC_EFEC_SCHEME_ERROR; } } - - if (i != recv_symbols_num) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_xor_decode|process recv_symbols into matrix failed"); - return -XQC_EFEC_SCHEME_ERROR; + xqc_list_for_each_safe(pos, next, fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_syb = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_syb->block_id < block_idx) { + continue; + } + if (src_syb->block_id == block_idx) { + if (src_syb->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xor decoder can't process src symbol with size bigger than XQC_MAX_SYMBOL_SIZE."); + return -XQC_EFEC_SCHEME_ERROR; + } + ret = xqc_xor_code_one_symbol(src_syb->payload, outputs[0], src_syb->payload_size); + if (ret != XQC_OK) { + return ret; + } + } + if (src_syb->block_id > block_idx) { + break; + } } - ret = xqc_xor_code_symbols(recv_symbols_buff, recv_symbols_num, outputs, - output_len, conn->remote_settings.fec_max_symbol_size); - if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_xor_decode|xor decode symbols failed"); return ret; @@ -93,14 +104,28 @@ xqc_xor_decode(xqc_connection_t *conn, unsigned char **outputs, xqc_int_t block_ } xqc_int_t -xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, unsigned char **outputs) +xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode) { - size_t stream_size; + size_t tmp_size; xqc_int_t ret; - stream_size = conn->conn_settings.fec_params.fec_max_symbol_size; + if (st_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_xor_encode|invalid input size:%d|", st_size); + return -XQC_EFEC_SYMBOL_ERROR; + } + + ret = xqc_xor_code_one_symbol(stream, outputs[0], st_size); + // set validation and payload size of fec_send_repair_symbols_buff object + tmp_size = xqc_max(st_size, conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][0].payload_size); + if (tmp_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|repair symbol payload exceeds the buffer size"); + ret = -XQC_EFEC_SCHEME_ERROR; + } + // have to set fec_send_repair_symbols_buff, otherwise the payload won't be set to 0 after encode process + xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][0], 1, outputs[0], + tmp_size); - ret = xqc_xor_code_one_symbol(stream, &outputs[0], stream_size); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_xor_encode|code one symbol failed"); return -XQC_EFEC_SCHEME_ERROR; @@ -111,6 +136,7 @@ xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, unsigned char **ou const xqc_fec_code_callback_t xqc_xor_code_cb = { .xqc_fec_init = xqc_xor_init, + .xqc_fec_init_one = xqc_xor_init_one, .xqc_fec_decode = xqc_xor_decode, .xqc_fec_encode = xqc_xor_encode, // .destroy = xqc_rs_destroy, diff --git a/src/transport/fec_schemes/xqc_xor.h b/src/transport/fec_schemes/xqc_xor.h index 04da0f012..083a4430e 100644 --- a/src/transport/fec_schemes/xqc_xor.h +++ b/src/transport/fec_schemes/xqc_xor.h @@ -8,7 +8,6 @@ #define _XQC_FEC_XOR_H_ -#include "src/transport/fec_schemes/xqc_xor.h" #include "src/transport/fec_schemes/xqc_galois_calculation.h" #include #include @@ -16,13 +15,12 @@ extern const xqc_fec_code_callback_t xqc_xor_code_cb; -xqc_int_t xqc_xor_code_one_symbol(unsigned char *input, unsigned char **outputs, xqc_int_t item_size); -xqc_int_t xqc_xor_code_symbols(unsigned char **inputs, xqc_int_t inputs_rows_num, unsigned char **outputs, - xqc_int_t outputs_rows_num, xqc_int_t item_size); +xqc_int_t xqc_xor_code_one_symbol(unsigned char *input, unsigned char *outputs, xqc_int_t item_size); -void xqc_xor_init(); -xqc_int_t xqc_xor_decode(xqc_connection_t *conn, unsigned char **outputs, xqc_int_t block_idx, - xqc_int_t *loss_symbols_idx, xqc_int_t loss_symbols_len); -xqc_int_t xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, unsigned char **outputs); +void xqc_xor_init(xqc_connection_t *conn); +void xqc_xor_init_one(xqc_connection_t *conn, uint8_t bm_idx); +xqc_int_t xqc_xor_decode(xqc_connection_t *conn, unsigned char **outputs, size_t *output_size, xqc_int_t block_idx); +xqc_int_t xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, size_t st_size, unsigned char **outputs, + uint8_t fec_bm_mode); #endif \ No newline at end of file diff --git a/src/transport/reinjection_control/xqc_reinj_deadline.c b/src/transport/reinjection_control/xqc_reinj_deadline.c index 1b4325c78..7703cd157 100644 --- a/src/transport/reinjection_control/xqc_reinj_deadline.c +++ b/src/transport/reinjection_control/xqc_reinj_deadline.c @@ -13,7 +13,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" diff --git a/src/transport/reinjection_control/xqc_reinj_default.c b/src/transport/reinjection_control/xqc_reinj_default.c index ba2d92a48..15e213929 100644 --- a/src/transport/reinjection_control/xqc_reinj_default.c +++ b/src/transport/reinjection_control/xqc_reinj_default.c @@ -13,7 +13,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" diff --git a/src/transport/reinjection_control/xqc_reinj_dgram.c b/src/transport/reinjection_control/xqc_reinj_dgram.c index f770d3d10..d8741f493 100644 --- a/src/transport/reinjection_control/xqc_reinj_dgram.c +++ b/src/transport/reinjection_control/xqc_reinj_dgram.c @@ -13,7 +13,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" diff --git a/src/transport/scheduler/xqc_scheduler_backup.c b/src/transport/scheduler/xqc_scheduler_backup.c index 32cc1db22..604644c6b 100644 --- a/src/transport/scheduler/xqc_scheduler_backup.c +++ b/src/transport/scheduler/xqc_scheduler_backup.c @@ -26,8 +26,8 @@ xqc_backup_scheduler_get_path(void *scheduler, xqc_connection_t *conn, xqc_packet_out_t *packet_out, int check_cwnd, int reinject, xqc_bool_t *cc_blocked) { - xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE] = { NULL }; - xqc_bool_t has_path[XQC_PATH_CLASS_PERF_CLASS_SIZE] = { XQC_FALSE }; + xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_bool_t has_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; xqc_path_perf_class_t path_class; xqc_bool_t available_path_exists; @@ -44,6 +44,14 @@ xqc_backup_scheduler_get_path(void *scheduler, xqc_connection_t *conn, *cc_blocked = XQC_FALSE; } + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + best_path[path_class] = NULL; + has_path[path_class] = XQC_FALSE; + } + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); @@ -79,7 +87,7 @@ xqc_backup_scheduler_get_path(void *scheduler, xqc_connection_t *conn, path_srtt = xqc_send_ctl_get_srtt(path->path_send_ctl); if (best_path[path_class] == NULL - || path_srtt < xqc_send_ctl_get_srtt(best_path[path_class]->path_send_ctl)) + || path_srtt < best_path[path_class]->path_send_ctl->ctl_srtt) { best_path[path_class] = path; } diff --git a/src/transport/scheduler/xqc_scheduler_backup.h b/src/transport/scheduler/xqc_scheduler_backup.h index fd6d394e8..c9f6c7786 100644 --- a/src/transport/scheduler/xqc_scheduler_backup.h +++ b/src/transport/scheduler/xqc_scheduler_backup.h @@ -10,4 +10,4 @@ extern const xqc_scheduler_callback_t xqc_backup_scheduler_cb; -#endif /* _XQC_SCHEDULER_BACKUP_H_INCLUDED_ */ \ No newline at end of file +#endif /* _XQC_SCHEDULER_BACKUP_H_INCLUDED_ */ diff --git a/src/transport/scheduler/xqc_scheduler_backup_fec.c b/src/transport/scheduler/xqc_scheduler_backup_fec.c new file mode 100644 index 000000000..4c871a29a --- /dev/null +++ b/src/transport/scheduler/xqc_scheduler_backup_fec.c @@ -0,0 +1,243 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#include "src/transport/scheduler/xqc_scheduler_backup_fec.h" +#include "src/transport/scheduler/xqc_scheduler_common.h" +#include "src/transport/xqc_send_ctl.h" + + +static size_t +xqc_backup_fec_scheduler_size() +{ + return 0; +} + +static void +xqc_backup_fec_scheduler_init(void *scheduler, xqc_log_t *log, xqc_scheduler_params_t *param) +{ + return; +} + +xqc_path_ctx_t * +xqc_send_on_standby_path(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_bool_t *has_path, + xqc_path_ctx_t **best_path) +{ + xqc_bool_t available_path_exists; + xqc_path_ctx_t *ret_path; + xqc_path_perf_class_t path_class; + + ret_path = NULL; + + available_path_exists = XQC_FALSE; + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + if (has_path[path_class] && (path_class & 1)) { + available_path_exists = XQC_TRUE; + } + if (best_path[path_class] != NULL) { + if (ret_path == NULL && (path_class & 1) == 0) { + ret_path = best_path[path_class]; + continue; + } else { + return best_path[path_class]; + } + } + } + return ret_path; +} + +xqc_path_ctx_t * +xqc_send_on_normal_path(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_bool_t *has_path, + xqc_path_ctx_t **best_path, int reinject) +{ + xqc_path_perf_class_t path_class; + xqc_bool_t available_path_exists; + + available_path_exists = XQC_FALSE; + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + if (has_path[path_class] && ((path_class & 1) == 0)) { + available_path_exists = XQC_TRUE; + } + + /* + * do not use a standby path if there + * is an available path with higher performence level + */ + if (best_path[path_class] != NULL) { + if (available_path_exists && (path_class & 1) && !reinject) { + /* skip standby path*/ + xqc_log(conn->log, XQC_LOG_DEBUG, + "|skip_standby_path|path_class:%d|path_id:%ui|", + path_class, best_path[path_class]->path_id); + continue; + + } else { + return best_path[path_class]; + } + } + } + return NULL; +} + +xqc_path_ctx_t * +xqc_backup_fec_scheduler_get_path(void *scheduler, xqc_connection_t *conn, + xqc_packet_out_t *packet_out, int check_cwnd, int reinject, + xqc_bool_t *cc_blocked) +{ + xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_bool_t has_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; + xqc_path_perf_class_t path_class; + xqc_bool_t available_path_exists; + + xqc_list_head_t *pos, *next; + xqc_path_ctx_t *path, *ret_path; + xqc_send_ctl_t *send_ctl; + xqc_bool_t path_can_send = XQC_FALSE; + + /* min RTT */ + uint64_t path_srtt = 0; + xqc_bool_t reached_cwnd_check = XQC_FALSE; + + if (cc_blocked) { + *cc_blocked = XQC_FALSE; + } + + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + best_path[path_class] = NULL; + has_path[path_class] = XQC_FALSE; + } + + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + + path_class = xqc_path_get_perf_class(path); + + /* skip inactive paths */ + /* skip frozen paths */ + if (path->path_state != XQC_PATH_STATE_ACTIVE + || path->app_path_status == XQC_APP_PATH_STATUS_FROZEN + || (reinject && (packet_out->po_path_id == path->path_id))) + { + goto skip_path; + } + + if (!reached_cwnd_check) { + reached_cwnd_check = XQC_TRUE; + if (cc_blocked) { + *cc_blocked = XQC_TRUE; + } + } + + has_path[path_class] = XQC_TRUE; + path_can_send = xqc_scheduler_check_path_can_send(path, packet_out, check_cwnd); + + if (!path_can_send) { + goto skip_path; + } + + if (cc_blocked) { + *cc_blocked = XQC_FALSE; + } + + path_srtt = xqc_send_ctl_get_srtt(path->path_send_ctl); + + if (best_path[path_class] == NULL + || path_srtt < best_path[path_class]->path_send_ctl->ctl_srtt) + { + best_path[path_class] = path; + } + +skip_path: + xqc_log(conn->log, XQC_LOG_DEBUG, + "|path srtt|conn:%p|path_id:%ui|path_srtt:%ui|path_class:%d|" + "can_send:%d|path_status:%d|path_state:%d|reinj:%d|" + "pkt_path_id:%ui|best_path:%i|", + conn, path->path_id, path_srtt, path_class, path_can_send, + path->app_path_status, path->path_state, reinject, + packet_out->po_path_id, + best_path[path_class] ? best_path[path_class]->path_id : -1); + } + + available_path_exists = XQC_FALSE; +#ifdef XQC_ENABLE_FEC + if (conn->fec_ctl && conn->fec_ctl->fec_mp_mode == XQC_FEC_MP_USE_STB && packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL) { + ret_path = xqc_send_on_standby_path(conn, packet_out, has_path, best_path); + + } else { + ret_path = xqc_send_on_normal_path(conn, packet_out, has_path, best_path, reinject); + } + +#else + ret_path = xqc_send_on_normal_path(conn, packet_out, has_path, best_path, reinject); +#endif + + if (ret_path != NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|" + "pn:%ui|size:%ud|reinj:%d|path_class:%d|", + ret_path->path_id, + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), + packet_out->po_pkt.pkt_num, + packet_out->po_used_size, reinject, path_class); + return ret_path; + } + + xqc_log(conn->log, XQC_LOG_DEBUG, + "|No available paths to schedule|conn:%p|", conn); + return NULL; +} + +void +xqc_backup_fec_scheduler_handle_conn_event(void *scheduler, + xqc_connection_t *conn, xqc_scheduler_conn_event_t event, void *event_arg) +{ + xqc_list_head_t *pos, *next; + xqc_path_ctx_t *path; + xqc_send_ctl_t *send_ctl; + xqc_usec_t now = 0, deadline; + + if (event == XQC_SCHED_EVENT_CONN_ROUND_START + && conn->conn_settings.standby_path_probe_timeout + && conn->enable_multipath + && (conn->conn_state == XQC_CONN_STATE_ESTABED)) + { + /* check if we need to probe standby paths */ + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + if (path->path_state == XQC_PATH_STATE_ACTIVE + && path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) + { + if (!now) { + now = xqc_monotonic_timestamp(); + } + + send_ctl = path->path_send_ctl; + + deadline = send_ctl->ctl_time_of_last_sent_ack_eliciting_packet[XQC_PNS_APP_DATA] + conn->conn_settings.standby_path_probe_timeout * 1000; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|standby_probe|path:%ui|deadline:%ui|now:%ui|now>=deadline:%d|last_send:%ui|", + path->path_id, deadline, now, now >= deadline, send_ctl->ctl_time_of_last_sent_ack_eliciting_packet[XQC_PNS_APP_DATA]); + + if (now >= deadline) { + xqc_path_standby_probe(path); + } + } + } + } +} + +const xqc_scheduler_callback_t xqc_backup_fec_scheduler_cb = { + .xqc_scheduler_size = xqc_backup_fec_scheduler_size, + .xqc_scheduler_init = xqc_backup_fec_scheduler_init, + .xqc_scheduler_get_path = xqc_backup_fec_scheduler_get_path, + .xqc_scheduler_handle_conn_event = xqc_backup_fec_scheduler_handle_conn_event, +}; \ No newline at end of file diff --git a/src/transport/scheduler/xqc_scheduler_backup_fec.h b/src/transport/scheduler/xqc_scheduler_backup_fec.h new file mode 100644 index 000000000..e32dc77b6 --- /dev/null +++ b/src/transport/scheduler/xqc_scheduler_backup_fec.h @@ -0,0 +1,13 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef _XQC_SCHEDULER_BACKUP_FEC_H_INCLUDED_ +#define _XQC_SCHEDULER_BACKUP_FEC_H_INCLUDED_ + +#include +#include + +extern const xqc_scheduler_callback_t xqc_backup_fec_scheduler_cb; + +#endif /* _XQC_SCHEDULER_BACKUP_FEC_H_INCLUDED_ */ diff --git a/src/transport/scheduler/xqc_scheduler_common.h b/src/transport/scheduler/xqc_scheduler_common.h index a111931c0..97bba67ba 100644 --- a/src/transport/scheduler/xqc_scheduler_common.h +++ b/src/transport/scheduler/xqc_scheduler_common.h @@ -6,4 +6,4 @@ xqc_bool_t xqc_scheduler_check_path_can_send(xqc_path_ctx_t *path, xqc_packet_out_t *packet_out, int check_cwnd); -#endif /* _XQC_SCHEDULER_COMMON_H_INCLUDED_ */ \ No newline at end of file +#endif \ No newline at end of file diff --git a/src/transport/scheduler/xqc_scheduler_interop.c b/src/transport/scheduler/xqc_scheduler_interop.c index 3c22ed975..49e46caa6 100644 --- a/src/transport/scheduler/xqc_scheduler_interop.c +++ b/src/transport/scheduler/xqc_scheduler_interop.c @@ -81,6 +81,7 @@ xqc_interop_scheduler_get_path(void *scheduler, if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { best_path = path; min_rtt = path_srtt; + } else { best_standby_path = path; min_rtt_standby = path_srtt; @@ -111,4 +112,4 @@ const xqc_scheduler_callback_t xqc_interop_scheduler_cb = { .xqc_scheduler_size = xqc_interop_scheduler_size, .xqc_scheduler_init = xqc_interop_scheduler_init, .xqc_scheduler_get_path = xqc_interop_scheduler_get_path, -}; \ No newline at end of file +}; diff --git a/src/transport/scheduler/xqc_scheduler_interop.h b/src/transport/scheduler/xqc_scheduler_interop.h index 027706f16..3d9cd5b8b 100644 --- a/src/transport/scheduler/xqc_scheduler_interop.h +++ b/src/transport/scheduler/xqc_scheduler_interop.h @@ -10,4 +10,4 @@ extern const xqc_scheduler_callback_t xqc_interop_scheduler_cb; -#endif /* _XQC_SCHEDULER_INTEROP_H_INCLUDED_ */ \ No newline at end of file +#endif diff --git a/src/transport/scheduler/xqc_scheduler_minrtt.c b/src/transport/scheduler/xqc_scheduler_minrtt.c index 7907c1b72..faa5c00f4 100644 --- a/src/transport/scheduler/xqc_scheduler_minrtt.c +++ b/src/transport/scheduler/xqc_scheduler_minrtt.c @@ -7,6 +7,7 @@ #include "src/transport/scheduler/xqc_scheduler_common.h" #include "src/transport/xqc_send_ctl.h" + static size_t xqc_minrtt_scheduler_size() { @@ -24,8 +25,8 @@ xqc_minrtt_scheduler_get_path(void *scheduler, xqc_connection_t *conn, xqc_packet_out_t *packet_out, int check_cwnd, int reinject, xqc_bool_t *cc_blocked) { + xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE]; xqc_path_perf_class_t path_class; - xqc_path_ctx_t *best_path[XQC_PATH_CLASS_PERF_CLASS_SIZE] = { NULL }; xqc_list_head_t *pos, *next; xqc_path_ctx_t *path; @@ -36,6 +37,13 @@ xqc_minrtt_scheduler_get_path(void *scheduler, xqc_bool_t reached_cwnd_check = XQC_FALSE; xqc_bool_t path_can_send = XQC_FALSE; + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; + path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; + path_class++) + { + best_path[path_class] = NULL; + } + if (cc_blocked) { *cc_blocked = XQC_FALSE; } @@ -95,6 +103,7 @@ xqc_minrtt_scheduler_get_path(void *scheduler, best_path[path_class] ? best_path[path_class]->path_id : -1); } + for (path_class = XQC_PATH_CLASS_AVAILABLE_HIGH; path_class < XQC_PATH_CLASS_PERF_CLASS_SIZE; path_class++) diff --git a/src/transport/scheduler/xqc_scheduler_minrtt.h b/src/transport/scheduler/xqc_scheduler_minrtt.h index de21abc6a..29afef566 100644 --- a/src/transport/scheduler/xqc_scheduler_minrtt.h +++ b/src/transport/scheduler/xqc_scheduler_minrtt.h @@ -10,4 +10,4 @@ extern const xqc_scheduler_callback_t xqc_minrtt_scheduler_cb; -#endif /* _XQC_SCHEDULER_MINRTT_H_INCLUDED_ */ \ No newline at end of file +#endif /* _XQC_SCHEDULER_MINRTT_H_INCLUDED_ */ diff --git a/src/transport/scheduler/xqc_scheduler_rap.h b/src/transport/scheduler/xqc_scheduler_rap.h index a010a9044..4f457338a 100644 --- a/src/transport/scheduler/xqc_scheduler_rap.h +++ b/src/transport/scheduler/xqc_scheduler_rap.h @@ -16,4 +16,4 @@ extern const xqc_scheduler_callback_t xqc_rap_scheduler_cb; -#endif /* _XQC_SCHEDULER_MINRTT_H_INCLUDED_ */ \ No newline at end of file +#endif diff --git a/src/transport/xqc_cid.c b/src/transport/xqc_cid.c index 3c3d062aa..d9eea4b4c 100644 --- a/src/transport/xqc_cid.c +++ b/src/transport/xqc_cid.c @@ -35,6 +35,8 @@ xqc_generate_cid(xqc_engine_t *engine, xqc_cid_t *ori_cid, xqc_cid_t *cid, return -XQC_EGENERATE_CID; } + cid->path_id = XQC_INITIAL_PATH_ID; /* default initial path_id = 0 */ + return XQC_OK; } @@ -64,6 +66,7 @@ xqc_cid_copy(xqc_cid_t *dst, xqc_cid_t *src) xqc_memcpy(dst->cid_buf, src->cid_buf, dst->cid_len); dst->cid_seq_num = src->cid_seq_num; xqc_memcpy(dst->sr_token, src->sr_token, XQC_STATELESS_RESET_TOKENLEN); + dst->path_id = src->path_id; } void @@ -71,6 +74,7 @@ xqc_cid_init_zero(xqc_cid_t *cid) { cid->cid_len = 0; cid->cid_seq_num = 0; + cid->path_id = 0; } void @@ -128,136 +132,205 @@ xqc_dcid_str_by_scid(xqc_engine_t *engine, const xqc_cid_t *scid) void xqc_init_cid_set(xqc_cid_set_t *cid_set) { - xqc_init_list_head(&cid_set->list_head); - cid_set->unused_cnt = 0; - cid_set->used_cnt = 0; - cid_set->retired_cnt = 0; + xqc_memzero(cid_set, sizeof(xqc_cid_set_t)); + xqc_init_list_head(&cid_set->cid_set_list); } -void -xqc_init_scid_set(xqc_scid_set_t *scid_set) +void +xqc_cid_set_inner_init(xqc_cid_set_inner_t *cid_set_inner) { - xqc_init_cid_set(&scid_set->cid_set); - xqc_cid_init_zero(&scid_set->user_scid); - scid_set->largest_scid_seq_num = 0; + xqc_memzero(cid_set_inner, sizeof(xqc_cid_set_inner_t)); + xqc_init_list_head(&cid_set_inner->cid_list); + xqc_init_list_head(&cid_set_inner->next); } -void -xqc_init_dcid_set(xqc_dcid_set_t *dcid_set) +void +xqc_cid_set_inner_destroy(xqc_cid_set_inner_t *cid_set_inner) { - xqc_init_cid_set(&dcid_set->cid_set); - xqc_cid_init_zero(&dcid_set->current_dcid); - dcid_set->largest_retire_prior_to = 0; + xqc_cid_inner_t *cid = NULL; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &cid_set_inner->cid_list) { + cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + xqc_list_del(pos); + xqc_free(cid); + } + + xqc_cid_set_inner_init(cid_set_inner); } void xqc_destroy_cid_set(xqc_cid_set_t *cid_set) { - xqc_cid_inner_t *cid = NULL; + xqc_cid_set_inner_t *cid_set_inner = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + xqc_list_for_each_safe(pos, next, &cid_set->cid_set_list) { + cid_set_inner = xqc_list_entry(pos, xqc_cid_set_inner_t, next); xqc_list_del(pos); - xqc_free(cid); + xqc_cid_set_inner_destroy(cid_set_inner); + xqc_free(cid_set_inner); } xqc_init_cid_set(cid_set); } -uint64_t -xqc_cid_set_cnt(xqc_cid_set_t *cid_set) +xqc_cid_set_inner_t* +xqc_get_path_cid_set(xqc_cid_set_t *cid_set, uint64_t path_id) { - return cid_set->unused_cnt + cid_set->used_cnt; + xqc_cid_set_inner_t *cid_set_inner = NULL; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &cid_set->cid_set_list) { + cid_set_inner = xqc_list_entry(pos, xqc_cid_set_inner_t, next); + if (cid_set_inner->path_id == path_id) { + return cid_set_inner; + } + } + + return NULL; } -xqc_bool_t -xqc_cid_set_validate_new_cid_limit(xqc_cid_set_t *cid_set, - uint64_t max_retire_prior_to, uint64_t *active_cid_limit) +xqc_cid_set_inner_t* +xqc_get_next_unused_path_cid_set(xqc_cid_set_t *cid_set) { + xqc_cid_set_inner_t *cid_set_inner = NULL; xqc_list_head_t *pos, *next; - xqc_cid_inner_t *cid = NULL; - uint64_t retire_cnt = 0; - if (xqc_cid_set_cnt(cid_set) + 1 <= *active_cid_limit) { - return XQC_TRUE; + xqc_list_for_each_safe(pos, next, &cid_set->cid_set_list) { + cid_set_inner = xqc_list_entry(pos, xqc_cid_set_inner_t, next); + if (cid_set_inner->set_state == XQC_CID_SET_UNUSED) { + return cid_set_inner; + } } - /* the new cid might exceed the active_cid_limit, but will not retire any - cid, shall not be inserted */ - if (max_retire_prior_to == 0) { - return XQC_FALSE; - } + return NULL; +} - /* validate if cid cnt is legal after to be retired */ - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - if (cid->cid.cid_seq_num < max_retire_prior_to) { - retire_cnt++; - } +int64_t +xqc_cid_set_get_unused_cnt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->unused_cnt; } + return XQC_ERROR; +} - if (xqc_cid_set_cnt(cid_set) + 1 - retire_cnt > *active_cid_limit) { - return XQC_FALSE; +int64_t +xqc_cid_set_get_used_cnt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->used_cnt; } + return XQC_ERROR; +} - /* allow the new connection id */ - *active_cid_limit = xqc_cid_set_cnt(cid_set) + 1; +int64_t +xqc_cid_set_get_retired_cnt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->retired_cnt; + } + return XQC_ERROR; +} - return XQC_TRUE; +int64_t +xqc_cid_set_get_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + return inner_set->largest_scid_seq_num; + } + return XQC_ERROR; } +xqc_int_t +xqc_cid_set_set_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id, uint64_t val) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (inner_set) { + inner_set->largest_scid_seq_num = val; + return XQC_OK; + } + return XQC_ERROR; +} xqc_int_t -xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit) +xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit, uint64_t path_id) { - if (cid_set->unused_cnt + cid_set->used_cnt > limit) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + if (!inner_set) { + return -XQC_ECONN_CID_NOT_FOUND; + } + + if ((inner_set->unused_cnt + inner_set->used_cnt) > limit) { return -XQC_EACTIVE_CID_LIMIT; } - xqc_cid_inner_t *inner_cid = xqc_malloc(sizeof(xqc_cid_inner_t)); + xqc_cid_inner_t *inner_cid = xqc_calloc(1, sizeof(xqc_cid_inner_t)); if (inner_cid == NULL) { return -XQC_EMALLOC; } + cid->path_id = path_id; xqc_cid_copy(&inner_cid->cid, cid); inner_cid->state = state; inner_cid->retired_ts = XQC_MAX_UINT64_VALUE; xqc_init_list_head(&inner_cid->list); - xqc_list_add_tail(&inner_cid->list, &cid_set->list_head); + xqc_list_add_tail(&inner_cid->list, &inner_set->cid_list); if (state == XQC_CID_UNUSED) { - cid_set->unused_cnt++; + inner_set->unused_cnt++; } else if (state == XQC_CID_USED) { - cid_set->used_cnt++; + inner_set->used_cnt++; } else if (state == XQC_CID_RETIRED) { - cid_set->retired_cnt++; + inner_set->retired_cnt++; } return XQC_OK; } xqc_int_t -xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid) +xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, uint64_t path_id) { xqc_cid_inner_t *inner_cid = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return XQC_ERROR; + } + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (xqc_cid_is_equal(cid, &inner_cid->cid) == XQC_OK) { if (inner_cid->state == XQC_CID_UNUSED) { - cid_set->unused_cnt--; + inner_set->unused_cnt--; + if (inner_cid->acked == XQC_CID_ACKED) { + inner_set->acked_unused--; + } } else if (inner_cid->state == XQC_CID_USED) { - cid_set->used_cnt--; + inner_set->used_cnt--; } else if (inner_cid->state == XQC_CID_RETIRED) { - cid_set->retired_cnt--; + inner_set->retired_cnt--; } xqc_list_del(pos); @@ -268,17 +341,50 @@ xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid) return XQC_ERROR; } +xqc_cid_inner_t * +xqc_cid_set_search_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid) +{ + xqc_cid_inner_t *inner_cid; + xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; + + xqc_list_for_each_safe(pos_set, next_set, &cid_set->cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + + if (xqc_cid_is_equal(cid, &inner_cid->cid) == XQC_OK) { + cid->cid_seq_num = inner_cid->cid.cid_seq_num; + cid->path_id = inner_cid->cid.path_id; + return inner_cid; + } + } + } + + return NULL; +} xqc_cid_inner_t * -xqc_cid_in_cid_set(const xqc_cid_set_t *cid_set, xqc_cid_t *cid) +xqc_cid_in_cid_set(xqc_cid_set_t *cid_set, xqc_cid_t *cid, uint64_t path_id) { xqc_cid_inner_t *inner_cid = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return NULL; + } + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (xqc_cid_is_equal(cid, &inner_cid->cid) == XQC_OK) { cid->cid_seq_num = inner_cid->cid.cid_seq_num; + cid->path_id = inner_cid->cid.path_id; return inner_cid; } } @@ -288,9 +394,9 @@ xqc_cid_in_cid_set(const xqc_cid_set_t *cid_set, xqc_cid_t *cid) xqc_int_t -xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_cid_state_t next_state) +xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_cid_state_t next_state, uint64_t path_id) { - if (xqc_cid_in_cid_set(cid_set, &cid->cid) == NULL) { + if (xqc_cid_in_cid_set(cid_set, &cid->cid, path_id) == NULL) { return -XQC_ECONN_CID_NOT_FOUND; } @@ -303,98 +409,148 @@ xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_c return -XQC_ECID_STATE; } - /* current_state < next_state */ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return -XQC_ECONN_CID_NOT_FOUND; + } if (current_state == XQC_CID_UNUSED) { - cid_set->unused_cnt--; + inner_set->unused_cnt--; + if (cid->acked == XQC_CID_ACKED) { + inner_set->acked_unused--; + } } else if (current_state == XQC_CID_USED) { - cid_set->used_cnt--; + inner_set->used_cnt--; } else if (current_state == XQC_CID_RETIRED) { - cid_set->retired_cnt--; + inner_set->retired_cnt--; } cid->state = next_state; if (next_state == XQC_CID_USED) { - cid_set->used_cnt++; + inner_set->used_cnt++; } else if (next_state == XQC_CID_RETIRED) { - cid_set->retired_cnt++; + inner_set->retired_cnt++; } return XQC_OK; } xqc_int_t -xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid) -{ - if (cid_set->unused_cnt == 0) { +xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, uint64_t path_id) +{ + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return -XQC_ECONN_NO_AVAIL_CID; + } + + if (inner_set->unused_cnt == 0) { return -XQC_ECONN_NO_AVAIL_CID; } xqc_cid_inner_t *inner_cid; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (inner_cid->state == XQC_CID_UNUSED) { xqc_cid_copy(cid, &inner_cid->cid); - return xqc_cid_switch_to_next_state(cid_set, inner_cid, XQC_CID_USED); + return xqc_cid_switch_to_next_state(cid_set, inner_cid, XQC_CID_USED, path_id); } } return -XQC_ECONN_NO_AVAIL_CID; } -xqc_cid_t * -xqc_get_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num) +xqc_cid_inner_t * +xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num, uint64_t path_id) { xqc_cid_inner_t *inner_cid = NULL; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (!inner_set) { + return NULL; + } + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); if (inner_cid->cid.cid_seq_num == seq_num) { - return &inner_cid->cid; + return inner_cid; } } return NULL; } -xqc_cid_inner_t * -xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num) +xqc_int_t +xqc_cid_set_add_path(xqc_cid_set_t *cid_set, uint64_t path_id) { - xqc_cid_inner_t *inner_cid = NULL; - xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); - xqc_list_for_each_safe(pos, next, &cid_set->list_head) { - inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (inner_set) { + return XQC_OK; + } - if (inner_cid->cid.cid_seq_num == seq_num) { - return inner_cid; - } + /* Note: the memory of inner_set will only be released on conn_destroy */ + inner_set = xqc_calloc(1, sizeof(xqc_cid_set_inner_t)); + if (!inner_set) { + return -XQC_EMALLOC; } - return NULL; + xqc_cid_set_inner_init(inner_set); + xqc_list_add_tail(&inner_set->next, &cid_set->cid_set_list); + inner_set->path_id = path_id; + cid_set->set_cnt[XQC_CID_SET_UNUSED]++; + return XQC_OK; } -xqc_bool_t -xqc_validate_retire_cid_frame(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid) +void +xqc_cid_set_update_state(xqc_cid_set_t *cid_set, + uint64_t path_id, xqc_cid_set_state_t state) { - /* maybe retired already */ - if (xqc_cid_in_cid_set(cid_set, &cid->cid) == NULL) { - return XQC_FALSE; - } + xqc_cid_set_inner_t *inner_set; + inner_set = xqc_get_path_cid_set(cid_set, path_id); - /* the cid is retired already */ - if (cid->state >= XQC_CID_RETIRED) { - return XQC_FALSE; + if (inner_set && inner_set->set_state != state) { + cid_set->set_cnt[inner_set->set_state]--; + cid_set->set_cnt[state]++; + inner_set->set_state = state; } - - return XQC_TRUE; } + +void +xqc_cid_set_on_cid_acked(xqc_cid_set_t *cid_set, uint64_t path_id, + uint64_t cid_seq) +{ + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos, *next; + xqc_cid_inner_t *inner_cid; + inner_set = xqc_get_path_cid_set(cid_set, path_id); + + if (inner_set) { + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (inner_cid->cid.cid_seq_num == cid_seq) { + if (inner_cid->acked == XQC_CID_UNACKED + && inner_cid->state == XQC_CID_UNUSED) + { + inner_set->acked_unused++; + } + inner_cid->acked = XQC_CID_ACKED; + } + } + } +} \ No newline at end of file diff --git a/src/transport/xqc_cid.h b/src/transport/xqc_cid.h index 56ed4cde5..39dbdf984 100644 --- a/src/transport/xqc_cid.h +++ b/src/transport/xqc_cid.h @@ -8,7 +8,6 @@ #include #include "src/common/xqc_list.h" - #define XQC_DEFAULT_CID_LEN 8 typedef enum { @@ -18,66 +17,101 @@ typedef enum { XQC_CID_REMOVED, } xqc_cid_state_t; +typedef enum { + XQC_CID_SET_UNUSED, + XQC_CID_SET_USED, + XQC_CID_SET_ABANDONED, + XQC_CID_SET_MAX_STATE, +} xqc_cid_set_state_t; + +typedef enum { + XQC_CID_UNACKED = 0, + XQC_CID_ACKED = 1 +} xqc_cid_flag_t; typedef struct xqc_cid_inner_s { xqc_list_head_t list; - xqc_cid_t cid; xqc_cid_state_t state; xqc_usec_t retired_ts; + xqc_cid_flag_t acked; } xqc_cid_inner_t; -typedef struct xqc_cid_set_s { - xqc_list_head_t list_head; - uint64_t unused_cnt; - uint64_t used_cnt; - uint64_t retired_cnt; -} xqc_cid_set_t; +typedef struct xqc_cid_set_inner_s { + xqc_list_head_t next; /* a list of cid inner structures */ + xqc_list_head_t cid_list; + uint64_t unused_cnt; + uint64_t used_cnt; + uint64_t retired_cnt; + uint64_t path_id; + union { + uint64_t largest_scid_seq_num; /* for scid set */ + uint64_t largest_retire_prior_to; /* for dcid set */ + }; + xqc_cid_set_state_t set_state; + uint32_t acked_unused; +} xqc_cid_set_inner_t; -typedef struct xqc_scid_set_s { - xqc_cid_t user_scid; /* one of the USED SCIDs, for create/close notify */ - xqc_cid_set_t cid_set; /* a set of SCID, includes used/unused/retired SCID */ - uint64_t largest_scid_seq_num; +typedef struct xqc_cid_set_s { + xqc_list_head_t cid_set_list; /* a list of xqc_cid_set_inner_t */ + union { unsigned char original_scid_str[XQC_MAX_CID_LEN * 2 + 1]; -} xqc_scid_set_t; - -typedef struct xqc_dcid_set_s { - xqc_cid_t current_dcid; /* one of the USED DCIDs, for send packets */ - xqc_cid_set_t cid_set; /* a set of DCID, includes used/unused/retired DCID */ - uint64_t largest_retire_prior_to; unsigned char current_dcid_str[XQC_MAX_CID_LEN * 2 + 1]; -} xqc_dcid_set_t; + }; + union { + xqc_cid_t user_scid; /* one of the USED SCIDs, for create/close notify */ + xqc_cid_t current_dcid; /* one of the USED DCIDs, for send packets */ + }; + uint32_t set_cnt[XQC_CID_SET_MAX_STATE]; +} xqc_cid_set_t; xqc_int_t xqc_generate_cid(xqc_engine_t *engine, xqc_cid_t *ori_cid, xqc_cid_t *cid, uint64_t cid_seq_num); - void xqc_cid_copy(xqc_cid_t *dst, xqc_cid_t *src); void xqc_cid_init_zero(xqc_cid_t *cid); void xqc_cid_set(xqc_cid_t *cid, const unsigned char *data, uint8_t len); -void xqc_init_scid_set(xqc_scid_set_t *scid_set); -void xqc_init_dcid_set(xqc_dcid_set_t *dcid_set); +void xqc_init_cid_set(xqc_cid_set_t *cid_set); void xqc_destroy_cid_set(xqc_cid_set_t *cid_set); -uint64_t xqc_cid_set_cnt(xqc_cid_set_t *cid_set); -xqc_bool_t xqc_cid_set_validate_new_cid_limit(xqc_cid_set_t *cid_set, - uint64_t max_retire_prior_to, uint64_t *active_cid_limit); +xqc_int_t xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, + xqc_cid_state_t state, uint64_t limit, uint64_t path_id); +xqc_int_t xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, uint64_t path_id); + +xqc_cid_inner_t *xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, + uint64_t seq_num, uint64_t path_id); +xqc_cid_inner_t *xqc_cid_in_cid_set(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, uint64_t path_id); +xqc_cid_inner_t *xqc_cid_set_search_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid); + +xqc_int_t xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, + xqc_cid_inner_t *cid, xqc_cid_state_t state, uint64_t path_id); + +xqc_int_t xqc_get_unused_cid(xqc_cid_set_t *cid_set, + xqc_cid_t *cid, uint64_t path_id); + +void xqc_cid_set_inner_init(xqc_cid_set_inner_t *cid_set_inner); +void xqc_cid_set_inner_destroy(xqc_cid_set_inner_t *cid_set_inner); +xqc_cid_set_inner_t* xqc_get_path_cid_set(xqc_cid_set_t *cid_set, uint64_t path_id); +int64_t xqc_cid_set_get_unused_cnt(xqc_cid_set_t *cid_set, uint64_t path_id); +int64_t xqc_cid_set_get_used_cnt(xqc_cid_set_t *cid_set, uint64_t path_id);\ +int64_t xqc_cid_set_get_retired_cnt(xqc_cid_set_t *cid_set, uint64_t path_id); +int64_t xqc_cid_set_get_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id); +xqc_int_t xqc_cid_set_set_largest_seq_or_rpt(xqc_cid_set_t *cid_set, uint64_t path_id, uint64_t val); -xqc_int_t xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit); -xqc_int_t xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid); +unsigned char *xqc_sr_token_str(xqc_engine_t *engine, const char *sr_token); -xqc_cid_t *xqc_get_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num); -xqc_cid_inner_t *xqc_get_inner_cid_by_seq(xqc_cid_set_t *cid_set, uint64_t seq_num); -xqc_cid_inner_t *xqc_cid_in_cid_set(const xqc_cid_set_t *cid_set, xqc_cid_t *cid); +xqc_int_t xqc_cid_set_add_path(xqc_cid_set_t *cid_set, uint64_t path_id); -xqc_int_t xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_cid_state_t state); -xqc_int_t xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid); +void xqc_cid_set_update_state(xqc_cid_set_t *cid_set, uint64_t path_id, xqc_cid_set_state_t state); -xqc_bool_t xqc_validate_retire_cid_frame(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid); +xqc_cid_set_inner_t* xqc_get_next_unused_path_cid_set(xqc_cid_set_t *cid_set); +void xqc_cid_set_on_cid_acked(xqc_cid_set_t *cid_set, uint64_t path_id, uint64_t cid_seq); -unsigned char *xqc_sr_token_str(xqc_engine_t *engine, const char *sr_token); #endif /* _XQC_CID_H_INCLUDED_ */ diff --git a/src/transport/xqc_client.c b/src/transport/xqc_client.c index 184cff2c8..905249ed6 100644 --- a/src/transport/xqc_client.c +++ b/src/transport/xqc_client.c @@ -82,15 +82,13 @@ xqc_client_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_setting xc->conn_flag |= XQC_CONN_FLAG_UPPER_CONN_EXIST; } - /* xqc_conn_destroy must be called before the connection is inserted into conns_active_pq */ - if (!(xc->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (xqc_conns_pq_push(engine->conns_active_pq, xc, 0)) { - return NULL; - } - xc->conn_flag |= XQC_CONN_FLAG_TICKING; + xqc_engine_remove_wakeup_queue(engine, xc); + + if (xqc_engine_add_active_queue(engine, xc) != XQC_OK) { + return NULL; } - xqc_engine_main_logic_internal(engine); + xqc_engine_conn_logic(engine, xc); /* when the connection is destroyed in the main logic, we should return error to upper level */ if (xqc_engine_conns_hash_find(engine, &scid, 's') == NULL) { diff --git a/src/transport/xqc_conn.c b/src/transport/xqc_conn.c index 6ab4e759f..55704b29b 100644 --- a/src/transport/xqc_conn.c +++ b/src/transport/xqc_conn.c @@ -24,7 +24,6 @@ #include "src/transport/xqc_frame_parser.h" #include "src/transport/xqc_packet_parser.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_multipath.h" #include "src/transport/xqc_reinjection.h" #include "src/transport/xqc_datagram.h" @@ -45,11 +44,12 @@ xqc_conn_settings_t internal_default_conn_settings = { .init_idle_time_out = XQC_CONN_INITIAL_IDLE_TIMEOUT, .idle_time_out = XQC_CONN_DEFAULT_IDLE_TIMEOUT, .enable_multipath = 0, - .multipath_version = XQC_MULTIPATH_04, + .multipath_version = XQC_MULTIPATH_10, .spurious_loss_detect_on = 0, .anti_amplification_limit = XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT, .keyupdate_pkt_threshold = 0, .max_pkt_out_size = XQC_PACKET_OUT_SIZE, + .probing_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE, .max_datagram_frame_size = 0, .mp_enable_reinjection = 0, .mp_ack_on_any_path = 0, @@ -90,17 +90,20 @@ xqc_conn_settings_t internal_default_conn_settings = { .enable_encode_fec = 0, .enable_decode_fec = 0, .fec_params = { - .fec_code_rate = XQC_FEC_CODE_RATE_DEFAULT, + .fec_code_rate = 0, .fec_ele_bit_size = XQC_FEC_ELE_BIT_SIZE_DEFAULT, .fec_protected_frames = XQC_FRAME_BIT_DATAGRAM | XQC_FRAME_BIT_STREAM, .fec_max_window_size = XQC_SYMBOL_CACHE_LEN, - .fec_max_symbol_size = XQC_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_HEADER_SPACE - XQC_FEC_SPACE, // limited by MTU value - .fec_max_symbol_num_per_block = XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, + .fec_mp_mode = XQC_FEC_MP_DEFAULT, + .fec_max_symbol_num_per_block = 10, .fec_encoder_schemes_num = 0, .fec_decoder_schemes_num = 0, .fec_encoder_scheme = 0, .fec_decoder_scheme = 0, }, + .disable_send_mmsg = 0, + .init_max_path_id = XQC_DEFAULT_INIT_MAX_PATH_ID, + .control_pto_value = 0 }; @@ -118,13 +121,40 @@ xqc_conn_dgram_probe_timeout(xqc_gp_timer_id_t gp_timer_id, } } +void +xqc_conn_set_default_sched_params(xqc_conn_settings_t *src_settings, xqc_conn_settings_t *settings) +{ + if (settings->scheduler_params.bw_Bps_thr == 0) { + settings->scheduler_params.bw_Bps_thr = src_settings->scheduler_params.bw_Bps_thr; + } + + if (settings->scheduler_params.loss_percent_thr_high == 0) { + settings->scheduler_params.loss_percent_thr_high = src_settings->scheduler_params.loss_percent_thr_high; + } + + if (settings->scheduler_params.loss_percent_thr_low == 0) { + settings->scheduler_params.loss_percent_thr_low = src_settings->scheduler_params.loss_percent_thr_low; + } + + if (settings->scheduler_params.pto_cnt_thr == 0) { + settings->scheduler_params.pto_cnt_thr = src_settings->scheduler_params.pto_cnt_thr; + } + + if (settings->scheduler_params.rtt_us_thr_high == 0) { + settings->scheduler_params.rtt_us_thr_high = src_settings->scheduler_params.rtt_us_thr_high; + } + + if (settings->scheduler_params.rtt_us_thr_low == 0) { + settings->scheduler_params.rtt_us_thr_low = src_settings->scheduler_params.rtt_us_thr_low; + } +} + void xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *settings) { engine->default_conn_settings.cong_ctrl_callback = settings->cong_ctrl_callback; engine->default_conn_settings.cc_params = settings->cc_params; - engine->default_conn_settings.scheduler_params = settings->scheduler_params; engine->default_conn_settings.pacing_on = settings->pacing_on; engine->default_conn_settings.ping_on = settings->ping_on; engine->default_conn_settings.so_sndbuf = settings->so_sndbuf; @@ -141,11 +171,15 @@ xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *se engine->default_conn_settings.init_recv_window = settings->init_recv_window; engine->default_conn_settings.initial_rtt = settings->initial_rtt; engine->default_conn_settings.initial_pto_duration = settings->initial_pto_duration; + engine->default_conn_settings.disable_send_mmsg = settings->disable_send_mmsg; #ifdef XQC_PROTECT_POOL_MEM engine->default_conn_settings.protect_pool_mem = settings->protect_pool_mem; #endif engine->default_conn_settings.adaptive_ack_frequency = settings->adaptive_ack_frequency; + engine->default_conn_settings.scheduler_params = settings->scheduler_params; + xqc_conn_set_default_sched_params(&internal_default_conn_settings, &engine->default_conn_settings); + if (engine->default_conn_settings.init_recv_window) { engine->default_conn_settings.init_recv_window = xqc_max(engine->default_conn_settings.init_recv_window, XQC_QUIC_MAX_MSS); } @@ -175,7 +209,6 @@ xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *se engine->default_conn_settings.idle_time_out = settings->idle_time_out; } - /* default value: 5x, it could be set to meet application need */ if (settings->anti_amplification_limit > 0) { engine->default_conn_settings.anti_amplification_limit = settings->anti_amplification_limit; } @@ -202,7 +235,14 @@ xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *se engine->default_conn_settings.multipath_version = settings->multipath_version; } else { - engine->default_conn_settings.multipath_version = XQC_MULTIPATH_04; + engine->default_conn_settings.multipath_version = XQC_MULTIPATH_10; + } + + if (settings->init_max_path_id == 0) { + engine->default_conn_settings.init_max_path_id = XQC_DEFAULT_INIT_MAX_PATH_ID; + + } else { + engine->default_conn_settings.init_max_path_id = settings->init_max_path_id; } engine->default_conn_settings.close_dgram_redundancy = settings->close_dgram_redundancy; @@ -214,6 +254,15 @@ xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *se engine->default_conn_settings.fec_params.fec_encoder_schemes, &engine->default_conn_settings.fec_params.fec_encoder_schemes_num); /* 如果一个fec scheme都没有设置成功, enable_encode_fec被置0 */ engine->default_conn_settings.enable_encode_fec = engine->default_conn_settings.fec_params.fec_encoder_schemes_num == 0 ? 0 : settings->enable_encode_fec; + if (settings->fec_params.fec_code_rate) { + engine->default_conn_settings.fec_params.fec_code_rate = settings->fec_params.fec_code_rate; + } + if (settings->fec_params.fec_max_symbol_num_per_block) { + engine->default_conn_settings.fec_params.fec_max_symbol_num_per_block = settings->fec_params.fec_max_symbol_num_per_block; + } + if (settings->fec_params.fec_mp_mode) { + engine->default_conn_settings.fec_params.fec_mp_mode = settings->fec_params.fec_mp_mode; + } } engine->default_conn_settings.enable_decode_fec = settings->enable_decode_fec; @@ -265,6 +314,10 @@ xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *se if (settings->keyupdate_pkt_threshold != UINT64_MAX) { engine->default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; } + + if (settings->probing_pkt_out_size > 0) { + engine->default_conn_settings.probing_pkt_out_size = settings->probing_pkt_out_size; + } } static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { @@ -293,7 +346,6 @@ static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { [XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT] = "HSK_CONFIRMED", [XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT] = "HSK_DONE_ACKED", [XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT] = "ADDR_VALIDATED", - [XQC_CONN_FLAG_NEW_CID_ACKED_SHIFT] = "NEW_CID_ACKED", [XQC_CONN_FLAG_LINGER_CLOSING_SHIFT] = "LINGER_CLOSING", [XQC_CONN_FLAG_RETRY_RECVD_SHIFT] = "RETRY_RECVD", [XQC_CONN_FLAG_TLS_HSK_COMPLETED_SHIFT] = "TLS_HSK_CMPTD", @@ -306,9 +358,8 @@ static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { [XQC_CONN_FLAG_PMTUD_PROBING_SHIFT] = "PMTUD_PROBING", [XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT] = "NO_DGRAM_NOTIFIED", [XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT] = "DGRAM_MSS_NOTIFY", - [XQC_CONN_FLAG_MP_WAIT_SCID_SHIFT] = "MP_WAIT_SCID", - [XQC_CONN_FLAG_MP_WAIT_DCID_SHIFT] = "MP_WAIT_DCID", - [XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT] = "MP_READY", + [XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT] = "MP_WAIT_MP_READY", + [XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT] = "MP_READY_NOTIFY", }; @@ -431,6 +482,7 @@ xqc_conn_init_trans_settings(xqc_connection_t *conn) ls->enable_multipath = conn->conn_settings.enable_multipath; ls->multipath_version = conn->conn_settings.multipath_version; + ls->init_max_path_id = conn->conn_settings.init_max_path_id; ls->max_datagram_frame_size = conn->conn_settings.max_datagram_frame_size; ls->disable_active_migration = ls->enable_multipath ? 0 : 1; @@ -467,8 +519,7 @@ xqc_conn_init_trans_settings(xqc_connection_t *conn) /* init FEC transport params */ if (conn->conn_settings.enable_encode_fec) { ls->enable_encode_fec = conn->conn_settings.enable_encode_fec; - ls->fec_max_symbols_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block * conn->conn_settings.fec_params.fec_code_rate; - ls->fec_max_symbol_size = conn->conn_settings.fec_params.fec_max_symbol_size; + ls->fec_max_symbols_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block; ls->fec_encoder_schemes_num = conn->conn_settings.fec_params.fec_encoder_schemes_num; for (xqc_int_t i = 0; i < conn->conn_settings.fec_params.fec_encoder_schemes_num; i++) { ls->fec_encoder_schemes[i] = conn->conn_settings.fec_params.fec_encoder_schemes[i]; @@ -546,34 +597,6 @@ xqc_conn_init_timer_manager(xqc_connection_t *conn) } } -void -xqc_conn_set_default_sched_params(xqc_engine_t *engine, xqc_conn_settings_t *settings) -{ - if (settings->scheduler_params.bw_Bps_thr == 0) { - settings->scheduler_params.bw_Bps_thr = engine->default_conn_settings.scheduler_params.bw_Bps_thr; - } - - if (settings->scheduler_params.loss_percent_thr_high == 0) { - settings->scheduler_params.loss_percent_thr_high = engine->default_conn_settings.scheduler_params.loss_percent_thr_high; - } - - if (settings->scheduler_params.loss_percent_thr_low == 0) { - settings->scheduler_params.loss_percent_thr_low = engine->default_conn_settings.scheduler_params.loss_percent_thr_low; - } - - if (settings->scheduler_params.pto_cnt_thr == 0) { - settings->scheduler_params.pto_cnt_thr = engine->default_conn_settings.scheduler_params.pto_cnt_thr; - } - - if (settings->scheduler_params.rtt_us_thr_high == 0) { - settings->scheduler_params.rtt_us_thr_high = engine->default_conn_settings.scheduler_params.rtt_us_thr_high; - } - - if (settings->scheduler_params.rtt_us_thr_low == 0) { - settings->scheduler_params.rtt_us_thr_low = engine->default_conn_settings.scheduler_params.rtt_us_thr_low; - } -} - xqc_connection_t * xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, const xqc_conn_settings_t *settings, void *user_data, xqc_conn_type_t type) @@ -601,7 +624,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_settings = *settings; xqc_memcpy(xc->conn_settings.conn_option_str, settings->conn_option_str, XQC_CO_STR_MAX_LEN); - xqc_conn_set_default_sched_params(engine, &xc->conn_settings); + xqc_conn_set_default_sched_params(&engine->default_conn_settings, &xc->conn_settings); if (xc->conn_settings.initial_rtt == 0) { xc->conn_settings.initial_rtt = XQC_kInitialRtt_us; @@ -706,10 +729,19 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, } if (xqc_conn_is_current_mp_version_supported(xc->conn_settings.multipath_version) != XQC_OK) { - xc->conn_settings.multipath_version = XQC_MULTIPATH_04; + xc->conn_settings.multipath_version = XQC_MULTIPATH_10; + } + + if (xc->conn_settings.init_max_path_id == 0) { + xc->conn_settings.init_max_path_id = XQC_DEFAULT_INIT_MAX_PATH_ID; + } + + if (xc->conn_settings.probing_pkt_out_size == 0) { + xc->conn_settings.probing_pkt_out_size = engine->default_conn_settings.probing_pkt_out_size; } #ifdef XQC_ENABLE_FEC + xc->fec_neg_fail_reason = 0; if (xc->conn_settings.enable_encode_fec || xc->conn_settings.enable_decode_fec) { @@ -730,12 +762,12 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, if (xc->conn_settings.fec_params.fec_protected_frames == 0) { xc->conn_settings.fec_params.fec_protected_frames = engine->default_conn_settings.fec_params.fec_protected_frames; } - if (xc->conn_settings.fec_params.fec_max_symbol_size == 0) { - xc->conn_settings.fec_params.fec_max_symbol_size = engine->default_conn_settings.fec_params.fec_max_symbol_size; - } if (xc->conn_settings.fec_params.fec_max_symbol_num_per_block == 0) { xc->conn_settings.fec_params.fec_max_symbol_num_per_block = engine->default_conn_settings.fec_params.fec_max_symbol_num_per_block; } + if (xc->conn_settings.fec_params.fec_mp_mode == 0) { + xc->conn_settings.fec_params.fec_mp_mode = engine->default_conn_settings.fec_params.fec_mp_mode; + } } if (xc->conn_settings.enable_decode_fec) { if (xc->conn_settings.fec_params.fec_max_window_size) { @@ -753,28 +785,40 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_pool = pool; - xqc_init_dcid_set(&xc->dcid_set); - xqc_init_scid_set(&xc->scid_set); + xqc_init_cid_set(&xc->dcid_set); + xqc_init_cid_set(&xc->scid_set); + + if (xqc_cid_set_add_path(&xc->dcid_set, XQC_INITIAL_PATH_ID) != XQC_OK) { + goto fail; + } + + if (xqc_cid_set_add_path(&xc->scid_set, XQC_INITIAL_PATH_ID) != XQC_OK) { + goto fail; + } + + xqc_cid_set_update_state(&xc->dcid_set, XQC_INITIAL_PATH_ID, XQC_CID_SET_USED); + xqc_cid_set_update_state(&xc->scid_set, XQC_INITIAL_PATH_ID, XQC_CID_SET_USED); + if (xqc_cid_set_insert_cid(&xc->dcid_set, dcid, XQC_CID_USED, + xc->local_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID)) + { + goto fail; + } xqc_cid_copy(&(xc->dcid_set.current_dcid), dcid); xqc_hex_dump(xc->dcid_set.current_dcid_str, dcid->cid_buf, dcid->cid_len); xc->dcid_set.current_dcid_str[dcid->cid_len * 2] = '\0'; - if (xqc_cid_set_insert_cid(&xc->dcid_set.cid_set, dcid, XQC_CID_USED, - xc->local_settings.active_connection_id_limit)) + + if (xqc_cid_set_insert_cid(&xc->scid_set, scid, XQC_CID_USED, + xc->remote_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID)) { goto fail; } - xqc_cid_copy(&(xc->scid_set.user_scid), scid); xqc_hex_dump(xc->scid_set.original_scid_str, scid->cid_buf, scid->cid_len); xc->scid_set.original_scid_str[scid->cid_len * 2] = '\0'; - xc->scid_set.largest_scid_seq_num = scid->cid_seq_num; - if (xqc_cid_set_insert_cid(&xc->scid_set.cid_set, scid, XQC_CID_USED, - xc->remote_settings.active_connection_id_limit)) - { - goto fail; - } - + xqc_cid_set_set_largest_seq_or_rpt(&xc->scid_set, XQC_INITIAL_PATH_ID, scid->cid_seq_num); xqc_cid_copy(&(xc->initial_scid), scid); xc->engine = engine; @@ -796,8 +840,8 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->max_stream_id_uni_remote = -1; xc->last_dgram = NULL; xc->pkt_out_size = xc->conn_settings.max_pkt_out_size; - xc->max_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; - xc->probing_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; + xc->max_pkt_out_size = xc->conn_settings.probing_pkt_out_size; + xc->probing_pkt_out_size = xc->conn_settings.probing_pkt_out_size; xc->probing_cnt = 0; for (xqc_encrypt_level_t encrypt_level = XQC_ENC_LEV_INIT; encrypt_level < XQC_ENC_LEV_MAX; encrypt_level++) { @@ -1022,7 +1066,7 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, xqc_cid_copy(&conn->original_dcid, scid); - if (xqc_cid_in_cid_set(&conn->scid_set.cid_set, &conn->original_dcid) == NULL) { + if (xqc_cid_in_cid_set(&conn->scid_set, &conn->original_dcid, XQC_INITIAL_PATH_ID) == NULL) { /* * if server choose it's own cid, then if server Initial is lost, * and if client Initial retransmit, server might use odcid to @@ -1165,7 +1209,7 @@ xqc_conn_server_on_alpn(xqc_connection_t *conn, const unsigned char *alpn, size_ if (conn->conn_flag & XQC_CONN_FLAG_LOCAL_TP_UPDATED) { ret = xqc_conn_encode_local_tp(conn, tp_buf, - XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tp_len); + XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tp_len); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|server encode tp error|ret:%d|", ret); goto err; @@ -1210,9 +1254,24 @@ xqc_conn_destroy(xqc_connection_t *xc) return; } + uint8_t fec_flag; xqc_conn_stats_t conn_stats; + xqc_fec_schemes_e ensch, desch; + unsigned char *ensch_str, *desch_str, *fec_mpm_str; + + fec_flag = 0; + ensch = xc->conn_settings.fec_params.fec_encoder_scheme; + desch = xc->conn_settings.fec_params.fec_decoder_scheme; + ensch_str = desch_str = fec_mpm_str = "NO_FEC"; + xqc_memzero(&conn_stats, sizeof(xqc_conn_stats_t)); xqc_conn_get_stats_internal(xc, &conn_stats); +#ifdef XQC_ENABLE_FEC + fec_flag = 1; + ensch_str = xqc_get_fec_scheme_str(ensch); + desch_str = xqc_get_fec_scheme_str(desch); + fec_mpm_str = xqc_get_fec_mp_mode_str(xc->fec_ctl); +#endif if (xc->tls) { xqc_tls_get_selected_alpn(xc->tls, &out_alpn, &out_alpn_len); @@ -1230,7 +1289,12 @@ xqc_conn_destroy(xqc_connection_t *xc) "mp_enable:%ud|create:%ud|validated:%ud|active:%ud|path_info:%s|alpn:%*s|rebind_count:%d|" "rebind_valid:%d|rtx_pkt:%ud|tlp_pkt:%ud|" "snd_pkt:%ud|spurious_loss:%ud|detected_loss:%ud|" - "max_pto:%ud|finished_streams:%ud|cli_bidi_s:%ud|svr_bidi_s:%ud|", + "max_pto:%ud|finished_streams:%ud|cli_bidi_s:%ud|svr_bidi_s:%ud|" + "fec_exist:%ud|" + "fec_ensch:%s|fec_desch:%s|fec_neg_fail:%ud|" + "fec_mp_mode:%s|send_fec_pkts:%ud|recovered_fec_num:%ud|" + "max_po_size:%uz|max_probing_size:%uz|ppo_size:%uz|" + , xc, xc->conn_flag & XQC_CONN_FLAG_HAS_0RTT ? 1:0, xc->conn_flag & XQC_CONN_FLAG_0RTT_OK ? 1:0, @@ -1249,13 +1313,15 @@ xqc_conn_destroy(xqc_connection_t *xc) conn_stats.total_rebind_valid, conn_stats.lost_count, conn_stats.tlp_count, conn_stats.send_count, conn_stats.spurious_loss_count, xc->detected_loss_cnt, - xc->max_pto_cnt, xc->finished_streams, xc->cli_bidi_streams, xc->svr_bidi_streams); + xc->max_pto_cnt, xc->finished_streams, xc->cli_bidi_streams, xc->svr_bidi_streams, + fec_flag, + ensch_str, desch_str, xc->fec_neg_fail_reason, + fec_mpm_str, conn_stats.send_fec_cnt, xc->fec_ctl ? xc->fec_ctl->fec_recover_pkt_cnt : 0, + xc->pkt_out_size, xc->max_pkt_out_size, xc->probing_pkt_out_size + ); xqc_log_event(xc->log, CON_CONNECTION_CLOSED, xc); - if (xc->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP) { - xqc_wakeup_pq_remove(xc->engine->conns_wait_wakeup_pq, xc); - xc->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; - } + xqc_engine_remove_wakeup_queue(xc->engine, xc); xqc_list_head_t *pos, *next; xqc_stream_t *stream; @@ -1526,13 +1592,10 @@ xqc_conn_send_ping(xqc_engine_t *engine, const xqc_cid_t *cid, void *ping_user_d return ret; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); - xqc_engine_main_logic_internal(engine); + xqc_engine_conn_logic(engine, conn); return XQC_OK; } @@ -1600,17 +1663,45 @@ xqc_conn_try_to_update_mss(xqc_connection_t *conn) ssize_t xqc_send_burst(xqc_connection_t *conn, xqc_path_ctx_t *path, struct iovec *iov, int cnt) { - ssize_t sent = 0; + ssize_t sent_size = 0; + int sent_cnt = 0; + + if (conn->pkt_filter_cb) { + + for (sent_cnt = 0; sent_cnt < cnt; sent_cnt++) { + sent_size = conn->pkt_filter_cb(iov[sent_cnt].iov_base, + iov[sent_cnt].iov_len, + (struct sockaddr *)conn->peer_addr, + conn->peer_addrlen, + conn->pkt_filter_cb_user_data); + if (sent_size < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|pkt_filter_cb error|conn:%p|" + "size:%ud|sent:%z|sent_cnt:%d|", + conn, iov[sent_cnt].iov_len, sent_size, + sent_cnt); + + sent_size = sent_size == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; + break; + } + } - if (conn->transport_cbs.write_mmsg_ex) { - sent = conn->transport_cbs.write_mmsg_ex(path->path_id, iov, cnt, + if (sent_size == -XQC_EAGAIN && sent_cnt == 0) { + sent_cnt = -XQC_EAGAIN; + + } else if (sent_size == -XQC_ESOCKET) { + sent_cnt = -XQC_EPACKET_FILETER_CALLBACK; + } + + } else if (conn->transport_cbs.write_mmsg_ex) { + sent_cnt = conn->transport_cbs.write_mmsg_ex(path->path_id, iov, cnt, (struct sockaddr *)path->peer_addr, path->peer_addrlen, xqc_conn_get_user_data(conn)); - if (sent < 0) { + if (sent_cnt < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|error send mmsg|"); - if (sent == XQC_SOCKET_ERROR) { + if (sent_cnt == XQC_SOCKET_ERROR) { path->path_flag |= XQC_PATH_FLAG_SOCKET_ERROR; if (xqc_conn_should_close(conn, path)) { xqc_log(conn->log, XQC_LOG_ERROR, "|socket exception, close connection|"); @@ -1618,24 +1709,28 @@ xqc_send_burst(xqc_connection_t *conn, xqc_path_ctx_t *path, struct iovec *iov, xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } } + + sent_cnt = sent_cnt == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } else { - sent = conn->transport_cbs.write_mmsg(iov, cnt, + sent_cnt = conn->transport_cbs.write_mmsg(iov, cnt, (struct sockaddr *)conn->peer_addr, conn->peer_addrlen, xqc_conn_get_user_data(conn)); - if (sent < 0) { + if (sent_cnt < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|error send mmsg|"); - if (sent == XQC_SOCKET_ERROR) { + if (sent_cnt == XQC_SOCKET_ERROR) { xqc_log(conn->log, XQC_LOG_ERROR, "|socket exception, close connection|"); conn->conn_state = XQC_CONN_STATE_CLOSED; xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } + + sent_cnt = sent_cnt == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } - return sent; + return sent_cnt; } xqc_int_t @@ -1666,13 +1761,14 @@ xqc_conn_schedule_packets(xqc_connection_t *conn, xqc_list_head_t *head, xqc_bool_t packets_are_limited_by_cc, xqc_send_type_t send_type) { ssize_t ret; - - xqc_list_head_t *pos, *next; + uint32_t send_repair_num, src_syb_num; + uint64_t stream_id; + xqc_bool_t cc_blocked, insert_repair; + xqc_usec_t now; xqc_path_ctx_t *path; + xqc_list_head_t *pos, *next; xqc_packet_out_t *packet_out; - xqc_bool_t cc_blocked; - - xqc_usec_t now; + xqc_stream_t *stream; now = xqc_monotonic_timestamp(); @@ -1707,6 +1803,31 @@ xqc_conn_schedule_packets(xqc_connection_t *conn, xqc_list_head_t *head, } } +#ifdef XQC_ENABLE_FEC + if (conn->conn_settings.enable_encode_fec + && conn->conn_settings.fec_params.fec_encoder_scheme + && !(packet_out->po_frame_types & XQC_FRAME_BIT_SID + || packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL)) + { + if (xqc_is_packet_fec_protected(conn, packet_out) == XQC_OK) { + insert_repair = XQC_FALSE; + ret = xqc_process_fec_protected_packet(conn, packet_out, &insert_repair); + // if insert repair packet after current po, update next pointer; + if (insert_repair) { + next = pos->next; + stream_id = packet_out->po_stream_id; + stream = xqc_find_stream_by_id(stream_id, conn->streams_hash); + if (stream) { + if (stream->stream_stats.fst_rpr_time == 0) { + stream->stream_stats.fst_rpr_time = xqc_monotonic_timestamp(); + } + stream->stream_stats.last_rpr_time = xqc_monotonic_timestamp(); + } + } + } + } +#endif + xqc_path_send_buffer_append(path, packet_out, &path->path_schedule_buf[send_type]); } } @@ -1936,7 +2057,8 @@ xqc_path_send_packets_batch(xqc_connection_t *conn, xqc_path_ctx_t *path, } } - if (send_burst_count < 0) { + /* @FIXME: in the case of EAGAIN, we should not reschedule packets. */ + if (send_burst_count < 0 && send_burst_count != -XQC_EAGAIN) { xqc_path_send_buffer_clear(conn, path, head, send_type); } @@ -2033,44 +2155,13 @@ xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, } } - if (ret < 0) { + /* @FIXME: in the case of EAGAIN, we should not reschedule packets. */ + if (ret < 0 && ret != -XQC_EAGAIN) { xqc_path_send_buffer_clear(conn, path, head, send_type); } } -#ifdef XQC_ENABLE_FEC -void -xqc_insert_fec_packets(xqc_connection_t *conn, xqc_list_head_t *head) -{ - xqc_int_t ret; - xqc_list_head_t *pos, *next; - xqc_packet_out_t *packet_out; - - xqc_list_for_each_safe(pos, next, head) { - packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - if (xqc_is_packet_fec_protected(conn, packet_out) == XQC_OK) - { - ret = xqc_process_fec_protected_packet(conn, packet_out); - if (ret != XQC_OK) { - break; - } - } - } - -} - -void -xqc_insert_fec_packets_all(xqc_connection_t *conn) -{ - if (conn->fec_ctl == NULL) { - return; - } - - xqc_list_head_t *head = &conn->conn_send_queue->sndq_send_packets; - xqc_insert_fec_packets(conn, head); -} -#endif void xqc_conn_send_packets(xqc_connection_t *conn) @@ -2184,7 +2275,8 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi if (sent < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|pkt_filter_cb error|conn:%p|" "size:%ud|sent:%z|", conn, len, sent); - return -XQC_EPACKET_FILETER_CALLBACK; + + return sent == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_EPACKET_FILETER_CALLBACK; } sent = len; @@ -2209,7 +2301,8 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } } - return -XQC_ESOCKET; + + return sent == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } else { @@ -2227,7 +2320,8 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi conn->conn_state = XQC_CONN_STATE_CLOSED; xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } - return -XQC_ESOCKET; + + return sent == XQC_SOCKET_EAGAIN ? -XQC_EAGAIN : -XQC_ESOCKET; } } @@ -2749,7 +2843,7 @@ xqc_path_send_one_or_two_ack_elicit_pkts(xqc_path_ctx_t *path, xqc_list_for_each_safe(pos, next, &c->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); xqc_list_splice_tail_init(&path->path_reinj_tmp_buf, - &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]); + &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]); } } } @@ -2817,13 +2911,10 @@ xqc_conn_close(xqc_engine_t *engine, const xqc_cid_t *cid) } end: - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); - xqc_engine_wakeup_once(conn->engine); + xqc_engine_wakeup_once(engine); return XQC_OK; } @@ -3041,11 +3132,8 @@ xqc_conn_send_version_negotiation(xqc_connection_t *c) packet_out->po_used_size = p - packet_out->po_buf; /* push to conns queue */ - if (!(c->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(c->engine->conns_active_pq, c, c->last_ticked_time)) { - c->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(c->engine, c); + xqc_engine_add_active_queue(c->engine, c); c->conn_flag &= ~XQC_CONN_FLAG_VERSION_NEGOTIATION; return XQC_OK; @@ -3054,39 +3142,16 @@ xqc_conn_send_version_negotiation(xqc_connection_t *c) void xqc_conn_continue_send_by_conn(xqc_connection_t *conn) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); if (!conn) { - xqc_log(conn->engine->log, XQC_LOG_ERROR, "|can not find connection|conn:%p|", conn); - return ; - } - xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); - -#ifdef XQC_ENABLE_FEC - if (conn->conn_settings.enable_encode_fec - && conn->conn_settings.fec_params.fec_encoder_scheme) - { - xqc_insert_fec_packets_all(conn); + return; } -#endif - xqc_conn_schedule_packets_to_paths(conn); - if (xqc_engine_is_sendmmsg_on(conn->engine)) { - xqc_conn_transmit_pto_probe_packets_batch(conn); - xqc_conn_retransmit_lost_packets_batch(conn); - xqc_conn_send_packets_batch(conn); - - } else { - xqc_conn_transmit_pto_probe_packets(conn); - xqc_conn_retransmit_lost_packets(conn); - xqc_conn_send_packets(conn); - } + xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); - if (conn->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_AFTER_SEND) { - xqc_conn_reinject_unack_packets(conn, XQC_REINJ_UNACK_AFTER_SEND); - xqc_conn_send_packets(conn); - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); } int @@ -3098,9 +3163,8 @@ xqc_conn_continue_send(xqc_engine_t *engine, const xqc_cid_t *cid) xqc_scid_str(engine, cid)); return -XQC_ECONN_NFOUND; } - xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); - xqc_engine_main_logic_internal(conn->engine); + xqc_conn_continue_send_by_conn(conn); return XQC_OK; } @@ -3136,11 +3200,11 @@ xqc_conn_encode_mp_settings(xqc_connection_t *conn, char *buf, size_t buf_sz) //len: 9 encode_val = conn->local_settings.multipath_version; - len += snprintf(buf + len, buf_sz - len, "/%d", encode_val); + len += snprintf(buf + len, buf_sz - len, "/%x", encode_val); //len: 13 encode_val = conn->remote_settings.multipath_version; - len += snprintf(buf + len, buf_sz - len, "/%d", encode_val); + len += snprintf(buf + len, buf_sz - len, "/%x", encode_val); buf[len] = 0; } @@ -3198,7 +3262,7 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) conn->fec_ctl ? conn->fec_ctl->fec_recover_pkt_cnt : 0, conn->fec_ctl ? conn->fec_ctl->fec_recover_failed_cnt : 0, conn->fec_ctl ? conn->fec_ctl->fec_flush_blk_cnt : 0, - conn->fec_ctl ? conn->fec_ctl->fec_recv_repair_num : 0 + conn->fec_ctl ? conn->fec_ctl->fec_recv_repair_num_total : 0 #endif ); @@ -3324,6 +3388,7 @@ xqc_conn_get_stats_internal(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats conn_stats->conn_err = (int)conn->conn_err; conn_stats->early_data_flag = XQC_0RTT_NONE; conn_stats->enable_multipath = conn->enable_multipath; + conn_stats->enable_fec = conn->conn_settings.fec_params.fec_encoder_scheme ? 1 : 0; conn_stats->spurious_loss_detect_on = conn->conn_settings.spurious_loss_detect_on; if (conn->conn_flag & XQC_CONN_FLAG_HAS_0RTT) { if (conn->conn_flag & XQC_CONN_FLAG_0RTT_OK) { @@ -3352,6 +3417,10 @@ xqc_conn_get_stats_internal(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats conn_stats->ack_info, sizeof(conn_stats->ack_info)); } + if (conn->fec_ctl) { + conn_stats->send_fec_cnt = conn->fec_ctl->fec_send_repair_num_total; + } + /* 3. 遍历路径,获取各个路径count加和 */ xqc_list_head_t *pos, *next; @@ -3396,6 +3465,7 @@ xqc_conn_get_stats(xqc_engine_t *engine, const xqc_cid_t *cid) xqc_memzero(&conn_stats, sizeof(conn_stats)); for (int i = 0; i < XQC_MAX_PATHS_COUNT; ++i) { conn_stats.paths_info[i].path_id = XQC_MAX_UINT64_VALUE; + conn_stats.paths_info[i].path_app_status = 0; } conn = xqc_engine_conns_hash_find(engine, cid, 's'); @@ -3719,6 +3789,49 @@ xqc_conn_update_flow_ctl_settings(xqc_connection_t *conn) flow_ctl->fc_max_streams_uni_can_send = remote_settings->max_streams_uni; } +xqc_int_t +xqc_conn_add_path_cid_sets(xqc_connection_t *conn, uint32_t start, uint32_t end) +{ + if (conn->enable_multipath) { + uint32_t path_id; + xqc_int_t ret; + /* add cid_set_inner for all paths */ + for (path_id = start; path_id <= end; path_id++) { + ret = xqc_cid_set_add_path(&conn->scid_set, path_id); + if (ret != XQC_OK) { + return ret; + } + + ret = xqc_cid_set_add_path(&conn->dcid_set, path_id); + if (ret != XQC_OK) { + return ret; + } + } + } + return XQC_OK; +} + +xqc_int_t +xqc_conn_try_to_enable_multipath(xqc_connection_t *conn) +{ + xqc_int_t ret = XQC_OK; + uint64_t path_id = 0; + + /* determine multipath mode */ + conn->enable_multipath = xqc_conn_enable_multipath(conn); + conn->conn_settings.multipath_version = xqc_conn_multipath_version_negotiation(conn); + if (conn->conn_settings.multipath_version == XQC_ERR_MULTIPATH_VERSION) { + xqc_log(conn->log, XQC_LOG_WARN, "|multipath_version_negotiation err|"); + conn->enable_multipath = 0; + } + + if (conn->enable_multipath) { + conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_MP_READY; + } + + return xqc_conn_add_path_cid_sets(conn, XQC_INITIAL_PATH_ID + 1, conn->curr_max_path_id); +} + xqc_int_t xqc_conn_handshake_complete(xqc_connection_t *conn) { @@ -3735,9 +3848,8 @@ xqc_conn_handshake_complete(xqc_connection_t *conn) xqc_stream_update_flow_ctl(stream); } - /* determine multipath mode */ - conn->enable_multipath = xqc_conn_enable_multipath(conn); + /* start pmtud probing immediately if mpquic is disabled */ if (!conn->enable_multipath && xqc_timer_is_set(&conn->conn_timer_manager, XQC_TIMER_PMTUD_PROBING)) { @@ -3745,17 +3857,6 @@ xqc_conn_handshake_complete(xqc_connection_t *conn) conn->conn_flag |= XQC_CONN_FLAG_PMTUD_PROBING; xqc_timer_unset(&conn->conn_timer_manager, XQC_TIMER_PMTUD_PROBING); } - - mp_version_ret = xqc_conn_multipath_version_negotiation(conn); - if (mp_version_ret == XQC_ERR_MULTIPATH_VERSION) { - xqc_log(conn->log, XQC_LOG_WARN, "|multipath_version_negotiation err|"); - conn->enable_multipath = 0; - } - conn->conn_settings.multipath_version = mp_version_ret; - - if (conn->enable_multipath) { - conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_SCID; - } /* conn's handshake is complete when TLS stack has reported handshake complete */ conn->conn_flag |= XQC_CONN_FLAG_HANDSHAKE_COMPLETED; @@ -4093,7 +4194,6 @@ xqc_conn_record_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) xqc_path_ctx_t *path; if (c->enable_multipath) { - //TODO: MPQUIC fix migration path = xqc_conn_find_path_by_path_id(c, packet_in->pi_path_id); } else { @@ -4105,6 +4205,11 @@ xqc_conn_record_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) return; } + /* update path stats */ + if (packet_in->pi_frame_types & (XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_DATAGRAM)) { + path->path_send_ctl->ctl_app_bytes_recv += packet_in->buf_size; + } + xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(c, path); xqc_send_ctl_t *send_ctl = path->path_send_ctl; @@ -4150,23 +4255,19 @@ xqc_conn_confirm_cid(xqc_connection_t *c, xqc_packet_t *pkt) if (!(c->conn_flag & XQC_CONN_FLAG_DCID_OK)) { - if (xqc_cid_in_cid_set(&c->dcid_set.cid_set, &pkt->pkt_scid) == NULL) { - /* delete original cid which is not chosen by peer */ - ret = xqc_cid_set_delete_cid(&c->dcid_set.cid_set, &c->original_dcid); - if (ret != XQC_OK) { - xqc_log(c->log, XQC_LOG_WARN, "|delete original dcid error"); - } - - /* insert peer's first dcid */ - ret = xqc_cid_set_insert_cid(&c->dcid_set.cid_set, &pkt->pkt_scid, XQC_CID_USED, - c->local_settings.active_connection_id_limit); + if (xqc_cid_in_cid_set(&c->dcid_set, &pkt->pkt_scid, XQC_INITIAL_PATH_ID) == NULL) { + ret = xqc_cid_set_insert_cid(&c->dcid_set, &pkt->pkt_scid, XQC_CID_USED, + c->local_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID); if (ret != XQC_OK) { xqc_log(c->log, XQC_LOG_ERROR, - "|xqc_cid_set_insert_cid error|limit:%ui|unused:%ui|used:%ui|", + "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", c->local_settings.active_connection_id_limit, - c->dcid_set.cid_set.unused_cnt, c->dcid_set.cid_set.used_cnt); + xqc_cid_set_get_unused_cnt(&c->dcid_set, XQC_INITIAL_PATH_ID), + xqc_cid_set_get_used_cnt(&c->dcid_set, XQC_INITIAL_PATH_ID)); return ret; } + //TODO: the original dcid should be removed from the dcid_set } if (XQC_OK != xqc_cid_is_equal(&c->dcid_set.current_dcid, &pkt->pkt_scid)) { @@ -4227,8 +4328,8 @@ xqc_conn_server_validate_address(xqc_connection_t *c, xqc_packet_in_t *pi) * client MAY send an Initial packet with PING/PADDING on PTO with server's CID */ if (c->scid_set.user_scid.cid_len >= XQC_CONN_ADDR_VALIDATION_CID_ENTROPY - && xqc_cid_in_cid_set(&c->scid_set.cid_set, &c->original_dcid) == NULL - && xqc_cid_in_cid_set(&c->scid_set.cid_set, &pi->pi_pkt.pkt_dcid) != NULL) + && xqc_cid_in_cid_set(&c->scid_set, &c->original_dcid, XQC_INITIAL_PATH_ID) == NULL + && xqc_cid_in_cid_set(&c->scid_set, &pi->pi_pkt.pkt_dcid, XQC_INITIAL_PATH_ID) != NULL) { xqc_conn_addr_validated(c); } @@ -4357,9 +4458,11 @@ xqc_conn_on_pkt_processed(xqc_connection_t *c, xqc_packet_in_t *pi, xqc_usec_t n c->conn_last_recv_time = now; - xqc_log(c->log, XQC_LOG_INFO, "|====>|conn:%p|path:%ui|size:%uz|pkt_type:%s|pkt_num:%ui|frame:%s|recv_time:%ui|", + xqc_log(c->log, XQC_LOG_INFO, "|====>|conn:%p|path:%ui|size:%uz|pkt_type:%s|pkt_num:%ui|frame:%s|recv_time:%ui|dcid:%s|dcid_seq:%ui|", c, pi->pi_path_id, pi->buf_size, xqc_pkt_type_2_str(pi->pi_pkt.pkt_type), pi->pi_pkt.pkt_num, - xqc_frame_type_2_str(c->engine, pi->pi_frame_types), pi->pkt_recv_time); + xqc_frame_type_2_str(c->engine, pi->pi_frame_types), pi->pkt_recv_time, + xqc_dcid_str(c->engine, &pi->pi_pkt.pkt_dcid), + pi->pi_pkt.pkt_dcid.cid_seq_num); return ret; } @@ -4511,24 +4614,38 @@ xqc_conn_check_handshake_complete(xqc_connection_t *conn) } -/* should have at lease one unused dcid & one unused scid */ xqc_int_t -xqc_conn_check_unused_cids(xqc_connection_t *conn) +xqc_conn_get_available_path_id(xqc_connection_t *conn, uint64_t *path_id) { - if (conn->dcid_set.cid_set.unused_cnt == 0 || conn->scid_set.cid_set.unused_cnt == 0) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|don't have available unused cid|%ui|%ui|", - conn->dcid_set.cid_set.unused_cnt, conn->scid_set.cid_set.unused_cnt); - return -XQC_EMP_NO_AVAIL_PATH_ID; + if (conn->enable_multipath + && conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) + { + /* principle: the next unused path ID has at least one unused DCID and one acked unused SCID */ + xqc_cid_set_inner_t *scid_inner_set = xqc_get_next_unused_path_cid_set(&conn->scid_set); + if (scid_inner_set) { + xqc_cid_set_inner_t *dcid_inner_set = xqc_get_path_cid_set(&conn->scid_set, scid_inner_set->path_id); + if (dcid_inner_set) { + if (dcid_inner_set->unused_cnt > 0 && scid_inner_set->acked_unused > 0) { + if (path_id) { + *path_id = scid_inner_set->path_id; + } + return XQC_OK; + } + } + + } } - return XQC_OK; + + return -XQC_EMP_NO_AVAIL_PATH_ID; } - void xqc_conn_destroy_cids(xqc_connection_t *conn) { xqc_cid_inner_t *cid = NULL; xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set = NULL; + xqc_list_head_t *pos_set, *next_set; if (conn->engine->conns_hash) { if (xqc_find_conns_hash(conn->engine->conns_hash, conn, @@ -4539,63 +4656,111 @@ xqc_conn_destroy_cids(xqc_connection_t *conn) conn->original_dcid.cid_buf, conn->original_dcid.cid_len); } + xqc_list_for_each_safe(pos_set, next_set, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); - xqc_list_for_each_safe(pos, next, &conn->scid_set.cid_set.list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - if (xqc_find_conns_hash(conn->engine->conns_hash, conn, - cid->cid.cid_buf, cid->cid.cid_len)) - { - xqc_remove_conns_hash(conn->engine->conns_hash, conn, - cid->cid.cid_buf, cid->cid.cid_len); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (xqc_find_conns_hash(conn->engine->conns_hash, conn, + cid->cid.cid_buf, cid->cid.cid_len)) + { + xqc_remove_conns_hash(conn->engine->conns_hash, conn, + cid->cid.cid_buf, cid->cid.cid_len); + } } } } - xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - if (conn->engine->conns_hash_dcid) { - /* delete relationship from conns_hash_dcid */ - if (xqc_find_conns_hash(conn->engine->conns_hash_dcid, conn, - cid->cid.cid_buf, cid->cid.cid_len)) - { - xqc_remove_conns_hash(conn->engine->conns_hash_dcid, conn, - cid->cid.cid_buf, cid->cid.cid_len); - } + xqc_list_for_each_safe(pos_set, next_set, &conn->dcid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + if (conn->engine->conns_hash_dcid) { + /* delete relationship from conns_hash_dcid */ + if (xqc_find_conns_hash(conn->engine->conns_hash_dcid, conn, + cid->cid.cid_buf, cid->cid.cid_len)) + { + xqc_remove_conns_hash(conn->engine->conns_hash_dcid, conn, + cid->cid.cid_buf, cid->cid.cid_len); + } - } - if (conn->engine->conns_hash_sr_token) { - /* delete relationship from conns_hash_sr_token */ - if (xqc_find_conns_hash(conn->engine->conns_hash_sr_token, conn, - cid->cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN)) - { - xqc_remove_conns_hash(conn->engine->conns_hash_sr_token, conn, - cid->cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN); + } + if (conn->engine->conns_hash_sr_token) { + /* delete relationship from conns_hash_sr_token */ + if (xqc_find_conns_hash(conn->engine->conns_hash_sr_token, conn, + cid->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN)) + { + xqc_remove_conns_hash(conn->engine->conns_hash_sr_token, conn, + cid->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN); + } } } } - xqc_destroy_cid_set(&conn->scid_set.cid_set); - xqc_destroy_cid_set(&conn->dcid_set.cid_set); + xqc_destroy_cid_set(&conn->scid_set); + xqc_destroy_cid_set(&conn->dcid_set); } - xqc_int_t xqc_conn_try_add_new_conn_id(xqc_connection_t *conn, uint64_t retire_prior_to) { - uint64_t active_cid_cnt = conn->scid_set.cid_set.unused_cnt + conn->scid_set.cid_set.used_cnt; - uint64_t unused_limit = 1; + xqc_int_t ret = XQC_OK; + uint8_t unused_limit = 2; + xqc_cid_set_inner_t *inner_set; + if (xqc_conn_is_handshake_confirmed(conn)) { - while (active_cid_cnt < conn->remote_settings.active_connection_id_limit - && conn->scid_set.cid_set.unused_cnt < unused_limit) + if (conn->enable_multipath && conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { - xqc_int_t ret = xqc_write_new_conn_id_frame_to_packet(conn, retire_prior_to); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_conn_id_frame_to_packet error|"); - return ret; + /* principle #1 there are two CIDs for the next path ID */ + inner_set = xqc_get_next_unused_path_cid_set(&conn->scid_set); + while (inner_set + && (inner_set->unused_cnt + inner_set->used_cnt) < conn->remote_settings.active_connection_id_limit + && inner_set->unused_cnt < unused_limit) + { + ret = xqc_write_mp_new_conn_id_frame_to_packet(conn, retire_prior_to, inner_set->path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_write_mp_new_conn_id_frame_to_packet error|path_id:%ui|", + inner_set->path_id); + return ret; + } + } + + /* principle #2 there are two CIDs for every in-use path ID */ + xqc_list_head_t *pos, *next; + xqc_list_for_each_safe(pos, next, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos, xqc_cid_set_inner_t, next); + if (inner_set->set_state == XQC_CID_SET_USED) { + while (inner_set + && (inner_set->unused_cnt + inner_set->used_cnt) < conn->remote_settings.active_connection_id_limit + && inner_set->unused_cnt < unused_limit) + { + ret = xqc_write_mp_new_conn_id_frame_to_packet(conn, retire_prior_to, inner_set->path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_write_mp_new_conn_id_frame_to_packet error|path_id:%ui|", + inner_set->path_id); + return ret; + } + } + } + } + + } else { + + inner_set = xqc_get_path_cid_set(&conn->scid_set, XQC_INITIAL_PATH_ID); + /* origin logic for new connection id */ + while ((inner_set->used_cnt + inner_set->unused_cnt) < conn->remote_settings.active_connection_id_limit + && inner_set->unused_cnt < unused_limit) + { + ret = xqc_write_new_conn_id_frame_to_packet(conn, retire_prior_to); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_conn_id_frame_to_packet error|"); + return ret; + } } - active_cid_cnt++; } } @@ -4727,13 +4892,13 @@ xqc_conn_check_dcid(xqc_connection_t *conn, xqc_cid_t *dcid) { xqc_int_t ret; - xqc_cid_inner_t *scid = xqc_cid_in_cid_set(&conn->scid_set.cid_set, dcid); + xqc_cid_inner_t *scid = xqc_cid_set_search_cid(&conn->scid_set, dcid); if (scid == NULL) { return -XQC_ECONN_CID_NOT_FOUND; } if (scid->state == XQC_CID_UNUSED) { - ret = xqc_cid_switch_to_next_state(&conn->scid_set.cid_set, scid, XQC_CID_USED); + ret = xqc_cid_switch_to_next_state(&conn->scid_set, scid, XQC_CID_USED, scid->cid.path_id); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_switch_to_next_state error|scid:%s|", xqc_scid_str(conn->engine, &scid->cid)); @@ -4749,9 +4914,9 @@ xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid) { xqc_int_t ret = XQC_OK; - ret = xqc_cid_switch_to_next_state(&conn->scid_set.cid_set, inner_cid, XQC_CID_RETIRED); + ret = xqc_cid_switch_to_next_state(&conn->scid_set, inner_cid, XQC_CID_RETIRED, inner_cid->cid.path_id); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|set cid retired error|ret:%d", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|set cid retired error|"); return ret; } @@ -4777,26 +4942,32 @@ xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid) /* switch another used scid to replace user_scid */ xqc_int_t -xqc_conn_update_user_scid(xqc_connection_t *conn, xqc_scid_set_t *scid_set) +xqc_conn_update_user_scid(xqc_connection_t *conn) { xqc_cid_inner_t *scid; xqc_list_head_t *pos, *next; - xqc_list_for_each_safe(pos, next, &scid_set->cid_set.list_head) { - scid = xqc_list_entry(pos, xqc_cid_inner_t, list); + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; - if (scid->state == XQC_CID_USED - && xqc_cid_is_equal(&scid_set->user_scid, &scid->cid) != XQC_OK) - { - if (conn->transport_cbs.conn_update_cid_notify) { - conn->transport_cbs.conn_update_cid_notify(conn, &scid_set->user_scid, &scid->cid, - xqc_conn_get_user_data(conn)); - } + xqc_list_for_each_safe(pos_set, next_set, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + scid = xqc_list_entry(pos, xqc_cid_inner_t, list); - // TODO: SCID changes - xqc_cid_copy(&scid_set->user_scid, &scid->cid); - xqc_datagram_record_mss(conn); - return XQC_OK; + if (scid->state == XQC_CID_USED + && xqc_cid_is_equal(&conn->scid_set.user_scid, &scid->cid) != XQC_OK) + { + if (conn->transport_cbs.conn_update_cid_notify) { + conn->transport_cbs.conn_update_cid_notify(conn, &conn->scid_set.user_scid, &scid->cid, + xqc_conn_get_user_data(conn)); + } + + xqc_cid_copy(&conn->scid_set.user_scid, &scid->cid); + xqc_datagram_record_mss(conn); + return XQC_OK; + } } } @@ -4944,7 +5115,6 @@ xqc_conn_on_recv_retry(xqc_connection_t *conn, xqc_cid_t *retry_scid) conn->conn_flag |= XQC_CONN_FLAG_RETRY_RECVD; /* change the DCID it uses for sending packets in response to Retry packet. */ - // TODO: DCID changes xqc_cid_copy(&conn->dcid_set.current_dcid, retry_scid); xqc_datagram_record_mss(conn); @@ -5035,6 +5205,7 @@ xqc_conn_set_remote_transport_params(xqc_connection_t *conn, settings->enable_multipath = params->enable_multipath; settings->multipath_version = params->multipath_version; + settings->init_max_path_id = params->init_max_path_id; settings->max_datagram_frame_size = params->max_datagram_frame_size; settings->close_dgram_redundancy = params->close_dgram_redundancy; @@ -5042,8 +5213,10 @@ xqc_conn_set_remote_transport_params(xqc_connection_t *conn, /* * set fec params to remote_settings */ - + + settings->fec_version = params->fec_version; if (params->fec_version != XQC_ERR_FEC_VERSION) { + // if current host enable fec encode, set decoder params of remote settings if (conn->conn_settings.enable_encode_fec) { settings->enable_decode_fec = params->enable_decode_fec; @@ -5056,7 +5229,6 @@ xqc_conn_set_remote_transport_params(xqc_connection_t *conn, if (conn->conn_settings.enable_decode_fec) { settings->enable_encode_fec = params->enable_encode_fec; settings->fec_max_symbols_num = params->fec_max_symbols_num; - settings->fec_max_symbol_size = params->fec_max_symbol_size; settings->fec_encoder_schemes_num = params->fec_encoder_schemes_num; for (xqc_int_t i = 0; i < settings->fec_encoder_schemes_num; i++) { settings->fec_encoder_schemes[i] = params->fec_encoder_schemes[i]; @@ -5103,6 +5275,7 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params params->no_crypto = settings->no_crypto; params->enable_multipath = settings->enable_multipath; params->multipath_version = settings->multipath_version; + params->init_max_path_id = settings->init_max_path_id; params->max_datagram_frame_size = settings->max_datagram_frame_size; params->close_dgram_redundancy = settings->close_dgram_redundancy; @@ -5110,7 +5283,6 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params #ifdef XQC_ENABLE_FEC if (conn->conn_settings.enable_encode_fec) { params->enable_encode_fec = settings->enable_encode_fec; - params->fec_max_symbol_size = settings->fec_max_symbol_size; params->fec_max_symbols_num = settings->fec_max_symbols_num; params->fec_encoder_schemes_num = settings->fec_encoder_schemes_num; for (xqc_int_t i = 0; i < settings->fec_encoder_schemes_num; i++) { @@ -5203,6 +5375,43 @@ xqc_conn_check_transport_params(xqc_connection_t *conn, const xqc_transport_para return XQC_OK; } +void +xqc_update_neg_info(xqc_connection_t *conn, xqc_transport_params_t params) +{ + xqc_trans_settings_t *ls = &conn->local_settings; + if (!ls->enable_encode_fec) { + conn->fec_neg_fail_reason |= XQC_LOCAL_NOT_SUPPORT_ENC; + } + if (!ls->enable_decode_fec) { + conn->fec_neg_fail_reason |= XQC_LOCAL_NOT_SUPPORT_DEC; + } + if (!params.enable_encode_fec) { + conn->fec_neg_fail_reason |= XQC_REMOTE_NOT_SUPPORT_ENC; + } + if (!params.enable_decode_fec) { + conn->fec_neg_fail_reason |= XQC_REMOTE_NOT_SUPPORT_DEC; + } +} + +void +xqc_check_fec_trans_param(xqc_connection_t *conn, xqc_transport_params_t params) +{ + if (params.enable_encode_fec) { + if (params.fec_max_symbols_num > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + conn->conn_settings.enable_decode_fec = 0; + conn->local_settings.enable_decode_fec = 0; + conn->fec_neg_fail_reason |= XQC_REMOTE_PARAM_ERR; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|remote_setting's max_symbol_number is too large to be decoded"); + } + if (params.fec_max_symbols_num == 0) { + conn->conn_settings.enable_decode_fec = 0; + conn->local_settings.enable_decode_fec = 0; + conn->fec_neg_fail_reason |= XQC_REMOTE_PARAM_ERR; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|remote_setting's max_symbol_number is zero"); + } + } +} + void xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) { @@ -5252,7 +5461,6 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) xqc_log(conn->log, XQC_LOG_DEBUG, "|1RTT_transport_params|max_datagram_frame_size:%ud|", conn->remote_settings.max_datagram_frame_size); - /* save no crypto flag */ if (params.no_crypto == 1) { conn->remote_settings.no_crypto = 1; @@ -5266,7 +5474,9 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) if (params.stateless_reset_token_present) { /* it is supposed to be only one existing cid in the dcid set, find the first node and copy the sr token to that cid */ - node = conn->dcid_set.cid_set.list_head.next; + //TODO: risky code + xqc_cid_set_inner_t *inner_set = xqc_get_path_cid_set(&conn->dcid_set, XQC_INITIAL_PATH_ID); + node = inner_set->cid_list.next; if (NULL != node) { cid_node = xqc_list_entry(node, xqc_cid_inner_t, list); xqc_memcpy(cid_node->cid.sr_token, params.stateless_reset_token, @@ -5299,6 +5509,13 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) re_encode_local_tp_flag = 1; } + ret = xqc_conn_try_to_enable_multipath(conn); + if(ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|enable multipath error|ret:%d|", ret); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return; + } /** Negotiate on whether send datagram redundancy on 1RTT packet; * on XQC_RED_NOT_USE(default): @@ -5326,24 +5543,22 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) #ifdef XQC_ENABLE_FEC + xqc_update_neg_info(conn, params); if (conn->conn_settings.enable_encode_fec || conn->conn_settings.enable_decode_fec) { + // update settings according to params + xqc_check_fec_trans_param(conn, params); ret = xqc_negotiate_fec_schemes(conn, params); if (ret == XQC_OK) { - if (conn->conn_type == XQC_CONN_TYPE_SERVER) { - re_encode_local_tp_flag = 1; - } - if (conn->conn_settings.fec_encode_callback.xqc_fec_init) { - conn->conn_settings.fec_encode_callback.xqc_fec_init(conn); - } - if (conn->conn_settings.fec_decode_callback.xqc_fec_init) { - conn->conn_settings.fec_decode_callback.xqc_fec_init(conn); - } + xqc_on_fec_negotiate_success(conn, params); + } + if (conn->conn_type == XQC_CONN_TYPE_SERVER) { + re_encode_local_tp_flag = 1; } } #endif - /* TODOfec:整合参数选择逻辑与更新 */ + // if local_settings needs to be updated, reencode local transport parameters if (re_encode_local_tp_flag) { uint8_t tp_buf[XQC_MAX_TRANSPORT_PARAM_BUF_LEN] = {0}; size_t tp_len = 0; @@ -5479,6 +5694,7 @@ xqc_settings_copy_from_transport_params(xqc_trans_settings_t *dest, dest->active_connection_id_limit = src->active_connection_id_limit; dest->enable_multipath = src->enable_multipath; + dest->init_max_path_id = src->init_max_path_id; dest->max_datagram_frame_size = src->max_datagram_frame_size; } @@ -5683,7 +5899,8 @@ xqc_conn_increase_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *p void -xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec_t now) +xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_send_ctl_t *ctl, + xqc_packet_out_t *packet_out, xqc_usec_t now) { xqc_stream_id_t stream_id; xqc_stream_t *stream[XQC_MAX_STREAM_FRAME_IN_PO] = {0}; @@ -5733,6 +5950,8 @@ xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_packet_out_t *p if (packet_out->po_flag & (XQC_POF_TLP | XQC_POF_LOST)) { stream[stream_cnt]->stream_stats.retrans_pkt_cnt++; } + stream[stream_cnt]->stream_stats.sent_pkt_cnt++; + stream[stream_cnt]->stream_stats.max_pto_backoff = xqc_max(stream[stream_cnt]->stream_stats.max_pto_backoff, ctl->ctl_pto_count); stream_cnt++; } } @@ -5760,6 +5979,31 @@ xqc_conn_get_max_pto(xqc_connection_t *conn) return max_pto; } +uint32_t +xqc_conn_get_max_pto_backoff(xqc_connection_t *conn, uint8_t available_only) +{ + xqc_path_ctx_t *path = NULL; + uint32_t max_pto = 0; + + xqc_list_head_t *pos, *next; + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + if (path->path_state != XQC_PATH_STATE_ACTIVE) { + continue; + } + + if (available_only + && path->app_path_status != XQC_APP_PATH_STATUS_AVAILABLE) + { + continue; + } + + max_pto = xqc_max(path->path_send_ctl->ctl_pto_count, max_pto); + } + + return max_pto; +} + xqc_usec_t xqc_conn_get_min_srtt(xqc_connection_t *conn, xqc_bool_t available_only) { @@ -6170,10 +6414,12 @@ xqc_int_t xqc_conn_handle_stateless_reset(xqc_connection_t *conn, const uint8_t *sr_token) { - xqc_int_t ret; - int res; - xqc_list_head_t *pos, *next; - xqc_cid_inner_t *cid; + xqc_int_t ret; + int res; + xqc_list_head_t *pos, *next; + xqc_cid_inner_t *cid; + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; if (NULL == conn || NULL == sr_token) { return -XQC_EPARAM; @@ -6185,20 +6431,31 @@ xqc_conn_handle_stateless_reset(xqc_connection_t *conn, } /* compare received stateless reset token with the ones peer sent */ - xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - - res = xqc_memcmp(sr_token, cid->cid.sr_token, - XQC_STATELESS_RESET_TOKENLEN); - if (0 == res) { - xqc_log(conn->log, XQC_LOG_INFO, "|====>|receive stateless reset" - "|cid:%s", xqc_dcid_str(conn->engine, &cid->cid)); - xqc_log_event(conn->log, TRA_STATELESS_RESET, conn); + xqc_list_for_each_safe(pos_set, next_set, &conn->dcid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - /* stateless reset received, close connection */ - xqc_conn_reset(conn); + res = xqc_memcmp(sr_token, cid->cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN); + if (0 == res) { + xqc_log(conn->log, XQC_LOG_INFO, "|====>|receive stateless reset" + "|cid:%s|sr_token:%s|", + xqc_dcid_str(conn->engine, &cid->cid), + xqc_sr_token_str(conn->engine, sr_token)); + xqc_log_event(conn->log, TRA_STATELESS_RESET, conn); + + if (inner_set->set_state < XQC_CID_SET_ABANDONED + && cid->state < XQC_CID_RETIRED) + { + /* only responds for non-retired CIDs */ + /* stateless reset received, close connection */ + xqc_conn_reset(conn); + } - goto end; + goto end; + } } } @@ -6262,68 +6519,3 @@ xqc_conn_handle_deprecated_stateless_reset(xqc_connection_t *conn, } #endif - - -/* Retire DCID on initial path. this is called when NEW_CONNECTION_ID frame with - Retire Prior To field is received. */ -xqc_int_t -xqc_conn_retire_dcid_prior_to(xqc_connection_t *conn, uint64_t retire_prior_to) -{ - xqc_int_t ret; - uint64_t seq_num; - xqc_cid_inner_t *inner_cid; - xqc_list_head_t *pos, *next; - - xqc_log(conn->log, XQC_LOG_DEBUG, "|retire cid prior to:%ui|current " - "largest_retire_prior_to:%ui|", retire_prior_to, - conn->dcid_set.largest_retire_prior_to); - - xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) { - - inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - seq_num = inner_cid->cid.cid_seq_num; - - if ((inner_cid->state == XQC_CID_UNUSED - || inner_cid->state == XQC_CID_USED) - && (seq_num >= conn->dcid_set.largest_retire_prior_to - && seq_num < retire_prior_to)) - { - ret = xqc_write_retire_conn_id_frame_to_packet(conn, seq_num); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, - "|xqc_write_retire_conn_id_frame_to_packet error|"); - return ret; - } - - /* change state */ - ret = xqc_cid_switch_to_next_state(&conn->dcid_set.cid_set, - inner_cid, XQC_CID_RETIRED); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|switch cid state to " - "RETIRED error|seq_num:%ui|cur_state:%d|", seq_num, - inner_cid->state); - } - - /* immediately delete cid */ - xqc_list_del(pos); - xqc_free(inner_cid); - - xqc_log(conn->log, XQC_LOG_INFO, "|cid[%ui] retired", seq_num); - } - } - - conn->dcid_set.largest_retire_prior_to = retire_prior_to; - - /* path dcid retired */ - if (conn->conn_initial_path->path_dcid.cid_seq_num < retire_prior_to) { - xqc_log(conn->log, XQC_LOG_DEBUG, ""); - xqc_cid_copy(&conn->conn_initial_path->path_dcid, - &conn->dcid_set.current_dcid); - } - - xqc_log(conn->log, XQC_LOG_DEBUG, "|retire_prior_to|%ui|increase to %ui" - "|cnt:%ui", conn->dcid_set.largest_retire_prior_to, - retire_prior_to, xqc_cid_set_cnt(&conn->dcid_set.cid_set)); - - return XQC_OK; -} diff --git a/src/transport/xqc_conn.h b/src/transport/xqc_conn.h index 96dc715c7..412cc5a43 100644 --- a/src/transport/xqc_conn.h +++ b/src/transport/xqc_conn.h @@ -120,7 +120,6 @@ typedef enum { XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT, XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT, XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT, - XQC_CONN_FLAG_NEW_CID_ACKED_SHIFT, XQC_CONN_FLAG_LINGER_CLOSING_SHIFT, XQC_CONN_FLAG_RETRY_RECVD_SHIFT, XQC_CONN_FLAG_TLS_CH_SHIFT, @@ -134,8 +133,7 @@ typedef enum { XQC_CONN_FLAG_PMTUD_PROBING_SHIFT, XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT, XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT, - XQC_CONN_FLAG_MP_WAIT_SCID_SHIFT, - XQC_CONN_FLAG_MP_WAIT_DCID_SHIFT, + XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT, XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT, XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT, XQC_CONN_FLAG_SHIFT_NUM, @@ -167,7 +165,6 @@ typedef enum { XQC_CONN_FLAG_HANDSHAKE_CONFIRMED = 1ULL << XQC_CONN_FLAG_HANDSHAKE_CONFIRMED_SHIFT, XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED = 1ULL << XQC_CONN_FLAG_HANDSHAKE_DONE_ACKED_SHIFT, XQC_CONN_FLAG_ADDR_VALIDATED = 1ULL << XQC_CONN_FLAG_ADDR_VALIDATED_SHIFT, - XQC_CONN_FLAG_NEW_CID_ACKED = 1ULL << XQC_CONN_FLAG_NEW_CID_ACKED_SHIFT, XQC_CONN_FLAG_LINGER_CLOSING = 1ULL << XQC_CONN_FLAG_LINGER_CLOSING_SHIFT, XQC_CONN_FLAG_RETRY_RECVD = 1ULL << XQC_CONN_FLAG_RETRY_RECVD_SHIFT, XQC_CONN_FLAG_TLS_CH_RECVD = 1ULL << XQC_CONN_FLAG_TLS_CH_SHIFT, @@ -181,8 +178,7 @@ typedef enum { XQC_CONN_FLAG_PMTUD_PROBING = 1ULL << XQC_CONN_FLAG_PMTUD_PROBING_SHIFT, XQC_CONN_FLAG_NO_DGRAM_NOTIFIED = 1ULL << XQC_CONN_FLAG_NO_DGRAM_NOTIFIED_SHIFT, XQC_CONN_FLAG_DGRAM_MSS_NOTIFY = 1ULL << XQC_CONN_FLAG_DGRAM_MSS_NOTIFY_SHIFT, - XQC_CONN_FLAG_MP_WAIT_SCID = 1ULL << XQC_CONN_FLAG_MP_WAIT_SCID_SHIFT, - XQC_CONN_FLAG_MP_WAIT_DCID = 1ULL << XQC_CONN_FLAG_MP_WAIT_DCID_SHIFT, + XQC_CONN_FLAG_MP_WAIT_MP_READY = 1ULL << XQC_CONN_FLAG_MP_WAIT_MP_READY_SHIFT, XQC_CONN_FLAG_MP_READY_NOTIFY = 1ULL << XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT, XQC_CONN_FLAG_HANDSHAKE_DONE_SENT = 1ULL << XQC_CONN_FLAG_HANDSHAKE_DONE_SENT_SHIFT, @@ -211,15 +207,17 @@ typedef struct { uint16_t max_datagram_frame_size; uint32_t conn_options[XQC_CO_MAX_NUM]; uint8_t conn_option_num; + + xqc_fec_version_t fec_version; uint64_t enable_encode_fec; uint64_t enable_decode_fec; - uint64_t fec_max_symbol_size; uint64_t fec_max_symbols_num; xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; xqc_int_t fec_encoder_schemes_num; xqc_int_t fec_decoder_schemes_num; xqc_dgram_red_setting_e close_dgram_redundancy; + uint64_t init_max_path_id; } xqc_trans_settings_t; @@ -280,8 +278,8 @@ struct xqc_connection_s { /* initial source connection id, RFC 9000, Section 7.3 */ xqc_cid_t initial_scid; - xqc_dcid_set_t dcid_set; - xqc_scid_set_t scid_set; + xqc_cid_set_t dcid_set; + xqc_cid_set_t scid_set; unsigned char peer_addr[sizeof(struct sockaddr_in6)]; socklen_t peer_addrlen; @@ -376,6 +374,10 @@ struct xqc_connection_s { uint32_t validated_path_count; uint32_t active_path_count; + uint64_t curr_max_path_id; + uint64_t local_max_path_id; + uint64_t remote_max_path_id; + /* for qlog */ uint32_t MTU_updated_count; uint32_t packet_dropped_count; @@ -450,7 +452,8 @@ struct xqc_connection_s { /* for fec */ xqc_fec_ctl_t *fec_ctl; - + uint32_t fec_neg_fail_reason; + /* receved pkts stats */ struct { @@ -583,11 +586,11 @@ void xqc_conn_process_packet_recved_path(xqc_connection_t *conn, xqc_cid_t *scid xqc_int_t xqc_conn_check_handshake_complete(xqc_connection_t *conn); -xqc_int_t xqc_conn_check_unused_cids(xqc_connection_t *conn); +xqc_int_t xqc_conn_get_available_path_id(xqc_connection_t *conn, uint64_t *path_id); xqc_int_t xqc_conn_try_add_new_conn_id(xqc_connection_t *conn, uint64_t retire_prior_to); xqc_int_t xqc_conn_check_dcid(xqc_connection_t *conn, xqc_cid_t *dcid); void xqc_conn_destroy_cids(xqc_connection_t *conn); -xqc_int_t xqc_conn_update_user_scid(xqc_connection_t *conn, xqc_scid_set_t *scid_set); +xqc_int_t xqc_conn_update_user_scid(xqc_connection_t *conn); xqc_int_t xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid); xqc_bool_t xqc_conn_peer_complete_address_validation(xqc_connection_t *c); @@ -613,7 +616,8 @@ xqc_int_t xqc_conn_confirm_key_update(xqc_connection_t *conn); /* from send_ctl */ void xqc_conn_decrease_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *packet_out); void xqc_conn_increase_unacked_stream_ref(xqc_connection_t *conn, xqc_packet_out_t *packet_out); -void xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec_t now); +void xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_send_ctl_t *ctl, + xqc_packet_out_t *packet_out, xqc_usec_t now); /* 选择所有path的PTO中最大的那个,作为conn的PTO,用于连接级别的定时器触发: * - XQC_TIMER_LINGER_CLOSE @@ -623,6 +627,8 @@ void xqc_conn_update_stream_stats_on_sent(xqc_connection_t *conn, xqc_packet_out */ xqc_usec_t xqc_conn_get_max_pto(xqc_connection_t *conn); +uint32_t xqc_conn_get_max_pto_backoff(xqc_connection_t *conn, uint8_t available_only); + void xqc_conn_ptmud_probing(xqc_connection_t *conn); /* 用于流控 */ @@ -684,12 +690,11 @@ xqc_int_t xqc_conn_send_ping_internal(xqc_connection_t *conn, void *ping_user_da void xqc_conn_encode_mp_settings(xqc_connection_t *conn, char *buf, size_t buf_sz); -xqc_int_t xqc_conn_retire_dcid_prior_to(xqc_connection_t *conn, uint64_t retire_prior_to); void xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_list_head_t *head, int congest, xqc_send_type_t send_type); -#ifdef XQC_ENABLE_FEC -void xqc_insert_fec_packets(xqc_connection_t *conn, xqc_list_head_t *head); -void xqc_insert_fec_packets_all(xqc_connection_t *conn); -#endif +xqc_int_t xqc_conn_try_to_enable_multipath(xqc_connection_t *conn); +xqc_int_t xqc_conn_add_path_cid_sets(xqc_connection_t *conn, uint32_t start, uint32_t end); + + #endif /* _XQC_CONN_H_INCLUDED_ */ diff --git a/src/transport/xqc_datagram.c b/src/transport/xqc_datagram.c index 13a763995..23f4cb646 100644 --- a/src/transport/xqc_datagram.c +++ b/src/transport/xqc_datagram.c @@ -239,11 +239,8 @@ xqc_int_t xqc_datagram_send(xqc_connection_t *conn, void *data, *dgram_id = dg_id; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); if (conn->conn_settings.datagram_redundant_probe && conn->dgram_probe_timer >= 0 @@ -258,7 +255,7 @@ xqc_int_t xqc_datagram_send(xqc_connection_t *conn, void *data, } /* call main logic to send packets out */ - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); return XQC_OK; } @@ -414,11 +411,8 @@ xqc_datagram_send_multiple_internal(xqc_connection_t *conn, } if (*sent_cnt > 0) { - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); data = iov[*sent_cnt - 1].iov_base; data_len = iov[*sent_cnt - 1].iov_len; @@ -436,7 +430,7 @@ xqc_datagram_send_multiple_internal(xqc_connection_t *conn, } /* call main logic to send packets out */ - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); } return ret < 0 ? ret : XQC_OK; diff --git a/src/transport/xqc_engine.c b/src/transport/xqc_engine.c index 4cde76bba..ecc57e9e2 100644 --- a/src/transport/xqc_engine.c +++ b/src/transport/xqc_engine.c @@ -18,7 +18,6 @@ #include "src/transport/xqc_packet_in.h" #include "src/transport/xqc_packet.h" #include "src/transport/xqc_cid.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_utils.h" #include "src/transport/xqc_timer.h" #include "src/transport/xqc_datagram.h" @@ -50,7 +49,7 @@ xqc_config_t default_client_config = { .reset_token_keylen = 0, .sendmmsg_on = 0, .enable_h3_ext = 0, - .log_disable = 0, + .manually_triggered_send = 0, }; @@ -73,7 +72,7 @@ xqc_config_t default_server_config = { .reset_token_keylen = 0, .sendmmsg_on = 0, .enable_h3_ext = 0, - .log_disable = 0, + .manually_triggered_send = 0, }; @@ -137,7 +136,6 @@ xqc_set_config(xqc_config_t *dst, const xqc_config_t *src) dst->cfg_log_level_name = src->cfg_log_level_name; dst->sendmmsg_on = src->sendmmsg_on; dst->enable_h3_ext = src->enable_h3_ext; - dst->log_disable = src->log_disable; return XQC_OK; } @@ -225,42 +223,32 @@ xqc_engine_conns_hash_destroy(xqc_str_hash_table_t *hash_table) } -xqc_pq_t * -xqc_engine_conns_pq_create(xqc_config_t *config) +int xqc_engine_conn_pq_operator(xqc_pq_t *pq, xqc_pq_element_t *e) { - xqc_pq_t *q = xqc_malloc(sizeof(xqc_pq_t)); - if (q == NULL) { - return NULL; + xqc_connection_t **conn; + conn = (xqc_connection_t**)e->data; + if (conn && *conn) { + (*conn)->wakeup_pq_index = xqc_pq_element_index(pq, e); } - - xqc_memzero(q, sizeof(xqc_pq_t)); - if (xqc_pq_init(q, sizeof(xqc_conns_pq_elem_t), - config->conns_active_pq_capacity, xqc_default_allocator, xqc_pq_revert_cmp)) - { - goto fail; - } - - return q; - -fail: - xqc_pq_destroy(q); - xqc_free(q); - return NULL; + return XQC_OK; } - -xqc_wakeup_pq_t * -xqc_engine_wakeup_pq_create(xqc_config_t *config) +xqc_pq_t * +xqc_engine_conns_pq_create(xqc_config_t *config, uint8_t is_wakeup) { - xqc_wakeup_pq_t *q = xqc_malloc(sizeof(xqc_wakeup_pq_t)); + xqc_pq_t *q = xqc_malloc(sizeof(xqc_pq_t)); if (q == NULL) { return NULL; } - xqc_memzero(q, sizeof(xqc_wakeup_pq_t)); + size_t capacity = is_wakeup == 1 ? + config->conns_wakeup_pq_capacity : + config->conns_active_pq_capacity; - if (xqc_wakeup_pq_init(q, config->conns_wakeup_pq_capacity, - xqc_default_allocator, xqc_wakeup_pq_revert_cmp)) + xqc_memzero(q, sizeof(xqc_pq_t)); + if (xqc_pq_init(q, sizeof(xqc_conns_pq_elem_t), + capacity, xqc_default_allocator, + xqc_pq_revert_cmp, xqc_engine_conn_pq_operator)) { goto fail; } @@ -268,7 +256,7 @@ xqc_engine_wakeup_pq_create(xqc_config_t *config) return q; fail: - xqc_wakeup_pq_destroy(q); + xqc_pq_destroy(q); xqc_free(q); return NULL; } @@ -315,23 +303,19 @@ xqc_engine_conns_pq_destroy(xqc_pq_t *q) xqc_free(q); } -void -xqc_engine_wakeup_pq_destroy(xqc_wakeup_pq_t *q) -{ - xqc_wakeup_pq_destroy(q); - xqc_free(q); -} - - xqc_usec_t xqc_engine_wakeup_after(xqc_engine_t *engine) { - xqc_wakeup_pq_elem_t *el = xqc_wakeup_pq_top(engine->conns_wait_wakeup_pq); + xqc_conns_pq_elem_t *el = xqc_conns_pq_top(engine->conns_wait_wakeup_pq); if (el) { xqc_usec_t now = xqc_monotonic_timestamp(); - return el->wakeup_time > now ? el->wakeup_time - now : 1; + xqc_log(engine->log, XQC_LOG_DEBUG, "|wakeup:%ui|now:%ui|diff:%ui|", + el->time_us, now, el->time_us - now); + return el->time_us > now ? el->time_us - now : 1; + } + xqc_log(engine->log, XQC_LOG_DEBUG, "|NULL wakeup top|"); return 0; } @@ -391,8 +375,8 @@ xqc_bool_t xqc_engine_check_config(xqc_engine_type_t engine_type, const xqc_config_t *engine_config, const xqc_engine_ssl_config_t *ssl_config, const xqc_transport_callbacks_t *transport_cbs) { - /* mismatch of sendmmsg_on enable and write_mmsg callback function */ - if (engine_config && engine_config->sendmmsg_on && transport_cbs->write_mmsg == NULL) { + /* mismatch of sendmmsg_on enable and write_mmsg & write_mmsg_ex callback function */ + if (engine_config && engine_config->sendmmsg_on && transport_cbs->write_mmsg == NULL && transport_cbs->write_mmsg_ex == NULL) { return XQC_FALSE; } @@ -444,58 +428,43 @@ xqc_engine_create(xqc_engine_type_t engine_type, xqc_engine_set_callback(engine, engine_callback, transport_cbs); engine->user_data = user_data; - engine->log_disable = engine->config->log_disable; engine->log = xqc_log_init(engine->config->cfg_log_level, engine->config->cfg_log_event, engine->config->cfg_qlog_importance, engine->config->cfg_log_timestamp, engine->config->cfg_log_level_name, engine, - &engine->eng_callback.log_callbacks, - engine->user_data); - + &engine->eng_callback.log_callbacks, engine->user_data); if (engine->log == NULL) { goto fail; } engine->rand_generator = xqc_random_generator_create(engine->log); if (engine->rand_generator == NULL) { - xqc_log(engine->log, XQC_LOG_ERROR, - "|unable to initialize random generator in engine|"); goto fail; } engine->conns_hash = xqc_engine_conns_hash_create(engine->config); if (engine->conns_hash == NULL) { - xqc_log(engine->log, XQC_LOG_ERROR, - "|unable to create connections hash|"); goto fail; } engine->conns_hash_dcid = xqc_engine_conns_hash_create(engine->config); if (engine->conns_hash_dcid == NULL) { - xqc_log(engine->log, XQC_LOG_ERROR, - "|unable to create connections hash for reset packets|"); goto fail; } engine->conns_hash_sr_token = xqc_engine_conns_hash_create(engine->config); if (engine->conns_hash_sr_token == NULL) { - xqc_log(engine->log, XQC_LOG_ERROR, - "|unable to create connections hash for stateless reset|"); goto fail; } - engine->conns_active_pq = xqc_engine_conns_pq_create(engine->config); + engine->conns_active_pq = xqc_engine_conns_pq_create(engine->config, 0); if (engine->conns_active_pq == NULL) { - xqc_log(engine->log, XQC_LOG_ERROR, - "|unable to create priority queue|"); goto fail; } - engine->conns_wait_wakeup_pq = xqc_engine_wakeup_pq_create(engine->config); + engine->conns_wait_wakeup_pq = xqc_engine_conns_pq_create(engine->config, 1); if (engine->conns_wait_wakeup_pq == NULL) { - xqc_log(engine->log, XQC_LOG_ERROR, - "|unable to create wakeup priority queue|"); goto fail; } @@ -504,12 +473,11 @@ xqc_engine_create(xqc_engine_type_t engine_type, engine->tls_ctx = xqc_tls_ctx_create((xqc_tls_type_t)engine->eng_type, ssl_config, &xqc_conn_tls_cbs, engine->log); if (NULL == engine->tls_ctx) { - xqc_log(engine->log, XQC_LOG_ERROR, "|create tls context error|"); + xqc_log(engine->log, XQC_LOG_ERROR, "|create tls context error"); goto fail; } } else { - xqc_log(engine->log, XQC_LOG_ERROR, "|invalid SSL configuration|"); goto fail; } @@ -523,22 +491,6 @@ xqc_engine_create(xqc_engine_type_t engine_type, } -xqc_connection_t * -xqc_conns_pq_pop_top_conn(xqc_pq_t *pq) -{ - /* used to traverse conns_pq */ - xqc_conns_pq_elem_t *el = xqc_conns_pq_top(pq); - if (XQC_UNLIKELY(el == NULL || el->conn == NULL)) { - xqc_conns_pq_pop(pq); - return NULL; - } - - xqc_connection_t *conn = el->conn; - xqc_conns_pq_pop(pq); - return conn; -} - - void xqc_engine_destroy(xqc_engine_t *engine) { @@ -566,32 +518,21 @@ xqc_engine_destroy(xqc_engine_t *engine) } conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - if (conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; - } - + /* active connections should never present in the wakeup queue */ xqc_conn_destroy(conn); } } if (engine->conns_wait_wakeup_pq) { - while (!xqc_wakeup_pq_empty(engine->conns_wait_wakeup_pq)) { + while (!xqc_pq_empty(engine->conns_wait_wakeup_pq)) { /* get conn from pq top and pop */ - xqc_wakeup_pq_elem_t *el = xqc_wakeup_pq_top(engine->conns_wait_wakeup_pq); - if (el == NULL || el->conn == NULL) { + conn = xqc_conns_pq_pop_top_conn(engine->conns_wait_wakeup_pq); + if (conn == NULL) { if (engine->log) { xqc_log(engine->log, XQC_LOG_ERROR, "|NULL ptr, skip|"); } - - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); continue; } - - /* get conn first then pop */ - conn = el->conn; - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); - conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; xqc_conn_destroy(conn); } @@ -603,7 +544,7 @@ xqc_engine_destroy(xqc_engine_t *engine) } if (engine->conns_wait_wakeup_pq) { - xqc_engine_wakeup_pq_destroy(engine->conns_wait_wakeup_pq); + xqc_engine_conns_pq_destroy(engine->conns_wait_wakeup_pq); engine->conns_wait_wakeup_pq = NULL; } @@ -792,27 +733,16 @@ xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) } if (conn->enable_multipath) { - - if (conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_SCID) { - if (conn->conn_flag & XQC_CONN_FLAG_NEW_CID_ACKED) { - conn->conn_flag &= ~XQC_CONN_FLAG_MP_WAIT_SCID; - conn->conn_flag &= ~XQC_CONN_FLAG_NEW_CID_ACKED; - conn->conn_flag |= XQC_CONN_FLAG_MP_READY_NOTIFY; - } - } - - if (conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_DCID - && !(conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_SCID)) + if ((conn->conn_flag & XQC_CONN_FLAG_MP_WAIT_MP_READY) + && xqc_conn_get_available_path_id(conn, NULL) == XQC_OK) { - conn->conn_flag &= ~XQC_CONN_FLAG_MP_WAIT_DCID; conn->conn_flag |= XQC_CONN_FLAG_MP_READY_NOTIFY; - } + conn->conn_flag &= ~XQC_CONN_FLAG_MP_WAIT_MP_READY; + } } /* for multi-path */ - if ((conn->conn_flag & XQC_CONN_FLAG_MP_READY_NOTIFY) - && xqc_conn_check_unused_cids(conn) == XQC_OK) - { + if (conn->conn_flag & XQC_CONN_FLAG_MP_READY_NOTIFY) { if (conn->transport_cbs.ready_to_create_path_notify) { conn->transport_cbs.ready_to_create_path_notify(&conn->scid_set.user_scid, xqc_conn_get_user_data(conn)); @@ -853,6 +783,10 @@ void xqc_engine_finish_recv (xqc_engine_t *engine) { xqc_engine_main_logic_internal(engine); } +void xqc_engine_finish_send (xqc_engine_t *engine) { + xqc_engine_main_logic_internal(engine); +} + void xqc_engine_main_logic_internal(xqc_engine_t *engine) { if (engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY) { @@ -864,6 +798,72 @@ void xqc_engine_main_logic_internal(xqc_engine_t *engine) { engine->eng_flag &= ~XQC_ENG_FLAG_NO_DESTROY; } +void +xqc_engine_conn_logic(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if (engine->eng_flag & XQC_ENG_FLAG_RUNNING) { + xqc_log(conn->log, XQC_LOG_DEBUG, + "|engine is running on conn:%s|", xqc_conn_addr_str(conn)); + return; + } + + engine->eng_flag |= XQC_ENG_FLAG_RUNNING; + + xqc_usec_t now = xqc_monotonic_timestamp(); + xqc_usec_t wake_after; + xqc_engine_process_conn(conn, now); + + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { + conn->last_ticked_time = now; + xqc_conn_schedule_packets_to_paths(conn); + + if (xqc_engine_is_sendmmsg_on(engine, conn)) { + xqc_conn_transmit_pto_probe_packets_batch(conn); + xqc_conn_retransmit_lost_packets_batch(conn); + xqc_conn_send_packets_batch(conn); + + } else { + xqc_conn_transmit_pto_probe_packets(conn); + xqc_conn_retransmit_lost_packets(conn); + xqc_conn_send_packets(conn); + } + + if (conn->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_AFTER_SEND) { + xqc_conn_reinject_unack_packets(conn, XQC_REINJ_UNACK_AFTER_SEND); + xqc_conn_send_packets(conn); + } + + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { + conn->next_tick_time = xqc_conn_next_wakeup_time(conn); + if (XQC_LIKELY(conn->next_tick_time != 0)) { + xqc_engine_remove_active_queue(engine, conn); + xqc_engine_add_wakeup_queue(engine, conn); + goto finish; + } + } + } + + conn->next_tick_time = 0; + xqc_engine_remove_active_queue(engine, conn); + xqc_engine_add_wakeup_queue(engine, conn); + +finish: + if (!xqc_pq_empty(engine->conns_active_pq)) { + /* If there are other acitve connections, we must wakeup immediately. */ + xqc_engine_wakeup_once(engine); + + } else { + wake_after = xqc_engine_wakeup_after(engine); + if (wake_after > 0) { + engine->eng_callback.set_event_timer(wake_after, engine->user_data); + } + } + + engine->eng_flag &= ~XQC_ENG_FLAG_RUNNING; + xqc_log(engine->log, XQC_LOG_DEBUG, "|END|"); + return; +} + /** * Process all connections @@ -877,31 +877,25 @@ xqc_engine_main_logic(xqc_engine_t *engine) } engine->eng_flag |= XQC_ENG_FLAG_RUNNING; - xqc_log(engine->log, XQC_LOG_DEBUG, "|BEGIN|"); - xqc_usec_t now = xqc_monotonic_timestamp(); xqc_connection_t *conn; - while (!xqc_wakeup_pq_empty(engine->conns_wait_wakeup_pq)) { - xqc_wakeup_pq_elem_t *el = xqc_wakeup_pq_top(engine->conns_wait_wakeup_pq); + xqc_log(engine->log, XQC_LOG_DEBUG, "|BEGIN|now:%ui|", now); + + while (!xqc_pq_empty(engine->conns_wait_wakeup_pq)) { + xqc_conns_pq_elem_t *el = xqc_conns_pq_top(engine->conns_wait_wakeup_pq); if (XQC_UNLIKELY(el == NULL || el->conn == NULL)) { - xqc_log(engine->log, XQC_LOG_ERROR, "|NULL ptr, skip|"); - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); /* no push between top and pop */ + xqc_log(engine->log, XQC_LOG_ERROR, "|wakeup|NULL ptr, skip|"); + xqc_conns_pq_pop(engine->conns_wait_wakeup_pq); /* no push between top and pop */ continue; } conn = el->conn; - if (el->wakeup_time <= now) { - xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); - conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; - - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - - } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|"); - } + if (el->time_us <= now) { + xqc_engine_remove_wakeup_queue(engine, conn); + if (xqc_engine_add_active_queue(engine, conn) != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|"); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); } } else { @@ -911,43 +905,20 @@ xqc_engine_main_logic(xqc_engine_t *engine) while (!xqc_pq_empty(engine->conns_active_pq)) { conn = xqc_conns_pq_pop_top_conn(engine->conns_active_pq); + if (XQC_UNLIKELY(conn == NULL)) { - xqc_log(engine->log, XQC_LOG_ERROR, "|NULL ptr, skip|"); + xqc_log(engine->log, XQC_LOG_ERROR, "|active|NULL ptr, skip|"); continue; } now = xqc_monotonic_timestamp(); xqc_engine_process_conn(conn, now); - - if (XQC_UNLIKELY(conn->conn_state == XQC_CONN_STATE_CLOSED)) { - conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { - xqc_log(engine->log, XQC_LOG_INFO, "|destroy conn from conns_active_pq while closed|" - "conn:%p|%s", conn, xqc_conn_addr_str(conn)); - xqc_conn_destroy(conn); - - } else { - if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - } - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, 0, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - } - continue; - - } else { + + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { conn->last_ticked_time = now; -#ifdef XQC_ENABLE_FEC - if (conn->conn_settings.enable_encode_fec - && conn->conn_settings.fec_params.fec_encoder_scheme) - { - xqc_insert_fec_packets_all(conn); - } - -#endif xqc_conn_schedule_packets_to_paths(conn); - if (xqc_engine_is_sendmmsg_on(engine)) { + if (xqc_engine_is_sendmmsg_on(engine, conn)) { xqc_conn_transmit_pto_probe_packets_batch(conn); xqc_conn_retransmit_lost_packets_batch(conn); xqc_conn_send_packets_batch(conn); @@ -963,63 +934,29 @@ xqc_engine_main_logic(xqc_engine_t *engine) xqc_conn_send_packets(conn); } - if (XQC_UNLIKELY(conn->conn_state == XQC_CONN_STATE_CLOSED)) { - conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { - xqc_log(engine->log, XQC_LOG_INFO, "|destroy conn from conns_active_pq after sending|" - "conn:%p|%s", conn, xqc_conn_addr_str(conn)); - - xqc_conn_destroy(conn); - - } else { - if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - } - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, 0, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; + if (XQC_LIKELY(conn->conn_state != XQC_CONN_STATE_CLOSED)) { + conn->next_tick_time = xqc_conn_next_wakeup_time(conn); + if (XQC_LIKELY(conn->next_tick_time != 0)) { + conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; + xqc_engine_add_wakeup_queue(engine, conn); + continue; } - continue; - } - - conn->next_tick_time = xqc_conn_next_wakeup_time(conn); - if (conn->next_tick_time) { - if (!(conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, conn->next_tick_time, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - - } else { - /* remove from pq then push again, update wakeup time */ - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, conn->next_tick_time, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - } - - } else { - /* it's unexpected that conn's tick timer is unset */ - xqc_log(conn->log, XQC_LOG_ERROR, "|destroy_connection|"); - conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; - - if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { - xqc_log(conn->log, XQC_LOG_ERROR, "|destroy unexpected conn with tick timer unset|"); - - xqc_conn_destroy(conn); - - } else { - if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { - xqc_wakeup_pq_remove(engine->conns_wait_wakeup_pq, conn); - } - xqc_wakeup_pq_push(engine->conns_wait_wakeup_pq, 0, conn); - conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; - } - continue; } } - /* - * xqc_engine_process_conn may insert conns_active_pq, XQC_CONN_FLAG_TICKING prevents - * duplicate insertions and must be placed after xqc_engine_process_conn. - */ + /* conn should be destroyed ( closed or next_tick_time = 0) */ conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; + if (!(engine->eng_flag & XQC_ENG_FLAG_NO_DESTROY)) { + xqc_log(engine->log, XQC_LOG_INFO, "|conn:%p|%s|" + "conn_state:%ud|next_tick_time:%ui", + conn, xqc_conn_addr_str(conn), + conn->conn_state, conn->next_tick_time); + xqc_conn_destroy(conn); + + } else { + conn->next_tick_time = 0; + xqc_engine_add_wakeup_queue(engine, conn); + } } xqc_usec_t wake_after = xqc_engine_wakeup_after(engine); @@ -1029,7 +966,7 @@ xqc_engine_main_logic(xqc_engine_t *engine) engine->eng_flag &= ~XQC_ENG_FLAG_RUNNING; - xqc_log(engine->log, XQC_LOG_DEBUG, "|END|"); + xqc_log(engine->log, XQC_LOG_DEBUG, "|END|now:%ui|", now); return; } @@ -1329,16 +1266,13 @@ xqc_engine_packet_process(xqc_engine_t *engine, recv_time, xqc_conn_get_idle_timeout(conn) * 1000); after_process: - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - - } else { - xqc_log(engine->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|conn:%p|", conn); - XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); - xqc_conn_destroy(conn); - return -XQC_EFATAL; - } + xqc_engine_remove_wakeup_queue(engine, conn); + + if (xqc_engine_add_active_queue(engine, conn) != XQC_OK) { + xqc_log(engine->log, XQC_LOG_ERROR, "|xqc_conns_pq_push error|conn:%p|", conn); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + xqc_conn_destroy(conn); + return -XQC_EFATAL; } /* main logic */ @@ -1356,6 +1290,12 @@ xqc_engine_packet_process(xqc_engine_t *engine, } + + + + + + uint8_t xqc_engine_config_get_cid_len(xqc_engine_t *engine) { @@ -1521,10 +1461,11 @@ xqc_engine_free_alpn_list(xqc_engine_t *engine) } xqc_bool_t -xqc_engine_is_sendmmsg_on(xqc_engine_t *engine) +xqc_engine_is_sendmmsg_on(xqc_engine_t *engine, xqc_connection_t *conn) { return engine->config->sendmmsg_on - && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex); + && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex) + && (!conn->conn_settings.disable_send_mmsg); } @@ -1545,3 +1486,58 @@ xqc_engine_set_priv_ctx(xqc_engine_t *engine, void *priv_ctx) engine->priv_ctx = priv_ctx; return XQC_OK; } + + +xqc_int_t +xqc_engine_add_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if (!(conn->conn_flag & (XQC_CONN_FLAG_WAIT_WAKEUP | XQC_CONN_FLAG_TICKING))) { + if(xqc_conns_pq_push(engine->conns_wait_wakeup_pq, + conn, conn->next_tick_time) != XQC_OK) + { + return -XQC_EMALLOC; + } + xqc_log(conn->log, XQC_LOG_DEBUG, "|next_tick_time:%ui|", conn->next_tick_time); + conn->conn_flag |= XQC_CONN_FLAG_WAIT_WAKEUP; + } + return XQC_OK; +} + +xqc_int_t +xqc_engine_remove_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if ((conn->conn_flag & XQC_CONN_FLAG_WAIT_WAKEUP)) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|next_tick_time:%ui|pq_index:%ud|", conn->next_tick_time, conn->wakeup_pq_index); + xqc_conns_pq_remove(engine->conns_wait_wakeup_pq, conn); + + conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; + } + return XQC_OK; +} + +xqc_int_t +xqc_engine_add_active_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + xqc_int_t ret = XQC_OK; + if (!(conn->conn_flag & (XQC_CONN_FLAG_WAIT_WAKEUP | XQC_CONN_FLAG_TICKING))) { + ret = xqc_conns_pq_push(engine->conns_active_pq, + conn, conn->last_ticked_time); + if (ret == 0) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|last_ticked_time:%ui|", conn->last_ticked_time); + conn->conn_flag |= XQC_CONN_FLAG_TICKING; + ret = XQC_OK; + } + } + return ret; +} + +xqc_int_t +xqc_engine_remove_active_queue(xqc_engine_t *engine, xqc_connection_t *conn) +{ + if ((conn->conn_flag & XQC_CONN_FLAG_TICKING)) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|last_ticked_time:%ui|pd_index:%ud|", conn->last_ticked_time, conn->wakeup_pq_index); + xqc_conns_pq_remove(engine->conns_active_pq, conn); + conn->conn_flag &= ~XQC_CONN_FLAG_TICKING; + } + return XQC_OK; +} \ No newline at end of file diff --git a/src/transport/xqc_engine.h b/src/transport/xqc_engine.h index e413f99c9..fc8d8ef45 100644 --- a/src/transport/xqc_engine.h +++ b/src/transport/xqc_engine.h @@ -50,15 +50,13 @@ typedef struct xqc_engine_s { xqc_str_hash_table_t *conns_hash_dcid; /* For reset packet */ xqc_str_hash_table_t *conns_hash_sr_token; /* For stateless reset */ xqc_pq_t *conns_active_pq; /* In process */ - xqc_wakeup_pq_t *conns_wait_wakeup_pq; /* Need wakeup after next tick time */ + xqc_pq_t *conns_wait_wakeup_pq; /* Need wakeup after next tick time */ uint8_t reset_sent_cnt[XQC_RESET_CNT_ARRAY_LEN]; /* remote addr hash */ xqc_usec_t reset_sent_cnt_cleared; /* tls context */ xqc_tls_ctx_t *tls_ctx; - /* common */ - xqc_bool_t log_disable; xqc_log_t *log; xqc_random_generator_t *rand_generator; @@ -112,9 +110,19 @@ void xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now); void xqc_engine_main_logic_internal(xqc_engine_t *engine); +void xqc_engine_conn_logic(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_add_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_remove_wakeup_queue(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_add_active_queue(xqc_engine_t *engine, xqc_connection_t *conn); + +xqc_int_t xqc_engine_remove_active_queue(xqc_engine_t *engine, xqc_connection_t *conn); + xqc_int_t xqc_engine_get_alpn_callbacks(xqc_engine_t *engine, const char *alpn, size_t alpn_len, xqc_app_proto_callbacks_t *cbs); -xqc_bool_t xqc_engine_is_sendmmsg_on(xqc_engine_t *engine); +xqc_bool_t xqc_engine_is_sendmmsg_on(xqc_engine_t *engine, xqc_connection_t *conn); #endif diff --git a/src/transport/xqc_fec.c b/src/transport/xqc_fec.c index 4cfed8687..4bf1dc99b 100644 --- a/src/transport/xqc_fec.c +++ b/src/transport/xqc_fec.c @@ -9,55 +9,65 @@ #include "src/transport/xqc_conn.h" #include "src/transport/xqc_send_queue.h" #include "src/transport/xqc_packet_out.h" -#include "src/transport/xqc_fec_scheme.h" #define XQC_FEC_MAX_SCHEME_VAL 32 xqc_int_t -xqc_is_fec_scheme_valid(xqc_fec_schemes_e scheme, xqc_fec_schemes_e *supported_schemes_buff, - xqc_int_t supported_schemes_buff_len) -{ - for (xqc_int_t i = 0; i < supported_schemes_buff_len; i++) { - if (scheme == supported_schemes_buff[i] - && xqc_is_fec_cb_exist(scheme) == XQC_OK) - { - return XQC_OK; - } - } - return -XQC_EFEC_NOT_SUPPORT_FEC; -} - -xqc_int_t -xqc_is_fec_cb_exist(xqc_fec_schemes_e scheme) +xqc_set_valid_encoder_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme) { switch (scheme) { +#ifdef XQC_ENABLE_RSC case XQC_REED_SOLOMON_CODE: + callback->xqc_fec_init = xqc_reed_solomon_code_cb.xqc_fec_init; + callback->xqc_fec_init_one = xqc_reed_solomon_code_cb.xqc_fec_init_one; + callback->xqc_fec_encode = xqc_reed_solomon_code_cb.xqc_fec_encode; + return XQC_OK; +#endif +#ifdef XQC_ENABLE_XOR case XQC_XOR_CODE: + callback->xqc_fec_init = xqc_xor_code_cb.xqc_fec_init; + callback->xqc_fec_init_one = xqc_xor_code_cb.xqc_fec_init_one; + callback->xqc_fec_encode = xqc_xor_code_cb.xqc_fec_encode; return XQC_OK; - - default: - return -XQC_EFEC_NOT_SUPPORT_FEC; +#endif +#ifdef XQC_ENABLE_PKM + case XQC_PACKET_MASK_CODE: + callback->xqc_fec_init = xqc_packet_mask_code_cb.xqc_fec_init; + callback->xqc_fec_init_one = xqc_packet_mask_code_cb.xqc_fec_init_one; + callback->xqc_fec_encode = xqc_packet_mask_code_cb.xqc_fec_encode; + return XQC_OK; +#endif } + + return -XQC_EFEC_SCHEME_ERROR; } xqc_int_t -xqc_set_valid_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme) +xqc_set_valid_decoder_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme) { switch (scheme) { +#ifdef XQC_ENABLE_RSC case XQC_REED_SOLOMON_CODE: - *callback = xqc_reed_solomon_code_cb; + callback->xqc_fec_decode = xqc_reed_solomon_code_cb.xqc_fec_decode; return XQC_OK; +#endif +#ifdef XQC_ENABLE_XOR case XQC_XOR_CODE: - *callback = xqc_xor_code_cb; + callback->xqc_fec_decode = xqc_xor_code_cb.xqc_fec_decode; + return XQC_OK; +#endif +#ifdef XQC_ENABLE_PKM + case XQC_PACKET_MASK_CODE: + callback->xqc_fec_decode_one = xqc_packet_mask_code_cb.xqc_fec_decode_one; return XQC_OK; +#endif } return -XQC_EFEC_SCHEME_ERROR; } - unsigned char * xqc_get_fec_scheme_str(xqc_fec_schemes_e scheme) { @@ -66,26 +76,42 @@ xqc_get_fec_scheme_str(xqc_fec_schemes_e scheme) return "Reed-Solomon"; case XQC_XOR_CODE: return "XOR"; - case XQC_PACKET_MASK: + case XQC_PACKET_MASK_CODE: return "Packet-Mask"; default: - return "Unknown"; + return "NO_FEC"; } } +unsigned char * +xqc_get_fec_mp_mode_str(xqc_fec_ctl_t *fec_ctl) +{ + if (fec_ctl == NULL) { + return "NO_FEC"; + } + if (fec_ctl->fec_mp_mode == XQC_FEC_MP_USE_STB) { + if (fec_ctl->fec_rep_path_id != XQC_MAX_UINT64_VALUE) { + return "USE_STB_PATH"; + } else { + return "NO_AVAI_STB_PATH"; + } + } + return "DEFAULT"; +} + xqc_int_t xqc_set_final_scheme(xqc_connection_t *conn, xqc_fec_schemes_e *local_fec_schemes_buff, xqc_int_t *local_fec_schemes_buff_len, - xqc_fec_schemes_e *remote_fec_schemes_buff, xqc_int_t remote_fec_schemes_buff_len, xqc_int_t *final_scheme, xqc_fec_code_callback_t *callback) + xqc_fec_schemes_e *remote_fec_schemes_buff, xqc_int_t remote_fec_schemes_buff_len) { uint32_t p, schemes_flag; - xqc_int_t i; + xqc_int_t i, ret; if (*local_fec_schemes_buff_len == 0 || remote_fec_schemes_buff_len == 0) { - return -XQC_EFEC_NOT_SUPPORT_FEC; + return 0; } p = schemes_flag = 0; - *final_scheme = 0; + ret = 0; for (i = 0; i < remote_fec_schemes_buff_len; i++) { if (remote_fec_schemes_buff[i] > XQC_FEC_MAX_SCHEME_VAL) { @@ -98,25 +124,12 @@ xqc_set_final_scheme(xqc_connection_t *conn, xqc_fec_schemes_e *local_fec_scheme /* 初始化schemes_flag */ for (i = 0; i < *local_fec_schemes_buff_len; i++) { if (schemes_flag & (1 << local_fec_schemes_buff[i])) { - *final_scheme = local_fec_schemes_buff[i]; + ret = local_fec_schemes_buff[i]; break; } } - if (*final_scheme == 0) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|Neither of the client and server have the same FEC scheme.|"); - return -XQC_EFEC_NOT_SUPPORT_FEC; - } - - if (xqc_set_valid_scheme_cb(callback, *final_scheme) != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_set_final_scheme|set valid scheme cb error|scheme_str: %s|scheme_num:%d|", xqc_get_fec_scheme_str(*final_scheme), *final_scheme); - return -XQC_EFEC_SCHEME_ERROR; - } - - local_fec_schemes_buff[0] = *final_scheme; - *local_fec_schemes_buff_len = 1; - xqc_log(conn->log, XQC_LOG_DEBUG, "|set final fec scheme: %s", xqc_get_fec_scheme_str(*final_scheme)); - return XQC_OK; + return ret; } xqc_int_t @@ -129,8 +142,8 @@ xqc_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out) case XQC_XOR_CODE: *out = XQC_XOR_CODE; return XQC_OK; - case XQC_PACKET_MASK: - *out = XQC_PACKET_MASK; + case XQC_PACKET_MASK_CODE: + *out = XQC_PACKET_MASK_CODE; return XQC_OK; default: break; @@ -161,12 +174,11 @@ xqc_set_fec_schemes(const xqc_fec_schemes_e *schemes, xqc_int_t schemes_len, fec_schemes_buff[j] = XQC_REED_SOLOMON_CODE; j++; break; - case XQC_PACKET_MASK: - fec_schemes_buff[j] = XQC_PACKET_MASK; + case XQC_PACKET_MASK_CODE: + fec_schemes_buff[j] = XQC_PACKET_MASK_CODE; j++; break; default: - /* TODOfec: 失败报错, 缺少报错途径 */ break; } @@ -177,26 +189,118 @@ xqc_set_fec_schemes(const xqc_fec_schemes_e *schemes, xqc_int_t schemes_len, return XQC_OK; } +/** + * @brief + * return XQC_TRUE if obj and cmp_buff has SAME payload content, + * otherwise return XQC_FALSE + * @param obj + * @param cmp_buff + * @return xqc_bool_t + */ +xqc_bool_t +xqc_fec_object_compare(xqc_fec_object_t *obj, unsigned char *cmp_buff) +{ + size_t obj_size; + unsigned char *obj_buff; + + if (!obj->is_valid) { + return XQC_FALSE; + } + obj_size = obj->payload_size; + obj_buff = obj->payload; + return xqc_memcmp(obj_buff, cmp_buff, obj_size) == 0 ? XQC_TRUE : XQC_FALSE; +} +xqc_int_t +xqc_send_repair_packets(xqc_connection_t *conn, xqc_fec_schemes_e scheme, xqc_list_head_t *prev, + xqc_bool_t *has_send_repair, uint8_t fec_bm_mode) +{ + uint32_t i, fss_esi, repair_num, pm_size, tmp_repair_num; + xqc_int_t ret; + unsigned char *rpr_key_p, *pm_p; + + *has_send_repair = XQC_FALSE; + repair_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + fss_esi = conn->fec_ctl->fec_send_block_num[fec_bm_mode]; + tmp_repair_num = 0; + + if (repair_num > XQC_REPAIR_LEN) { + xqc_log(conn->log ,XQC_LOG_ERROR, "|quic_fec|repair number exceeds buff size"); + return -XQC_EFEC_SYMBOL_ERROR; + } + if (repair_num > conn->fec_ctl->fec_send_symbol_num[fec_bm_mode]) { + xqc_log(conn->log, XQC_LOG_ERROR, "|source symbols number or repair symbol number invalid|src:%d|rpr:%d|", conn->fec_ctl->fec_send_symbol_num[fec_bm_mode], repair_num); + return -XQC_EFEC_SYMBOL_ERROR; + } + + switch (scheme) { + case XQC_REED_SOLOMON_CODE: + case XQC_XOR_CODE: + /* Generate repair packets. */ + ret = xqc_write_repair_packets(conn, fss_esi, prev, repair_num, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_gen_repair_packet error|"); + return -XQC_EWRITE_PKT; + } + *has_send_repair = XQC_TRUE; + break; + case XQC_PACKET_MASK_CODE: + for (i = 0; i < repair_num; i++) { + pm_p = conn->fec_ctl->fec_send_decode_matrix[fec_bm_mode][i]; + if (xqc_fec_object_compare(&conn->fec_ctl->fec_send_repair_key[fec_bm_mode][i], pm_p)) { + xqc_packet_out_t *packet_out = xqc_write_one_repair_packet(conn, fss_esi, tmp_repair_num, fec_bm_mode); + if (packet_out == NULL) { + xqc_log(conn->log ,XQC_LOG_ERROR, "|quic_fec|generate one repair packet error"); + continue; + } + tmp_repair_num++; + xqc_send_queue_move_to_head(&packet_out->po_list, prev); + *has_send_repair = XQC_TRUE; + prev = &packet_out->po_list; + } + } + break; + default: + xqc_log(conn->log ,XQC_LOG_ERROR, "|quic_fec|error type of fec scheme"); + return -XQC_EFEC_SCHEME_ERROR; + } + + return XQC_OK; +} + xqc_int_t xqc_is_packet_fec_protected(xqc_connection_t *conn, xqc_packet_out_t *packet_out) { - if (packet_out->po_frame_types & conn->conn_settings.fec_params.fec_protected_frames) { + if (packet_out->po_flag & XQC_POF_USE_FEC + && packet_out->po_frame_types & conn->conn_settings.fec_params.fec_protected_frames) + { return XQC_OK; } + return -XQC_EFEC_NOT_SUPPORT_FEC; } xqc_int_t -xqc_is_fec_params_valid(xqc_int_t src_symbol_num, xqc_int_t total_symbol_num, - xqc_int_t max_window_size) +xqc_check_fec_params(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t repair_symbol_num, + xqc_int_t max_window_size, xqc_int_t symbol_size) { - if (src_symbol_num <= 0 || src_symbol_num > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + if (repair_symbol_num < 0 || repair_symbol_num > XQC_REPAIR_LEN || repair_symbol_num > src_symbol_num) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid fec repair symbol:%d|src_num:%d|", repair_symbol_num, src_symbol_num); + return -XQC_EFEC_SCHEME_ERROR; + } + if (repair_symbol_num == 0) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|current code rate is too low to generate repair packets."); return -XQC_EFEC_SYMBOL_ERROR; } - if (total_symbol_num <= src_symbol_num) { + if (src_symbol_num <= 0 || src_symbol_num > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|src_symbol_num invalid|%d|", src_symbol_num); return -XQC_EFEC_SYMBOL_ERROR; } if (max_window_size <= 0 || max_window_size > XQC_SYMBOL_CACHE_LEN) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|max_window_size invalid|%d|", max_window_size); + return -XQC_EFEC_SYMBOL_ERROR; + } + if (symbol_size < 0 || symbol_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|symbol_size invalid|%d|", symbol_size); return -XQC_EFEC_SYMBOL_ERROR; } @@ -205,82 +309,50 @@ xqc_is_fec_params_valid(xqc_int_t src_symbol_num, xqc_int_t total_symbol_num, /* process fec protected packet with stream mode */ xqc_int_t -xqc_process_fec_protected_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +xqc_process_fec_protected_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_bool_t *if_add_repair) { - xqc_int_t i, ret, fss_esi, header_len, payload_len, symbol_idx, max_src_symbol_num, max_total_symbol_num, max_symbol_size; - unsigned char *p; - - symbol_idx = 0; - max_src_symbol_num = conn->local_settings.fec_max_symbols_num; - max_total_symbol_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block; - max_symbol_size = conn->conn_settings.fec_params.fec_max_symbol_size; - - if (xqc_is_packet_fec_protected(conn, packet_out) != XQC_OK) { - return -XQC_EFEC_NOT_SUPPORT_FEC; - } - - if (xqc_is_fec_params_valid(max_src_symbol_num, max_total_symbol_num, conn->conn_settings.fec_params.fec_max_window_size) != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_is_fec_params_valid|fec params invalid|"); - return -XQC_EFEC_SYMBOL_ERROR; - } - - if (packet_out->po_frame_types & XQC_FRAME_BIT_SID - || packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL) - { - return XQC_OK; - } + uint8_t fec_bm_mode; + xqc_int_t i, ret, fss_esi, header_len, payload_len, max_src_symbol_num, repair_symbol_num; + unsigned char *p; header_len = packet_out->po_payload - packet_out->po_buf; payload_len = packet_out->po_used_size - header_len; - if (max_symbol_size < payload_len) { - return -XQC_EFEC_NOT_SUPPORT_FEC; - } - /* padding symbol to max symbol size */ - ret = xqc_gen_padding_frame_with_len(conn, packet_out, max_symbol_size - payload_len, - XQC_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_FEC_SPACE); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_process_fec_protected_packet|packet header is larger than expected(32 bytes)"); - return -XQC_EFEC_SYMBOL_ERROR; - } + fec_bm_mode = packet_out->po_stream_fec_blk_mode; + max_src_symbol_num = xqc_get_fec_blk_size(conn, fec_bm_mode); + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; - symbol_idx = conn->fec_ctl->fec_send_src_symbols_num % max_src_symbol_num; - payload_len = packet_out->po_used_size - header_len; - if (payload_len != max_symbol_size) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|payload len is not equal to fec max symbol size|"); - return -XQC_EFEC_SYMBOL_ERROR; + ret = xqc_check_fec_params(conn, max_src_symbol_num, repair_symbol_num, conn->conn_settings.fec_params.fec_max_window_size, payload_len); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_is_fec_params_valid|fec params invalid|"); + return -XQC_EPARAM; } - /* 为当前packet 生成SID Frame */ + /* attach sid frame to current packet */ ret = xqc_write_sid_frame_to_one_packet(conn, packet_out); - if (ret != XQC_OK) { + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return XQC_OK; + + } else if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_write_sid_frame_to_one_packet error|"); return -XQC_EFEC_SYMBOL_ERROR; } + /* FEC encoder */ - ret = xqc_fec_encoder(conn, packet_out->po_payload); + ret = xqc_fec_encoder(conn, packet_out->po_payload, payload_len, fec_bm_mode); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_fec_encoder error|"); + xqc_fec_ctl_init_send_params(conn, fec_bm_mode); return ret; } - conn->fec_ctl->fec_send_src_symbols_num += 1; - /* Whether current symbol is the final of one block. */ - symbol_idx = conn->fec_ctl->fec_send_src_symbols_num % max_src_symbol_num; - if (symbol_idx == 0) { - fss_esi = conn->fec_ctl->fec_send_src_symbols_num - max_src_symbol_num; - - /* Generate repair packets. */ - ret = xqc_write_repair_packets(conn, fss_esi, &packet_out->po_list); + conn->fec_ctl->fec_send_symbol_num[fec_bm_mode] += 1; + /* Try to generate repair packets, only succeed when send_symbol_numbers satisfy the limits */ + if (conn->fec_ctl->fec_send_symbol_num[fec_bm_mode] == max_src_symbol_num) { + ret = xqc_send_repair_packets(conn, conn->conn_settings.fec_params.fec_encoder_scheme, &packet_out->po_list, if_add_repair, fec_bm_mode); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_gen_repair_packet error|"); - return -XQC_EWRITE_PKT; - } - /* Free the src symbol buff after we've finished the process of the block. */ - xqc_fec_ctl_init_send_params(conn->fec_ctl); - if (conn->fec_ctl->fec_send_src_symbols_num >= XQC_FEC_MAX_SYMBOL_PAYLOAD_ID) { - conn->fec_ctl->fec_send_src_symbols_num = 0; - fss_esi = 0; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_send_repair_packets error: %d|", ret); } + xqc_fec_ctl_init_send_params(conn, fec_bm_mode); } return XQC_OK; @@ -288,13 +360,14 @@ xqc_process_fec_protected_packet(xqc_connection_t *conn, xqc_packet_out_t *packe xqc_int_t -xqc_gen_src_payload_id(xqc_fec_ctl_t *fec_ctl, uint64_t *payload_id) +xqc_gen_src_payload_id(xqc_fec_ctl_t *fec_ctl, uint64_t *payload_id, uint8_t bm_idx) { xqc_connection_t *conn = fec_ctl->conn; - if (fec_ctl->fec_send_src_symbols_num < 0 || fec_ctl->fec_send_src_symbols_num >= XQC_FEC_MAX_SYMBOL_PAYLOAD_ID) { + + if (fec_ctl->fec_send_block_num[bm_idx] > XQC_FEC_MAX_BLOCK_NUM || fec_ctl->fec_send_symbol_num[bm_idx] > XQC_FEC_MAX_SYMBOL_NUM) { return -XQC_EFEC_SYMBOL_ERROR; } - *payload_id = fec_ctl->fec_send_src_symbols_num; + *payload_id = fec_ctl->fec_send_block_num[bm_idx] << 8 | fec_ctl->fec_send_symbol_num[bm_idx]; return XQC_OK; } @@ -302,92 +375,152 @@ xqc_fec_ctl_t * xqc_fec_ctl_create(xqc_connection_t *conn) { xqc_int_t i, j; + uint32_t repair_num; xqc_fec_ctl_t *fec_ctl = NULL; - - fec_ctl = xqc_malloc(sizeof(xqc_fec_ctl_t)); + + fec_ctl = xqc_calloc(1, sizeof(xqc_fec_ctl_t)); if (fec_ctl == NULL) { return NULL; } fec_ctl->conn = conn; - fec_ctl->fec_flow_id = 0; - fec_ctl->fec_recover_pkt_cnt = 0; - fec_ctl->fec_processed_blk_num = 0; - fec_ctl->fec_flush_blk_cnt = 0; - fec_ctl->fec_recover_failed_cnt = 0; - fec_ctl->fec_ignore_blk_cnt = 0; - fec_ctl->fec_recv_repair_num = 0; + if (conn->conn_settings.fec_params.fec_code_rate == 0) { + fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ] = 1; - fec_ctl->fec_send_src_symbols_num = 0; - fec_ctl->fec_send_repair_symbols_num = 0; + } else { + repair_num = xqc_max(1, conn->conn_settings.fec_params.fec_max_symbol_num_per_block * conn->conn_settings.fec_params.fec_code_rate); + fec_ctl->fec_send_required_repair_num[XQC_DEFAULT_SIZE_REQ] = xqc_min(repair_num, XQC_REPAIR_LEN); + } + if (conn->conn_settings.enable_multipath) { + fec_ctl->fec_mp_mode = conn->conn_settings.fec_params.fec_mp_mode; + } + fec_ctl->fec_rep_path_id = XQC_MAX_UINT64_VALUE; for (i = 0; i < XQC_REPAIR_LEN; i++) { - unsigned char *key_p = xqc_calloc(1, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK); - xqc_set_object_value(&fec_ctl->fec_send_repair_key[i], 0, key_p, 0); - - unsigned char *syb_p = xqc_calloc(1, XQC_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_HEADER_SPACE - XQC_FEC_SPACE); - xqc_set_object_value(&fec_ctl->fec_send_repair_symbols_buff[i], 0, syb_p, 0); + unsigned char *recv_syb_p = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + if (recv_syb_p == NULL) { + goto process_emalloc; + } + xqc_set_object_value(&fec_ctl->fec_gen_repair_symbols_buff[i], 0, recv_syb_p, 0); } - for (i = 0; i < XQC_SYMBOL_CACHE_LEN; i++) { - fec_ctl->fec_recv_block_idx[i] = -1; - fec_ctl->fec_recv_symbols_num[i] = 0; - fec_ctl->fec_recv_repair_symbols_num[i] = 0; - fec_ctl->fec_recv_symbols_flag[i] = 0; - for (j = 0; j < XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; j++) { - unsigned char *syb_p = xqc_calloc(1, XQC_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_HEADER_SPACE - XQC_FEC_SPACE); - xqc_set_object_value(&fec_ctl->fec_recv_symbols_buff[i][j], 0, syb_p, 0); + for (i = 0; i < XQC_BLOCK_MODE_LEN; i++) { + if (i == XQC_SLIM_SIZE_REQ) { + continue; } + fec_ctl->fec_send_block_num[i] = i; for (j = 0; j < XQC_REPAIR_LEN; j++) { - unsigned char *key_p = xqc_calloc(1, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK); - xqc_set_object_value(&fec_ctl->fec_recv_repair_key[i][j], 0, key_p, 0); + unsigned char *key_p = xqc_calloc(XQC_MAX_RPR_KEY_SIZE, sizeof(unsigned char)); + if (key_p == NULL) { + goto process_emalloc; + } + xqc_set_object_value(&fec_ctl->fec_send_repair_key[i][j], 0, key_p, 0); + + unsigned char *syb_p = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + if (syb_p == NULL) { + goto process_emalloc; + } + xqc_set_object_value(&fec_ctl->fec_send_repair_symbols_buff[i][j], 0, syb_p, 0); } } + // FEC 2.0: init repair symbols list and source symbols list + fec_ctl->fec_src_syb_num = 0; + fec_ctl->fec_rpr_syb_num = 0; + xqc_init_list_head(&fec_ctl->fec_recv_rpr_syb_list); + xqc_init_list_head(&fec_ctl->fec_recv_src_syb_list); + xqc_init_list_head(&fec_ctl->fec_free_src_list); + xqc_init_list_head(&fec_ctl->fec_free_rpr_list); + return fec_ctl; +process_emalloc: + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|create_fec_ctl fail to malloc for params"); + xqc_fec_ctl_destroy(fec_ctl); + return NULL; } void xqc_fec_ctl_destroy(xqc_fec_ctl_t *fec_ctl) { xqc_int_t i, j; + xqc_list_head_t *pos, *next; + fec_ctl->fec_flow_id = 0; - fec_ctl->fec_send_src_symbols_num = 0; - fec_ctl->fec_send_repair_symbols_num = 0; for (i = 0; i < XQC_REPAIR_LEN; i++) { - if (fec_ctl->fec_send_repair_key[i].payload != NULL) { - xqc_free(fec_ctl->fec_send_repair_key[i].payload); - fec_ctl->fec_send_repair_key[i].is_valid = 0; - } - if (fec_ctl->fec_send_repair_symbols_buff[i].payload != NULL) { - xqc_free(fec_ctl->fec_send_repair_symbols_buff[i].payload); - fec_ctl->fec_send_repair_symbols_buff[i].is_valid = 0; + if (fec_ctl->fec_gen_repair_symbols_buff[i].payload != NULL) { + xqc_free(fec_ctl->fec_gen_repair_symbols_buff[i].payload); + fec_ctl->fec_gen_repair_symbols_buff[i].is_valid = 0; } } - for (i = 0; i < XQC_SYMBOL_CACHE_LEN; i++) { - fec_ctl->fec_recv_symbols_flag[i] = 0; - fec_ctl->fec_recv_symbols_num[i] = 0; - fec_ctl->fec_recv_block_idx[i] = 0; - - for (j = 0; j < XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; j++) { - if (fec_ctl->fec_recv_symbols_buff[i][j].payload != NULL) { - xqc_free(fec_ctl->fec_recv_symbols_buff[i][j].payload); - fec_ctl->fec_recv_symbols_buff[i][j].is_valid = 0; - } + for (i = 0; i < XQC_BLOCK_MODE_LEN; i++) { + if (i == XQC_SLIM_SIZE_REQ) { + continue; } + fec_ctl->fec_send_symbol_num[i] = 0; + fec_ctl->fec_send_block_num[i] = 0; for (j = 0; j < XQC_REPAIR_LEN; j++) { - if (fec_ctl->fec_recv_repair_key[i][j].payload != NULL) { - xqc_free(fec_ctl->fec_recv_repair_key[i][j].payload); - fec_ctl->fec_recv_repair_key[i][j].is_valid = 0; + if (fec_ctl->fec_send_repair_key[i][j].payload != NULL) { + xqc_free(fec_ctl->fec_send_repair_key[i][j].payload); + fec_ctl->fec_send_repair_key[i][j].is_valid = 0; + } + if (fec_ctl->fec_send_repair_symbols_buff[i][j].payload != NULL) { + xqc_free(fec_ctl->fec_send_repair_symbols_buff[i][j].payload); + fec_ctl->fec_send_repair_symbols_buff[i][j].is_valid = 0; } } } + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol); + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol); + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_free_src_list) { + xqc_fec_src_syb_t *symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol); + } + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_free_rpr_list) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + xqc_free(symbol->payload); + xqc_free(symbol->repair_key); + xqc_free(symbol->recv_mask); + xqc_free(symbol); + } + xqc_free(fec_ctl); } +void +xqc_set_fec_blk_size(xqc_connection_t *conn, xqc_transport_params_t params) +{ + switch (params.fec_version) { + case XQC_FEC_02: + xqc_memcpy(conn->fec_ctl->fec_send_block_mode_size, fec_blk_size_v2, XQC_BLOCK_MODE_LEN); + break; + + default: + break; + } +} + +uint8_t +xqc_get_fec_blk_size(xqc_connection_t *conn, uint8_t blk_md) { + if (blk_md == XQC_DEFAULT_SIZE_REQ) { + return xqc_min(XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, xqc_max(0, conn->conn_settings.fec_params.fec_max_symbol_num_per_block)); + } + return conn->fec_ctl->fec_send_block_mode_size[blk_md]; +} xqc_int_t xqc_fec_ctl_save_symbol(unsigned char **symbol_buff_addr, const unsigned char *data, @@ -402,23 +535,45 @@ xqc_fec_ctl_save_symbol(unsigned char **symbol_buff_addr, const unsigned char *d } xqc_int_t -xqc_fec_ctl_init_send_params(xqc_fec_ctl_t *fec_ctl) +xqc_fec_ctl_init_send_params(xqc_connection_t *conn, uint8_t bm_idx) { + double loss_rate; + uint32_t send_repair_num; xqc_int_t i, symbol_size, key_size; - + xqc_fec_ctl_t *fec_ctl = conn->fec_ctl; + symbol_size = key_size = 0; - fec_ctl->fec_send_repair_symbols_num = 0; + fec_ctl->fec_send_symbol_num[bm_idx] = 0; for (i = 0 ; i < XQC_REPAIR_LEN; i++) { - if (fec_ctl->fec_send_repair_key[i].is_valid) { - xqc_init_object_value(&fec_ctl->fec_send_repair_key[i]); + if (conn->conn_settings.fec_params.fec_encoder_scheme != XQC_REED_SOLOMON_CODE) { + if (fec_ctl->fec_send_repair_key[bm_idx][i].is_valid) { + fec_ctl->fec_send_repair_key[bm_idx][i].payload_size = XQC_MAX_RPR_KEY_SIZE; + xqc_init_object_value(&fec_ctl->fec_send_repair_key[bm_idx][i]); + } } - - if (fec_ctl->fec_send_repair_symbols_buff[i].is_valid) { - xqc_init_object_value(&fec_ctl->fec_send_repair_symbols_buff[i]); + if (fec_ctl->fec_send_repair_symbols_buff[bm_idx][i].is_valid) { + fec_ctl->fec_send_repair_symbols_buff[bm_idx][i].payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_init_object_value(&fec_ctl->fec_send_repair_symbols_buff[bm_idx][i]); } } + // each time init send param, add 1 to send_block_num, so that symbol from different block won't be mixed + if (conn->fec_ctl->fec_send_block_num[bm_idx] >= XQC_FEC_MAX_BLOCK_NUM - XQC_BLOCK_MODE_LEN) { + conn->fec_ctl->fec_send_block_num[bm_idx] = bm_idx; + + } else { + conn->fec_ctl->fec_send_block_num[bm_idx] += XQC_BLOCK_MODE_LEN; + } + if (conn->conn_settings.fec_params.fec_code_rate == 0 && conn->conn_settings.fec_params.fec_encoder_scheme != XQC_XOR_CODE) { + loss_rate = xqc_conn_recent_loss_rate(conn); + send_repair_num = xqc_min(XQC_REPAIR_LEN, xqc_max(1, (int)(loss_rate * xqc_get_fec_blk_size(conn, bm_idx) / 100))); + if (conn->fec_ctl->fec_send_required_repair_num[bm_idx] != send_repair_num) { + // edit encode repair key + conn->fec_ctl->fec_send_required_repair_num[bm_idx] = send_repair_num; + conn->conn_settings.fec_callback.xqc_fec_init_one(conn, bm_idx); + } + } return XQC_OK; } @@ -428,7 +583,7 @@ xqc_set_object_value(xqc_fec_object_t *object, xqc_int_t is_valid, { object->is_valid = is_valid; object->payload = payload; - object->payload_size = size; + object->payload_size = xqc_min(XQC_MAX_SYMBOL_SIZE, size); } void @@ -439,24 +594,72 @@ xqc_init_object_value(xqc_fec_object_t *object) object->payload_size = 0; } +void +xqc_init_src_symbol_value(xqc_fec_src_syb_t *symbol) +{ + symbol->block_id = 0; + symbol->symbol_idx = 0; + xqc_memset(symbol->payload, 0, xqc_min(XQC_MAX_SYMBOL_SIZE, symbol->payload_size)); + symbol->payload_size = 0; +} + +void +xqc_init_rpr_symbol_value(xqc_fec_rpr_syb_t *symbol) +{ + symbol->block_id = 0; + symbol->symbol_idx = 0; + xqc_memset(symbol->payload, 0, XQC_MAX_SYMBOL_SIZE); + symbol->payload_size = 0; + xqc_memset(symbol->repair_key, 0, XQC_MAX_RPR_KEY_SIZE); + xqc_memset(symbol->recv_mask, 0, XQC_MAX_RPR_KEY_SIZE); + symbol->repair_key_size = 0; +} + +void +xqc_remove_src_symbol_from_list(xqc_fec_ctl_t *fec_ctl, xqc_fec_src_syb_t *src_symbol) +{ + xqc_list_del_init(&src_symbol->fec_list); + xqc_init_src_symbol_value(src_symbol); + // save payload for further uses + xqc_list_add_tail(&src_symbol->fec_list, &fec_ctl->fec_free_src_list); + fec_ctl->fec_src_syb_num--; +} + +void +xqc_remove_rpr_symbol_from_list(xqc_fec_ctl_t *fec_ctl, xqc_fec_rpr_syb_t *rpr_symbol) +{ + xqc_list_del_init(&rpr_symbol->fec_list); + xqc_init_rpr_symbol_value(rpr_symbol); + // save payload for further uses + xqc_list_add_tail(&rpr_symbol->fec_list, &fec_ctl->fec_free_rpr_list); + fec_ctl->fec_rpr_syb_num--; +} + xqc_int_t -xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, xqc_int_t block_idx) +xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) { xqc_int_t j, symbol_size, key_size; + xqc_list_head_t *pos, *next; - fec_ctl->fec_recv_symbols_num[block_idx] = 0; - fec_ctl->fec_recv_repair_symbols_num[block_idx] = 0; - fec_ctl->fec_recv_symbols_flag[block_idx] = 0; - for (j = 0; j < XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; j++) { - if (fec_ctl->fec_recv_symbols_buff[block_idx][j].is_valid) { - xqc_init_object_value(&fec_ctl->fec_recv_symbols_buff[block_idx][j]); + // FEC 2.0 update symbols list + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id > block_id) { + break; + } + if (src_symbol->block_id == block_id) { + xqc_remove_src_symbol_from_list(fec_ctl, src_symbol); } } - for (j = 0; j < XQC_REPAIR_LEN; j++) { - if (fec_ctl->fec_recv_repair_key[block_idx][j].is_valid) { - xqc_init_object_value(&fec_ctl->fec_recv_repair_key[block_idx][j]); + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_id) { + break; + } + if (rpr_symbol->block_id == block_id) { + xqc_remove_rpr_symbol_from_list(fec_ctl, rpr_symbol); } } @@ -466,8 +669,8 @@ xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, xqc_int_t block_idx) xqc_int_t xqc_negotiate_fec_schemes(xqc_connection_t *conn, xqc_transport_params_t params) { - xqc_int_t ret; - + xqc_int_t ret, encode_scheme, decode_scheme; + xqc_trans_settings_t *ls = &conn->local_settings; ret = -XQC_EFEC_NOT_SUPPORT_FEC; /* * 如果对端发来了多种FEC schemes选择,接收端需要选择其中的一种FEC schemes并重新encode local_settings @@ -479,185 +682,708 @@ xqc_negotiate_fec_schemes(xqc_connection_t *conn, xqc_transport_params_t params) */ if (params.fec_version == XQC_ERR_FEC_VERSION) { xqc_log(conn->log, XQC_LOG_DEBUG, "|remote fec version is not supported."); - conn->conn_settings.enable_encode_fec = 0; - conn->conn_settings.enable_decode_fec = 0; + conn->fec_neg_fail_reason |= XQC_OLD_FEC_VERSION; return ret; } - if (conn->conn_type == XQC_CONN_TYPE_SERVER) { - /* server as encoder */ - if (params.enable_decode_fec - && params.fec_decoder_schemes_num > 0 - && conn->local_settings.enable_encode_fec - && conn->local_settings.fec_encoder_schemes_num > 0 - && xqc_set_final_scheme(conn, conn->local_settings.fec_encoder_schemes, &conn->local_settings.fec_encoder_schemes_num, params.fec_decoder_schemes, - params.fec_decoder_schemes_num, &conn->conn_settings.fec_params.fec_encoder_scheme, &conn->conn_settings.fec_encode_callback) == XQC_OK) + if (ls->enable_encode_fec && params.enable_decode_fec) { + // server should provide only 1 scheme if negotiation success; + if (conn->conn_type == XQC_CONN_TYPE_CLIENT + && params.fec_decoder_schemes_num > 1) { - /* TODOfec:变长数组/单测 */ - /* 设置重新编码至transport param的flag */ - xqc_log(conn->log, XQC_LOG_DEBUG, "|server set final encoder fec scheme: %s", - xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_encoder_scheme)); - ret = XQC_OK; + conn->fec_neg_fail_reason |= XQC_CLIENT_RECEIVE_INV_DEC; + goto set_decoder; + } - } else { - conn->local_settings.enable_encode_fec = 0; - conn->local_settings.fec_encoder_schemes_num = 0; + encode_scheme = xqc_set_final_scheme(conn, ls->fec_encoder_schemes, &ls->fec_encoder_schemes_num, + params.fec_decoder_schemes, params.fec_decoder_schemes_num); + if (encode_scheme == 0) { + ls->enable_encode_fec = 0; conn->conn_settings.enable_encode_fec = 0; - conn->conn_settings.fec_params.fec_encoder_scheme = 0; - xqc_log(conn->log, XQC_LOG_DEBUG, "|negotiation on final encoder scheme failed.|"); + conn->fec_neg_fail_reason |= XQC_NO_COMMON_FEC_ENC; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec encoder schemes failed."); + goto set_decoder; } + // set valid encoder scheme + ret = xqc_set_valid_encoder_scheme_cb(&conn->conn_settings.fec_callback, encode_scheme); + if (ret != XQC_OK) { + ls->enable_encode_fec = 0; + conn->conn_settings.enable_encode_fec = 0; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|set fec encoder cb failed with scheme num: %d", encode_scheme); + goto set_decoder; + } + conn->conn_settings.fec_params.fec_encoder_scheme = encode_scheme; + // change fec scheme in local_settings + ls->fec_encoder_schemes[0] = conn->conn_settings.fec_params.fec_encoder_scheme; + ls->fec_encoder_schemes_num = 1; + xqc_log(conn->log, XQC_LOG_DEBUG, "|set final encoder fec scheme: %s", + xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_encoder_scheme)); + ret = XQC_OK; + } - /* server as encoder */ - if (params.enable_encode_fec - && params.fec_encoder_schemes_num > 0 - && conn->local_settings.enable_decode_fec - && conn->local_settings.fec_decoder_schemes_num > 0 - && xqc_set_final_scheme(conn, conn->local_settings.fec_decoder_schemes, &conn->local_settings.fec_decoder_schemes_num, params.fec_encoder_schemes, - params.fec_encoder_schemes_num, &conn->conn_settings.fec_params.fec_decoder_scheme, &conn->conn_settings.fec_decode_callback) == XQC_OK) +set_decoder: + if (ls->enable_decode_fec && params.enable_encode_fec) { + // server should provide only 1 scheme if negotiation success; + if (conn->conn_type == XQC_CONN_TYPE_CLIENT + && params.fec_encoder_schemes_num > 1) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|server set final decoder fec scheme: %s", - xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_decoder_scheme)); - ret = XQC_OK; + conn->fec_neg_fail_reason |= XQC_CLIENT_RECEIVE_INV_ENC; + goto end; + } - } else { - conn->local_settings.enable_decode_fec = 0; - conn->local_settings.fec_decoder_schemes_num = 0; + decode_scheme = xqc_set_final_scheme(conn, ls->fec_decoder_schemes, &ls->fec_decoder_schemes_num, + params.fec_encoder_schemes, params.fec_encoder_schemes_num); + if (decode_scheme == 0) { + ls->enable_decode_fec = 0; conn->conn_settings.enable_decode_fec = 0; - conn->conn_settings.fec_params.fec_decoder_scheme = 0; - xqc_log(conn->log, XQC_LOG_DEBUG, "|negotiation on final decoder scheme failed.|"); + conn->fec_neg_fail_reason |= XQC_NO_COMMON_FEC_DEC; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec decoder schemes failed."); + goto end; + } + // set valid encoder scheme + ret = xqc_set_valid_decoder_scheme_cb(&conn->conn_settings.fec_callback, decode_scheme); + if (ret != XQC_OK) { + ls->enable_decode_fec = 0; + conn->conn_settings.enable_decode_fec = 0; + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|set fec decoder cb failed with scheme num: %d", decode_scheme); + goto end; + } + conn->conn_settings.fec_params.fec_decoder_scheme = decode_scheme; + // change fec scheme in local_settings + ls->fec_decoder_schemes[0] = conn->conn_settings.fec_params.fec_decoder_scheme; + ls->fec_decoder_schemes_num = 1; + xqc_log(conn->log, XQC_LOG_DEBUG, "|set final decoder fec scheme: %s", + xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_decoder_scheme)); + ret = XQC_OK; + } +end: + if (conn->conn_type == XQC_CONN_TYPE_CLIENT) { + if (conn->conn_settings.fec_params.fec_encoder_scheme == 0) { + conn->conn_settings.enable_encode_fec = 0; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec encoder schemes failed."); + } + if (conn->conn_settings.fec_params.fec_decoder_scheme == 0) { + conn->conn_settings.enable_decode_fec = 0; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|negotiate fec decoder schemes failed."); } - return ret; } + return ret; +} +xqc_int_t +xqc_insert_src_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + uint64_t block_id, uint64_t symbol_idx, xqc_int_t *blk_output, + unsigned char *symbol, xqc_int_t symbol_size) +{ + xqc_list_head_t *pos, *next; + xqc_int_t ret, blk_num_flag; + xqc_fec_src_syb_t *src_symbol; + + ret = 0; + blk_num_flag = 1; + src_symbol = NULL; + + xqc_list_for_each_reverse_safe(pos, next, symbol_list) { + xqc_fec_src_syb_t *cur_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (block_id < cur_symbol->block_id) { + continue; + } + if (block_id == cur_symbol->block_id) { + if (symbol_idx < cur_symbol->symbol_idx) { + continue; + + } else if (cur_symbol->symbol_idx == symbol_idx) { + // current symbol already exists. + return -XQC_EFEC_TOLERABLE_ERROR; + } + } + break; - /* client端接收fec schemes逻辑 */ - if (conn->conn_type == XQC_CONN_TYPE_CLIENT - && params.enable_decode_fec - && params.fec_decoder_schemes_num == 1 - && conn->local_settings.enable_encode_fec - && xqc_is_fec_scheme_valid(params.fec_decoder_schemes[0], conn->local_settings.fec_encoder_schemes, conn->local_settings.fec_encoder_schemes_num) == XQC_OK) - { - conn->conn_settings.fec_params.fec_encoder_scheme = params.fec_decoder_schemes[0]; - ret = xqc_set_valid_scheme_cb(&conn->conn_settings.fec_encode_callback, conn->conn_settings.fec_params.fec_encoder_scheme); - if (ret == XQC_OK) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|client set final encoder fec scheme: %s", - xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_encoder_scheme)); + } - } else { - conn->conn_settings.enable_encode_fec = 0; - conn->conn_settings.fec_params.fec_encoder_scheme = 0; - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|set valid scheme %s error|ret:%d|", - conn->conn_settings.fec_params.fec_encoder_scheme, ret); + // push into src symbol list; + src_symbol = xqc_build_src_symbol(conn, block_id, symbol_idx, symbol, symbol_size); + if (src_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|build source symbol error|block_id:%d|symbol_idx:%d|symbol_size:%d", block_id, symbol_idx, symbol_size); + return -XQC_EMALLOC; + } + + // insert into proper position + xqc_list_add(&src_symbol->fec_list, pos); + *blk_output += 1; + return XQC_OK; +} + +xqc_int_t +xqc_insert_rpr_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + xqc_fec_rpr_syb_t *tmp_rpr_symbol, xqc_int_t *blk_output, xqc_fec_rpr_syb_t **rpr_symbol) +{ + xqc_list_head_t *pos, *next; + xqc_int_t ret, blk_num_flag, window_limit, block_id, symbol_idx; + + ret = 0; + blk_num_flag = 1; + window_limit = conn->conn_settings.fec_params.fec_max_window_size; + *rpr_symbol = NULL; + block_id = tmp_rpr_symbol->block_id; + symbol_idx = tmp_rpr_symbol->symbol_idx; + + if (block_id < 0) { + return -XQC_EFEC_SYMBOL_ERROR; + } + + xqc_list_for_each_reverse_safe(pos, next, symbol_list) { + xqc_fec_rpr_syb_t *cur_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (block_id < cur_symbol->block_id) { + continue; } - } else { - conn->conn_settings.enable_encode_fec = 0; - conn->conn_settings.fec_params.fec_encoder_scheme = 0; - xqc_log(conn->log, XQC_LOG_DEBUG, "|invalid fec schemes, negotiation on final encoder scheme failed."); + if (block_id == cur_symbol->block_id) { + if (symbol_idx < cur_symbol->symbol_idx) { + continue; + + } else if (cur_symbol->symbol_idx == symbol_idx) { + // current symbol already exists. + return -XQC_EFEC_TOLERABLE_ERROR; + } + } + break; } - if (conn->conn_type == XQC_CONN_TYPE_CLIENT - && params.enable_encode_fec - && params.fec_encoder_schemes_num == 1 - && conn->local_settings.enable_decode_fec - && xqc_is_fec_scheme_valid(params.fec_encoder_schemes[0], conn->local_settings.fec_decoder_schemes, conn->local_settings.fec_decoder_schemes_num) == XQC_OK) - { - conn->conn_settings.fec_params.fec_decoder_scheme = params.fec_encoder_schemes[0]; - ret = xqc_set_valid_scheme_cb(&conn->conn_settings.fec_decode_callback, conn->conn_settings.fec_params.fec_decoder_scheme); - if (ret == XQC_OK) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|client set final decoder fec scheme: %s", - xqc_get_fec_scheme_str(conn->conn_settings.fec_params.fec_decoder_scheme)); + // insert into rpr symbol list; + *rpr_symbol = xqc_build_rpr_symbol(conn, tmp_rpr_symbol); + if (*rpr_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|build repair symbol error|block_id:%d|symbol_idx:%d|symbol_size:%d", block_id, symbol_idx, tmp_rpr_symbol->payload_size); + return -XQC_EMALLOC; + } - } else { - conn->conn_settings.enable_decode_fec = 0; - conn->conn_settings.fec_params.fec_decoder_scheme = 0; - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|set valid scheme scheme error|ret:%d|", ret); + // insert into proper position + xqc_list_add(&(*rpr_symbol)->fec_list, pos); + *blk_output += 1; + return XQC_OK; +} + + +xqc_fec_src_syb_t * +xqc_create_src_symbol() +{ + xqc_fec_src_syb_t *src_symbol = (xqc_fec_src_syb_t *)xqc_calloc(1, sizeof(xqc_fec_src_syb_t)); + if (src_symbol == NULL) { + return NULL; + } + + src_symbol->payload = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + if (src_symbol->payload == NULL) { + xqc_free(src_symbol); + return NULL; + } + + return src_symbol; +} + +xqc_fec_rpr_syb_t * +xqc_create_rpr_symbol() +{ + xqc_fec_rpr_syb_t *rpr_symbol = (xqc_fec_rpr_syb_t *)xqc_calloc(1, sizeof(xqc_fec_rpr_syb_t)); + if (rpr_symbol == NULL) { + return NULL; + } + rpr_symbol->payload = xqc_calloc(XQC_MAX_SYMBOL_SIZE, sizeof(unsigned char)); + rpr_symbol->repair_key = xqc_calloc(XQC_MAX_RPR_KEY_SIZE, sizeof(unsigned char)); + rpr_symbol->recv_mask = xqc_calloc(XQC_MAX_RPR_KEY_SIZE, sizeof(unsigned char)); + if (rpr_symbol->payload == NULL || rpr_symbol->repair_key == NULL || rpr_symbol->recv_mask == NULL) { + if (rpr_symbol->payload != NULL) { + xqc_free(rpr_symbol->payload); + } + if (rpr_symbol->repair_key != NULL) { + xqc_free(rpr_symbol->repair_key); } + if (rpr_symbol->recv_mask != NULL) { + xqc_free(rpr_symbol->recv_mask); + } + xqc_free(rpr_symbol); + return NULL; + } + return rpr_symbol; +} - } else { - conn->conn_settings.enable_decode_fec = 0; - conn->conn_settings.fec_params.fec_decoder_scheme = 0; - xqc_log(conn->log, XQC_LOG_DEBUG, "|invalid fec schemes, negotiation on final decoder scheme failed."); +xqc_fec_src_syb_t * +xqc_new_src_symbol(xqc_list_head_t *fec_free_list) +{ + // try to fetch an available symbol in free list, otherwise malloc a new space + xqc_list_head_t *pos, *next; + xqc_fec_src_syb_t *src_symbol; + + xqc_list_for_each_safe(pos, next, fec_free_list) { + src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_list_del_init(&src_symbol->fec_list); + if (src_symbol->payload == NULL) { + xqc_free(src_symbol); + return NULL; + } + return src_symbol; } - return ret; + return xqc_create_src_symbol(); } -void -xqc_fec_record_flush_blk(xqc_connection_t *conn, xqc_int_t block_id) +xqc_fec_rpr_syb_t * +xqc_new_rpr_symbol(xqc_list_head_t *fec_free_list) { - xqc_int_t skip_block, window_size, block_cache_idx; + // try to fetch an available symbol in free list, otherwise malloc a new space + xqc_list_head_t *pos, *next; + xqc_fec_rpr_syb_t *rpr_symbol; + + xqc_list_for_each_safe(pos, next, fec_free_list) { + rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + xqc_list_del_init(&rpr_symbol->fec_list); + return rpr_symbol; + } + return xqc_create_rpr_symbol(); +} - window_size = conn->conn_settings.fec_params.fec_max_window_size; - block_cache_idx = block_id % window_size; - - if (conn->fec_ctl->fec_recv_symbols_num[block_cache_idx] != 0) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|block_%d will be flushed by block_%d|", conn->fec_ctl->fec_recv_block_idx[block_cache_idx], block_id); - if (conn->fec_ctl->fec_flush_blk_cnt == XQC_MAX_UINT32_VALUE) { - xqc_log(conn->log, XQC_LOG_WARN, "|fec flushed block count exceeds maximum."); - conn->fec_ctl->fec_flush_blk_cnt = 0; - } - conn->fec_ctl->fec_flush_blk_cnt++; - - /* record the number of blocks that is skipped */ - if (block_id - conn->fec_ctl->fec_recv_block_idx[block_cache_idx] > window_size) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|block_%d skipped to block_%d|", conn->fec_ctl->fec_recv_block_idx[block_cache_idx], block_id); - if (conn->fec_ctl->fec_ignore_blk_cnt == XQC_MAX_UINT32_VALUE) { - xqc_log(conn->log, XQC_LOG_WARN, "|fec ignored block count exceeds maximum."); - conn->fec_ctl->fec_ignore_blk_cnt = 0; +xqc_fec_rpr_syb_t * +xqc_get_rpr_symbol(xqc_list_head_t *head, uint64_t block_id, uint64_t symbol_id) +{ + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, head) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (symbol->block_id > block_id) { + break; + } + if (symbol->block_id == block_id) { + if (symbol->symbol_idx > symbol_id) { + break; + } + if (symbol->symbol_idx == symbol_id){ + return symbol; } - skip_block = (block_id - conn->fec_ctl->fec_recv_block_idx[block_cache_idx]) / window_size - 1; - conn->fec_ctl->fec_ignore_blk_cnt += skip_block; } } + return NULL; } -xqc_int_t -xqc_process_valid_symbol(xqc_connection_t *conn, xqc_int_t block_id, xqc_int_t symbol_idx, +void +xqc_update_rpr_symbol_mask_on_src(xqc_list_head_t *head, xqc_int_t block_id, + xqc_int_t pi_sym_idx) +{ + xqc_list_head_t *pos, *next; + xqc_int_t mask_offset; + + mask_offset = pi_sym_idx / 8; + + if (mask_offset >= XQC_MAX_RPR_KEY_SIZE) { + return; + } + + // traverse rpr list + xqc_list_for_each_safe(pos, next, head) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (symbol->block_id > block_id) { + break; + } + + if (symbol->block_id == block_id + && *(symbol->repair_key + mask_offset) & (1 << (7 - pi_sym_idx % 8))) + { + *(symbol->recv_mask + mask_offset) |= (1 << (7 - pi_sym_idx % 8)); + } + } +} + +void +xqc_update_rpr_symbol_mask_on_rpr(xqc_list_head_t *head, xqc_fec_rpr_syb_t *rpr_symbol) +{ + xqc_list_head_t *pos, *next; + + // traverse src list + xqc_list_for_each_safe(pos, next, head) { + xqc_fec_src_syb_t *symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + xqc_int_t block_id, symbol_idx, mask_offset; + + block_id = symbol->block_id; + symbol_idx = symbol->symbol_idx; + mask_offset = symbol_idx / 8; + + if (mask_offset >= XQC_MAX_RPR_KEY_SIZE) { + continue; + } + + if (block_id > rpr_symbol->block_id) { + break; + } + + if (block_id == rpr_symbol->block_id + && *(rpr_symbol->repair_key + mask_offset) & (1 << (7 - symbol_idx % 8))) + { + *(rpr_symbol->recv_mask + mask_offset) |= (1 << (7 - symbol_idx % 8)); + } + } +} + + +xqc_fec_src_syb_t * +xqc_build_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, unsigned char *symbol, xqc_int_t symbol_size) { - xqc_int_t ret, block_cache_idx, window_size; - unsigned char *tmp_payload_p; + xqc_int_t is_repair_symbol = 0, ret; + xqc_list_head_t *fec_free_src_list; + xqc_fec_src_syb_t *src_symbol = NULL; + + if (symbol_size > XQC_MAX_SYMBOL_SIZE) { + return src_symbol; + } + + fec_free_src_list = &conn->fec_ctl->fec_free_src_list; + src_symbol = xqc_new_src_symbol(fec_free_src_list); + if (src_symbol == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|get src symbol error|"); + return NULL; + } + src_symbol->block_id = block_id; + src_symbol->symbol_idx = symbol_idx; + xqc_memcpy(src_symbol->payload, symbol, symbol_size); + src_symbol->payload_size = symbol_size; + xqc_init_list_head(&src_symbol->fec_list); + + return src_symbol; +} + + +xqc_fec_rpr_syb_t * +xqc_build_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol) +{ + size_t symbol_size, repair_key_size; + xqc_int_t is_repair_symbol = 1, ret; + xqc_list_head_t *fec_free_rpr_list; + xqc_fec_rpr_syb_t *rpr_symbol = NULL; + + symbol_size = tmp_rpr_symbol->payload_size; + repair_key_size = tmp_rpr_symbol->repair_key_size; + + if (symbol_size > XQC_MAX_SYMBOL_SIZE || repair_key_size > XQC_MAX_RPR_KEY_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid symbol params|symbol_size:%d|symbol_key_size:%d|", symbol_size, repair_key_size); + return rpr_symbol; + } + + fec_free_rpr_list = &conn->fec_ctl->fec_free_rpr_list; + rpr_symbol = xqc_new_rpr_symbol(fec_free_rpr_list); + + if (rpr_symbol == NULL || rpr_symbol->payload == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|get rpr symbol error|"); + return rpr_symbol; + } + rpr_symbol->block_id = tmp_rpr_symbol->block_id; + rpr_symbol->symbol_idx = tmp_rpr_symbol->symbol_idx; + xqc_memcpy(rpr_symbol->payload, tmp_rpr_symbol->payload, symbol_size); + rpr_symbol->payload_size = symbol_size; + xqc_memcpy(rpr_symbol->repair_key, tmp_rpr_symbol->repair_key, repair_key_size); + rpr_symbol->repair_key_size = repair_key_size; + xqc_init_list_head(&rpr_symbol->fec_list); + + return rpr_symbol; +} + +xqc_int_t +xqc_get_min_src_blk_num(xqc_connection_t *conn) +{ + xqc_fec_ctl_t *fec_ctl = conn->fec_ctl; + if (!xqc_list_empty(&fec_ctl->fec_recv_src_syb_list)) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(fec_ctl->fec_recv_src_syb_list.next, xqc_fec_src_syb_t, fec_list); + return src_symbol->block_id; + } + return -1; +} + +xqc_int_t +xqc_get_min_rpr_blk_num(xqc_connection_t *conn) +{ + xqc_fec_ctl_t *fec_ctl = conn->fec_ctl; + if (!xqc_list_empty(&fec_ctl->fec_recv_rpr_syb_list)) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(fec_ctl->fec_recv_rpr_syb_list.next, xqc_fec_rpr_syb_t, fec_list); + return rpr_symbol->block_id; + } + return -1; +} + + +xqc_bool_t +xqc_if_src_blk_exists(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id == block_id) { + return XQC_TRUE; + } + } + return XQC_FALSE; +} + +xqc_bool_t +xqc_if_rpr_blk_exists(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id == block_id) { + return XQC_TRUE; + } + } + return XQC_FALSE; +} + + +xqc_int_t +xqc_process_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, + unsigned char *symbol, xqc_int_t symbol_size) +{ + xqc_int_t ret, window_size, min_block_id; + xqc_fec_ctl_t *fec_ctl; + xqc_list_head_t *symbol_list, *rpr_list; + xqc_fec_src_syb_t *src_symbol; + window_size = conn->conn_settings.fec_params.fec_max_window_size; - block_cache_idx = block_id % window_size; - - /* if block_id exceeds the older block id, flush the old block */ - if (block_id > conn->fec_ctl->fec_recv_block_idx[block_cache_idx]) { - /* record the number of non-empty older blocks */ - xqc_fec_record_flush_blk(conn, block_id); - /* flush the old block */ - xqc_fec_ctl_init_recv_params(conn->fec_ctl, block_cache_idx); - conn->fec_ctl->fec_recv_block_idx[block_cache_idx] = block_id; - xqc_log(conn->log, XQC_LOG_DEBUG, "|init fec block id: %d|", conn->fec_ctl->fec_recv_block_idx[block_cache_idx]); - - } else if (block_id != conn->fec_ctl->fec_recv_block_idx[block_cache_idx]) { - /* receive block idx smaller than current block idx. */ - xqc_log(conn->log, XQC_LOG_DEBUG, "|fec window is taken by other block|block_id:%d|", conn->fec_ctl->fec_recv_block_idx[block_cache_idx]); - return -XQC_EFEC_SYMBOL_ERROR; + fec_ctl = conn->fec_ctl; + symbol_list = &conn->fec_ctl->fec_recv_src_syb_list; + src_symbol = NULL; - } else if (conn->fec_ctl->fec_recv_symbols_num[block_cache_idx] == 0) { - return XQC_OK; + if (block_id != 0 + && !xqc_if_src_blk_exists(conn->fec_ctl, block_id) + && block_id <= conn->fec_ctl->fec_max_fin_blk_id) + { + return -XQC_EFEC_TOLERABLE_ERROR; } - if (conn->fec_ctl->fec_recv_symbols_flag[block_cache_idx] & (1 << symbol_idx) - || conn->fec_ctl->fec_recv_symbols_buff[block_cache_idx][symbol_idx].is_valid) + if (conn->fec_ctl->fec_src_syb_num > window_size + && !xqc_if_src_blk_exists(conn->fec_ctl, block_id)) { - /* here the symbol value should not exits,otherwise it means there're some repeated sid in this block. */ - return -XQC_EFEC_SYMBOL_ERROR; + while (conn->fec_ctl->fec_src_syb_num > window_size) { + min_block_id = xqc_get_min_src_blk_num(conn); + if (min_block_id == -1) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|window_size and src_symbol_list length is not match"); + return -XQC_EFEC_TOLERABLE_ERROR; + } + // flush the smallest old block + xqc_fec_ctl_init_recv_params(conn->fec_ctl, min_block_id); + } } - ret = xqc_fec_ctl_save_symbol(&conn->fec_ctl->fec_recv_symbols_buff[block_cache_idx][symbol_idx].payload, - symbol, symbol_size); + // insert into src symbol_list according to block id and symbol idx + ret = xqc_insert_src_symbol_by_seq(conn, symbol_list, block_id, symbol_idx, &conn->fec_ctl->fec_src_syb_num, symbol, symbol_size); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|save source symbol error|"); - return -XQC_EFEC_SYMBOL_ERROR; + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|current symbol is already exists|block_id:%d|symbol_idx:%d", block_id, symbol_idx); + return ret; } - tmp_payload_p = conn->fec_ctl->fec_recv_symbols_buff[block_cache_idx][symbol_idx].payload; + // update repair symbol recv_mask + if (conn->conn_settings.fec_params.fec_decoder_scheme == XQC_PACKET_MASK_CODE) { + rpr_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + xqc_update_rpr_symbol_mask_on_src(rpr_list, block_id, symbol_idx); + } + + return XQC_OK; +} + + +xqc_int_t +xqc_process_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol) +{ + xqc_int_t ret, window_size, min_block_id, block_id; + xqc_fec_ctl_t *fec_ctl; + xqc_list_head_t *symbol_list, *src_list; + xqc_fec_rpr_syb_t *rpr_symbol; + + window_size = conn->conn_settings.fec_params.fec_max_window_size; + fec_ctl = conn->fec_ctl; + symbol_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + rpr_symbol = NULL; + min_block_id = xqc_get_min_rpr_blk_num(conn); + block_id = tmp_rpr_symbol->block_id; + + if (block_id != 0 + && !xqc_if_src_blk_exists(conn->fec_ctl, block_id) + && block_id <= conn->fec_ctl->fec_max_fin_blk_id) + { + return -XQC_EFEC_TOLERABLE_ERROR; + } - xqc_set_object_value(&conn->fec_ctl->fec_recv_symbols_buff[block_cache_idx][symbol_idx], 1, tmp_payload_p, symbol_size); + if (conn->fec_ctl->fec_rpr_syb_num > window_size + && !xqc_if_rpr_blk_exists(conn->fec_ctl, block_id)) + { + while (conn->fec_ctl->fec_rpr_syb_num > window_size) { + min_block_id = xqc_get_min_rpr_blk_num(conn); + if (min_block_id == -1) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|window_size and rpr_symbol_list length is not match"); + return -XQC_EFEC_TOLERABLE_ERROR; + } + // flush the smallest old block + xqc_fec_ctl_init_recv_params(conn->fec_ctl, min_block_id); + } + } - conn->fec_ctl->fec_recv_symbols_flag[block_cache_idx] ^= (1 << symbol_idx); - conn->fec_ctl->fec_recv_symbols_num[block_cache_idx]++; + // insert into src symbol_list according to block id and symbol idx + ret = xqc_insert_rpr_symbol_by_seq(conn, symbol_list, tmp_rpr_symbol, &conn->fec_ctl->fec_rpr_syb_num, &rpr_symbol); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|quic_fec|current symbol is already exists|block_id:%d|symbol_idx:%d", block_id, tmp_rpr_symbol->symbol_idx); + return ret; + } + // link src symbols to the rpr symbols using pkt mask + if (conn->conn_settings.fec_params.fec_decoder_scheme == XQC_PACKET_MASK_CODE) { + src_list = &conn->fec_ctl->fec_recv_src_syb_list; + xqc_update_rpr_symbol_mask_on_rpr(src_list, rpr_symbol); + } return XQC_OK; -} \ No newline at end of file +} + +xqc_int_t +xqc_get_symbol_flag(xqc_connection_t *conn, uint64_t block_id) +{ + xqc_list_head_t *pos, *next; + xqc_int_t symbol_flag, max_src_symbol_num; + + symbol_flag = 0; + max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; + + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id > block_id) { + break; + } + if (src_symbol->block_id == block_id) { + symbol_flag |= (1 << src_symbol->symbol_idx); + } + } + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_id) { + break; + } + if (rpr_symbol->block_id == block_id) { + symbol_flag |= (1 << (rpr_symbol->symbol_idx + max_src_symbol_num)); + } + } + return symbol_flag; +} + +xqc_int_t +xqc_get_symbols_buff(unsigned char **output, xqc_fec_ctl_t *fec_ctl, uint64_t block_id, size_t *size) +{ + xqc_list_head_t *pos, *next, *fec_recv_src_syb_list, *fec_recv_rpr_syb_list; + xqc_int_t i = 0; + + fec_recv_src_syb_list = &fec_ctl->fec_recv_src_syb_list; + fec_recv_rpr_syb_list = &fec_ctl->fec_recv_rpr_syb_list; + *size = 0; + + // check 一下当前block idx能否成功被flush + + xqc_list_for_each_safe(pos, next, fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_syb = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_syb->block_id == block_id) { + xqc_memcpy(output[i++], src_syb->payload, xqc_min(XQC_MAX_SYMBOL_SIZE, src_syb->payload_size)); + } + } + + xqc_list_for_each_safe(pos, next, fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_syb = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_syb->block_id == block_id) { + if (rpr_syb->payload_size > XQC_MAX_SYMBOL_SIZE) { + return -XQC_EPARAM; + } + xqc_memcpy(output[i++], rpr_syb->payload, xqc_min(XQC_MAX_SYMBOL_SIZE, rpr_syb->payload_size)); + if (rpr_syb->payload_size > *size) { + *size = rpr_syb->payload_size; + } + } + } + return i; +} + +xqc_int_t +xqc_cnt_blk_num(xqc_fec_ctl_t *fec_ctl) +{ + xqc_int_t ret = 0, block_id = -1; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + + if (src_symbol->block_id != block_id) { + ret++; + block_id = src_symbol->block_id; + } + } + return ret; +} + +xqc_int_t +xqc_cnt_src_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_int_t ret = 0; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_src_syb_list) { + xqc_fec_src_syb_t *src_symbol = xqc_list_entry(pos, xqc_fec_src_syb_t, fec_list); + if (src_symbol->block_id > block_id) { + break; + } + if (src_symbol->block_id == block_id) { + ret++; + } + } + return ret; +} + +xqc_int_t +xqc_cnt_rpr_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_int_t ret = 0; + xqc_list_head_t *pos, *next; + + xqc_list_for_each_safe(pos, next, &fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *rpr_symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + if (rpr_symbol->block_id > block_id) { + break; + } + if (rpr_symbol->block_id == block_id) { + ret++; + } + } + return ret; +} + +xqc_int_t +xqc_cnt_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id) +{ + xqc_int_t ret = 0; + + ret += xqc_cnt_src_symbols_num(fec_ctl, block_id); + ret += xqc_cnt_rpr_symbols_num(fec_ctl, block_id); + + return ret; +} +void +xqc_on_fec_negotiate_success(xqc_connection_t *conn, xqc_transport_params_t params) +{ + uint8_t i; + if (conn->conn_settings.enable_encode_fec) { + if (conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE) { + xqc_set_fec_blk_size(conn, params); + for (i = XQC_NORMAL_SIZE_REQ; i < XQC_BLOCK_MODE_LEN; i++) { + if (conn->conn_settings.fec_params.fec_code_rate == 0) { + conn->fec_ctl->fec_send_required_repair_num[i] = 1; + + } else { + conn->fec_ctl->fec_send_required_repair_num[i] = xqc_min(xqc_max(1, conn->fec_ctl->fec_send_block_mode_size[i] * conn->conn_settings.fec_params.fec_code_rate), XQC_REPAIR_LEN); + } + } + } + if (conn->conn_settings.fec_callback.xqc_fec_init != NULL) { + conn->conn_settings.fec_callback.xqc_fec_init(conn); + } + } +} diff --git a/src/transport/xqc_fec.h b/src/transport/xqc_fec.h index df4c3c538..ae39d83a6 100644 --- a/src/transport/xqc_fec.h +++ b/src/transport/xqc_fec.h @@ -12,24 +12,73 @@ #include #include #include "src/transport/xqc_packet_out.h" -#include "src/transport/xqc_fec_scheme.h" +// #include "src/transport/xqc_fec_scheme.h" #include "src/transport/xqc_transport_params.h" +#include "src/common/xqc_str.h" #define XQC_FEC_ELE_BIT_SIZE_DEFAULT 8 #define XQC_FEC_MAX_SYMBOL_NUM_TOTAL 256 #define XQC_FEC_MAX_SYMBOL_PAYLOAD_ID 0xffffffff - XQC_FEC_MAX_SYMBOL_NUM_TOTAL -#define XQC_FEC_MAX_SYMBOL_NUM_PBLOCK 4 /* 2^XQC_FEC_ELE_BIT_SIZE_DEFAULT */ -#define XQC_FEC_CODE_RATE_DEFAULT 0.75 -#define XQC_REPAIR_LEN 1 /* (1-XQC_FEC_CODE_RATE_DEFAULT) * XQC_FEC_MAX_SYMBOL_NUM_PBLOCK */ -#define XQC_SYMBOL_CACHE_LEN 10 - +#define XQC_FEC_MAX_BLOCK_NUM 0x00ffffff +#define XQC_FEC_MAX_SYMBOL_NUM 0x000000ff +#define XQC_FEC_MAX_SYMBOL_NUM_PBLOCK 48 /* 2^XQC_FEC_ELE_BIT_SIZE_DEFAULT */ +#define XQC_FEC_CODE_RATE_DEFAULT 0.95 +#define XQC_REPAIR_LEN 10 /* (1-XQC_FEC_CODE_RATE_DEFAULT) * XQC_FEC_MAX_SYMBOL_NUM_PBLOCK */ +#define XQC_BLOCK_MODE_LEN 5 +#define XQC_SYMBOL_CACHE_LEN 96 +#define XQC_MAX_RPR_KEY_SIZE 10 +#define XQC_MAX_SYMBOL_SIZE XQC_MAX_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_FEC_SPACE +#define XQC_MAX_PM_SIZE 288 + +static const uint8_t fec_blk_size_v2[XQC_BLOCK_MODE_LEN] = {0, 0, 4, 5, 20}; typedef struct xqc_fec_object_s { size_t payload_size; xqc_int_t is_valid; unsigned char *payload; } xqc_fec_object_t; +// FEC 2.0 params + +typedef struct xqc_fec_src_syb_s { + size_t payload_size; + unsigned char *payload; + xqc_list_head_t fec_list; + xqc_int_t block_id; + xqc_int_t symbol_idx; +} xqc_fec_src_syb_t; + +typedef struct xqc_fec_rpr_syb_s { + size_t payload_size; + unsigned char *payload; + size_t repair_key_size; + unsigned char *repair_key; + unsigned char *recv_mask; + xqc_list_head_t fec_list; + xqc_int_t block_id; + xqc_int_t symbol_idx; +} xqc_fec_rpr_syb_t; + +typedef struct xqc_fec_payload_s { + unsigned char *payload; + xqc_list_head_t pld_list; +} xqc_fec_payload_t; + +typedef enum { + XQC_LOCAL_NOT_SUPPORT_ENC = 1 << 0, + XQC_LOCAL_NOT_SUPPORT_DEC = 1 << 1, + XQC_REMOTE_NOT_SUPPORT_ENC = 1 << 2, + XQC_REMOTE_NOT_SUPPORT_DEC = 1 << 3, + XQC_NO_COMMON_FEC_ENC = 1 << 4, + XQC_NO_COMMON_FEC_DEC = 1 << 5, + XQC_OLD_FEC_VERSION = 1 << 6, + XQC_CLIENT_RECEIVE_INV_ENC = 1 << 7, + XQC_CLIENT_RECEIVE_INV_DEC = 1 << 8, + XQC_REMOTE_PARAM_ERR = 1 << 9 +} xqc_fec_neg_fail_reason_e; + + + typedef struct xqc_fec_ctl_s { xqc_connection_t *conn; @@ -38,22 +87,31 @@ typedef struct xqc_fec_ctl_s { uint32_t fec_processed_blk_num; uint32_t fec_flush_blk_cnt; uint32_t fec_recover_failed_cnt; - uint32_t fec_ignore_blk_cnt; - uint32_t fec_recv_repair_num; - - xqc_int_t fec_send_src_symbols_num; /* src symbols id for current fec process*/ - xqc_int_t fec_send_repair_symbols_num; - xqc_fec_object_t fec_send_repair_key[XQC_REPAIR_LEN]; - xqc_fec_object_t fec_send_repair_symbols_buff[XQC_REPAIR_LEN]; - - xqc_int_t fec_recv_block_idx[XQC_SYMBOL_CACHE_LEN]; - xqc_int_t fec_recv_symbols_num[XQC_SYMBOL_CACHE_LEN]; - xqc_int_t fec_recv_repair_symbols_num[XQC_SYMBOL_CACHE_LEN]; - xqc_fec_object_t fec_recv_repair_key[XQC_SYMBOL_CACHE_LEN][XQC_REPAIR_LEN]; - xqc_fec_object_t fec_recv_symbols_buff[XQC_SYMBOL_CACHE_LEN][XQC_FEC_MAX_SYMBOL_NUM_PBLOCK]; - uint64_t fec_recv_symbols_flag[XQC_SYMBOL_CACHE_LEN]; - - unsigned char LC_GM[XQC_MAX_MT_ROW][XQC_MAX_MT_ROW]; + uint32_t fec_recv_repair_num_total; + uint32_t fec_send_repair_num_total; + xqc_int_t fec_max_fin_blk_id; + + xqc_fec_mp_mode_e fec_mp_mode; + uint64_t fec_rep_path_id; + + uint32_t fec_send_block_num[XQC_BLOCK_MODE_LEN]; + uint8_t fec_send_block_mode_size[XQC_BLOCK_MODE_LEN]; + uint32_t fec_send_required_repair_num[XQC_BLOCK_MODE_LEN]; + uint32_t fec_send_symbol_num[XQC_BLOCK_MODE_LEN]; /* src symbols number for current fec process */ + xqc_fec_object_t fec_send_repair_key[XQC_BLOCK_MODE_LEN][XQC_REPAIR_LEN]; + xqc_fec_object_t fec_send_repair_symbols_buff[XQC_BLOCK_MODE_LEN][XQC_REPAIR_LEN]; + uint8_t fec_send_decode_matrix[XQC_BLOCK_MODE_LEN][XQC_REPAIR_LEN][XQC_MAX_RPR_KEY_SIZE]; + unsigned char decode_matrix[XQC_MAX_MT_ROW][XQC_MAX_MT_ROW]; + + // FEC 2.0 params + xqc_list_head_t fec_free_src_list; + xqc_list_head_t fec_free_rpr_list; + xqc_list_head_t fec_recv_src_syb_list; /* source symbols (including recovered source symbols) list */ + xqc_list_head_t fec_recv_rpr_syb_list; /* repair symbols list */ + + xqc_int_t fec_src_syb_num; + xqc_int_t fec_rpr_syb_num; + xqc_fec_object_t fec_gen_repair_symbols_buff[XQC_REPAIR_LEN]; } xqc_fec_ctl_t; xqc_int_t xqc_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out); @@ -70,13 +128,8 @@ xqc_int_t xqc_set_fec_schemes(const xqc_fec_schemes_e *schemes, xqc_int_t scheme * server set the final fec scheme */ xqc_int_t xqc_set_final_scheme(xqc_connection_t *conn, xqc_fec_schemes_e *local_fec_schemes_buff, xqc_int_t *local_fec_schemes_buff_len, - xqc_fec_schemes_e *remote_fec_schemes_buff, xqc_int_t remote_fec_schemes_buff_len, xqc_int_t *final_scheme, xqc_fec_code_callback_t *callback); -/* - * @desc - * check if the fec scheme is supported by current host - */ -xqc_int_t xqc_is_fec_scheme_valid(xqc_fec_schemes_e scheme, xqc_fec_schemes_e *supported_schemes_buff, - xqc_int_t supported_schemes_buff_len); + xqc_fec_schemes_e *remote_fec_schemes_buff, xqc_int_t remote_fec_schemes_buff_len); + xqc_int_t xqc_is_packet_fec_protected(xqc_connection_t *conn, xqc_packet_out_t *packet_out); @@ -86,30 +139,65 @@ xqc_fec_ctl_t *xqc_fec_ctl_create(xqc_connection_t *conn); void xqc_fec_ctl_destroy(xqc_fec_ctl_t *fec_ctl); -xqc_int_t xqc_gen_src_payload_id(xqc_fec_ctl_t *fec_ctl, uint64_t *payload_id); +xqc_int_t xqc_gen_src_payload_id(xqc_fec_ctl_t *fec_ctl, uint64_t *payload_id, uint8_t bm_idx); xqc_int_t xqc_fec_ctl_save_symbol(unsigned char **symbol_buff, const unsigned char *data, xqc_int_t data_len); -xqc_int_t xqc_fec_ctl_init_send_params(xqc_fec_ctl_t *fec_ctl); +xqc_int_t xqc_fec_ctl_init_send_params(xqc_connection_t *conn, uint8_t bm_idx); + +xqc_int_t xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, uint64_t block_id); -xqc_int_t xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, xqc_int_t block_idx); +unsigned char *xqc_get_fec_scheme_str(xqc_fec_schemes_e scheme); -xqc_int_t xqc_set_valid_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme); +unsigned char *xqc_get_fec_mp_mode_str(xqc_fec_ctl_t *fec_ctl); xqc_int_t xqc_negotiate_fec_schemes(xqc_connection_t *conn, xqc_transport_params_t params); -xqc_int_t xqc_process_fec_protected_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out); +xqc_int_t xqc_process_fec_protected_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_bool_t *if_add_repair); void xqc_set_object_value(xqc_fec_object_t *object, xqc_int_t is_valid, unsigned char *payload, size_t size); -xqc_int_t xqc_is_fec_cb_exist(xqc_fec_schemes_e scheme); - void xqc_init_object_value(xqc_fec_object_t *object); -xqc_int_t xqc_process_valid_symbol(xqc_connection_t *conn, xqc_int_t block_id, xqc_int_t symbol_idx, +xqc_int_t xqc_process_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, + unsigned char *symbol, xqc_int_t symbol_size); + +xqc_int_t xqc_process_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol); + + +xqc_int_t xqc_get_symbols_buff(unsigned char **output, xqc_fec_ctl_t *fec_ctl, uint64_t block_idx, size_t *size); + +xqc_fec_rpr_syb_t *xqc_get_rpr_symbol(xqc_list_head_t *head, uint64_t block_id, uint64_t symbol_id); + +xqc_int_t xqc_cnt_blk_num(xqc_fec_ctl_t *fec_ctl); +xqc_int_t xqc_cnt_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id); +xqc_int_t xqc_cnt_src_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id); +xqc_int_t xqc_cnt_rpr_symbols_num(xqc_fec_ctl_t *fec_ctl, uint64_t block_id); + +xqc_int_t xqc_get_symbol_flag(xqc_connection_t *conn, uint64_t block_id); + +xqc_fec_src_syb_t *xqc_build_src_symbol(xqc_connection_t *conn, uint64_t block_id, uint64_t symbol_idx, unsigned char *symbol, xqc_int_t symbol_size); -void xqc_fec_record_flush_blk(xqc_connection_t *conn, xqc_int_t block_id); +xqc_int_t xqc_insert_src_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + uint64_t block_id, uint64_t symbol_idx, xqc_int_t *blk_output, + unsigned char *symbol, xqc_int_t symbol_size); + +xqc_int_t xqc_insert_rpr_symbol_by_seq(xqc_connection_t *conn, xqc_list_head_t *symbol_list, + xqc_fec_rpr_syb_t *tmp_rpr_symbol, xqc_int_t *blk_output, xqc_fec_rpr_syb_t **rpr_symbol); + +void xqc_remove_rpr_symbol_from_list(xqc_fec_ctl_t *fec_ctl, xqc_fec_rpr_syb_t *rpr_symbol); + +xqc_int_t xqc_check_fec_params(xqc_connection_t *conn, xqc_int_t src_symbol_num, xqc_int_t total_symbol_num, + xqc_int_t max_window_size, xqc_int_t symbol_size); + +xqc_fec_rpr_syb_t *xqc_build_rpr_symbol(xqc_connection_t *conn, xqc_fec_rpr_syb_t *tmp_rpr_symbol); + +void xqc_set_fec_blk_size(xqc_connection_t *conn, xqc_transport_params_t params); + +uint8_t xqc_get_fec_blk_size(xqc_connection_t *conn, uint8_t blk_md); + +void xqc_on_fec_negotiate_success(xqc_connection_t *conn, xqc_transport_params_t params); #endif /* _XQC_FEC_H_INCLUDED_ */ \ No newline at end of file diff --git a/src/transport/xqc_fec_scheme.c b/src/transport/xqc_fec_scheme.c index bdc4b5da8..0ee66d244 100644 --- a/src/transport/xqc_fec_scheme.c +++ b/src/transport/xqc_fec_scheme.c @@ -5,170 +5,229 @@ #include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_fec.h" #include "src/transport/xqc_conn.h" - xqc_int_t -xqc_fec_encoder(xqc_connection_t *conn, unsigned char *stream) +xqc_fec_encoder_check_params(xqc_connection_t *conn, xqc_int_t repair_symbol_num, xqc_fec_schemes_e encoder_scheme, size_t st_size) { - xqc_int_t i, ret, symbol_idx, src_symbol_num, max_symbol_num, repair_symbol_num; - unsigned char *repair_symbols_payload_buff[XQC_REPAIR_LEN]; - - src_symbol_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block * conn->conn_settings.fec_params.fec_code_rate; - symbol_idx = conn->fec_ctl->fec_send_src_symbols_num % src_symbol_num; - max_symbol_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block; - repair_symbol_num = max_symbol_num - src_symbol_num; - - if (repair_symbol_num < 0) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_encoder|fec source symbols' number exceeds maximum symbols number per block"); - return -XQC_EFEC_SCHEME_ERROR; + if (encoder_scheme == XQC_XOR_CODE) { + if (repair_symbol_num > 1) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|xor fec scheme can only maintain one repair symbol"); + return -XQC_EPARAM; + } } - if (repair_symbol_num == 0) { - xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|current code rate is too low to generate repair packets."); - return XQC_OK; + if (st_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|stream size is too large to get fec encode|st_size:%zu|", st_size); + return -XQC_EPARAM; } - conn->fec_ctl->fec_send_repair_symbols_num = repair_symbol_num; - - if (conn->conn_settings.fec_encode_callback.xqc_fec_encode == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_encoder|fec encode_uni callback is NULL"); - return -XQC_EFEC_SCHEME_ERROR; - } + return XQC_OK; +} - for (i = 0; i < repair_symbol_num; i++) { - repair_symbols_payload_buff[i] = conn->fec_ctl->fec_send_repair_symbols_buff[i].payload; - } +xqc_int_t +xqc_fec_encoder(xqc_connection_t *conn, unsigned char *input, size_t st_size, uint8_t fec_bm_mode) +{ + xqc_int_t i, ret, repair_symbol_num; + unsigned char *repair_symbols_payload_buff[XQC_REPAIR_LEN]; - ret = conn->conn_settings.fec_encode_callback.xqc_fec_encode(conn, stream, repair_symbols_payload_buff); + // validate encode params + ret = xqc_fec_encoder_check_params(conn, conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode], conn->conn_settings.fec_params.fec_encoder_scheme, st_size); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|fec scheme encode_uni error"); - return -XQC_EFEC_SCHEME_ERROR; - } + return ret; + } + // in some case fec_code_rate will change in xqc_fec_encoder_check_params + repair_symbol_num = conn->fec_ctl->fec_send_required_repair_num[fec_bm_mode]; + + if (conn->conn_settings.fec_callback.xqc_fec_encode) { + // encode stream value into fec_send_repair_symbols_buff + for (i = 0; i < repair_symbol_num; i++) { + repair_symbols_payload_buff[i] = conn->fec_ctl->fec_send_repair_symbols_buff[fec_bm_mode][i].payload; + if (repair_symbols_payload_buff[i] == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fail to malloc memory for fec_send_repair_symbols_buff"); + return -XQC_EMALLOC; + } + } + + ret = conn->conn_settings.fec_callback.xqc_fec_encode(conn, input, st_size, repair_symbols_payload_buff, fec_bm_mode); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_fec_encoder|fec scheme encode_uni error"); + return -XQC_EFEC_SCHEME_ERROR; + } - for (i = 0; i < repair_symbol_num; i++) { - xqc_set_object_value(&conn->fec_ctl->fec_send_repair_symbols_buff[i], 1, repair_symbols_payload_buff[i], - conn->conn_settings.fec_params.fec_max_symbol_size); + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_encoder|fec encode_uni callback is NULL"); + return -XQC_EFEC_SCHEME_ERROR; } return XQC_OK; } xqc_int_t -xqc_process_recovered_packet(xqc_connection_t *conn, unsigned char **recovered_symbols_buff, - xqc_int_t loss_symbol_idx_len) +xqc_process_recovered_packet(xqc_connection_t *conn, unsigned char *recovered_payload, size_t symbol_size) { - xqc_int_t i, ret, res, symbol_idx, symbol_size; + xqc_int_t i, ret, res; - symbol_size = conn->remote_settings.fec_max_symbol_size; res = XQC_OK; + xqc_packet_in_t *new_packet = xqc_calloc(1, sizeof(xqc_packet_in_t)); + if (new_packet == NULL) { + return -XQC_EMALLOC; + } - for (i = 0; i < loss_symbol_idx_len; i++) { - symbol_idx = i; - if (recovered_symbols_buff[symbol_idx] == NULL) { - xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_process_recovered_packet|symbol %d recover failed", symbol_idx); - continue; - } - xqc_packet_in_t *new_packet = xqc_calloc(1, sizeof(xqc_packet_in_t)); - if (new_packet == NULL) { - return -XQC_EMALLOC; - } - - new_packet->decode_payload = recovered_symbols_buff[symbol_idx]; - new_packet->decode_payload_len = symbol_size; - new_packet->pos = new_packet->decode_payload; - new_packet->last = new_packet->decode_payload + symbol_size; - new_packet->pkt_recv_time = xqc_monotonic_timestamp(); - new_packet->pi_path_id = 0; - new_packet->pi_flag |= XQC_PIF_FEC_RECOVERED; + new_packet->decode_payload = recovered_payload; + new_packet->decode_payload_len = symbol_size; + new_packet->pos = new_packet->decode_payload; + new_packet->last = new_packet->decode_payload + symbol_size; + new_packet->pkt_recv_time = xqc_monotonic_timestamp(); + new_packet->pi_path_id = 0; + new_packet->pi_flag |= XQC_PIF_FEC_RECOVERED; - ret = xqc_process_frames(conn, new_packet); - xqc_free(new_packet); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_recovered_packet|process recovered packet failed"); - res = -XQC_EFEC_SCHEME_ERROR; + ret = xqc_process_frames(conn, new_packet); + xqc_free(new_packet); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process recovered packet failed|ret:%d", ret); + res = -XQC_EFEC_SCHEME_ERROR; - } else { - if (conn->fec_ctl->fec_recover_pkt_cnt == XQC_MAX_UINT32_VALUE) { - xqc_log(conn->log, XQC_LOG_WARN, "|fec recovered packet number exceeds maximum."); - conn->fec_ctl->fec_recover_pkt_cnt = 0; - } - conn->fec_ctl->fec_recover_pkt_cnt++; - } + } else { + conn->fec_ctl->fec_recover_pkt_cnt++; } return res; } + xqc_int_t -xqc_fec_decoder(xqc_connection_t *conn, xqc_int_t block_idx) +xqc_fec_cc_decoder(xqc_connection_t *conn, xqc_fec_rpr_syb_t *rpr_symbol, uint8_t lack_syb_id) { - xqc_int_t i, ret, max_src_symbol_num, loss_src_num; - xqc_int_t loss_symbol_idx[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK] = {-1}; - unsigned char *recovered_symbols_buff[XQC_FEC_MAX_SYMBOL_NUM_PBLOCK]; + xqc_int_t ret, block_id, symbol_idx, mask_offset; + unsigned char *payload_p; - ret = loss_src_num = 0; - for (i = 0; i < XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; i++) { - recovered_symbols_buff[i] = xqc_calloc(1, XQC_PACKET_OUT_SIZE + XQC_ACK_SPACE - XQC_HEADER_SPACE - XQC_FEC_SPACE); + ret = -XQC_EFEC_SYMBOL_ERROR; + block_id = rpr_symbol->block_id; + symbol_idx = rpr_symbol->symbol_idx; + payload_p = conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload; + + if (payload_p == NULL || rpr_symbol->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|invalid symbol payload"); + goto cc_decoder_end; + } + if (conn->conn_settings.fec_callback.xqc_fec_decode_one == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_decode_one doesn't exists"); + goto cc_decoder_end; } - - max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; - if (conn->fec_ctl->fec_recv_symbols_num[block_idx] < max_src_symbol_num) { - ret = -XQC_EFEC_SYMBOL_ERROR; - goto end; + ret = conn->conn_settings.fec_callback.xqc_fec_decode_one(conn, payload_p, block_id, symbol_idx); + xqc_set_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[0], 1, payload_p, rpr_symbol->payload_size); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_decode_one error"); + goto cc_decoder_end; } - for (i = 0; i < max_src_symbol_num; i++) { - if ((conn->fec_ctl->fec_recv_symbols_flag[block_idx] & (1 << i)) == 0) { - loss_symbol_idx[loss_src_num] = i; - loss_src_num++; + ret = xqc_process_recovered_packet(conn, payload_p, rpr_symbol->payload_size); + if (ret == XQC_OK) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|process packet of block %d successfully.", block_id); + // insert into source list + ret = xqc_process_src_symbol(conn, block_id, lack_syb_id, payload_p, rpr_symbol->payload_size); + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + ret = XQC_OK; } + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process source symbol error|ret:%d", ret); + } + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process recovered packet error|ret:%d|bid:%d|symbol_size:%d", ret, block_id, rpr_symbol->payload_size); + } + +cc_decoder_end: + if (conn->fec_ctl->fec_gen_repair_symbols_buff[0].is_valid) { + conn->fec_ctl->fec_gen_repair_symbols_buff[0].payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_init_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[0]); } + conn->fec_ctl->fec_processed_blk_num++; + + if (ret == XQC_OK) { + return XQC_OK; + } + + conn->fec_ctl->fec_recover_failed_cnt++; + return ret; +} + +/** + * @brief fec block code decoder; + * + * @param conn + * @param block_id + * @return xqc_int_t + */ +xqc_int_t +xqc_fec_bc_decoder(xqc_connection_t *conn, xqc_int_t block_id, xqc_int_t loss_src_num) +{ + size_t symbol_size; + xqc_int_t i, ret, symbol_flag, rpr_syb_num, src_syb_num, symbol_idx; + unsigned char *recovered_symbols_buff[XQC_REPAIR_LEN]; + xqc_list_head_t *pos, *next; + + ret = symbol_size = 0; /* proceeds if there's no loss src symbol */ if (loss_src_num == 0) { ret = XQC_OK; - goto end; + goto bc_decoder_end; } - - /* generate loss packets payload */ - if (conn->conn_settings.fec_decode_callback.xqc_fec_decode == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_decoder|fec decode callback is NULL"); - ret = -XQC_EFEC_SCHEME_ERROR; - goto end; + + for (i = 0; i < loss_src_num; i++) { + recovered_symbols_buff[i] = conn->fec_ctl->fec_gen_repair_symbols_buff[i].payload; + if (recovered_symbols_buff[i] == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fec_gen_repair_symbols_buff is NULL"); + ret = -XQC_EMALLOC; + goto bc_decoder_end; + } } - ret = conn->conn_settings.fec_decode_callback.xqc_fec_decode(conn, recovered_symbols_buff, block_idx, loss_symbol_idx, loss_src_num); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_WARN, "|fec scheme decode error"); + + /* generate loss packets payload */ + if (conn->conn_settings.fec_callback.xqc_fec_decode) { + ret = conn->conn_settings.fec_callback.xqc_fec_decode(conn, recovered_symbols_buff, &symbol_size, block_id); + for (i = 0; i < loss_src_num; i++) { + xqc_set_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[i], 1, recovered_symbols_buff[i], + symbol_size); + } + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|fec scheme decode error"); + ret = -XQC_EFEC_SCHEME_ERROR; + goto bc_decoder_end; + } + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_fec_bc_decoder|fec decode callback is NULL"); ret = -XQC_EFEC_SCHEME_ERROR; - goto end; + goto bc_decoder_end; } /* 封装 new packets并解析数据帧 */ - ret = xqc_process_recovered_packet(conn, recovered_symbols_buff, loss_src_num); - if (ret == XQC_OK) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|process packet of block %d successfully.", conn->fec_ctl->fec_recv_block_idx[block_idx]); + for (i = 0; i < loss_src_num; i++) { + if (recovered_symbols_buff[i] == NULL) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|xqc_process_recovered_packet|symbol %d recover failed", i); + break; + } + ret = xqc_process_recovered_packet(conn, recovered_symbols_buff[i], symbol_size); + if (ret == XQC_OK) { + xqc_log(conn->log, XQC_LOG_DEBUG, "|process packet of block %d successfully.", block_id); + } } -end: - if (conn->fec_ctl->fec_processed_blk_num == XQC_MAX_UINT32_VALUE) { - xqc_log(conn->log, XQC_LOG_WARN, "|fec processed block number exceeds maximum."); - conn->fec_ctl->fec_processed_blk_num = 0; - } +bc_decoder_end: conn->fec_ctl->fec_processed_blk_num++; /* free recovered symbols buff */ - for (i = 0; i < XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; i++) { - if (recovered_symbols_buff[i] != NULL) { - xqc_free(recovered_symbols_buff[i]); + for (i = 0; i < loss_src_num; i++) { + if (conn->fec_ctl->fec_gen_repair_symbols_buff[i].is_valid) { + conn->fec_ctl->fec_gen_repair_symbols_buff[i].payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_init_object_value(&conn->fec_ctl->fec_gen_repair_symbols_buff[i]); } } if (ret == XQC_OK) { return XQC_OK; } - if (conn->fec_ctl->fec_recover_failed_cnt == XQC_MAX_UINT32_VALUE) { - xqc_log(conn->log, XQC_LOG_WARN, "|fec recovered failed number exceeds maximum."); - conn->fec_ctl->fec_recover_failed_cnt = 0; - } conn->fec_ctl->fec_recover_failed_cnt++; return ret; } \ No newline at end of file diff --git a/src/transport/xqc_fec_scheme.h b/src/transport/xqc_fec_scheme.h index 8f7c077d5..3f14bcd91 100644 --- a/src/transport/xqc_fec_scheme.h +++ b/src/transport/xqc_fec_scheme.h @@ -10,6 +10,7 @@ #include #include +#include "src/transport/xqc_fec.h" #include "src/transport/fec_schemes/xqc_reed_solomon.h" @@ -19,11 +20,14 @@ typedef enum { } xqc_fec_encode_type_t; -xqc_int_t xqc_fec_encoder(xqc_connection_t *conn, unsigned char *stream); +xqc_int_t xqc_fec_encoder(xqc_connection_t *conn, unsigned char *input, size_t st_size, uint8_t fec_bm_mode); -xqc_int_t xqc_fec_decoder(xqc_connection_t *conn, xqc_int_t block_idx); +xqc_int_t xqc_fec_bc_decoder(xqc_connection_t *conn, xqc_int_t block_id, xqc_int_t loss_src_num); -xqc_int_t xqc_process_recovered_packet(xqc_connection_t *conn, unsigned char **recovered_symbols_buff, - xqc_int_t loss_symbol_idx_len); +xqc_int_t xqc_fec_cc_decoder(xqc_connection_t *conn, xqc_fec_rpr_syb_t *rpr_symbol, uint8_t lack_syb_id); + +xqc_int_t xqc_process_recovered_packet(xqc_connection_t *conn, unsigned char *recovered_payload, size_t symbol_size); + +xqc_int_t xqc_fec_encoder_check_params(xqc_connection_t *conn, xqc_int_t repair_symbol_num, xqc_fec_schemes_e encoder_scheme, size_t st_size); #endif /* _XQC_FEC_SCHEME_H_INCLUDED_ */ diff --git a/src/transport/xqc_frame.c b/src/transport/xqc_frame.c index c294f3d04..5ef9ebd09 100644 --- a/src/transport/xqc_frame.c +++ b/src/transport/xqc_frame.c @@ -45,6 +45,12 @@ static const char * const frame_type_2_str[XQC_FRAME_NUM] = { [XQC_FRAME_ACK_MP] = "ACK_MP", [XQC_FRAME_PATH_ABANDON] = "PATH_ABANDON", [XQC_FRAME_PATH_STATUS] = "PATH_STATUS", + [XQC_FRAME_PATH_AVAILABLE] = "PATH_AVAILABLE", + [XQC_FRAME_PATH_STANDBY] = "PATH_STANDBY", + [XQC_FRAME_MP_NEW_CONNECTION_ID] = "MP_NEW_CONN_ID", + [XQC_FRAME_MP_RETIRE_CONNECTION_ID] = "MP_RETIRE_CONN_ID", + [XQC_FRAME_MAX_PATH_ID] = "MAX_PATH_ID", + [XQC_FRAME_PATH_FROZEN] = "PATH_FROZEN", [XQC_FRAME_DATAGRAM] = "DATAGRAM", [XQC_FRAME_Extension] = "Extension", }; @@ -183,10 +189,13 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } if (conn->conn_state == XQC_CONN_STATE_CLOSING) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|closing state|frame_type:%ui|", + xqc_log(conn->log, XQC_LOG_DEBUG, "|closing state|frame_type:%xL|", frame_type); - /* respond connection close when recv any packet */ - if (frame_type != 0x1c && frame_type != 0x1d) { + /* respond connection close when recv any packet except conn_close and ack / ack_mp */ + if (frame_type != 0x1c && frame_type != 0x1d + && frame_type != XQC_TRANS_FRAME_TYPE_MP_ACK0 + && frame_type != XQC_TRANS_FRAME_TYPE_MP_ACK1) + { xqc_conn_immediate_close(conn); packet_in->pos = packet_in->last; return XQC_OK; @@ -199,7 +208,7 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) return XQC_OK; } - xqc_log(conn->log, XQC_LOG_DEBUG, "|frame_type:%ui|", frame_type); + xqc_log(conn->log, XQC_LOG_DEBUG, "|frame_type:%xL|", frame_type); switch (frame_type) { @@ -278,74 +287,68 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case 0x31: ret = xqc_process_datagram_frame(conn, packet_in); break; - case 0xbaba00: - case 0xbaba01: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - ret = xqc_process_ack_mp_frame(conn, packet_in); - } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version mp_ack frame or cannot process frame in mp version 04|"); - ret = -XQC_EMP_INVALID_MP_VERTION; - } - break; - case 0x15228c00: - case 0x15228c01: - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { + case XQC_TRANS_FRAME_TYPE_MP_ACK0: + case XQC_TRANS_FRAME_TYPE_MP_ACK1: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { ret = xqc_process_ack_mp_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version mp_ack frame or cannot process frame in mp version 05|"); - ret = -XQC_EMP_INVALID_MP_VERTION; - } - break; - case 0xbaba05: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - ret = xqc_process_path_abandon_frame(conn, packet_in); - } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_abandon frame or cannot process frame in mp version 04|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c05: - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { + case XQC_TRANS_FRAME_TYPE_MP_ABANDON: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { ret = xqc_process_path_abandon_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_abandon frame or cannot process frame in mp version 05|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0xbaba06: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { + + case XQC_TRANS_FRAME_TYPE_MP_STANDBY: + case XQC_TRANS_FRAME_TYPE_MP_AVAILABLE: + case XQC_TRANS_FRAME_TYPE_MP_FROZEN: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { ret = xqc_process_path_status_frame(conn, packet_in); + } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 04|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c06: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_05) { - ret = xqc_process_path_status_frame(conn, packet_in); - + + case XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_mp_new_conn_id_frame(conn, packet_in); + } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 05|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c07: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_06) { - ret = xqc_process_path_standby_frame(conn, packet_in); + case XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_mp_retire_conn_id_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 06|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; - case 0x15228c08: - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_06) { - ret = xqc_process_path_available_frame(conn, packet_in); + case XQC_TRANS_FRAME_TYPE_MAX_PATH_ID: + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + ret = xqc_process_max_path_id_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|receive wrong mp version path_status frame or cannot process frame in mp version 06|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; @@ -359,7 +362,7 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } else { xqc_log(conn->log, XQC_LOG_ERROR, "|fec negotiation failed but still received fec packet."); - ret = -XQC_EFEC_NOT_SUPPORT_FEC; + return -XQC_EIGNORE_PKT; } break; @@ -371,7 +374,7 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } else { xqc_log(conn->log, XQC_LOG_ERROR, "|fec negotiation failed but still received fec packet."); - ret = -XQC_EFEC_NOT_SUPPORT_FEC; + return -XQC_EIGNORE_PKT; } break; #endif @@ -456,7 +459,7 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_log(conn->log, XQC_LOG_DEBUG, "|offset:%ui|data_length:%ud|fin:%ud|stream_id:%ui|path:%ui|", stream_frame->data_offset, stream_frame->data_length, stream_frame->fin, stream_id, packet_in->pi_path_id); - /* TODOfec: which step should be skip considering current packet is fec recovered? */ + stream = xqc_find_stream_by_id(stream_id, conn->streams_hash); if (!stream) { if ((conn->conn_type == XQC_CONN_TYPE_SERVER && (stream_type == XQC_CLI_BID || stream_type == XQC_CLI_UNI)) @@ -480,6 +483,10 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) conn->stream_stats.recv_bytes += stream_frame->data_length; + if (packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) { + stream->stream_stats.recov_pkt_cnt++; + } + if (!(packet_in->pi_flag & XQC_PIF_FEC_RECOVERED)) { xqc_stream_path_metrics_on_recv(conn, stream, packet_in); if (packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) { @@ -741,7 +748,8 @@ xqc_process_ack_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_path_ctx_t *path = conn->conn_initial_path; xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); ret = xqc_send_ctl_on_ack_received(path->path_send_ctl, pn_ctl, conn->conn_send_queue, - &ack_info, packet_in->pkt_recv_time, 1); + &ack_info, packet_in->pkt_recv_time, + packet_in->pi_path_id == path->path_id); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_send_ctl_on_ack_received error|"); @@ -770,15 +778,13 @@ xqc_process_ping_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_int_t xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { - xqc_int_t ret = XQC_ERROR; - xqc_cid_t new_conn_cid; - uint64_t retire_prior_to; - uint64_t largest_retire_prior_to; - uint64_t cid_limit; - + xqc_int_t ret = XQC_ERROR; + xqc_cid_t new_conn_cid; + uint64_t retire_prior_to, curr_rpi; - /* the initial cid limit */ - cid_limit = conn->local_settings.active_connection_id_limit; + xqc_cid_inner_t *inner_cid; + xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; ret = xqc_parse_new_conn_id_frame(packet_in, &new_conn_cid, &retire_prior_to, conn); if (ret != XQC_OK) { @@ -788,7 +794,8 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in } xqc_log(conn->log, XQC_LOG_DEBUG, "|new_conn_id|%s|sr_token:%s", - xqc_scid_str(conn->engine, &new_conn_cid), xqc_sr_token_str(conn->engine, new_conn_cid.sr_token)); + xqc_scid_str(conn->engine, &new_conn_cid), + xqc_sr_token_str(conn->engine, new_conn_cid.sr_token)); if (retire_prior_to > new_conn_cid.cid_seq_num) { /* @@ -803,9 +810,15 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in } /* TODO: write_retire_conn_id_frame 可能涉及到 替换 path.dcid (当前无 retire_prior_to 因此不涉及) */ + curr_rpi = xqc_cid_set_get_largest_seq_or_rpt(&conn->dcid_set, XQC_INITIAL_PATH_ID); + if (curr_rpi < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current retire_prior_to error:%i|", + curr_rpi); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; + } - /* the current cid was retired and is needed no more */ - if (new_conn_cid.cid_seq_num < conn->dcid_set.largest_retire_prior_to) { + if (new_conn_cid.cid_seq_num < curr_rpi) { /* * An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller * than the Retire Prior To field of a previously received NEW_CONNECTION_ID frame @@ -813,7 +826,7 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in * connection ID, unless it has already done so for that sequence number. */ xqc_log(conn->log, XQC_LOG_DEBUG, "|seq_num:%ui smaller than largest_retire_prior_to:%ui|", - new_conn_cid.cid_seq_num, conn->dcid_set.largest_retire_prior_to); + new_conn_cid.cid_seq_num, curr_rpi); ret = xqc_write_retire_conn_id_frame_to_packet(conn, new_conn_cid.cid_seq_num); if (ret != XQC_OK) { @@ -824,25 +837,36 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in return XQC_OK; } - /* store dcid & add unused_dcid_count */ - if (xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &new_conn_cid) != NULL) { - return XQC_OK; - } + if (retire_prior_to > curr_rpi) { + /* + * Upon receipt of an increased Retire Prior To field, the peer MUST stop using the + * corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames before + * adding the newly provided connection ID to the set of active connection IDs. + */ + inner_set = xqc_get_path_cid_set(&conn->dcid_set, XQC_INITIAL_PATH_ID); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + uint64_t seq_num = inner_cid->cid.cid_seq_num; + if ((inner_cid->state == XQC_CID_UNUSED || inner_cid->state == XQC_CID_USED) + && (seq_num >= curr_rpi && seq_num < retire_prior_to)) + { + ret = xqc_write_retire_conn_id_frame_to_packet(conn, seq_num); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_retire_conn_id_frame_to_packet error|"); + return ret; + } + } + } - /* check if insertion of the new conneciton id will violate the cid limit */ - largest_retire_prior_to = xqc_max(retire_prior_to, - conn->dcid_set.largest_retire_prior_to); - if (!xqc_cid_set_validate_new_cid_limit(&conn->dcid_set.cid_set, - largest_retire_prior_to, &cid_limit)) - { - xqc_log(conn->log, XQC_LOG_ERROR, "|retire_prior_to:%ui greater than seq_num:%ui|", - retire_prior_to, new_conn_cid.cid_seq_num); - XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); - return -XQC_EPROTO; + xqc_log(conn->log, XQC_LOG_DEBUG, "|retire_prior_to|%ui|increase to|%ui|", + curr_rpi, retire_prior_to); + xqc_cid_set_set_largest_seq_or_rpt(&conn->dcid_set, XQC_INITIAL_PATH_ID, retire_prior_to); } - xqc_log(conn->log, XQC_LOG_DEBUG, "|nci allow to be inserted|seq:%ui|dcid_cnt:%ui|cid_limit:%ui", - new_conn_cid.cid_seq_num, xqc_cid_set_cnt(&conn->dcid_set.cid_set), cid_limit); + /* store dcid & add unused_dcid_count */ + if (xqc_cid_in_cid_set(&conn->dcid_set, &new_conn_cid, XQC_INITIAL_PATH_ID) != NULL) { + return XQC_OK; + } /* insert into dcid-connection hash, for processing the deprecated stateless reset packet */ @@ -865,31 +889,18 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in return ret; } - /* An endpoint MAY send connection IDs that temporarily exceed a peer's - * limit if the NEW_CONNECTION_ID frame also requires the retirement of any - * excess, by including a sufficiently large value in the Retire Prior To - * field. Hence it is not reasonable to consider it as an error */ - ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &new_conn_cid, - XQC_CID_UNUSED, cid_limit); + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &new_conn_cid, + XQC_CID_UNUSED, + conn->local_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error" - "|local_limit:%ui|largest_limit:%ui|retire_prior_to:%ui|" - "unused:%ui|used:%ui|", - conn->local_settings.active_connection_id_limit, - cid_limit, retire_prior_to, conn->dcid_set.cid_set.unused_cnt, - conn->dcid_set.cid_set.used_cnt); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", + conn->local_settings.active_connection_id_limit, + xqc_cid_set_get_unused_cnt(&conn->dcid_set, XQC_INITIAL_PATH_ID), + xqc_cid_set_get_used_cnt(&conn->dcid_set, XQC_INITIAL_PATH_ID)); return ret; } - /* - * Upon receipt of an increased Retire Prior To field, the peer MUST stop - * using the corresponding connection IDs and retire them with - * RETIRE_CONNECTION_ID frames before adding the newly provided connection - * ID to the set of active connection IDs. - */ - if (retire_prior_to > conn->dcid_set.largest_retire_prior_to) { - xqc_conn_retire_dcid_prior_to(conn, retire_prior_to); - } return XQC_OK; } @@ -898,7 +909,7 @@ xqc_int_t xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; - uint64_t seq_num; + uint64_t seq_num = 0, largest_scid_seq_num = 0; ret = xqc_parse_retire_conn_id_frame(packet_in, &seq_num); if (ret != XQC_OK) { @@ -911,27 +922,32 @@ xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet return XQC_OK; } - if (seq_num > conn->scid_set.largest_scid_seq_num) { + largest_scid_seq_num = xqc_cid_set_get_largest_seq_or_rpt(&conn->scid_set, XQC_INITIAL_PATH_ID); + if (largest_scid_seq_num < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current largest_scid_seq_num error:%i|", + largest_scid_seq_num); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; + } + + if (seq_num > largest_scid_seq_num) { /* * Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number * greater than any previously sent to the peer MUST be treated as a * connection error of type PROTOCOL_VIOLATION. */ - xqc_log(conn->log, XQC_LOG_ERROR, "|no match seq_num|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|no match seq_num|seq:%ui|", seq_num); XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); return -XQC_EPROTO; } - xqc_cid_inner_t *inner_cid = xqc_get_inner_cid_by_seq(&conn->scid_set.cid_set, seq_num); + xqc_cid_inner_t *inner_cid = xqc_get_inner_cid_by_seq(&conn->scid_set, seq_num, XQC_INITIAL_PATH_ID); if (inner_cid == NULL) { xqc_log(conn->log, XQC_LOG_DEBUG, "|can't find scid with seq_num:%ui|", seq_num); return XQC_OK; } - /* skip if cid not available anymore */ - if (!xqc_validate_retire_cid_frame(&conn->scid_set.cid_set, inner_cid)) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|cid not valid any more|seq_num:%ui", - seq_num); + if (inner_cid->state >= XQC_CID_RETIRED) { return XQC_OK; } @@ -954,7 +970,7 @@ xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet /* update SCID */ if (XQC_OK == xqc_cid_is_equal(&conn->scid_set.user_scid, &inner_cid->cid)) { - ret = xqc_conn_update_user_scid(conn, &conn->scid_set); + ret = xqc_conn_update_user_scid(conn); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have other used scid, can't retire user_scid|"); return ret; @@ -963,12 +979,7 @@ xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet xqc_log(conn->log, XQC_LOG_DEBUG, "|switch scid to %ui|", conn->scid_set.user_scid.cid_seq_num); } - /* TODO: 如果对应 “Active” Path 则需要替换 CID */ - // xqc_path_ctx_t *path = xqc_conn_find_path_by_scid(conn, &inner_cid->cid); - // if (path != NULL) { - // xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|state:%d|", path->path_id, path->path_state); - // } - + /* TODO: update path scid */ return XQC_OK; } @@ -1466,24 +1477,24 @@ xqc_process_path_challenge_frame(xqc_connection_t *conn, xqc_packet_in_t *packet return XQC_OK; } - //TODO: MPQUIC fix migration xqc_path_ctx_t *path = NULL; if (conn->enable_multipath) { - path = xqc_conn_find_path_by_scid(conn, &packet_in->pi_pkt.pkt_dcid); + path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); } else { path = conn->conn_initial_path; } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|path_id=%ui|", packet_in->pi_path_id); if (path == NULL) { if (conn->conn_type == XQC_CONN_TYPE_SERVER) { /* try to create new path */ - path = xqc_conn_create_path_inner(conn, &packet_in->pi_pkt.pkt_dcid, NULL, XQC_APP_PATH_STATUS_AVAILABLE); + path = xqc_conn_create_path_inner(conn, &packet_in->pi_pkt.pkt_dcid, NULL, XQC_APP_PATH_STATUS_AVAILABLE, packet_in->pi_path_id); if (path == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_create_path_inner err|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_create_path_inner err|%ui|", packet_in->pi_path_id); return -XQC_EMP_CREATE_PATH; } - packet_in->pi_path_id = path->path_id; conn->validating_path_id = path->path_id; conn->conn_flag |= XQC_CONN_FLAG_RECV_NEW_PATH; @@ -1527,10 +1538,9 @@ xqc_process_path_response_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_ return XQC_OK; } - //TODO: MPQUIC fix migration xqc_path_ctx_t *path = NULL; if (conn->enable_multipath) { - path = xqc_conn_find_path_by_scid(conn, &packet_in->pi_pkt.pkt_dcid); + path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|ingnore path response|pkt_dcid:%s|path_id:%ui|", @@ -1603,8 +1613,8 @@ xqc_process_ack_mp_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_int_t ret; xqc_ack_info_t ack_info; - uint64_t dcid_seq_num; - ret = xqc_parse_ack_mp_frame(packet_in, conn, &dcid_seq_num, &ack_info); + uint64_t path_id = 0; + ret = xqc_parse_ack_mp_frame(packet_in, conn, &path_id, &ack_info); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_ack_mp_frame error|"); return ret; @@ -1614,9 +1624,16 @@ xqc_process_ack_mp_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) return XQC_OK; } - xqc_path_ctx_t *path_to_be_acked = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } + + xqc_path_ctx_t *path_to_be_acked = xqc_conn_find_path_by_path_id(conn, path_id); if (path_to_be_acked == NULL) { - xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|dcid_seq:%ui|", dcid_seq_num); + xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|path:%ui|", path_id); return XQC_OK; } @@ -1650,21 +1667,31 @@ xqc_process_path_abandon_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_i { xqc_int_t ret = XQC_ERROR; - uint64_t dcid_seq_num; + uint64_t path_id = 0; uint64_t error_code; - ret = xqc_parse_path_abandon_frame(packet_in, &dcid_seq_num, &error_code); + ret = xqc_parse_path_abandon_frame(packet_in, &path_id, &error_code); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_abandon_frame error|"); return ret; } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + xqc_log(conn->log, XQC_LOG_DEBUG, "|path abandon|path_id:%ui|", path_id); + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } + //MPQUIC: path associated cid resources should be released and path id should be consumed anyway + xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); + "|no context for abandoned path|path_id:%ui|pi_path_id:%ui|", + path_id, packet_in->pi_path_id); + xqc_cid_set_update_state(&conn->dcid_set, path_id, XQC_CID_SET_ABANDONED); + xqc_cid_set_update_state(&conn->scid_set, path_id, XQC_CID_SET_ABANDONED); return XQC_OK; /* ignore */ } @@ -1691,34 +1718,42 @@ xqc_process_path_abandon_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_i return XQC_OK; } -xqc_int_t +xqc_int_t xqc_process_path_status_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; - - uint64_t dcid_seq_num; + uint64_t path_id = 0; uint64_t path_status_seq_num; uint64_t path_status; - ret = xqc_parse_path_status_frame(packet_in, &dcid_seq_num, &path_status_seq_num, &path_status); + ret = xqc_parse_path_status_frame(packet_in, &path_id, &path_status_seq_num, &path_status); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_status_frame error|"); return ret; } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + xqc_log(conn->log, XQC_LOG_DEBUG, "|path status:%ui|path_id:%ui|", path_status, path_id); + + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } + + xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|pi_path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); + "|invalid path|path_id:%ui|pi_path_id:%ui|", + path_id, packet_in->pi_path_id); return XQC_OK; /* ignore */ } if (path_status_seq_num > path->app_path_status_recv_seq_num) { path->app_path_status_recv_seq_num = path_status_seq_num; path->next_app_path_state = path_status; - + if (path->path_state < XQC_PATH_STATE_ACTIVE) { path->path_flag |= XQC_PATH_FLAG_RECV_STATUS; @@ -1730,99 +1765,317 @@ xqc_process_path_status_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in return XQC_OK; } + xqc_int_t -xqc_process_path_standby_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +xqc_process_mp_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; + xqc_cid_t new_conn_cid; + uint64_t retire_prior_to, curr_rpi; - uint64_t dcid_seq_num; - uint64_t path_status_seq_num; - uint64_t path_status; + xqc_cid_inner_t *inner_cid; + xqc_list_head_t *pos, *next; + xqc_cid_set_inner_t *inner_set; + uint64_t path_id; - ret = xqc_parse_path_standby_frame(packet_in, &dcid_seq_num, &path_status_seq_num, &path_status); + ret = xqc_parse_mp_new_conn_id_frame(packet_in, &new_conn_cid, &retire_prior_to, &path_id, conn); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_status_frame error|"); + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_parse_new_conn_id_frame error|"); return ret; } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } - if (path == NULL) { - xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|pi_path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); - return XQC_OK; /* ignore */ + xqc_log(conn->log, XQC_LOG_DEBUG, "|new_conn_id|%s|sr_token:%s", + xqc_scid_str(conn->engine, &new_conn_cid), + xqc_sr_token_str(conn->engine, new_conn_cid.sr_token)); + + if (retire_prior_to > new_conn_cid.cid_seq_num) { + /* + * The Retire Prior To field MUST be less than or equal to the Sequence Number field. + * Receiving a value greater than the Sequence Number MUST be treated as a connection + * error of type FRAME_ENCODING_ERROR. + */ + xqc_log(conn->log, XQC_LOG_ERROR, "|path:%ui|retire_prior_to:%ui greater than seq_num:%ui|", + path_id, retire_prior_to, new_conn_cid.cid_seq_num); + XQC_CONN_ERR(conn, TRA_FRAME_ENCODING_ERROR); + return -XQC_EPROTO; } - if (path_status_seq_num > path->app_path_status_recv_seq_num) { - path->app_path_status_recv_seq_num = path_status_seq_num; - path->next_app_path_state = path_status; + /* TODO: write_retire_conn_id_frame 可能涉及到 替换 path.dcid (当前无 retire_prior_to 因此不涉及) */ + curr_rpi = xqc_cid_set_get_largest_seq_or_rpt(&conn->dcid_set, path_id); + if (curr_rpi < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current retire_prior_to error:%i|path:%ui|", + curr_rpi, path_id); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; + } - if (path->path_state < XQC_PATH_STATE_ACTIVE) { - path->path_flag |= XQC_PATH_FLAG_RECV_STATUS; + if (new_conn_cid.cid_seq_num < curr_rpi) { + /* + * An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller + * than the Retire Prior To field of a previously received NEW_CONNECTION_ID frame + * MUST send a corresponding RETIRE_CONNECTION_ID frame that retires the newly received + * connection ID, unless it has already done so for that sequence number. + */ + xqc_log(conn->log, XQC_LOG_DEBUG, "|seq_num:%ui smaller than largest_retire_prior_to:%ui|", + new_conn_cid.cid_seq_num, curr_rpi); - } else { - xqc_set_application_path_status(path, path->next_app_path_state, XQC_FALSE); + ret = xqc_write_mp_retire_conn_id_frame_to_packet(conn, new_conn_cid.cid_seq_num, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path:%ui|xqc_write_mp_retire_conn_id_frame_to_packet error|", path_id); + return ret; + } + + return XQC_OK; + } + + if (retire_prior_to > curr_rpi) { + /* + * Upon receipt of an increased Retire Prior To field, the peer MUST stop using the + * corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames before + * adding the newly provided connection ID to the set of active connection IDs. + */ + inner_set = xqc_get_path_cid_set(&conn->dcid_set, path_id); + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + uint64_t seq_num = inner_cid->cid.cid_seq_num; + if ((inner_cid->state == XQC_CID_UNUSED || inner_cid->state == XQC_CID_USED) + && (seq_num >= curr_rpi && seq_num < retire_prior_to)) + { + ret = xqc_write_mp_retire_conn_id_frame_to_packet(conn, seq_num, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path_id:%ui|xqc_write_mp_retire_conn_id_frame_to_packet error|", + path_id); + return ret; + } + } } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|retire_prior_to|%ui|increase to|%ui|", + path_id, curr_rpi, retire_prior_to); + xqc_cid_set_set_largest_seq_or_rpt(&conn->dcid_set, path_id, retire_prior_to); + } + + /* store dcid & add unused_dcid_count */ + if (xqc_cid_in_cid_set(&conn->dcid_set, &new_conn_cid, path_id) != NULL) { + return XQC_OK; + } + + /* insert into dcid-connection hash, for processing the deprecated stateless + reset packet */ + ret = xqc_insert_conns_hash(conn->engine->conns_hash_dcid, conn, + new_conn_cid.cid_buf, new_conn_cid.cid_len); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|insert new_cid into conns_hash_dcid failed|"); + return ret; + } + + /* insert into sr_token-connection hash, for processing stateless reset + packet */ + ret = xqc_insert_conns_hash(conn->engine->conns_hash_sr_token, conn, + new_conn_cid.sr_token, + XQC_STATELESS_RESET_TOKENLEN); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|insert new_cid into conns_hash_sr_token failed|"); + return ret; + } + + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &new_conn_cid, + XQC_CID_UNUSED, + conn->local_settings.active_connection_id_limit, + path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|path:%ui|", + conn->local_settings.active_connection_id_limit, + xqc_cid_set_get_unused_cnt(&conn->dcid_set, path_id), + xqc_cid_set_get_used_cnt(&conn->dcid_set, path_id), + path_id); + return ret; } return XQC_OK; } - xqc_int_t -xqc_process_path_available_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +xqc_process_mp_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret = XQC_ERROR; + uint64_t seq_num = 0, largest_scid_seq_num = 0, path_id; - uint64_t dcid_seq_num; - uint64_t path_status_seq_num; - uint64_t path_status; - - ret = xqc_parse_path_available_frame(packet_in, &dcid_seq_num, &path_status_seq_num, &path_status); + ret = xqc_parse_mp_retire_conn_id_frame(packet_in, &seq_num, &path_id); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_path_status_frame error|"); + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_parse_retire_conn_id_frame error|"); return ret; } + + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } - xqc_path_ctx_t *path = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); + if (path_id > conn->local_max_path_id) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path_id exceeds limit|path_id:%ui|limit:%ui|", + path_id, conn->local_max_path_id); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return -XQC_EILLEGAL_FRAME; + } - if (path == NULL) { - xqc_log(conn->log, XQC_LOG_WARN, - "|invalid path|dcid_seq_num:%ui|pi_path_id:%ui|", - dcid_seq_num, packet_in->pi_path_id); - return XQC_OK; /* ignore */ + largest_scid_seq_num = xqc_cid_set_get_largest_seq_or_rpt(&conn->scid_set, path_id); + if (largest_scid_seq_num < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|current largest_scid_seq_num error:%i|path:%ui|", + largest_scid_seq_num, path_id); + XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); + return -XQC_EPROTO; } - if (path_status_seq_num > path->app_path_status_recv_seq_num) { - path->app_path_status_recv_seq_num = path_status_seq_num; - path->next_app_path_state = path_status; + if (seq_num > largest_scid_seq_num) { + /* + * Receipt of a RETIRE_CONNECTION_ID frame containing a sequence number + * greater than any previously sent to the peer MUST be treated as a + * connection error of type PROTOCOL_VIOLATION. + */ + xqc_log(conn->log, XQC_LOG_ERROR, "|no match seq_num|seq:%ui|path:%ui|", seq_num, path_id); + XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); + return -XQC_EPROTO; + } - if (path->path_state < XQC_PATH_STATE_ACTIVE) { - path->path_flag |= XQC_PATH_FLAG_RECV_STATUS; + xqc_cid_inner_t *inner_cid = xqc_get_inner_cid_by_seq(&conn->scid_set, seq_num, path_id); + if (inner_cid == NULL) { + xqc_log(conn->log, XQC_LOG_DEBUG, + "|can't find scid with seq_num:%ui|path:%ui|", + seq_num, path_id); + return XQC_OK; + } - } else { - xqc_set_application_path_status(path, path->next_app_path_state, XQC_FALSE); + if (inner_cid->state >= XQC_CID_RETIRED) { + return XQC_OK; + } + + if (XQC_OK == xqc_cid_is_equal(&inner_cid->cid, &packet_in->pi_pkt.pkt_dcid)) { + /* + * The sequence number specified in a RETIRE_CONNECTION_ID frame MUST NOT refer to + * the Destination Connection ID field of the packet in which the frame is contained. + * The peer MAY treat this as a connection error of type PROTOCOL_VIOLATION. + */ + xqc_log(conn->log, XQC_LOG_ERROR, "|seq_num refer to pkt_dcid|"); + XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION); + return -XQC_EPROTO; + } + + ret = xqc_conn_set_cid_retired_ts(conn, inner_cid); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_set_cid_retired_ts error|"); + return ret; + } + + /* update SCID */ + if (XQC_OK == xqc_cid_is_equal(&conn->scid_set.user_scid, &inner_cid->cid)) { + ret = xqc_conn_update_user_scid(conn); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have other used scid, can't retire user_scid|"); + return ret; } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|switch scid to %ui|", conn->scid_set.user_scid.cid_seq_num); } return XQC_OK; } +xqc_int_t +xqc_process_max_path_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +{ + xqc_int_t ret = XQC_ERROR; + uint64_t max_path_id, new_max_path_id; + + ret = xqc_parse_max_path_id_frame(packet_in, &max_path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_process_max_paths_frame error|"); + return ret; + } + + xqc_log(conn->log, XQC_LOG_DEBUG, + "|max_path_id:%ui|prev_max_path_id:%ui|", max_path_id, conn->remote_max_path_id); + + if (conn->remote_max_path_id < max_path_id) { + conn->remote_max_path_id = max_path_id; + new_max_path_id = xqc_min(conn->local_max_path_id, conn->remote_max_path_id); + if (new_max_path_id > conn->curr_max_path_id) { + if (xqc_conn_add_path_cid_sets(conn, conn->curr_max_path_id + 1, new_max_path_id) != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|add_path_cid_sets_error|"); + return -XQC_EMALLOC; + } + conn->curr_max_path_id = new_max_path_id; + } + } + + return ret; +} + #ifdef XQC_ENABLE_FEC + +uint32_t +xqc_parse_block_number(uint64_t payload_id) +{ + return payload_id >> 8; +} + +uint32_t +xqc_parse_symbol_number(uint64_t payload_id) +{ + return payload_id & 0xff; +} + + xqc_int_t xqc_process_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { - xqc_int_t ret; + xqc_int_t ret, remain_frame_len, symbol_size; + uint64_t src_payload_id, symbol_idx, block_id; - ret = xqc_parse_sid_frame(conn, packet_in); + ret = xqc_parse_sid_frame(conn, packet_in, &src_payload_id, &symbol_size); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_sid_frame err|ret:%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_parse_sid_frame err|ret:%d|", ret); + return -XQC_EFEC_SYMBOL_ERROR; } - if (ret == -XQC_EVINTREAD) { - return ret; + // If current packet is fec recovered, should not be used in fec decoder + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + if (symbol_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|received source symbol size is too large"); + return XQC_OK; } - /* if there's error, just ignore fec module */ + + block_id = xqc_parse_block_number(src_payload_id); + symbol_idx = xqc_parse_symbol_number(src_payload_id); + // update buffered symbols according to received symbol. + ret = xqc_process_src_symbol(conn, block_id, symbol_idx, packet_in->decode_payload, symbol_size); + if (ret != XQC_OK) { + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return XQC_OK; + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|process source symbol error"); + return ret; + } + } + + xqc_try_process_fec_decode(conn, block_id); return XQC_OK; } @@ -1830,15 +2083,31 @@ xqc_int_t xqc_process_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) { xqc_int_t ret; - - ret = xqc_parse_repair_frame(conn, packet_in); + xqc_fec_rpr_syb_t tmp_rpr_syb; + + conn->fec_ctl->fec_recv_repair_num_total++; + xqc_memset(&tmp_rpr_syb, 0, sizeof(xqc_fec_rpr_syb_t)); + ret = xqc_parse_repair_frame(conn, packet_in, &tmp_rpr_syb); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_repair_frame err|ret:%d|", ret); + if (ret != -XQC_EFEC_TOLERABLE_ERROR) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_parse_repair_frame error|err:%d", ret); + return ret; + } + return XQC_OK; } - if (ret == -XQC_EVINTREAD) { + + // update buffered symbols according to received symbol. + ret = xqc_process_rpr_symbol(conn, &tmp_rpr_syb); + if (ret != XQC_OK) { + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return XQC_OK; + } + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_parse_repair_frame error|err:%d", ret); return ret; } - /* if there's error, just ignore fec module */ + + xqc_try_process_fec_decode(conn, tmp_rpr_syb.block_id); return XQC_OK; } + #endif \ No newline at end of file diff --git a/src/transport/xqc_frame.h b/src/transport/xqc_frame.h index ff7d18857..bf7ca5af3 100644 --- a/src/transport/xqc_frame.h +++ b/src/transport/xqc_frame.h @@ -33,6 +33,10 @@ typedef enum { XQC_FRAME_PATH_STATUS, XQC_FRAME_PATH_STANDBY, XQC_FRAME_PATH_AVAILABLE, + XQC_FRAME_MP_NEW_CONNECTION_ID, + XQC_FRAME_MP_RETIRE_CONNECTION_ID, + XQC_FRAME_MAX_PATH_ID, + XQC_FRAME_PATH_FROZEN, XQC_FRAME_DATAGRAM, XQC_FRAME_Extension, XQC_FRAME_NUM, @@ -41,36 +45,40 @@ typedef enum { } xqc_frame_type_t; typedef enum { - XQC_FRAME_BIT_PADDING = 1 << XQC_FRAME_PADDING, - XQC_FRAME_BIT_PING = 1 << XQC_FRAME_PING, - XQC_FRAME_BIT_ACK = 1 << XQC_FRAME_ACK, - XQC_FRAME_BIT_RESET_STREAM = 1 << XQC_FRAME_RESET_STREAM, - XQC_FRAME_BIT_STOP_SENDING = 1 << XQC_FRAME_STOP_SENDING, - XQC_FRAME_BIT_CRYPTO = 1 << XQC_FRAME_CRYPTO, - XQC_FRAME_BIT_NEW_TOKEN = 1 << XQC_FRAME_NEW_TOKEN, - XQC_FRAME_BIT_STREAM = 1 << XQC_FRAME_STREAM, - XQC_FRAME_BIT_MAX_DATA = 1 << XQC_FRAME_MAX_DATA, - XQC_FRAME_BIT_MAX_STREAM_DATA = 1 << XQC_FRAME_MAX_STREAM_DATA, - XQC_FRAME_BIT_MAX_STREAMS = 1 << XQC_FRAME_MAX_STREAMS, - XQC_FRAME_BIT_DATA_BLOCKED = 1 << XQC_FRAME_DATA_BLOCKED, - XQC_FRAME_BIT_STREAM_DATA_BLOCKED = 1 << XQC_FRAME_STREAM_DATA_BLOCKED, - XQC_FRAME_BIT_STREAMS_BLOCKED = 1 << XQC_FRAME_STREAMS_BLOCKED, - XQC_FRAME_BIT_NEW_CONNECTION_ID = 1 << XQC_FRAME_NEW_CONNECTION_ID, - XQC_FRAME_BIT_RETIRE_CONNECTION_ID = 1 << XQC_FRAME_RETIRE_CONNECTION_ID, - XQC_FRAME_BIT_PATH_CHALLENGE = 1 << XQC_FRAME_PATH_CHALLENGE, - XQC_FRAME_BIT_PATH_RESPONSE = 1 << XQC_FRAME_PATH_RESPONSE, - XQC_FRAME_BIT_CONNECTION_CLOSE = 1 << XQC_FRAME_CONNECTION_CLOSE, - XQC_FRAME_BIT_HANDSHAKE_DONE = 1 << XQC_FRAME_HANDSHAKE_DONE, - XQC_FRAME_BIT_ACK_MP = 1 << XQC_FRAME_ACK_MP, - XQC_FRAME_BIT_PATH_ABANDON = 1 << XQC_FRAME_PATH_ABANDON, - XQC_FRAME_BIT_PATH_STATUS = 1 << XQC_FRAME_PATH_STATUS, - XQC_FRAME_BIT_PATH_STANDBY = 1 << XQC_FRAME_PATH_STANDBY, - XQC_FRAME_BIT_PATH_AVAILABLE = 1 << XQC_FRAME_PATH_AVAILABLE, - XQC_FRAME_BIT_DATAGRAM = 1 << XQC_FRAME_DATAGRAM, - XQC_FRAME_BIT_Extension = 1 << XQC_FRAME_Extension, - XQC_FRAME_BIT_NUM = 1 << XQC_FRAME_NUM, - XQC_FRAME_BIT_SID = 1 << XQC_FRAME_SID, - XQC_FRAME_BIT_REPAIR_SYMBOL = 1 << XQC_FRAME_REPAIR_SYMBOL, + XQC_FRAME_BIT_PADDING = 1ULL << XQC_FRAME_PADDING, + XQC_FRAME_BIT_PING = 1ULL << XQC_FRAME_PING, + XQC_FRAME_BIT_ACK = 1ULL << XQC_FRAME_ACK, + XQC_FRAME_BIT_RESET_STREAM = 1ULL << XQC_FRAME_RESET_STREAM, + XQC_FRAME_BIT_STOP_SENDING = 1ULL << XQC_FRAME_STOP_SENDING, + XQC_FRAME_BIT_CRYPTO = 1ULL << XQC_FRAME_CRYPTO, + XQC_FRAME_BIT_NEW_TOKEN = 1ULL << XQC_FRAME_NEW_TOKEN, + XQC_FRAME_BIT_STREAM = 1ULL << XQC_FRAME_STREAM, + XQC_FRAME_BIT_MAX_DATA = 1ULL << XQC_FRAME_MAX_DATA, + XQC_FRAME_BIT_MAX_STREAM_DATA = 1ULL << XQC_FRAME_MAX_STREAM_DATA, + XQC_FRAME_BIT_MAX_STREAMS = 1ULL << XQC_FRAME_MAX_STREAMS, + XQC_FRAME_BIT_DATA_BLOCKED = 1ULL << XQC_FRAME_DATA_BLOCKED, + XQC_FRAME_BIT_STREAM_DATA_BLOCKED = 1ULL << XQC_FRAME_STREAM_DATA_BLOCKED, + XQC_FRAME_BIT_STREAMS_BLOCKED = 1ULL << XQC_FRAME_STREAMS_BLOCKED, + XQC_FRAME_BIT_NEW_CONNECTION_ID = 1ULL << XQC_FRAME_NEW_CONNECTION_ID, + XQC_FRAME_BIT_RETIRE_CONNECTION_ID = 1ULL << XQC_FRAME_RETIRE_CONNECTION_ID, + XQC_FRAME_BIT_PATH_CHALLENGE = 1ULL << XQC_FRAME_PATH_CHALLENGE, + XQC_FRAME_BIT_PATH_RESPONSE = 1ULL << XQC_FRAME_PATH_RESPONSE, + XQC_FRAME_BIT_CONNECTION_CLOSE = 1ULL << XQC_FRAME_CONNECTION_CLOSE, + XQC_FRAME_BIT_HANDSHAKE_DONE = 1ULL << XQC_FRAME_HANDSHAKE_DONE, + XQC_FRAME_BIT_ACK_MP = 1ULL << XQC_FRAME_ACK_MP, + XQC_FRAME_BIT_PATH_ABANDON = 1ULL << XQC_FRAME_PATH_ABANDON, + XQC_FRAME_BIT_PATH_STATUS = 1ULL << XQC_FRAME_PATH_STATUS, + XQC_FRAME_BIT_PATH_STANDBY = 1ULL << XQC_FRAME_PATH_STANDBY, + XQC_FRAME_BIT_PATH_AVAILABLE = 1ULL << XQC_FRAME_PATH_AVAILABLE, + XQC_FRAME_BIT_MP_NEW_CONNECTION_ID = 1ULL << XQC_FRAME_MP_NEW_CONNECTION_ID, + XQC_FRAME_BIT_MP_RETIRE_CONNECTION_ID = 1ULL << XQC_FRAME_MP_RETIRE_CONNECTION_ID, + XQC_FRAME_BIT_MAX_PATH_ID = 1ULL << XQC_FRAME_MAX_PATH_ID, + XQC_FRAME_BIT_PATH_FROZEN = 1ULL << XQC_FRAME_PATH_FROZEN, + XQC_FRAME_BIT_DATAGRAM = 1ULL << XQC_FRAME_DATAGRAM, + XQC_FRAME_BIT_Extension = 1ULL << XQC_FRAME_Extension, + XQC_FRAME_BIT_NUM = 1ULL << XQC_FRAME_NUM, + XQC_FRAME_BIT_SID = 1ULL << XQC_FRAME_SID, + XQC_FRAME_BIT_REPAIR_SYMBOL = 1ULL << XQC_FRAME_REPAIR_SYMBOL, } xqc_frame_type_bit_t; @@ -83,7 +91,7 @@ typedef enum { CONNECTION_CLOSE frames, are not sent again when packet loss is detected, but as described in Section 10. */ -#define XQC_IS_ACK_ELICITING(types) ((types) & ~(XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP| XQC_FRAME_BIT_PADDING | XQC_FRAME_BIT_CONNECTION_CLOSE | XQC_FRAME_BIT_SID | XQC_FRAME_BIT_REPAIR_SYMBOL)) +#define XQC_IS_ACK_ELICITING(types) ((types) & ~(XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP| XQC_FRAME_BIT_PADDING | XQC_FRAME_BIT_CONNECTION_CLOSE)) /* * https://tools.ietf.org/html/draft-ietf-quic-recovery-24#section-3 @@ -160,14 +168,16 @@ xqc_int_t xqc_process_path_abandon_frame(xqc_connection_t *conn, xqc_packet_in_t xqc_int_t xqc_process_path_status_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); -xqc_int_t xqc_process_path_standby_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); - -xqc_int_t xqc_process_path_available_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); - xqc_int_t xqc_process_datagram_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); xqc_int_t xqc_process_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); xqc_int_t xqc_process_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); +xqc_int_t xqc_process_mp_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + +xqc_int_t xqc_process_mp_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + +xqc_int_t xqc_process_max_path_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + #endif /* _XQC_FRAME_H_INCLUDED_ */ diff --git a/src/transport/xqc_frame_parser.c b/src/transport/xqc_frame_parser.c index a615337ef..040b4ff09 100644 --- a/src/transport/xqc_frame_parser.c +++ b/src/transport/xqc_frame_parser.c @@ -257,6 +257,8 @@ xqc_gen_stream_frame(xqc_packet_out_t *packet_out, if (length_len) { *p++ = 0; + } else { + packet_out->po_flag |= XQC_POF_STREAM_NO_LEN; } } @@ -317,6 +319,7 @@ xqc_parse_stream_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, p += vlen; if (length > end - p) { + xqc_log(conn->log, XQC_LOG_ERROR, "|parse stream frame error|stream length:%d|packet length:%d",length, end - p); return -XQC_EILLEGAL_FRAME; } frame->data_length = length; @@ -535,23 +538,154 @@ xqc_parse_ping_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn) } #ifdef XQC_ENABLE_FEC + + +void +xqc_get_lack_src_syb(unsigned char* pm, unsigned char* recv_mask, xqc_int_t m_size, + uint8_t *syb_idx, uint8_t *syb_num) +{ + uint8_t i, flag, cur_syb_id; + + *syb_idx = XQC_FEC_MAX_SYMBOL_NUM_PBLOCK; + *syb_num = 0; + flag = 0x80; + cur_syb_id = 0; + + if (m_size > XQC_MAX_RPR_KEY_SIZE) { + return; + } + + for (i = 0; i < m_size; i++) { + while (1) { + if ((flag & (*(pm + i) ^ *(recv_mask + i)))) { + *syb_num = *syb_num + 1; + if (*syb_idx == XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + *syb_idx = cur_syb_id; + } + } + cur_syb_id++; + if (flag == 0x01) { + break; + } + flag = flag >> 1; + } + flag = 0x80; + } +} + +void +xqc_try_process_fec_decode(xqc_connection_t *conn, xqc_int_t block_id) +{ + xqc_int_t ret, max_src_symbol_num, recv_src_num, recv_rpr_num; + xqc_list_head_t *pos, *next; + xqc_fec_schemes_e fec_scheme; + + max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; + fec_scheme = conn->conn_settings.fec_params.fec_decoder_scheme; + recv_src_num = xqc_cnt_src_symbols_num(conn->fec_ctl, block_id); + recv_rpr_num = xqc_cnt_rpr_symbols_num(conn->fec_ctl, block_id); + + switch (fec_scheme) { + case XQC_REED_SOLOMON_CODE: + case XQC_XOR_CODE: + if (recv_src_num + recv_rpr_num >= max_src_symbol_num) { + /* FEC decode/flush buffer */ + if (recv_src_num >= max_src_symbol_num) { + xqc_fec_ctl_init_recv_params(conn->fec_ctl, block_id); + goto after_decoder; + + } else if (recv_rpr_num > 0) { + ret = xqc_fec_bc_decoder(conn, block_id, max_src_symbol_num - recv_src_num); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fec xqc_fec_bc_decoder error|ret:%d|", ret); + } + xqc_fec_ctl_init_recv_params(conn->fec_ctl, block_id); + goto after_decoder; + } + } + return; + case XQC_PACKET_MASK_CODE: + // check each recv mask in rpr symbol, if only lack one src symbol + xqc_list_for_each_safe(pos, next, &conn->fec_ctl->fec_recv_rpr_syb_list) { + xqc_fec_rpr_syb_t *symbol = xqc_list_entry(pos, xqc_fec_rpr_syb_t, fec_list); + uint8_t lack_syb_num, fst_lack_syb_id; + lack_syb_num = fst_lack_syb_id = 0; + + if (symbol->block_id < block_id) { + continue; + } + if (symbol->block_id > block_id) { + break; + } + xqc_get_lack_src_syb(symbol->repair_key, symbol->recv_mask, symbol->repair_key_size, + &fst_lack_syb_id, &lack_syb_num); + if (lack_syb_num == 0) { + xqc_remove_rpr_symbol_from_list(conn->fec_ctl, symbol); + + } else if (lack_syb_num == 1) { + // current repair packet satisfy the conditions of decoding + ret = xqc_fec_cc_decoder(conn, symbol, fst_lack_syb_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|fec xqc_fec_cc_decoder error|ret:%d|", ret); + } + xqc_remove_rpr_symbol_from_list(conn->fec_ctl, symbol); + } + } + return; + default: + return; + } +after_decoder: + if (block_id > conn->fec_ctl->fec_max_fin_blk_id) { + conn->fec_ctl->fec_max_fin_blk_id = block_id; + } +} +xqc_int_t +xqc_check_gen_sid_param(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + xqc_int_t po_remained_size; + + if (packet_out->po_flag & XQC_POF_STREAM_NO_LEN) { + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|packet_out stream frame have no LEN bit, cannot support superaddition of other frame.|"); + return -XQC_EFEC_TOLERABLE_ERROR; + } + + po_remained_size = packet_out->po_buf_size - packet_out->po_used_size + (packet_out->po_frame_types & XQC_FRAME_BIT_ACK ? XQC_ACK_SPACE : 0); + if (po_remained_size < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|po_used_size exceeds po_buf_size|po_used_size:%d|po_buf_size:%d|", packet_out->po_used_size, packet_out->po_buf_size); + return -XQC_EPARAM; + } + + if (po_remained_size < packet_out->po_reserved_size || packet_out->po_reserved_size == 0) { + if (packet_out->po_reserved_size != 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|packet_out reserved buff are taken|po_frame:%d|po_buf_size:%d|po_used_size:%d|po_reserved_size:%d", + packet_out->po_frame_types, packet_out->po_buf_size, packet_out->po_used_size, packet_out->po_reserved_size); + + } else if (conn->conn_settings.fec_params.fec_encoder_scheme != 0){ + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|reserved size is zero"); + } + return -XQC_EFEC_TOLERABLE_ERROR; + } + return XQC_OK; +} + ssize_t xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) -{ - size_t dst_buf_len = XQC_FEC_SPACE; +{ + size_t dst_buf_len = packet_out->po_reserved_size; uint64_t flow_id = 0, src_payload_id = 0, frame_type = 0xfec5; unsigned need, frame_type_bits, flow_id_bits, src_payload_id_bits; xqc_int_t ret = 0; unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf, *end = dst_buf + dst_buf_len; - if (packet_out->po_used_size > XQC_QUIC_MAX_MSS) { - xqc_log(conn->log, XQC_LOG_ERROR, "|packet_out too large|"); - return -XQC_ENOBUF; + ret = xqc_check_gen_sid_param(conn, packet_out); + if (ret != XQC_OK) { + return ret; } /* gen src_payload_id and save src symbol */ - ret = xqc_gen_src_payload_id(conn->fec_ctl, &src_payload_id); + ret = xqc_gen_src_payload_id(conn->fec_ctl, &src_payload_id, packet_out->po_stream_fec_blk_mode); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|generate source payload id error."); return -XQC_EFEC_SYMBOL_ERROR; @@ -564,9 +698,6 @@ xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) + xqc_vint_len(flow_id_bits) + xqc_vint_len(src_payload_id_bits); /* Explicit Source Payload ID */ - // xqc_log(conn->log, XQC_LOG_DEBUG, "|src_payload_id: %d, len: %d, sid_frame_len: %d", - // src_payload_id, xqc_vint_len(src_payload_id_bits), need); - if (dst_buf + need > end) { xqc_log(conn->log, XQC_LOG_ERROR, "|data length exceed packetout buffer."); return -XQC_ENOBUF; @@ -580,82 +711,43 @@ xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) xqc_vint_write(dst_buf, src_payload_id, src_payload_id_bits, xqc_vint_len(src_payload_id_bits)); dst_buf += xqc_vint_len(src_payload_id_bits); - + packet_out->po_frame_types |= XQC_FRAME_BIT_SID; return dst_buf - begin; } xqc_int_t -xqc_parse_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +xqc_parse_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, uint64_t *src_payload_id, xqc_int_t *symbol_size) { int vlen; - uint64_t frame_type, flow_id, src_payload_id; - xqc_int_t ret, sid_frame_len, symbol_size, symbol_idx, max_src_symbol_num, tmp_block_idx, block_cache_idx, window_size; + uint64_t frame_type, flow_id; + xqc_int_t ret, remain_frame_len, tmp_len; unsigned char *p = packet_in->pos, *tmp_payload_p; const unsigned char *end = packet_in->last; - ret = sid_frame_len = symbol_size = symbol_idx = tmp_block_idx = block_cache_idx = 0; - max_src_symbol_num = conn->remote_settings.fec_max_symbols_num; - window_size = conn->conn_settings.fec_params.fec_max_window_size; + ret = *symbol_size = *src_payload_id = 0; + remain_frame_len = packet_in->last - packet_in->pos; vlen = xqc_vint_read(p, end, &frame_type); if (vlen < 0 || frame_type != 0xfec5) { return -XQC_EVINTREAD; } p += vlen; - sid_frame_len += vlen; + // TODOfec: flow_id is to be connected to stream vlen = xqc_vint_read(p, end, &flow_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - sid_frame_len += vlen; - vlen = xqc_vint_read(p, end, &src_payload_id); + vlen = xqc_vint_read(p, end, src_payload_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { - goto end_parse; - } - - sid_frame_len += vlen; - tmp_block_idx = (int)src_payload_id / max_src_symbol_num; - block_cache_idx = tmp_block_idx % window_size; - - if (max_src_symbol_num <= 0 - || max_src_symbol_num > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) - { - xqc_log(conn->log, XQC_LOG_ERROR, "|remote max_src_symbol_num invalid|"); - ret = -XQC_EPARAM; - goto end_parse; - } - - symbol_size = packet_in->decode_payload_len - sid_frame_len; - if (symbol_size != conn->remote_settings.fec_max_symbol_size) { - /* symbol size is different from the declared one */ - xqc_log(conn->log, XQC_LOG_DEBUG, "|fec symbol size error, src_payload_id: %d, remote declared size: %d, received size: %d, sid_frame_len: %d, packet_num: %d", - src_payload_id, conn->remote_settings.fec_max_symbol_size, symbol_size, sid_frame_len, packet_in->pi_pkt.pkt_num); - goto end_parse; - } - - symbol_idx = src_payload_id % max_src_symbol_num; - if (xqc_process_valid_symbol(conn, tmp_block_idx, symbol_idx, packet_in->decode_payload, symbol_size) != XQC_OK) { - goto end_parse; - } - - if (conn->fec_ctl->fec_recv_symbols_num[block_cache_idx] >= max_src_symbol_num) { - /* FEC解码操作/flush缓存 */ - ret = xqc_fec_decoder(conn, block_cache_idx); - xqc_fec_ctl_init_recv_params(conn->fec_ctl, block_cache_idx); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|fec decode error|"); - goto end_parse; - } - } + *symbol_size = packet_in->decode_payload_len - remain_frame_len; end_parse: packet_in->pos = (unsigned char *)p; @@ -664,35 +756,52 @@ xqc_parse_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } xqc_int_t -xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t fss_esi, - xqc_int_t repair_idx, xqc_int_t repair_key_size) +xqc_gen_repair_frame_check_param(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + xqc_int_t repair_idx, uint8_t bm_idx, xqc_int_t repair_key_size, xqc_int_t repair_symbol_size) { if (packet_out == NULL || repair_idx < 0 || repair_idx >= XQC_REPAIR_LEN - || repair_key_size < 0) + || repair_key_size < 0 + || repair_symbol_size <= 0 + || repair_symbol_size >= XQC_MAX_SYMBOL_SIZE) { - xqc_log(conn->log, XQC_LOG_WARN, "fec parameter error"); + xqc_log(conn->log, XQC_LOG_WARN, "|quic_fec|fec parameter error|repair_idx:%d|repair_key_size:%d|repair_symbol_size:%d|", repair_idx, repair_key_size, repair_symbol_size); return -XQC_EPARAM; } if (conn->conn_settings.fec_params.fec_ele_bit_size <= 0 - || (!conn->fec_ctl->fec_send_repair_key[repair_idx].is_valid && conn->conn_settings.fec_params.fec_encoder_scheme != XQC_XOR_CODE) - || conn->conn_settings.fec_params.fec_max_symbol_size <= 0 - || !conn->fec_ctl->fec_send_repair_symbols_buff[repair_idx].is_valid) + || (!conn->fec_ctl->fec_send_repair_key[bm_idx][repair_idx].is_valid && conn->conn_settings.fec_params.fec_encoder_scheme != XQC_XOR_CODE) + || !conn->fec_ctl->fec_send_repair_symbols_buff[bm_idx][repair_idx].is_valid) { xqc_log(conn->log, XQC_LOG_WARN, "No available repair key or repair symbol"); return -XQC_EFEC_SYMBOL_ERROR; } + return XQC_OK; +} + +xqc_int_t +xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t fss_esi, + xqc_int_t repair_idx, uint8_t bm_idx) +{ size_t dst_buf_len; uint64_t flow_id, frame_type, repair_payload_id; - unsigned need, frame_type_bits, flow_id_bits, fss_esi_bits, repair_key_bits, repair_payload_id_bits; - xqc_int_t ret, repair_symbol_size; + unsigned need, frame_type_bits, flow_id_bits, fss_esi_bits, repair_key_bits, repair_payload_id_bits, repair_key_size_bits, repair_symbol_size_bits; + xqc_int_t ret, repair_symbol_size, repair_key_size; unsigned char *dst_buf, *repair_symbol_p, *repair_key_p; - const unsigned char *begin, *end; + repair_key_p = conn->fec_ctl->fec_send_repair_key[bm_idx][repair_idx].payload; + repair_key_size = conn->fec_ctl->fec_send_repair_key[bm_idx][repair_idx].payload_size; + repair_symbol_p = conn->fec_ctl->fec_send_repair_symbols_buff[bm_idx][repair_idx].payload; + repair_symbol_size = conn->fec_ctl->fec_send_repair_symbols_buff[bm_idx][repair_idx].payload_size; + + ret = xqc_gen_repair_frame_check_param(conn, packet_out, repair_idx, bm_idx, repair_key_size, repair_symbol_size); + if (ret != XQC_OK) { + return ret; + } + dst_buf_len = xqc_get_po_remained_size_with_ack_spc(packet_out) + XQC_FEC_SPACE; dst_buf = packet_out->po_buf + packet_out->po_used_size; begin = dst_buf; end = dst_buf + dst_buf_len; @@ -700,31 +809,27 @@ xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_i frame_type = 0xfec6; flow_id = conn->fec_ctl->fec_flow_id; repair_payload_id = repair_idx; - repair_symbol_size = conn->local_settings.fec_max_symbol_size; frame_type_bits = xqc_vint_get_2bit(frame_type); flow_id_bits = xqc_vint_get_2bit(flow_id); fss_esi_bits = xqc_vint_get_2bit(fss_esi); repair_payload_id_bits = xqc_vint_get_2bit(repair_payload_id); - repair_key_p = conn->fec_ctl->fec_send_repair_key[repair_idx].payload; - repair_symbol_p = conn->fec_ctl->fec_send_repair_symbols_buff[repair_idx].payload; - - if (conn->conn_settings.fec_params.fec_encoder_scheme == XQC_XOR_CODE) { - repair_key_size = 0; - } + repair_key_size_bits = xqc_vint_get_2bit(repair_key_size); + repair_symbol_size_bits = xqc_vint_get_2bit(repair_symbol_size); need = xqc_vint_len(frame_type_bits) + xqc_vint_len(flow_id_bits) + xqc_vint_len(fss_esi_bits) + xqc_vint_len(repair_payload_id_bits) + + xqc_vint_len(repair_key_size_bits) + repair_key_size + + xqc_vint_len(repair_symbol_size_bits) + repair_symbol_size; if (dst_buf + need > end) { return -XQC_ENOBUF; } - xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); @@ -737,125 +842,89 @@ xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_i xqc_vint_write(dst_buf, repair_payload_id, repair_payload_id_bits, xqc_vint_len(repair_payload_id_bits)); dst_buf += xqc_vint_len(repair_payload_id_bits); + xqc_vint_write(dst_buf, repair_key_size, repair_key_size_bits, xqc_vint_len(repair_key_size_bits)); + dst_buf += xqc_vint_len(repair_key_size_bits); + xqc_memcpy(dst_buf, repair_key_p, repair_key_size); dst_buf += repair_key_size; + xqc_vint_write(dst_buf, repair_symbol_size, repair_symbol_size_bits, xqc_vint_len(repair_symbol_size_bits)); + dst_buf += xqc_vint_len(repair_symbol_size_bits); + xqc_memcpy(dst_buf, repair_symbol_p, repair_symbol_size); dst_buf += repair_symbol_size; - packet_out->po_frame_types |= XQC_FRAME_BIT_REPAIR_SYMBOL; packet_out->po_used_size += dst_buf - begin; return XQC_OK; } xqc_int_t -xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, + xqc_fec_rpr_syb_t *rpr_symbol) { int vlen = 0; - uint64_t frame_type, flow_id, fss_esi, repair_payload_id, repair_payload_len, symbol_idx, symbol_size; - xqc_int_t ret, repair_symbol_size, repair_key_size, src_symbol_num, tmp_block_idx, block_cache_idx, window_size; + uint64_t frame_type, flow_id, fss_esi, repair_payload_id, repair_symbol_size, repair_key_size; + xqc_int_t ret; unsigned char *p = packet_in->pos, *end = packet_in->last, *tmp_payload_p, *repair_key_p, *repair_symbol_p; - frame_type = flow_id = fss_esi = repair_payload_id = symbol_idx = 0; - ret = tmp_block_idx = 0; - repair_symbol_size = conn->remote_settings.fec_max_symbol_size; - symbol_size = repair_payload_len = block_cache_idx = 0; - src_symbol_num = conn->remote_settings.fec_max_symbols_num; - window_size = conn->conn_settings.fec_params.fec_max_window_size; - if (conn->conn_settings.fec_params.fec_decoder_scheme == XQC_XOR_CODE) { - repair_key_size = 0; - } else { - repair_key_size = ((conn->conn_settings.fec_params.fec_ele_bit_size - 1) / 8 + 1) * src_symbol_num; - } + frame_type = flow_id = fss_esi = repair_payload_id = 0; + ret = 0; vlen = xqc_vint_read(p, end, &frame_type); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - repair_payload_len += vlen; vlen = xqc_vint_read(p, end, &flow_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - repair_payload_len += vlen; + vlen = xqc_vint_read(p, end, &fss_esi); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - repair_payload_len += vlen; - tmp_block_idx = (int)fss_esi / src_symbol_num; - block_cache_idx = tmp_block_idx % window_size; + rpr_symbol->block_id = fss_esi; vlen = xqc_vint_read(p, end, &repair_payload_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - repair_payload_len += vlen; + rpr_symbol->symbol_idx = repair_payload_id; - repair_key_p = p; - repair_symbol_p = p + repair_key_size; - p += repair_key_size + repair_symbol_size; - - if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { - goto end_parse_repair; + vlen = xqc_vint_read(p, end, &repair_key_size); + if (vlen < 0) { + return -XQC_EVINTREAD; } + p += vlen; + rpr_symbol->repair_key_size = repair_key_size; + rpr_symbol->repair_key = p; - if (conn->fec_ctl->fec_recv_repair_num == XQC_MAX_UINT32_VALUE) { - xqc_log(conn->log, XQC_LOG_WARN, "|fec recovered packet number exceeds maximum.\n"); - conn->fec_ctl->fec_recv_repair_num = 0; + p = p + rpr_symbol->repair_key_size; + vlen = xqc_vint_read(p, end, &repair_symbol_size); + if (vlen < 0) { + return -XQC_EVINTREAD; } - conn->fec_ctl->fec_recv_repair_num++; + p += vlen; + rpr_symbol->payload_size = repair_symbol_size; + rpr_symbol->payload = p; - if (conn->remote_settings.fec_max_symbol_size <= 0 - || conn->remote_settings.fec_max_symbols_num <= 0) - { - xqc_log(conn->log, XQC_LOG_ERROR, "|repair symbol size error or repair symbol len error|fec_max_symbol_size:%d|fec_max_symbols_num:%d|", - conn->remote_settings.fec_max_symbol_size, conn->remote_settings.fec_max_symbols_num); - ret = -XQC_EFEC_SYMBOL_ERROR; - goto end_parse_repair; - } - - symbol_size = packet_in->decode_payload_len - repair_payload_len - repair_key_size; - if (symbol_size != conn->remote_settings.fec_max_symbol_size) { - /* symbol size is different from the declared one */ - xqc_log(conn->log, XQC_LOG_DEBUG, "|fec symbol size error, fss_esi: %d, remote declared size: %d, received size: %d, repair_payload_id: %d, repair_key_size:%d, packet_num: %d", - fss_esi, conn->remote_settings.fec_max_symbol_size, symbol_size, repair_payload_id, repair_key_size, packet_in->pi_pkt.pkt_num); - ret = -XQC_EFEC_SYMBOL_ERROR; - goto end_parse_repair; - } + p += rpr_symbol->payload_size; - symbol_idx = src_symbol_num + repair_payload_id; - if (xqc_process_valid_symbol(conn, tmp_block_idx, symbol_idx, repair_symbol_p, repair_symbol_size) != XQC_OK) { + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + ret = -XQC_EFEC_TOLERABLE_ERROR; goto end_parse_repair; } - - ret = xqc_fec_ctl_save_symbol(&conn->fec_ctl->fec_recv_repair_key[block_cache_idx][repair_payload_id].payload, - repair_key_p, repair_key_size); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|save repair key error|"); + if (rpr_symbol->payload_size > XQC_MAX_SYMBOL_SIZE) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|received repair symbol size is too large"); + ret = -XQC_EIGNORE_PKT; goto end_parse_repair; } - tmp_payload_p = conn->fec_ctl->fec_recv_repair_key[block_cache_idx][repair_payload_id].payload; - xqc_set_object_value(&conn->fec_ctl->fec_recv_repair_key[block_cache_idx][repair_payload_id], 1, tmp_payload_p, repair_key_size); - - conn->fec_ctl->fec_recv_repair_symbols_num[block_cache_idx]++; - - if (conn->fec_ctl->fec_recv_symbols_num[block_cache_idx] >= src_symbol_num) { - /* FEC解码操作 */ - ret = xqc_fec_decoder(conn, block_cache_idx); - /* flush symbol缓存 */ - xqc_fec_ctl_init_recv_params(conn->fec_ctl, block_cache_idx); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|fec decode error|"); - goto end_parse_repair; - } - } end_parse_repair: packet_in->pos = (unsigned char *) p; @@ -1035,7 +1104,7 @@ xqc_parse_ack_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, xqc_ack_ * negotiated, ACK frames in 1-RTT packets acknowledge packets sent * with the Connection ID having sequence number 0. */ - ack_info->dcid_seq_num = 0; + ack_info->path_id = 0; ack_info->pns = packet_in->pi_pkt.pkt_pns; vlen = xqc_vint_read(p, end, &largest_acked); @@ -1839,8 +1908,6 @@ xqc_gen_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, *dst_buf++ = 0x18; - unsigned char stateless_reset_token[XQC_STATELESS_RESET_TOKENLEN] = {0}; - unsigned sequence_number_bits = xqc_vint_get_2bit(new_cid->cid_seq_num); unsigned retire_prior_to_bits = xqc_vint_get_2bit(retire_prior_to); uint64_t cid_len = new_cid->cid_len; @@ -2120,7 +2187,7 @@ xqc_parse_path_response_frame(xqc_packet_in_t *packet_in, unsigned char *data) * * ACK_MP Frame { * Type (i) = TBD-00..TBD-01 , - * Destination Connection ID Sequence Number (i), + * Path ID (i), * Largest Acknowledged (i), * ACK Delay (i), * ACK Range Count (i), @@ -2133,19 +2200,15 @@ xqc_parse_path_response_frame(xqc_packet_in_t *packet_in, unsigned char *data) */ ssize_t -xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, +xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t path_id, xqc_packet_out_t *packet_out, xqc_usec_t now, int ack_delay_exponent, xqc_recv_record_t *recv_record, xqc_usec_t largest_pkt_recv_time, int *has_gap, xqc_packet_number_t *largest_ack) { uint64_t frame_type; - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - frame_type = 0xbaba00; - - } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { - /* 06 is the same with 05 */ - frame_type = 0x15228c00; + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + frame_type = XQC_TRANS_FRAME_TYPE_MP_ACK0; } else { return -XQC_EMP_INVALID_MP_VERTION; @@ -2195,13 +2258,13 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, ack_delay = ack_delay >> ack_delay_exponent; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_bits = xqc_vint_get_2bit(dcid_seq); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); unsigned lagest_recv_bits = xqc_vint_get_2bit(lagest_recv); unsigned ack_delay_bits = xqc_vint_get_2bit(ack_delay); unsigned first_ack_range_bits = xqc_vint_get_2bit(first_ack_range); need = + xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_bits) + + xqc_vint_len(path_id_bits) + xqc_vint_len(lagest_recv_bits) + xqc_vint_len(ack_delay_bits) + 1 /* range_count */ @@ -2214,8 +2277,8 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - xqc_vint_write(dst_buf, dcid_seq, dcid_seq_bits, xqc_vint_len(dcid_seq_bits)); - dst_buf += xqc_vint_len(dcid_seq_bits); + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); xqc_vint_write(dst_buf, lagest_recv, lagest_recv_bits, xqc_vint_len(lagest_recv_bits)); dst_buf += xqc_vint_len(lagest_recv_bits); @@ -2283,7 +2346,7 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, xqc_int_t xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, - uint64_t *dcid_seq_num, xqc_ack_info_t *ack_info) + uint64_t *path_id, xqc_ack_info_t *ack_info) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; @@ -2303,13 +2366,13 @@ xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, } p += vlen; - vlen = xqc_vint_read(p, end, dcid_seq_num); + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - ack_info->dcid_seq_num = *dcid_seq_num; + ack_info->path_id = *path_id; ack_info->pns = packet_in->pi_pkt.pkt_pns; vlen = xqc_vint_read(p, end, &largest_acked); @@ -2381,22 +2444,19 @@ xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, /* - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-05#name-path_abandon-frame - * * PATH_ABANDON Frame { * Type (i) = TBD-03, - * DCID Sequence Number (i), + * Path ID (i), * Error Code (i), * Reason Phrase Length (i), * Reason Phrase (..), * } * - * Figure 6: PATH_ABANDON Frame Format */ ssize_t xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, uint64_t error_code) + uint64_t path_id, uint64_t error_code) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; @@ -2404,13 +2464,10 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, uint64_t frame_type; need = po_remained_size = 0; - - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - frame_type = 0xbaba05; - - } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_05) { + + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { /* same frame type in 05 and 06 */ - frame_type = 0x15228c05; + frame_type = XQC_TRANS_FRAME_TYPE_MP_ABANDON; } else { return -XQC_EMP_INVALID_MP_VERTION; @@ -2420,12 +2477,12 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, uint8_t *reason = NULL; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); unsigned error_code_bits = xqc_vint_get_2bit(error_code); unsigned reason_len_bits = xqc_vint_get_2bit(reason_len); need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) + + xqc_vint_len(path_id_bits) + xqc_vint_len(error_code_bits) + xqc_vint_len(reason_len_bits) + reason_len; @@ -2441,9 +2498,9 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); + /* Path ID (i) */ + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); /* Error Code (i) */ xqc_vint_write(dst_buf, error_code, error_code_bits, xqc_vint_len(error_code_bits)); @@ -2466,7 +2523,7 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, uint64_t *error_code) + uint64_t *path_id, uint64_t *error_code) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; @@ -2481,8 +2538,8 @@ xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + /* Path ID (i) */ + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } @@ -2515,49 +2572,49 @@ xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, } -/* - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-05#name-path_status-frame - * - * PATH_STATUS Frame { - * Type (i) = TBD-03, - * DCID Sequence Number (i), - * Path Status sequence number (i), - * Path Status (i), - * } - * - * Figure 7: PATH_STATUS Frame Format - */ - -ssize_t +ssize_t xqc_gen_path_status_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num, uint64_t path_status) + uint64_t path_id, + uint64_t path_status_seq_num, + xqc_app_path_status_t status) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; unsigned need = 0; uint64_t frame_type; - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - frame_type = 0xbaba06; + uint64_t ft_flag; - } else if (conn->conn_settings.multipath_version == XQC_MULTIPATH_05) { - frame_type = 0x15228c06; + if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + switch (status) { + case XQC_APP_PATH_STATUS_STANDBY: + frame_type = XQC_TRANS_FRAME_TYPE_MP_STANDBY; + ft_flag = XQC_FRAME_BIT_PATH_STANDBY; + break; + case XQC_APP_PATH_STATUS_AVAILABLE: + frame_type = XQC_TRANS_FRAME_TYPE_MP_AVAILABLE; + ft_flag = XQC_FRAME_BIT_PATH_AVAILABLE; + break; + case XQC_APP_PATH_STATUS_FROZEN: + frame_type = XQC_TRANS_FRAME_TYPE_MP_FROZEN; + ft_flag = XQC_FRAME_BIT_PATH_FROZEN; + break; + default: + return -XQC_EMP_PATH_STATE_ERROR; + } } else { return -XQC_EMP_INVALID_MP_VERTION; } unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); unsigned path_status_seq_num_bits = xqc_vint_get_2bit(path_status_seq_num); - unsigned path_status_bits = xqc_vint_get_2bit(path_status); need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) - + xqc_vint_len(path_status_seq_num_bits) - + xqc_vint_len(path_status_bits); + + xqc_vint_len(path_id_bits) + + xqc_vint_len(path_status_seq_num_bits); /* check packout_out have enough buffer length */ if (need > xqc_get_po_remained_size(packet_out)) { @@ -2568,27 +2625,22 @@ xqc_gen_path_status_frame(xqc_connection_t *conn, xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); + /* Path ID (i) */ + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); /* Path Status sequence number (i) */ xqc_vint_write(dst_buf, path_status_seq_num, path_status_seq_num_bits, xqc_vint_len(path_status_seq_num_bits)); dst_buf += xqc_vint_len(path_status_seq_num_bits); - /* Path Status (i) */ - xqc_vint_write(dst_buf, path_status, path_status_bits, xqc_vint_len(path_status_bits)); - dst_buf += xqc_vint_len(path_status_bits); - - packet_out->po_frame_types |= XQC_FRAME_BIT_PATH_STATUS; + packet_out->po_frame_types |= ft_flag; return dst_buf - begin; - } -xqc_int_t +xqc_int_t xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, + uint64_t *path_id, uint64_t *path_status_seq_num, uint64_t *path_status) { unsigned char *p = packet_in->pos; @@ -2603,8 +2655,8 @@ xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + /* Path ID (i) */ + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } @@ -2617,86 +2669,105 @@ xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* Path Status (i) */ - vlen = xqc_vint_read(p, end, path_status); - if (vlen < 0) { - return -XQC_EVINTREAD; - } - p += vlen; - packet_in->pos = p; - packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_STATUS; + switch (frame_type) { + case XQC_TRANS_FRAME_TYPE_MP_STANDBY: + *path_status = XQC_APP_PATH_STATUS_STANDBY; + packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_STANDBY; + break; + case XQC_TRANS_FRAME_TYPE_MP_AVAILABLE: + *path_status = XQC_APP_PATH_STATUS_AVAILABLE; + packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_AVAILABLE; + break; + case XQC_TRANS_FRAME_TYPE_MP_FROZEN: + *path_status = XQC_APP_PATH_STATUS_FROZEN; + packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_FROZEN; + break; + default: + return -XQC_EILLEGAL_FRAME; + } return XQC_OK; } /* - * PATH_STANDBY Frame { - * Type (i) = TBD-03 (experiments use 0x15228c07) - * Destination Connection ID Sequence Number (i), - * Path Status sequence number (i), - * } * - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-06#section-8.3 + * MP_NEW_CONNECTION_ID Frame { + * Type (i) = 0x15228c09, + * Path Identifier (i), + * Sequence Number (i), + * Retire Prior To (i), + * Length (8), + * Connection ID (8..160), + * Stateless Reset Token (128), + * } + * + * Figure 39: MP_NEW_CONNECTION_ID Frame Format * */ ssize_t -xqc_gen_path_standby_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num) +xqc_gen_mp_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, + uint64_t retire_prior_to, const uint8_t *sr_token, uint64_t path_id) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; - unsigned need = 0; - - uint64_t frame_type; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - frame_type = 0x15228c07; - } else { - return -XQC_EMP_INVALID_MP_VERTION; - } + /* write frame type */ + uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); - unsigned path_status_seq_num_bits = xqc_vint_get_2bit(path_status_seq_num); + xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); + dst_buf += xqc_vint_len(frame_type_bits); - need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) - + xqc_vint_len(path_status_seq_num_bits); + /* Path ID (i) */ + unsigned path_id_bits = xqc_vint_get_2bit(path_id); + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); - /* check packout_out have enough buffer length */ - if (need > xqc_get_po_remained_size(packet_out)) { - return -XQC_ENOBUF; + unsigned sequence_number_bits = xqc_vint_get_2bit(new_cid->cid_seq_num); + unsigned retire_prior_to_bits = xqc_vint_get_2bit(retire_prior_to); + uint64_t cid_len = new_cid->cid_len; + uint8_t cid_len_bits = xqc_vint_get_2bit(cid_len); + + /* make sure cid_len won't exceed XQC_MAX_CID_LEN */ + if (cid_len > XQC_MAX_CID_LEN) { + return -XQC_EPARAM; } - /* Type(i) */ - xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); - dst_buf += xqc_vint_len(frame_type_bits); + xqc_vint_write(dst_buf, new_cid->cid_seq_num, + sequence_number_bits, xqc_vint_len(sequence_number_bits)); + dst_buf += xqc_vint_len(sequence_number_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); - /* Path Status sequence number (i) */ - xqc_vint_write(dst_buf, path_status_seq_num, path_status_seq_num_bits, xqc_vint_len(path_status_seq_num_bits)); - dst_buf += xqc_vint_len(path_status_seq_num_bits); + xqc_vint_write(dst_buf, retire_prior_to, retire_prior_to_bits, xqc_vint_len(retire_prior_to_bits)); + dst_buf += xqc_vint_len(retire_prior_to_bits); - packet_out->po_frame_types |= XQC_FRAME_BIT_PATH_STANDBY; + xqc_vint_write(dst_buf, cid_len, cid_len_bits, xqc_vint_len(cid_len_bits)); + dst_buf += xqc_vint_len(cid_len_bits); + + xqc_memcpy(dst_buf, new_cid->cid_buf, new_cid->cid_len); + dst_buf += new_cid->cid_len; + + if (sr_token) { + xqc_memcpy(dst_buf, sr_token, XQC_STATELESS_RESET_TOKENLEN); + dst_buf += XQC_STATELESS_RESET_TOKENLEN; + } + + packet_out->po_frame_types |= XQC_FRAME_BIT_MP_NEW_CONNECTION_ID; return dst_buf - begin; } + xqc_int_t -xqc_parse_path_standby_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status) +xqc_parse_mp_new_conn_id_frame(xqc_packet_in_t *packet_in, + xqc_cid_t *new_cid, uint64_t *retire_prior_to, uint64_t *path_id, + xqc_connection_t *conn) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; - int vlen; + /* frame type */ uint64_t frame_type = 0; vlen = xqc_vint_read(p, end, &frame_type); /* get frame_type */ if (vlen < 0) { @@ -2704,97 +2775,100 @@ xqc_parse_path_standby_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + /* Path ID (i) */ + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } + new_cid->path_id = *path_id; p += vlen; - /* Path Status sequence number (i) */ - vlen = xqc_vint_read(p, end, path_status_seq_num); + /* Sequence Number (i) */ + vlen = xqc_vint_read(p, end, &new_cid->cid_seq_num); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - *path_status = 1; /* 1 - Standby */ + /* Retire Prior To (i) */ + vlen = xqc_vint_read(p, end, retire_prior_to); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + /* Length (8) */ + if (p >= end) { + return -XQC_EPROTO; + } + new_cid->cid_len = *p++; + if (new_cid->cid_len > XQC_MAX_CID_LEN) { + return -XQC_EPROTO; + } + + /* Connection ID (8..160) */ + if (p + new_cid->cid_len > end) { + return -XQC_EPROTO; + } + xqc_memcpy(new_cid->cid_buf, p, new_cid->cid_len); + p += new_cid->cid_len; + + /* Stateless Reset Token (128) */ + if (p + XQC_STATELESS_RESET_TOKENLEN > end) { + return -XQC_EPROTO; + } + xqc_memcpy(new_cid->sr_token, p, XQC_STATELESS_RESET_TOKENLEN); + p += XQC_STATELESS_RESET_TOKENLEN; packet_in->pos = p; - packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_STANDBY; + packet_in->pi_frame_types |= XQC_FRAME_BIT_MP_NEW_CONNECTION_ID; + xqc_log_event(conn->log, TRA_FRAMES_PROCESSED, XQC_FRAME_NEW_CONNECTION_ID, new_cid, retire_prior_to); return XQC_OK; } /* - * - * PATH_AVAILABLE Frame { - * Type (i) = TBD-03 (experiments use 0x15228c08), - * Destination Connection ID Sequence Number (i), - * Path Status sequence number (i), - * } - * - * - * https://datatracker.ietf.org/doc/html/draft-ietf-quic-multipath-06#section-8.4 + * MP_RETIRE_CONNECTION_ID Frame { + * Type (i) = 0x15228c0a, + * Path ID (i), + * Sequence Number (i), + * } * */ ssize_t -xqc_gen_path_available_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num) +xqc_gen_mp_retire_conn_id_frame(xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; - unsigned need = 0; - - uint64_t frame_type; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - frame_type = 0x15228c08; - } else { - return -XQC_EMP_INVALID_MP_VERTION; - } + /* write frame type */ + uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID; unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); - unsigned dcid_seq_num_bits = xqc_vint_get_2bit(dcid_seq_num); - unsigned path_status_seq_num_bits = xqc_vint_get_2bit(path_status_seq_num); - - need = xqc_vint_len(frame_type_bits) - + xqc_vint_len(dcid_seq_num_bits) - + xqc_vint_len(path_status_seq_num_bits); - - /* check packout_out have enough buffer length */ - if (need > xqc_get_po_remained_size(packet_out)) { - return -XQC_ENOBUF; - } - - /* Type(i) */ xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); - /* DCID Sequence Number (i) */ - xqc_vint_write(dst_buf, dcid_seq_num, dcid_seq_num_bits, xqc_vint_len(dcid_seq_num_bits)); - dst_buf += xqc_vint_len(dcid_seq_num_bits); + unsigned path_id_bits = xqc_vint_get_2bit(path_id); + xqc_vint_write(dst_buf, path_id, path_id_bits, xqc_vint_len(path_id_bits)); + dst_buf += xqc_vint_len(path_id_bits); - /* Path Status sequence number (i) */ - xqc_vint_write(dst_buf, path_status_seq_num, path_status_seq_num_bits, xqc_vint_len(path_status_seq_num_bits)); - dst_buf += xqc_vint_len(path_status_seq_num_bits); + unsigned sequence_number_bits = xqc_vint_get_2bit(seq_num); + xqc_vint_write(dst_buf, seq_num, sequence_number_bits, xqc_vint_len(sequence_number_bits)); + dst_buf += xqc_vint_len(sequence_number_bits); - packet_out->po_frame_types |= XQC_FRAME_BIT_PATH_AVAILABLE; + packet_out->po_frame_types |= XQC_FRAME_BIT_MP_RETIRE_CONNECTION_ID; return dst_buf - begin; } + xqc_int_t -xqc_parse_path_available_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status) +xqc_parse_mp_retire_conn_id_frame(xqc_packet_in_t *packet_in, uint64_t *seq_num, uint64_t *path_id) { unsigned char *p = packet_in->pos; const unsigned char *end = packet_in->last; - int vlen; + /* frame type */ uint64_t frame_type = 0; vlen = xqc_vint_read(p, end, &frame_type); /* get frame_type */ if (vlen < 0) { @@ -2802,17 +2876,13 @@ xqc_parse_path_available_frame(xqc_packet_in_t *packet_in, } p += vlen; - /* DCID Sequence Number (i) */ - vlen = xqc_vint_read(p, end, dcid_seq_num); + vlen = xqc_vint_read(p, end, path_id); if (vlen < 0) { return -XQC_EVINTREAD; } p += vlen; - *path_status = 2; /* 2 - available */ - - /* Path Status sequence number (i) */ - vlen = xqc_vint_read(p, end, path_status_seq_num); + vlen = xqc_vint_read(p, end, seq_num); if (vlen < 0) { return -XQC_EVINTREAD; } @@ -2820,7 +2890,67 @@ xqc_parse_path_available_frame(xqc_packet_in_t *packet_in, packet_in->pos = p; - packet_in->pi_frame_types |= XQC_FRAME_BIT_PATH_AVAILABLE; + packet_in->pi_frame_types |= XQC_FRAME_BIT_MP_RETIRE_CONNECTION_ID; return XQC_OK; } + + +/* + * + * MAX_PATH_ID Frame { + * Type (i) = 0x15228c0c, + * Maximum Path Identifier (i), + * } + * + * Figure: MAX_PATH_ID Frame Format + * */ +ssize_t +xqc_gen_max_path_id_frame(xqc_packet_out_t *packet_out, uint64_t max_path_id) +{ + unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; + const unsigned char *begin = dst_buf; + + /* write frame type */ + uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MAX_PATH_ID; + unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); + xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); + dst_buf += xqc_vint_len(frame_type_bits); + + unsigned max_paths_bits = xqc_vint_get_2bit(max_path_id); + xqc_vint_write(dst_buf, max_path_id, max_paths_bits, xqc_vint_len(max_paths_bits)); + dst_buf += xqc_vint_len(max_paths_bits); + + packet_out->po_frame_types |= XQC_FRAME_BIT_MAX_PATH_ID; + + return dst_buf - begin; +} + + +xqc_int_t +xqc_parse_max_path_id_frame(xqc_packet_in_t *packet_in, uint64_t *max_path_id) +{ + unsigned char *p = packet_in->pos; + const unsigned char *end = packet_in->last; + int vlen; + + /* frame type */ + uint64_t frame_type = 0; + vlen = xqc_vint_read(p, end, &frame_type); /* get frame_type */ + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + vlen = xqc_vint_read(p, end, max_path_id); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + + packet_in->pos = p; + + packet_in->pi_frame_types |= XQC_FRAME_BIT_MAX_PATH_ID; + + return XQC_OK; +} \ No newline at end of file diff --git a/src/transport/xqc_frame_parser.h b/src/transport/xqc_frame_parser.h index ca79e9574..2a71fc7de 100644 --- a/src/transport/xqc_frame_parser.h +++ b/src/transport/xqc_frame_parser.h @@ -6,6 +6,7 @@ #define _XQC_FRAME_PARSER_H_INCLUDED_ #include +#include "src/transport/xqc_fec.h" #include "src/transport/xqc_frame.h" #include "src/transport/xqc_packet_in.h" #include "src/transport/xqc_packet_out.h" @@ -15,6 +16,16 @@ #define XQC_DATAGRAM_LENGTH_FIELD_BYTES 2 #define XQC_DATAGRAM_HEADER_BYTES (XQC_DATAGRAM_LENGTH_FIELD_BYTES + 1) +#define XQC_TRANS_FRAME_TYPE_MP_ACK0 0x15228c00 +#define XQC_TRANS_FRAME_TYPE_MP_ACK1 0x15228c01 +#define XQC_TRANS_FRAME_TYPE_MP_ABANDON 0x15228c05 +#define XQC_TRANS_FRAME_TYPE_MP_STANDBY 0x15228c07 +#define XQC_TRANS_FRAME_TYPE_MP_AVAILABLE 0x15228c08 +#define XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID 0x15228c09 +#define XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID 0x15228c0a +#define XQC_TRANS_FRAME_TYPE_MAX_PATH_ID 0x15228c0c +#define XQC_TRANS_FRAME_TYPE_MP_FROZEN 0x15228cff + /** * generate datagram frame */ @@ -126,47 +137,46 @@ ssize_t xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t path_id, xqc_packe int ack_delay_exponent, xqc_recv_record_t *recv_record, xqc_usec_t largest_pkt_recv_time, int *has_gap, xqc_packet_number_t *largest_ack); xqc_int_t xqc_parse_ack_mp_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn, - uint64_t *dcid_seq_num, xqc_ack_info_t *ack_info); + uint64_t *path_id, xqc_ack_info_t *ack_info); ssize_t xqc_gen_path_abandon_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, uint64_t dcid_seq_num, uint64_t error_code); + xqc_packet_out_t *packet_out, uint64_t path_id, uint64_t error_code); xqc_int_t xqc_parse_path_abandon_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, uint64_t *error_code); + uint64_t *path_id, uint64_t *error_code); ssize_t xqc_gen_path_status_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num, uint64_t path_status); + uint64_t path_id, + uint64_t path_status_seq_num, + xqc_app_path_status_t status); xqc_int_t xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status); + uint64_t *path_id, + uint64_t *path_status_seq_num, uint64_t *path_status); -ssize_t xqc_gen_path_standby_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num); +ssize_t xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out); -xqc_int_t xqc_parse_path_standby_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status); +xqc_int_t xqc_parse_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, uint64_t *src_payload_id, xqc_int_t *symbol_size); -ssize_t xqc_gen_path_available_frame(xqc_connection_t *conn, - xqc_packet_out_t *packet_out, - uint64_t dcid_seq_num, - uint64_t path_status_seq_num); +xqc_int_t xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t fss_esi, + xqc_int_t repair_idx, uint8_t bm_idx); -xqc_int_t xqc_parse_path_available_frame(xqc_packet_in_t *packet_in, - uint64_t *dcid_seq_num, - uint64_t *path_status_seq_num, uint64_t *path_status); +xqc_int_t xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, + xqc_fec_rpr_syb_t *rpr_symbol); -ssize_t xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out); +ssize_t xqc_gen_mp_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, + uint64_t retire_prior_to, const uint8_t *sr_token, uint64_t path_id); -xqc_int_t xqc_parse_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); +xqc_int_t xqc_parse_mp_new_conn_id_frame(xqc_packet_in_t *packet_in, + xqc_cid_t *new_cid, uint64_t *retire_prior_to, uint64_t *path_id, xqc_connection_t *conn); -xqc_int_t xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_int_t fss_esi, - xqc_int_t repair_idx, xqc_int_t repair_key_size); -xqc_int_t xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); +ssize_t xqc_gen_mp_retire_conn_id_frame(xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id); + +xqc_int_t xqc_parse_mp_retire_conn_id_frame(xqc_packet_in_t *packet_in, uint64_t *seq_num, uint64_t *path_id); + +ssize_t xqc_gen_max_path_id_frame(xqc_packet_out_t *packet_out, uint64_t max_path_id); +xqc_int_t xqc_parse_max_path_id_frame(xqc_packet_in_t *packet_in, uint64_t *max_path_id); +void xqc_try_process_fec_decode(xqc_connection_t *conn, xqc_int_t block_id); #endif /*_XQC_FRAME_PARSER_H_INCLUDED_*/ diff --git a/src/transport/xqc_multipath.c b/src/transport/xqc_multipath.c index 0d1136cd7..34a624c41 100644 --- a/src/transport/xqc_multipath.c +++ b/src/transport/xqc_multipath.c @@ -9,7 +9,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/transport/xqc_reinjection.h" #include "src/transport/xqc_frame_parser.h" @@ -72,7 +71,7 @@ xqc_path_destroy(xqc_path_ctx_t *path) } xqc_path_ctx_t * -xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) +xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid, uint64_t path_id) { xqc_path_ctx_t *path = NULL; @@ -86,12 +85,14 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) if (path == NULL) { return NULL; } + xqc_memzero(path, sizeof(xqc_path_ctx_t)); path->path_state = XQC_PATH_STATE_INIT; path->parent_conn = conn; path->app_path_status = XQC_APP_PATH_STATUS_AVAILABLE; path->app_path_status_send_seq_num = 0; path->app_path_status_recv_seq_num = 0; + path->path_id = path_id; path->path_pn_ctl = xqc_pn_ctl_create(conn); if (path->path_pn_ctl == NULL) { @@ -109,16 +110,15 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) xqc_init_list_head(&path->path_reinj_tmp_buf); /* cid & path_id init */ - if (scid == NULL) { - if (xqc_get_unused_cid(&conn->scid_set.cid_set, &path->path_scid) != XQC_OK) { + if (xqc_get_unused_cid(&conn->scid_set, &path->path_scid, path_id) != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available scid|"); goto err; } } else { /* already have scid */ - xqc_cid_inner_t *inner_cid = xqc_cid_in_cid_set(&conn->scid_set.cid_set, scid); + xqc_cid_inner_t *inner_cid = xqc_cid_in_cid_set(&conn->scid_set, scid, path_id); if (inner_cid == NULL) { xqc_log(conn->log, XQC_LOG_DEBUG, "|invalid scid:%s|", xqc_scid_str(conn->engine, scid)); goto err; @@ -128,18 +128,20 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) } if (dcid == NULL) { - if (xqc_get_unused_cid(&(conn->dcid_set.cid_set), &(path->path_dcid)) != XQC_OK) { + if (xqc_get_unused_cid(&conn->dcid_set, &(path->path_dcid), path_id) != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|MP|conn don't have available dcid|"); goto err; } } else { + //TODO: risky code /* already have dcid */ xqc_cid_copy(&(path->path_dcid), dcid); } - //TODO: MPQUIC fix migration - path->path_id = conn->create_path_count; + xqc_cid_set_update_state(&conn->dcid_set, path_id, XQC_CID_SET_USED); + xqc_cid_set_update_state(&conn->scid_set, path_id, XQC_CID_SET_USED); + path->path_create_time = xqc_monotonic_timestamp(); path->curr_pkt_out_size = conn->pkt_out_size; path->path_max_pkt_out_size = conn->max_pkt_out_size; @@ -211,7 +213,9 @@ xqc_path_init(xqc_path_ctx_t *path, xqc_connection_t *conn) xqc_path_addr_str(path), path->peer_addrlen); xqc_log(conn->engine->log, XQC_LOG_DEBUG, "|path:%ui|dcid:%s|scid:%s|state:%d|", - path->path_id, xqc_dcid_str(conn->engine, &path->path_dcid), xqc_scid_str(path->parent_conn->engine, &path->path_scid), path->path_state); + path->path_id, xqc_dcid_str(conn->engine, &path->path_dcid), + xqc_scid_str(conn->engine, &path->path_scid), + path->path_state); return XQC_OK; } @@ -325,6 +329,9 @@ xqc_path_immediate_close(xqc_path_ctx_t *path) xqc_timer_set(&path->path_send_ctl->path_timer_manager, XQC_TIMER_PATH_DRAINING, now, 3 * pto); } + xqc_cid_set_update_state(&conn->scid_set, path->path_id, XQC_CID_SET_ABANDONED); + xqc_cid_set_update_state(&conn->dcid_set, path->path_id, XQC_CID_SET_ABANDONED); + return XQC_OK; } @@ -350,7 +357,7 @@ xqc_path_closed(xqc_path_ctx_t *path) xqc_conn_get_user_data(conn)); } - /* TODO: releadse path recource */ + /* TODO: release path recource */ return XQC_OK; } @@ -371,20 +378,20 @@ xqc_conn_enable_multipath(xqc_connection_t *conn) if (conn->dcid_set.current_dcid.cid_len == 0 || conn->scid_set.user_scid.cid_len == 0) { - xqc_log(conn->log, XQC_LOG_ERROR, - "|mutlipath is not possible for connections" - " with zero-length DCID|"); - if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { - XQC_CONN_ERR(conn, TRA_TRANSPORT_PARAMETER_ERROR); - - } else { - XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION_05); - } - return XQC_CONN_NOT_SUPPORT_MULTIPATH; + xqc_log(conn->log, XQC_LOG_ERROR, "|zero-length DCID|"); + XQC_CONN_ERR(conn, TRA_MP_PROTOCOL_VIOLATION); + return XQC_CONN_MP_DISABLED; } - return XQC_CONN_MULTIPATH_MULTIPLE_PNS; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|1RTT_transport_params|max_path_id:local:%ui|max_path_id:remote:%ui|", + conn->local_settings.init_max_path_id, conn->remote_settings.init_max_path_id); + conn->local_max_path_id = conn->local_settings.init_max_path_id; + conn->remote_max_path_id = conn->remote_settings.init_max_path_id; + conn->curr_max_path_id = xqc_min(conn->local_max_path_id, conn->remote_max_path_id); + + return XQC_CONN_MP_ENABLED; } - return XQC_CONN_NOT_SUPPORT_MULTIPATH; + return XQC_CONN_MP_DISABLED; } xqc_multipath_version_t @@ -405,13 +412,7 @@ xqc_conn_is_current_mp_version_supported(xqc_multipath_version_t mp_version) { xqc_int_t ret; switch (mp_version) { - case XQC_MULTIPATH_04: - ret = XQC_OK; - break; - case XQC_MULTIPATH_05: - ret = XQC_OK; - break; - case XQC_MULTIPATH_06: + case XQC_MULTIPATH_10: ret = XQC_OK; break; default: @@ -427,6 +428,7 @@ xqc_conn_create_path(xqc_engine_t *engine, const xqc_cid_t *scid, uint64_t *new_ xqc_connection_t *conn = NULL; xqc_path_ctx_t *path = NULL; xqc_app_path_status_t ps_inner = XQC_APP_PATH_STATUS_AVAILABLE; + uint64_t path_id = 0; conn = xqc_engine_conns_hash_find(engine, scid, 's'); if (!conn) { @@ -444,36 +446,30 @@ xqc_conn_create_path(xqc_engine_t *engine, const xqc_cid_t *scid, uint64_t *new_ return -XQC_EMP_NOT_SUPPORT_MP; } - /* must have at least one available unused scid & dcid */ - if (xqc_conn_check_unused_cids(conn) != XQC_OK) { - if (conn->dcid_set.cid_set.unused_cnt == 0) { - conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_DCID; - } - - if (conn->scid_set.cid_set.unused_cnt == 0) { - conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_SCID; - } - + if (xqc_conn_get_available_path_id(conn, &path_id) != XQC_OK) { + conn->conn_flag |= XQC_CONN_FLAG_MP_WAIT_MP_READY; xqc_log(conn->log, XQC_LOG_WARN, "|don't have available cid for new path|"); return -XQC_EMP_NO_AVAIL_PATH_ID; } + xqc_log(conn->log, XQC_LOG_DEBUG, + "|find available path_id:%ui|", path_id); + if (path_status == XQC_APP_PATH_STATUS_STANDBY) { ps_inner = XQC_APP_PATH_STATUS_STANDBY; } - path = xqc_conn_create_path_inner(conn, NULL, NULL, ps_inner); + path = xqc_conn_create_path_inner(conn, NULL, NULL, ps_inner, path_id); if (path == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_create_path_inner error|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_path_create error|%ui|", path_id); return -XQC_EMP_CREATE_PATH; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); + + xqc_engine_wakeup_once(engine); *new_path_id = path->path_id; @@ -525,13 +521,10 @@ xqc_conn_close_path(xqc_engine_t *engine, const xqc_cid_t *scid, uint64_t closed return ret; } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(engine, conn); + xqc_engine_add_active_queue(engine, conn); - xqc_engine_main_logic_internal(engine); + xqc_engine_conn_logic(engine, conn); return XQC_OK; } @@ -544,7 +537,7 @@ xqc_conn_init_paths_list(xqc_connection_t *conn) conn->conn_initial_path = xqc_conn_create_path_inner(conn, &conn->scid_set.user_scid, &conn->dcid_set.current_dcid, - XQC_APP_PATH_STATUS_AVAILABLE); + XQC_APP_PATH_STATUS_AVAILABLE, 0); if (conn->conn_initial_path == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_conn_create_path_inner fail|"); return -XQC_EMP_CREATE_PATH; @@ -565,24 +558,6 @@ xqc_conn_destroy_paths_list(xqc_connection_t *conn) } } -xqc_path_ctx_t * -xqc_conn_find_path_by_dcid_seq(xqc_connection_t *conn, uint64_t dcid_seq_num) -{ - xqc_path_ctx_t *path = NULL; - xqc_list_head_t *pos, *next; - - xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { - path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - - if (path->path_dcid.cid_seq_num == dcid_seq_num) { - return path; - } - } - - return NULL; -} - - xqc_path_ctx_t * xqc_conn_find_path_by_path_id(xqc_connection_t *conn, uint64_t path_id) { @@ -600,54 +575,37 @@ xqc_conn_find_path_by_path_id(xqc_connection_t *conn, uint64_t path_id) return NULL; } + xqc_path_ctx_t * xqc_conn_find_path_by_scid(xqc_connection_t *conn, xqc_cid_t *scid) { xqc_path_ctx_t *path = NULL; xqc_list_head_t *pos, *next; + xqc_cid_inner_t *inner_cid = NULL; - xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { - path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - - if (xqc_cid_is_equal(&path->path_scid, scid) == XQC_OK) { - return path; - } + inner_cid = xqc_cid_set_search_cid(&conn->scid_set, scid); + if (inner_cid != NULL) { + return xqc_conn_find_path_by_path_id(conn, inner_cid->cid.path_id); } - if (xqc_cid_is_equal(&conn->original_dcid, scid) == XQC_OK) { + if (conn->conn_type == XQC_CONN_TYPE_SERVER + && xqc_cid_is_equal(&conn->original_dcid, scid) == XQC_OK) + { return conn->conn_initial_path; } return NULL; } -xqc_path_ctx_t * -xqc_conn_find_path_by_dcid(xqc_connection_t *conn, xqc_cid_t *dcid) -{ - xqc_path_ctx_t *path = NULL; - xqc_list_head_t *pos, *next; - - xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { - path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - - if (xqc_cid_is_equal(&path->path_dcid, dcid) == XQC_OK) { - return path; - } - } - - return NULL; -} - - xqc_path_ctx_t * xqc_conn_create_path_inner(xqc_connection_t *conn, - xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status) + xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status, uint64_t path_id) { xqc_int_t ret = XQC_ERROR; xqc_path_ctx_t *path = NULL; - path = xqc_path_create(conn, scid, dcid); + path = xqc_path_create(conn, scid, dcid, path_id); if (path == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_path_create error|"); return NULL; @@ -680,19 +638,24 @@ xqc_conn_path_metrics_print(xqc_connection_t *conn, xqc_conn_stats_t *stats) xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); - if (path->path_state >= XQC_PATH_STATE_VALIDATING && paths_num < XQC_MAX_PATHS_COUNT) { + if (path->path_state >= XQC_PATH_STATE_ACTIVE && paths_num < XQC_MAX_PATHS_COUNT) { if (path == NULL || path->path_send_ctl == NULL) { continue; } - if (path->path_send_ctl->ctl_recv_count == 0) { - continue; - } - stats->paths_info[paths_num].path_id = path->path_id; stats->paths_info[paths_num].path_pkt_recv_count = path->path_send_ctl->ctl_recv_count; stats->paths_info[paths_num].path_pkt_send_count = path->path_send_ctl->ctl_send_count; + stats->paths_info[paths_num].path_send_bytes = path->path_send_ctl->ctl_app_bytes_send; + stats->paths_info[paths_num].path_recv_bytes = path->path_send_ctl->ctl_app_bytes_recv; + stats->paths_info[paths_num].path_app_status = path->app_path_status; + + if (path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) { + stats->standby_path_app_bytes += path->path_send_ctl->ctl_app_bytes_send + path->path_send_ctl->ctl_app_bytes_recv; + } + + stats->total_app_bytes += path->path_send_ctl->ctl_app_bytes_send + path->path_send_ctl->ctl_app_bytes_recv; paths_num++; } @@ -923,7 +886,7 @@ xqc_path_send_buffer_clear(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_lis if (packet_out->po_flag & XQC_POF_TLP) { xqc_send_queue_move_to_head(&packet_out->po_list, &send_queue->sndq_pto_probe_packets); - } else if (packet_out->po_flag & XQC_POF_RETRANSED) { + } else if (packet_out->po_flag & XQC_POF_LOST) { xqc_send_queue_move_to_head(&packet_out->po_list, &send_queue->sndq_lost_packets); } else { @@ -1056,7 +1019,8 @@ xqc_conn_server_init_path_addr(xqc_connection_t *conn, uint64_t path_id, /* check if ip address is same with sub-connections created */ if (xqc_is_same_addr(peer_addr, (struct sockaddr *)active_path->peer_addr)) { xqc_path_immediate_close(path); - xqc_log(conn->engine->log, XQC_LOG_STATS, "|MP|path:%ui|conn:%s|cannot activate this path, due to the same IP|curIP:%s|conflictIP:%s|", + xqc_log(conn->engine->log, XQC_LOG_STATS, "|MP|path:%ui|conn:%s|" + "cannot activate this path, due to the same IP|curIP:%s|conflictIP:%s|", path_id, xqc_conn_addr_str(conn), xqc_peer_addr_str(conn->engine, (struct sockaddr*)peer_addr, conn->peer_addrlen), xqc_local_addr_str(conn->engine, (struct sockaddr*)active_path->peer_addr, active_path->peer_addrlen)); @@ -1128,7 +1092,7 @@ xqc_path_validate(xqc_path_ctx_t *path) path->path_flag &= ~XQC_PATH_FLAG_SEND_STATUS; xqc_int_t ret = xqc_set_application_path_status(path, path->next_app_path_state, XQC_TRUE); if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_path_status_frame_to_packet error|"); + xqc_log(conn->log, XQC_LOG_ERROR, "|error|"); } } @@ -1253,18 +1217,16 @@ xqc_set_application_path_status(xqc_path_ctx_t *path, xqc_app_path_status_t stat if (is_tx) { xqc_int_t ret = XQC_ERROR; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - ret = xqc_write_path_standby_or_available_frame_to_packet(conn, path); - } else { - ret = xqc_write_path_status_frame_to_packet(conn, path); - } + + ret = xqc_write_path_status_frame_to_packet(conn, path); if (ret != XQC_OK) { path->app_path_status = last_status; - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_path_status_frame_to_packet error|%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|error|%d|", ret); return ret; } } + xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|app_path_status:%d->%d|", path->path_id, last_status, status); path->app_path_status_changed_count++; path->last_app_path_status_changed_time = xqc_monotonic_timestamp(); @@ -1281,11 +1243,12 @@ xqc_set_application_path_status(xqc_path_ctx_t *path, xqc_app_path_status_t stat } + xqc_int_t xqc_conn_mark_path_standby(xqc_engine_t *engine, const xqc_cid_t *cid, uint64_t path_id) { - xqc_connection_t *conn = NULL; xqc_path_ctx_t *path = NULL; + xqc_connection_t *conn = NULL; conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { @@ -1481,6 +1444,34 @@ xqc_path_get_perf_class(xqc_path_ctx_t *path) return XQC_PATH_CLASS_STANDBY_HIGH; } +double +xqc_conn_recent_loss_rate(xqc_connection_t *conn) +{ + double loss_rate0 = 0, loss_rate1 = 0; + unsigned lost_cnt0, lost_cnt1, send_cnt0, send_cnt1; + xqc_path_ctx_t *path; + xqc_list_head_t *pos, *next; + + lost_cnt0 = lost_cnt1 = send_cnt0 = send_cnt1 = 0; + + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + lost_cnt0 += path->path_send_ctl->ctl_recent_lost_count[0]; + send_cnt0 += path->path_send_ctl->ctl_recent_send_count[0]; + lost_cnt1 += path->path_send_ctl->ctl_recent_lost_count[1]; + send_cnt1 += path->path_send_ctl->ctl_recent_send_count[1]; + } + + if (send_cnt0) { + loss_rate0 = 100.0 * lost_cnt0 / send_cnt0; + } + + if (send_cnt1) { + loss_rate1 = 100.0 * lost_cnt1 / send_cnt1; + } + + return xqc_max(loss_rate0, loss_rate1); +} double xqc_path_recent_loss_rate(xqc_path_ctx_t *path) diff --git a/src/transport/xqc_multipath.h b/src/transport/xqc_multipath.h index 78ce62ee4..d387630b1 100644 --- a/src/transport/xqc_multipath.h +++ b/src/transport/xqc_multipath.h @@ -9,6 +9,7 @@ #include #include #include +#include "src/transport/xqc_cid.h" #include "src/common/xqc_common.h" #include "src/transport/xqc_packet.h" #include "src/transport/xqc_recv_record.h" @@ -17,8 +18,8 @@ /* enable multipath */ typedef enum { - XQC_CONN_NOT_SUPPORT_MULTIPATH = 0, /* 00 */ - XQC_CONN_MULTIPATH_MULTIPLE_PNS = 1, /* 01 */ + XQC_CONN_MP_DISABLED = 0, /* 00 */ + XQC_CONN_MP_ENABLED = 1, /* 01 */ } xqc_multipath_mode_t; /* path state */ @@ -30,21 +31,6 @@ typedef enum { XQC_PATH_STATE_CLOSED = 4, /* PATH_ABANDONED acked or draining timeout */ } xqc_path_state_t; -/* application layer path status */ -typedef enum { - /* max */ - XQC_APP_PATH_STATUS_NONE, - /* suggest that no traffic should be sent on that path if another path is available */ - XQC_APP_PATH_STATUS_STANDBY = 1, - /* allow the peer to use its own logic to split traffic among available paths */ - XQC_APP_PATH_STATUS_AVAILABLE = 2, - /* freeze a path */ - XQC_APP_PATH_STATUS_FROZEN = 3, - /* max */ - XQC_APP_PATH_STATUS_MAX, -} xqc_app_path_status_t; - - /* path close mode: passive & proactive */ typedef enum { XQC_PATH_CLOSE_PASSIVE = 0, @@ -85,6 +71,7 @@ typedef enum { XQC_PATH_SPECIFIED_BY_PTMUD = 1 << 4, /* PMTUD Probe */ XQC_PATH_SPECIFIED_BY_KAP = 1 << 5, /* Keepalive Probe */ XQC_PATH_SPECIFIED_BY_PQP = 1 << 6, /* Path Quality Probe */ + XQC_PATH_SPECIFIED_BY_FEC = 1 << 7, /* FEC repair symbol */ } xqc_path_specified_flag_t; typedef enum { @@ -213,7 +200,7 @@ void xqc_path_schedule_buf_pre_destroy(xqc_send_queue_t *send_queue, xqc_path_ct /* create path inner */ xqc_path_ctx_t *xqc_conn_create_path_inner(xqc_connection_t *conn, - xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status); + xqc_cid_t *scid, xqc_cid_t *dcid, xqc_app_path_status_t path_status, uint64_t path_id); /* server update client addr when recv path_challenge frame */ xqc_int_t xqc_conn_server_init_path_addr(xqc_connection_t *conn, uint64_t path_id, @@ -233,8 +220,6 @@ xqc_int_t xqc_path_closed(xqc_path_ctx_t *path); /* find path */ xqc_path_ctx_t *xqc_conn_find_path_by_path_id(xqc_connection_t *conn, uint64_t path_id); xqc_path_ctx_t *xqc_conn_find_path_by_scid(xqc_connection_t *conn, xqc_cid_t *scid); -xqc_path_ctx_t *xqc_conn_find_path_by_dcid(xqc_connection_t *conn, xqc_cid_t *dcid); -xqc_path_ctx_t *xqc_conn_find_path_by_dcid_seq(xqc_connection_t *conn, uint64_t dcid_seq); void xqc_path_send_buffer_append(xqc_path_ctx_t *path, xqc_packet_out_t *packet_out, xqc_list_head_t *head); void xqc_path_send_buffer_remove(xqc_path_ctx_t *path, xqc_packet_out_t *packet_out); @@ -268,6 +253,8 @@ xqc_path_perf_class_t xqc_path_get_perf_class(xqc_path_ctx_t *path); double xqc_path_recent_loss_rate(xqc_path_ctx_t *path); +double xqc_conn_recent_loss_rate(xqc_connection_t *conn); + #endif /* XQC_MULTIPATH_H */ diff --git a/src/transport/xqc_packet_out.c b/src/transport/xqc_packet_out.c index 8e39cb681..697f338f6 100644 --- a/src/transport/xqc_packet_out.c +++ b/src/transport/xqc_packet_out.c @@ -17,6 +17,7 @@ #include "src/transport/xqc_datagram.h" #include "src/transport/xqc_reinjection.h" #include "src/transport/xqc_packet_out.h" +#include "src/transport/xqc_cid.h" xqc_packet_out_t * @@ -74,7 +75,7 @@ xqc_packet_out_create(size_t po_buf_size) || ((*path)->path_state >= XQC_PATH_STATE_CLOSING) || (*path)->app_path_status == XQC_APP_PATH_STATUS_FROZEN) { - po->po_path_flag &= ~(XQC_PATH_SPECIFIED_BY_ACK | XQC_PATH_SPECIFIED_BY_PTO | XQC_PATH_SPECIFIED_BY_REINJ); + po->po_path_flag &= ~(XQC_PATH_SPECIFIED_BY_ACK | XQC_PATH_SPECIFIED_BY_PTO | XQC_PATH_SPECIFIED_BY_REINJ | XQC_PATH_SPECIFIED_BY_FEC); if (po->po_path_flag) { if ((*path == NULL) @@ -104,7 +105,7 @@ xqc_packet_out_can_attach_ack(xqc_packet_out_t *po, return XQC_FALSE; } - if (po->po_frame_types & (XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP)) { + if (po->po_frame_types & (XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP | XQC_FRAME_BIT_REPAIR_SYMBOL)) { return XQC_FALSE; } @@ -112,7 +113,7 @@ xqc_packet_out_can_attach_ack(xqc_packet_out_t *po, return XQC_FALSE; } - if (po->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL) { + if (po->po_flag & XQC_POF_STREAM_NO_LEN) { return XQC_FALSE; } @@ -170,6 +171,7 @@ xqc_packet_out_copy(xqc_packet_out_t *dst, xqc_packet_out_t *src) dst->po_user_data = src->po_user_data; dst->po_path_id = src->po_path_id; + dst->po_reserved_size = src->po_reserved_size; dst->po_flag &= ~XQC_POF_IN_UNACK_LIST; dst->po_flag &= ~XQC_POF_IN_PATH_BUF_LIST; @@ -447,60 +449,77 @@ xqc_write_sid_frame_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *pack ssize_t ret; ret = xqc_gen_sid_frame(conn, packet_out); + if (ret == -XQC_EFEC_TOLERABLE_ERROR) { + return ret; - if (ret < 0) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_sid_frame error|"); + } else if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_gen_sid_frame error|"); return -XQC_EWRITE_PKT; } packet_out->po_used_size += ret; + packet_out->po_reserved_size -= ret; return XQC_OK; } +xqc_packet_out_t * +xqc_write_one_repair_packet(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_int_t repair_idx, + uint8_t bm_idx) +{ + uint64_t path_id; + xqc_int_t ret; + xqc_packet_out_t *packet_out; + xqc_send_queue_t *send_queue = conn->conn_send_queue; + + packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + + if (packet_out == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); + return NULL; + } + + ret = xqc_gen_repair_frame(conn, packet_out, fss_esi, repair_idx, bm_idx); + if (ret < 0) { + /* 少发几个repair packet不构成逻辑错误,只是恢复能力减弱了 */ + xqc_log(conn->log, XQC_LOG_WARN, "|xqc_gen_repair_frame error|"); + xqc_send_queue_remove_send(&packet_out->po_list); + xqc_send_queue_insert_free(packet_out, &send_queue->sndq_free_packets, send_queue); + return NULL; + } + + conn->fec_ctl->fec_send_repair_num_total++; + + return packet_out; +} + xqc_int_t -xqc_write_repair_packets(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_list_head_t *prev) +xqc_write_repair_packets(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_list_head_t *prev, xqc_int_t repair_packet_num, + uint8_t bm_idx) { - xqc_int_t ret, repair_packet_num, max_symbol_num, max_src_symbol_num, curr_repair_idx, repair_symbol_size, repair_key_size; + xqc_int_t ret, curr_repair_idx; xqc_path_ctx_t *path; - xqc_packet_out_t *packet_out; xqc_list_head_t *head; - - max_src_symbol_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block * conn->conn_settings.fec_params.fec_code_rate; - max_symbol_num = conn->conn_settings.fec_params.fec_max_symbol_num_per_block; - curr_repair_idx = 0; - repair_key_size = max_src_symbol_num; + xqc_packet_out_t *packet_out; - repair_packet_num = conn->fec_ctl->fec_send_repair_symbols_num; + curr_repair_idx = 0; if (repair_packet_num <= 0) { xqc_log(conn->log, XQC_LOG_WARN, "|current code rate is too low to generate repair packets."); return XQC_OK; } - - if (conn->fec_ctl->fec_send_src_symbols_num % max_src_symbol_num + repair_packet_num >= max_symbol_num) { - xqc_log(conn->log, XQC_LOG_ERROR, "|the sum of both symbols number exceeds max symbol number in one block|"); - return -XQC_EFEC_SYMBOL_ERROR; - } for (xqc_int_t i = 0; i < repair_packet_num; i++) { - packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + packet_out = xqc_write_one_repair_packet(conn, fss_esi, curr_repair_idx, bm_idx); if (packet_out == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); - return -XQC_EWRITE_PKT; - } - - ret = xqc_gen_repair_frame(conn, packet_out, fss_esi, curr_repair_idx, repair_key_size); - if (ret < 0) { - /* 少发几个repair packet不构成逻辑错误,只是恢复能力减弱了 */ - xqc_log(conn->log, XQC_LOG_WARN, "|xqc_gen_repair_frame error|"); continue; } curr_repair_idx++; - } - // move to the next position of current src symbol - xqc_send_queue_move_to_head(&packet_out->po_list, prev); + // move to the next position of current src symbol + xqc_send_queue_move_to_head(&packet_out->po_list, prev); + prev = &packet_out->po_list; + } return XQC_OK; } @@ -568,7 +587,7 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) } /* Acknowledgements of Initial and Handshake packets MUST be carried using ACK frames */ - if (pkt_type > XQC_PTYPE_HSK && conn->enable_multipath == XQC_CONN_MULTIPATH_MULTIPLE_PNS) { + if (pkt_type > XQC_PTYPE_HSK && conn->enable_multipath == XQC_CONN_MP_ENABLED) { is_mp_ack = 1; } @@ -576,7 +595,7 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) /* Try to attach ack or mp_ack to packet_out in path_buffer */ xqc_list_for_each_safe(pos, next, &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - + if (xqc_packet_out_can_attach_ack(packet_out, path, pkt_type)) { ret = xqc_write_ack_or_mp_ack_to_one_packet(conn, packet_out, pns, path, is_mp_ack); if (ret == -XQC_ENOBUF) { @@ -595,7 +614,7 @@ xqc_write_ack_or_mp_ack_to_packets(xqc_connection_t *conn) if (!is_mp_ack) { xqc_list_for_each_safe(pos, next, &conn->conn_send_queue->sndq_send_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - + if (xqc_packet_out_can_attach_ack(packet_out, path, pkt_type)) { ret = xqc_write_ack_to_one_packet(conn, packet_out, pns); if (ret == -XQC_ENOBUF) { @@ -1185,6 +1204,12 @@ xqc_write_stream_frame_to_packet(xqc_connection_t *conn, packet_out->po_used_size += n_written; packet_out->po_stream_id = stream->stream_id; packet_out->po_stream_offset = stream->stream_send_offset; + if (stream->stream_fec_blk_mode != XQC_SLIM_SIZE_REQ && conn->conn_settings.fec_params.fec_encoder_scheme) { + packet_out->po_flag |= XQC_POF_USE_FEC; + if (conn->conn_settings.fec_params.fec_encoder_scheme == XQC_PACKET_MASK_CODE) { + packet_out->po_stream_fec_blk_mode = stream->stream_fec_blk_mode; + } + } if (fin && *send_data_written == payload_size) { stream->stream_flag |= XQC_STREAM_FLAG_FIN_WRITE; @@ -1238,6 +1263,7 @@ xqc_write_datagram_frame_to_packet(xqc_connection_t *conn, xqc_pkt_type_t pkt_ty packet_out->po_flag |= XQC_POF_QOS_PROBING; } else { + packet_out->po_flag |= XQC_POF_USE_FEC; packet_out->po_flag |= XQC_POF_NOT_REINJECT; } @@ -1279,11 +1305,18 @@ xqc_write_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_pr xqc_packet_out_t *packet_out = NULL; xqc_cid_t new_conn_cid; uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN]; + xqc_cid_set_inner_t *inner_set; + + inner_set = xqc_get_path_cid_set(&conn->scid_set, XQC_INITIAL_PATH_ID); + + if (!inner_set) { + return -XQC_EGENERATE_CID; + } /* only reserve bits for server side */ - ++conn->scid_set.largest_scid_seq_num; + inner_set->largest_scid_seq_num++; if (XQC_OK != xqc_generate_cid(conn->engine, &conn->scid_set.user_scid, &new_conn_cid, - conn->scid_set.largest_scid_seq_num)) + inner_set->largest_scid_seq_num)) { xqc_log(conn->log, XQC_LOG_WARN, "|generate cid error|"); return -XQC_EGENERATE_CID; @@ -1295,13 +1328,15 @@ xqc_write_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_pr conn->engine->config->reset_token_keylen); /* insert to scid_set & add scid_unused_cnt */ - ret = xqc_cid_set_insert_cid(&conn->scid_set.cid_set, &new_conn_cid, XQC_CID_UNUSED, - conn->remote_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->scid_set, &new_conn_cid, XQC_CID_UNUSED, + conn->remote_settings.active_connection_id_limit, + XQC_INITIAL_PATH_ID); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, - "|xqc_cid_set_insert_cid error|limit:%ui|unused:%ui|used:%ui|", + "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", conn->remote_settings.active_connection_id_limit, - conn->scid_set.cid_set.unused_cnt, conn->scid_set.cid_set.used_cnt); + xqc_cid_set_get_unused_cnt(&conn->scid_set, XQC_INITIAL_PATH_ID), + xqc_cid_set_get_used_cnt(&conn->scid_set, XQC_INITIAL_PATH_ID)); return ret; } @@ -1325,6 +1360,8 @@ xqc_write_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_pr goto error; } packet_out->po_used_size += ret; + packet_out->po_new_cid_seq = new_conn_cid.cid_seq_num; + packet_out->po_new_cid_path = XQC_INITIAL_PATH_ID; xqc_log(conn->log, XQC_LOG_DEBUG, "|gen_new_scid|cid:%s|sr_token:%s|seq_num:%ui", xqc_scid_str(conn->engine, &new_conn_cid), xqc_sr_token_str(conn->engine, new_conn_cid.sr_token), @@ -1343,21 +1380,28 @@ xqc_int_t xqc_write_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_num) { xqc_int_t ret = XQC_ERROR; + xqc_path_ctx_t *path = conn->conn_initial_path; - /* select new current_dcid to replace the cid to be retired */ - if (seq_num == conn->dcid_set.current_dcid.cid_seq_num) { - // TODO: DCID changes - ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &conn->dcid_set.current_dcid); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available dcid" - "|seq_num:%ui|cur_cid_seq_num:%ui", seq_num, - conn->dcid_set.current_dcid.cid_seq_num); - return ret; + /* change path_dcid */ + if (path->path_dcid.cid_seq_num == seq_num) { + ret = xqc_get_unused_cid(&conn->dcid_set, &path->path_dcid, XQC_INITIAL_PATH_ID); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|conn have no available dcid|"); + return ret; } xqc_datagram_record_mss(conn); } - xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|", - xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid), conn->dcid_set.current_dcid.cid_seq_num); + + /* replace conn current_dcid */ + if (seq_num == conn->dcid_set.current_dcid.cid_seq_num + && conn->dcid_set.current_dcid.path_id == XQC_INITIAL_PATH_ID) + { + xqc_cid_copy(&conn->dcid_set.current_dcid, &path->path_dcid); + } + + xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|", + xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid), + conn->dcid_set.current_dcid.cid_seq_num); xqc_packet_out_t *packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); if (packet_out == NULL) { @@ -1404,28 +1448,12 @@ xqc_write_path_challenge_frame_to_packet(xqc_connection_t *conn, if (attach_path_status) { path->app_path_status_send_seq_num++; - //TODO: MPQUIC fix migration - - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_06) { - if (path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) { - ret = xqc_gen_path_standby_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { - ret = xqc_gen_path_available_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else { - ret = -XQC_EMP_PATH_STATE_ERROR; - xqc_log(conn->log, XQC_LOG_DEBUG, - "|xqc_write_path_challenge_frame_to_packet path_status didn't set|%d|", path->app_path_status); - } - } else { - ret = xqc_gen_path_status_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num, (uint64_t)path->app_path_status); - } - + ret = xqc_gen_path_status_frame(conn, packet_out, path->path_id, + path->app_path_status_send_seq_num, + path->app_path_status); if (ret < 0) { /* ignore */ - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_path_status_frame error|%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|attach status error|%d|", ret); } else { xqc_log(conn->log, XQC_LOG_DEBUG, @@ -1492,8 +1520,7 @@ xqc_write_ack_mp_to_one_packet(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); - //TODO: MPQUIC fix migration - ret = xqc_gen_ack_mp_frame(conn, path->path_scid.cid_seq_num, packet_out, now, + ret = xqc_gen_ack_mp_frame(conn, path->path_id, packet_out, now, conn->local_settings.ack_delay_exponent, &pn_ctl->ctl_recv_record[packet_out->po_pkt.pkt_pns], path->path_send_ctl->ctl_largest_recv_time[pns], @@ -1541,11 +1568,9 @@ xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *p return -XQC_EWRITE_PKT; } - /* dcid_seq_num = path->scid.cid_seq_num */ - //TODO: MPQUIC fix migration - uint64_t dcid_seq_num = path->path_scid.cid_seq_num; + uint64_t path_id = path->path_id; - ret = xqc_gen_path_abandon_frame(conn, packet_out, dcid_seq_num, 0); + ret = xqc_gen_path_abandon_frame(conn, packet_out, path_id, 0); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_path_abandon_frame error|%d|", ret); goto error; @@ -1555,8 +1580,8 @@ xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *p xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); - xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|dcid_seq_num:%ui|", - path->path_id, dcid_seq_num); + xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|path_id:%ui|", + path->path_id, path_id); return XQC_OK; @@ -1565,6 +1590,7 @@ xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *p return ret; } + xqc_int_t xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path) { @@ -1577,82 +1603,214 @@ xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *pa } path->app_path_status_send_seq_num++; - //TODO: MPQUIC fix migration - ret = xqc_gen_path_status_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num, (uint64_t)path->app_path_status); + + ret = xqc_gen_path_status_frame(conn, packet_out, path->path_id, + path->app_path_status_send_seq_num, + path->app_path_status); if (ret < 0) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_path_status_frame error|%d|", ret); + xqc_log(conn->log, XQC_LOG_ERROR, "|error|%d|", ret); goto error; } packet_out->po_used_size += ret; xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + xqc_log(conn->log, XQC_LOG_DEBUG, "|status=%d|", path->app_path_status); + return XQC_OK; -error: + error: xqc_maybe_recycle_packet_out(packet_out, conn); return ret; } +size_t +xqc_get_po_remained_size(xqc_packet_out_t *po) +{ + size_t res; + + res = po->po_buf_size - po->po_used_size - po->po_reserved_size; + + return xqc_max(res, 0); +} + +size_t +xqc_get_po_remained_size_with_ack_spc(xqc_packet_out_t *po) +{ + return xqc_get_po_remained_size(po) + XQC_ACK_SPACE; +} xqc_int_t -xqc_write_path_standby_or_available_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path) +xqc_write_mp_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_prior_to, uint64_t path_id) { - xqc_int_t ret = XQC_ERROR; + xqc_int_t ret = XQC_ERROR; + xqc_packet_out_t *packet_out = NULL; + xqc_cid_t new_conn_cid; + uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN]; + xqc_cid_set_inner_t *inner_set; - xqc_packet_out_t *packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); - if (packet_out == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); - return -XQC_EWRITE_PKT; + inner_set = xqc_get_path_cid_set(&conn->scid_set, path_id); + + if (!inner_set) { + return -XQC_EGENERATE_CID; } - path->app_path_status_send_seq_num++; + if (path_id == XQC_INITIAL_PATH_ID + || ((inner_set->unused_cnt + inner_set->used_cnt + inner_set->retired_cnt) > 0)) + { + inner_set->largest_scid_seq_num++; + } + + if (XQC_OK != xqc_generate_cid(conn->engine, &conn->scid_set.user_scid, &new_conn_cid, + inner_set->largest_scid_seq_num)) + { + xqc_log(conn->log, XQC_LOG_WARN, "|generate cid error|"); + return -XQC_EGENERATE_CID; + } - if (path->app_path_status == XQC_APP_PATH_STATUS_STANDBY) { - ret = xqc_gen_path_standby_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else if (path->app_path_status == XQC_APP_PATH_STATUS_AVAILABLE) { - ret = xqc_gen_path_available_frame(conn, packet_out, path->path_scid.cid_seq_num, - path->app_path_status_send_seq_num); - } else { - xqc_log(conn->log, XQC_LOG_WARN, "|xqc_write_path_standby_or_available_frame_to_packet status error|%d|", path->app_path_status); - ret = -XQC_EMP_PATH_STATE_ERROR; - goto error; + /* generate stateless reset token */ + xqc_gen_reset_token(&new_conn_cid, sr_token, XQC_STATELESS_RESET_TOKENLEN, + conn->engine->config->reset_token_key, + conn->engine->config->reset_token_keylen); + + /* insert to scid_set & add scid_unused_cnt */ + ret = xqc_cid_set_insert_cid(&conn->scid_set, &new_conn_cid, XQC_CID_UNUSED, + conn->remote_settings.active_connection_id_limit, + path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|xqc_cid_set_insert_cid error|limit:%ui|unused:%i|used:%i|", + conn->remote_settings.active_connection_id_limit, + xqc_cid_set_get_unused_cnt(&conn->scid_set, path_id), + xqc_cid_set_get_used_cnt(&conn->scid_set, path_id)); + return ret; } + ret = xqc_insert_conns_hash(conn->engine->conns_hash, conn, + new_conn_cid.cid_buf, new_conn_cid.cid_len); if (ret < 0) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_path_standby_or_available_frame_to_packet error|%d|", ret); - goto error; + xqc_log(conn->log, XQC_LOG_ERROR, "|insert new_cid into conns_hash failed|"); + return ret; } + packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + if (packet_out == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); + return -XQC_EWRITE_PKT; + } + + ret = xqc_gen_mp_new_conn_id_frame(packet_out, &new_conn_cid, retire_prior_to, + sr_token, path_id); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_mp_new_conn_id_frame error|"); + goto error; + } packet_out->po_used_size += ret; - xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + packet_out->po_new_cid_seq = new_conn_cid.cid_seq_num; + packet_out->po_new_cid_path = path_id; - xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_write_path_standby_or_available_frame_to_packet|status=%d|", path->app_path_status); + xqc_log(conn->log, XQC_LOG_DEBUG, "|path_id:%ui|cid:%s|sr_token:%s|seq_num:%ui", + path_id, + xqc_scid_str(conn->engine, &new_conn_cid), + xqc_sr_token_str(conn->engine, new_conn_cid.sr_token), + new_conn_cid.cid_seq_num); + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); return XQC_OK; - error: +error: xqc_maybe_recycle_packet_out(packet_out, conn); return ret; } -size_t -xqc_get_po_remained_size(xqc_packet_out_t *po) + +xqc_int_t +xqc_write_mp_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_num, uint64_t path_id) { - size_t res; + xqc_int_t ret = XQC_ERROR; + xqc_path_ctx_t *path; - res = po->po_buf_size - po->po_used_size - po->po_reserved_size; - if (res >= 0) { - return res; + path = xqc_conn_find_path_by_path_id(conn, path_id); + + /* replace path's dcid */ + if (path && path->path_dcid.cid_seq_num == seq_num) { + ret = xqc_get_unused_cid(&conn->dcid_set, &path->path_dcid, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path:%ui|don't have available dcid|", + path_id); + return ret; + } + xqc_datagram_record_mss(conn); + } + + /* select new current_dcid to replace the cid to be retired */ + if (seq_num == conn->dcid_set.current_dcid.cid_seq_num + && path_id == conn->dcid_set.current_dcid.path_id) + { + if (!path) { + ret = xqc_get_unused_cid(&conn->dcid_set, &conn->dcid_set.current_dcid, path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, + "|path:%ui|don't have available dcid|", + path_id); + return ret; + } + xqc_datagram_record_mss(conn); + + } else { + xqc_cid_copy(&conn->dcid_set.current_dcid, &path->path_dcid); + } + } - return po->po_buf_size - po->po_used_size; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|path_id:%ui|", + xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid), + conn->dcid_set.current_dcid.cid_seq_num, path_id); + + xqc_packet_out_t *packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + if (packet_out == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); + return -XQC_EWRITE_PKT; + } + + ret = xqc_gen_mp_retire_conn_id_frame(packet_out, seq_num, path_id); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_mp_retire_conn_id_frame error|"); + xqc_maybe_recycle_packet_out(packet_out, conn); + return ret; + } + + packet_out->po_used_size += ret; + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + + return XQC_OK; } -size_t -xqc_get_po_remained_size_with_ack_spc(xqc_packet_out_t *po) +int +xqc_write_max_path_id_to_packet(xqc_connection_t *conn, uint64_t max_path_id) { - return xqc_get_po_remained_size(po) + XQC_ACK_SPACE; -} + ssize_t ret = XQC_ERROR; + xqc_packet_out_t *packet_out; + xqc_log(conn->log, XQC_LOG_DEBUG, "|set max_path_id:%ui|", max_path_id); + packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER); + if (packet_out == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_new_packet error|"); + return -XQC_EWRITE_PKT; + } + + ret = xqc_gen_max_path_id_frame(packet_out, max_path_id); + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_max_streams_frame error|"); + goto error; + } + packet_out->po_used_size += ret; + xqc_send_queue_move_to_high_pri(&packet_out->po_list, conn->conn_send_queue); + xqc_log(conn->log, XQC_LOG_DEBUG, "|max_path_id:%ui|", max_path_id); + return XQC_OK; + +error: + xqc_maybe_recycle_packet_out(packet_out, conn); + return -XQC_EWRITE_PKT; +} \ No newline at end of file diff --git a/src/transport/xqc_packet_out.h b/src/transport/xqc_packet_out.h index 83b5f37b2..c988920a7 100644 --- a/src/transport/xqc_packet_out.h +++ b/src/transport/xqc_packet_out.h @@ -45,6 +45,8 @@ typedef enum { XQC_POF_QOS_HIGH = 1 << 18, XQC_POF_QOS_PROBING = 1 << 19, XQC_POF_SPURIOUS_LOSS = 1 << 20, + XQC_POF_USE_FEC = 1 << 21, + XQC_POF_STREAM_NO_LEN = 1 << 22, /* for stream without LEN bit, shouldn't attach different frame to it */ } xqc_packet_out_flag_t; typedef struct xqc_po_stream_frame_s { @@ -84,6 +86,7 @@ typedef struct xqc_packet_out_s { /* the stream related to stream frame */ xqc_po_stream_frame_t po_stream_frames[XQC_MAX_STREAM_FRAME_IN_PO]; unsigned int po_stream_frames_idx; + uint8_t po_stream_fec_blk_mode; uint32_t po_origin_ref_cnt; /* reference count of original packet */ uint32_t po_acked; @@ -121,6 +124,9 @@ typedef struct xqc_packet_out_s { xqc_usec_t po_sched_cwnd_blk_ts; xqc_usec_t po_send_cwnd_blk_ts; xqc_usec_t po_send_pacing_blk_ts; + + uint64_t po_new_cid_seq; + uint32_t po_new_cid_path; } xqc_packet_out_t; xqc_bool_t xqc_packet_out_on_specific_path(xqc_connection_t *conn, @@ -211,14 +217,22 @@ xqc_int_t xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_pat xqc_int_t xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path); -xqc_int_t xqc_write_path_standby_or_available_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path); - xqc_int_t xqc_write_sid_frame_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out); -xqc_int_t xqc_write_repair_packets(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_list_head_t *prev); +xqc_int_t xqc_write_repair_packets(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_list_head_t *prev, xqc_int_t repair_packet_num, + uint8_t bm_idx); + +xqc_packet_out_t *xqc_write_one_repair_packet(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_int_t repair_idx, + uint8_t bm_idx); int xqc_write_pmtud_ping_to_packet(xqc_path_ctx_t *path, size_t probing_size, xqc_pkt_type_t pkt_type); +xqc_int_t xqc_write_mp_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_prior_to, uint64_t path_id); + +xqc_int_t xqc_write_mp_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_num, uint64_t path_id); + +int xqc_write_max_path_id_to_packet(xqc_connection_t *conn, uint64_t max_path_id); + /** * @brief Get remained space size in packet out buff. * diff --git a/src/transport/xqc_packet_parser.c b/src/transport/xqc_packet_parser.c index ec7729f23..a7d78a100 100644 --- a/src/transport/xqc_packet_parser.c +++ b/src/transport/xqc_packet_parser.c @@ -198,7 +198,7 @@ xqc_gen_short_packet_header(xqc_packet_out_t *packet_out, unsigned char *dcid, u unsigned int need = 1 + dcid_len + packet_number_len; unsigned char *dst_buf = packet_out->po_buf; - size_t dst_buf_size = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_size = xqc_get_po_remained_size(packet_out); packet_out->po_pkt.pkt_type = XQC_PTYPE_SHORT_HEADER; @@ -275,21 +275,7 @@ xqc_packet_parse_short_header(xqc_connection_t *c, xqc_packet_in_t *packet_in) return -XQC_EILLPKT; } - //TODO: MPQUIC fix migration - if (c->enable_multipath) { - /* try to find the path */ - path = xqc_conn_find_path_by_scid(c, &packet_in->pi_pkt.pkt_dcid); - - } else { - path = c->conn_initial_path; - } - - if (path != NULL) { - packet_in->pi_path_id = path->path_id; - - } else { - packet_in->pi_path_id = XQC_UNKNOWN_PATH_ID; - } + packet_in->pi_path_id = packet_in->pi_pkt.pkt_dcid.path_id; xqc_log(c->log, XQC_LOG_DEBUG, "|parse short header|path:%ui|pkt_dcid:%s|spin_bit:%ud|", packet_in->pi_path_id, xqc_scid_str(c->engine, &(packet->pkt_dcid)), spin_bit); @@ -373,7 +359,7 @@ xqc_gen_long_packet_header (xqc_packet_out_t *packet_out, unsigned char pktno_bits) { unsigned char *dst_buf = packet_out->po_buf; - size_t dst_buf_size = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_size = xqc_get_po_remained_size(packet_out); xqc_pkt_type_t type = packet_out->po_pkt.pkt_type; xqc_packet_number_t packet_number = packet_out->po_pkt.pkt_num; @@ -642,7 +628,9 @@ xqc_packet_encrypt_buf(xqc_connection_t *conn, xqc_packet_out_t *packet_out, /* do packet protection */ //TODO: MPQUIC fix migration uint32_t nonce_path_id = (conn->enable_multipath) ? - (uint32_t)path->path_dcid.cid_seq_num : 0; + (uint32_t)path->path_id : 0; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|encryption nonce|path_id:%ui|pn:%ui|", nonce_path_id, packet_out->po_pkt.pkt_num); ret = xqc_tls_encrypt_payload(conn->tls, level, packet_out->po_pkt.pkt_num, nonce_path_id, dst_header, header_len, payload, payload_len, @@ -762,16 +750,9 @@ xqc_packet_decrypt(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_packet_parse_packet_number(pktno, pktno_len, &truncated_pn); /* decode packet number */ - // TODO: MPQUIC fix migration xqc_packet_number_t largest_pn = 0; - if (packet_in->pi_path_id != XQC_UNKNOWN_PATH_ID) { - xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); - if (path == NULL) { - xqc_log(conn->log, XQC_LOG_ERROR, - "|canno find the path|path_id:%ui|", - packet_in->pi_path_id); - return -XQC_EMP_PATH_NOT_FOUND; - } + xqc_path_ctx_t *path = xqc_conn_find_path_by_path_id(conn, packet_in->pi_path_id); + if (path) { xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); xqc_pkt_num_space_t pns = packet_in->pi_pkt.pkt_pns; largest_pn = xqc_recv_record_largest(&pn_ctl->ctl_recv_record[pns]); @@ -797,9 +778,10 @@ xqc_packet_decrypt(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } /* decrypt packet payload */ - // TODO: MPQUIC fix migration uint32_t nonce_path_id = (conn->enable_multipath) ? - (uint32_t)packet_in->pi_pkt.pkt_dcid.cid_seq_num : 0; + (uint32_t)packet_in->pi_path_id : 0; + + xqc_log(conn->log, XQC_LOG_DEBUG, "|decryption nonce|path_id:%ui|pn:%ui|", nonce_path_id, packet_in->pi_pkt.pkt_num); ret = xqc_tls_decrypt_payload(conn->tls, level, packet_in->pi_pkt.pkt_num, nonce_path_id, header, header_len, payload, payload_len, @@ -1037,8 +1019,8 @@ xqc_packet_parse_retry(xqc_connection_t *c, xqc_packet_in_t *packet_in) /* check conn type, only client can receive a Retry packet */ if (c->conn_type != XQC_CONN_TYPE_CLIENT) { - xqc_log(c->log, XQC_LOG_WARN, "|invalid conn_type recvd retry packet|%d|ignored|", c->conn_type); - return -XQC_EIGNORE_PKT; + xqc_log(c->log, XQC_LOG_WARN, "|invalid conn_type|%d|", c->conn_type); + return -XQC_EPROTO; } /** @@ -1304,6 +1286,7 @@ xqc_packet_parse_long_header(xqc_connection_t *c, XQC_BUFF_LEFT_SIZE(pos, end), dcid->cid_len + 1); return -XQC_EILLPKT; } + dcid->path_id = XQC_INITIAL_PATH_ID; xqc_memcpy(dcid->cid_buf, pos, dcid->cid_len); pos += dcid->cid_len; @@ -1318,6 +1301,7 @@ xqc_packet_parse_long_header(xqc_connection_t *c, XQC_BUFF_LEFT_SIZE(pos, end), scid->cid_len); return -XQC_EILLPKT; } + scid->path_id = XQC_INITIAL_PATH_ID; xqc_memcpy(scid->cid_buf, pos, scid->cid_len); pos += scid->cid_len; @@ -1328,8 +1312,8 @@ xqc_packet_parse_long_header(xqc_connection_t *c, && XQC_CONN_FLAG_DCID_OK & c->conn_flag) { /* check cid */ - if (xqc_cid_in_cid_set(&c->scid_set.cid_set, &(packet->pkt_dcid)) == NULL - || xqc_cid_in_cid_set(&c->dcid_set.cid_set, &(packet->pkt_scid)) == NULL) + if (xqc_cid_set_search_cid(&c->scid_set, &(packet->pkt_dcid)) == NULL + || xqc_cid_set_search_cid(&c->dcid_set, &(packet->pkt_scid)) == NULL) { /* log & ignore packet */ xqc_log(c->log, XQC_LOG_ERROR, "|invalid dcid or scid|"); diff --git a/src/transport/xqc_recv_record.h b/src/transport/xqc_recv_record.h index fa44e5cfb..be44d2b95 100644 --- a/src/transport/xqc_recv_record.h +++ b/src/transport/xqc_recv_record.h @@ -33,7 +33,7 @@ typedef struct xqc_recv_record_s { typedef struct xqc_ack_info_s { xqc_pkt_num_space_t pns; - uint64_t dcid_seq_num; + uint64_t path_id; unsigned n_ranges; /* must > 0 */ xqc_pktno_range_t ranges[XQC_MAX_ACK_RANGE_CNT]; xqc_usec_t ack_delay; diff --git a/src/transport/xqc_reinjection.c b/src/transport/xqc_reinjection.c index 00c8b9144..178c3d1fd 100644 --- a/src/transport/xqc_reinjection.c +++ b/src/transport/xqc_reinjection.c @@ -10,7 +10,6 @@ #include "src/transport/xqc_cid.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_utils.h" -#include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_packet_out.h" #include "src/common/xqc_common.h" diff --git a/src/transport/xqc_send_ctl.c b/src/transport/xqc_send_ctl.c index c0d114d91..ee456ab3e 100644 --- a/src/transport/xqc_send_ctl.c +++ b/src/transport/xqc_send_ctl.c @@ -655,6 +655,9 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ } send_ctl->ctl_bytes_send += packet_out->po_enc_size; + if (packet_out->po_frame_types & (XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_DATAGRAM)) { + send_ctl->ctl_app_bytes_send += packet_out->po_enc_size; + } if (packet_out->po_largest_ack > 0) { xqc_ack_sent_record_add(&pn_ctl->ack_sent_record[pns], packet_out, send_ctl->ctl_srtt, now); @@ -669,7 +672,7 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ packet_out->po_pkt.pkt_num; } - xqc_conn_update_stream_stats_on_sent(send_ctl->ctl_conn, packet_out, now); + xqc_conn_update_stream_stats_on_sent(send_ctl->ctl_conn, send_ctl, packet_out, now); xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|path:%ui|inflight:%ud|applimit:%ui|", @@ -1320,7 +1323,7 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); xqc_list_splice_tail_init(&path->path_reinj_tmp_buf, - &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]); + &path->path_schedule_buf[XQC_SEND_TYPE_NORMAL]); } } @@ -1544,10 +1547,10 @@ xqc_send_ctl_on_packet_acked(xqc_send_ctl_t *send_ctl, } /* TODO: fix NEW_CID_RECEIVED */ - if (packet_out->po_frame_types & XQC_FRAME_BIT_NEW_CONNECTION_ID) { - packet_out->po_frame_types &= ~XQC_FRAME_BIT_NEW_CONNECTION_ID; - conn->conn_flag |= XQC_CONN_FLAG_NEW_CID_ACKED; + if (packet_out->po_frame_types & (XQC_FRAME_BIT_NEW_CONNECTION_ID | XQC_FRAME_BIT_MP_NEW_CONNECTION_ID)) { + xqc_cid_set_on_cid_acked(&conn->scid_set, packet_out->po_new_cid_path, packet_out->po_new_cid_seq); } + if (do_cc) { xqc_send_ctl_cc_on_ack(send_ctl, packet_out, now); @@ -1564,7 +1567,7 @@ xqc_send_ctl_on_packet_acked(xqc_send_ctl_t *send_ctl, xqc_usec_t xqc_send_ctl_get_pto_time_and_space(xqc_send_ctl_t *send_ctl, xqc_usec_t now, xqc_pkt_num_space_t *pns_ret) { - xqc_usec_t t; + xqc_usec_t t, duration; xqc_usec_t pto_timeout = XQC_MAX_UINT64_VALUE; xqc_connection_t *c = send_ctl->ctl_conn; xqc_int_t pto_cnt = send_ctl->ctl_pto_count; @@ -1574,8 +1577,13 @@ xqc_send_ctl_get_pto_time_and_space(xqc_send_ctl_t *send_ctl, xqc_usec_t now, xq backoff = xqc_min(backoff, 1 << 16); /* get pto duration */ - xqc_usec_t duration = (send_ctl->ctl_srtt - + xqc_max(4 * send_ctl->ctl_rttvar, XQC_kGranularity * 1000)); + if (c->conn_settings.control_pto_value) { + duration = send_ctl->ctl_srtt + send_ctl->ctl_srtt / 4; + + } else { + duration = (send_ctl->ctl_srtt + + xqc_max(4 * send_ctl->ctl_rttvar, XQC_kGranularity * 1000)); + } /* RTT has not been measured yet*/ if (send_ctl->ctl_first_rtt_sample_time == 0 @@ -1835,7 +1843,6 @@ xqc_send_ctl_get_est_bw(xqc_send_ctl_t *send_ctl) } uint64_t -xqc_send_ctl_get_pacing_rate(xqc_send_ctl_t *send_ctl) -{ +xqc_send_ctl_get_pacing_rate(xqc_send_ctl_t *send_ctl) { return xqc_pacing_rate_calc(&send_ctl->ctl_pacing); } diff --git a/src/transport/xqc_send_ctl.h b/src/transport/xqc_send_ctl.h index e874781c2..024a97fa4 100644 --- a/src/transport/xqc_send_ctl.h +++ b/src/transport/xqc_send_ctl.h @@ -134,6 +134,10 @@ typedef struct xqc_send_ctl_s { uint64_t ctl_bytes_send; uint64_t ctl_bytes_recv; + /* only accounts for stream and datagram packets */ + uint64_t ctl_app_bytes_send; + uint64_t ctl_app_bytes_recv; + const xqc_cong_ctrl_callback_t *ctl_cong_callback; void *ctl_cong; diff --git a/src/transport/xqc_send_queue.c b/src/transport/xqc_send_queue.c index f23407188..64b7b4a4e 100644 --- a/src/transport/xqc_send_queue.c +++ b/src/transport/xqc_send_queue.c @@ -116,7 +116,7 @@ xqc_send_queue_get_packet_out(xqc_send_queue_t *send_queue, unsigned need, xqc_p xqc_list_for_each_reverse(pos, &send_queue->sndq_send_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); if (packet_out->po_pkt.pkt_type == pkt_type - && packet_out->po_buf_size >= packet_out->po_used_size + need) + && xqc_get_po_remained_size(packet_out) >= need) { return packet_out; } @@ -140,11 +140,13 @@ xqc_send_queue_get_packet_out_for_stream(xqc_send_queue_t *send_queue, unsigned xqc_list_for_each_reverse(pos, &send_queue->sndq_send_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); if (packet_out->po_pkt.pkt_type == pkt_type - && packet_out->po_buf_size >= packet_out->po_used_size + need + && xqc_get_po_remained_size(packet_out) >= need && packet_out->po_stream_frames_idx < XQC_MAX_STREAM_FRAME_IN_PO && packet_out->po_stream_frames_idx > 0 /* Avoid Head-of-Line blocking. */ - && packet_out->po_stream_frames[packet_out->po_stream_frames_idx - 1].ps_stream_id == stream->stream_id) + && packet_out->po_stream_frames[packet_out->po_stream_frames_idx - 1].ps_stream_id == stream->stream_id + && !(packet_out->po_frame_types & XQC_FRAME_BIT_SID) + && !(packet_out->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL)) { return packet_out; } @@ -592,7 +594,7 @@ xqc_send_ctl_stream_frame_can_drop(xqc_packet_out_t *packet_out, xqc_stream_id_t * removing R may also free N via xqc_send_ctl_indirectly_ack_or_drop_po. If that * happens, an infinite loop that traversing the free_packets list is triggered. */ - uint64_t mask = ~(XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP | XQC_FRAME_BIT_SID | XQC_FRAME_BIT_REPAIR_SYMBOL); + uint64_t mask = ~(XQC_FRAME_BIT_STREAM | XQC_FRAME_BIT_ACK | XQC_FRAME_BIT_ACK_MP | XQC_FRAME_BIT_SID); if ((packet_out->po_frame_types & mask) == 0) { drop = 0; for (int i = 0; i < XQC_MAX_STREAM_FRAME_IN_PO; i++) { diff --git a/src/transport/xqc_stream.c b/src/transport/xqc_stream.c index 119115bcf..657d77158 100644 --- a/src/transport/xqc_stream.c +++ b/src/transport/xqc_stream.c @@ -43,14 +43,8 @@ xqc_stream_ready_to_write(xqc_stream_t *stream) stream->stream_flag |= XQC_STREAM_FLAG_READY_TO_WRITE; } - if (!(stream->stream_conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (xqc_conns_pq_push(stream->stream_conn->engine->conns_active_pq, - stream->stream_conn, stream->stream_conn->last_ticked_time) != 0) { - return; - } - - stream->stream_conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } + xqc_engine_remove_wakeup_queue(stream->stream_conn->engine, stream->stream_conn); + xqc_engine_add_active_queue(stream->stream_conn->engine, stream->stream_conn); } void @@ -74,14 +68,8 @@ xqc_stream_ready_to_read(xqc_stream_t *stream) stream->stream_flag |= XQC_STREAM_FLAG_READY_TO_READ; } - if (!(stream->stream_conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (xqc_conns_pq_push(stream->stream_conn->engine->conns_active_pq, - stream->stream_conn, stream->stream_conn->last_ticked_time) != 0) { - return; - } - - stream->stream_conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } + xqc_engine_remove_wakeup_queue(stream->stream_conn->engine, stream->stream_conn); + xqc_engine_add_active_queue(stream->stream_conn->engine, stream->stream_conn); } void @@ -95,6 +83,40 @@ xqc_stream_shutdown_read(xqc_stream_t *stream) } } +xqc_bool_t +xqc_stream_is_terminal_state(xqc_stream_t *stream) +{ + xqc_bool_t check_send_state, check_recv_state; + xqc_conn_type_t conn_type = stream->stream_conn->conn_type; + + if (stream->stream_type == XQC_CLI_BID || stream->stream_type == XQC_SVR_BID) { + check_send_state = XQC_TRUE; + check_recv_state = XQC_TRUE; + } else if ((stream->stream_type == XQC_CLI_UNI && conn_type == XQC_CONN_TYPE_CLIENT) + || (stream->stream_type == XQC_SVR_UNI && conn_type == XQC_CONN_TYPE_SERVER)) { + /* Uni Stream Send side */ + check_send_state = XQC_TRUE; + check_recv_state = XQC_FALSE; + } else { + /* Uni Stream Recv side */ + check_send_state = XQC_FALSE; + check_recv_state = XQC_TRUE; + } + + if (check_send_state && check_recv_state) { + return (stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD + || stream->stream_state_send == XQC_SEND_STREAM_ST_RESET_RECVD) + && (stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ + || stream->stream_state_recv == XQC_RECV_STREAM_ST_RESET_READ); + } else if (check_send_state) { + return stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD + || stream->stream_state_send == XQC_SEND_STREAM_ST_RESET_RECVD; + } else { + return stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ + || stream->stream_state_recv == XQC_RECV_STREAM_ST_RESET_READ; + } +} + void xqc_stream_maybe_need_close(xqc_stream_t *stream) { @@ -114,8 +136,9 @@ xqc_stream_maybe_need_close(xqc_stream_t *stream) xqc_stream_record_trans_state(stream, XQC_FALSE); } - if ((stream->stream_state_send == XQC_SEND_STREAM_ST_DATA_RECVD || stream->stream_state_send == XQC_SEND_STREAM_ST_RESET_RECVD) - && (stream->stream_state_recv == XQC_RECV_STREAM_ST_DATA_READ || stream->stream_state_recv == XQC_RECV_STREAM_ST_RESET_READ)) + stream->stream_stats.max_pto_backoff = xqc_max(stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(stream->stream_conn, 1)); + + if (xqc_stream_is_terminal_state(stream)) { xqc_log(stream->stream_conn->log, XQC_LOG_DEBUG, "|stream_id:%ui|stream_type:%d|", stream->stream_id, stream->stream_type); stream->stream_flag |= XQC_STREAM_FLAG_NEED_CLOSE; @@ -815,13 +838,13 @@ xqc_stream_close(xqc_stream_t *stream) } } - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + stream->stream_stats.max_pto_backoff = xqc_max(stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(conn, 1)); + + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); + xqc_stream_shutdown_write(stream); - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); return XQC_OK; } @@ -930,6 +953,8 @@ xqc_read_crypto_stream(xqc_stream_t *stream) xqc_stream_frame_t *stream_frame = NULL; xqc_connection_t *conn = stream->stream_conn; + xqc_log(conn->log, XQC_LOG_DEBUG, "|xqc_read_crypto_stream|level:%d|", stream->stream_encrypt_level); + xqc_list_head_t *pos, *next; xqc_list_for_each_safe(pos, next, &stream->stream_data_in.frames_tailq) { stream_frame = xqc_list_entry(pos, xqc_stream_frame_t, sf_list); @@ -1126,6 +1151,7 @@ xqc_crypto_stream_on_write(xqc_stream_t *stream, void *user_data) switch (cur_state) { case XQC_CONN_STATE_CLIENT_INIT: + crypto_data_list = &conn->initial_crypto_data_list; next_state = XQC_CONN_STATE_CLIENT_INITIAL_SENT; break; @@ -1134,6 +1160,7 @@ xqc_crypto_stream_on_write(xqc_stream_t *stream, void *user_data) case XQC_CONN_STATE_SERVER_INITIAL_RECVD: xqc_log(stream->stream_conn->log, XQC_LOG_DEBUG, "|cur_state:%d|switch|", cur_state); + /* haven't recved enough data for client hello */ if (conn->conn_type == XQC_CONN_TYPE_SERVER && !(conn->conn_flag & XQC_CONN_FLAG_TLS_CH_RECVD)) { return XQC_OK; @@ -1486,17 +1513,17 @@ xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t send_data xqc_log_event(conn->log, TRA_STREAM_DATA_MOVED, stream, 0, send_data_size, 0, fin, ret, pkt_type, buff_1rtt, offset); - if (!(conn->conn_flag & XQC_CONN_FLAG_TICKING)) { - if (0 == xqc_conns_pq_push(conn->engine->conns_active_pq, conn, conn->last_ticked_time)) { - conn->conn_flag |= XQC_CONN_FLAG_TICKING; - } - } + xqc_engine_remove_wakeup_queue(conn->engine, conn); + xqc_engine_add_active_queue(conn->engine, conn); xqc_stream_record_trans_state(stream, XQC_TRUE); + /* update max_pto stats */ + stream->stream_stats.max_pto_backoff = xqc_max(stream->stream_stats.max_pto_backoff, xqc_conn_get_max_pto_backoff(conn, 1)); + /* application layer call the main logic */ if (!(stream->stream_flag & XQC_STREAM_FLAG_HAS_H3)) { - xqc_engine_main_logic_internal(conn->engine); + xqc_engine_conn_logic(conn->engine, conn); } if (offset == 0 && !fin_only_done) { diff --git a/src/transport/xqc_stream.h b/src/transport/xqc_stream.h index c3e39bdad..6692d8191 100644 --- a/src/transport/xqc_stream.h +++ b/src/transport/xqc_stream.h @@ -154,11 +154,17 @@ struct xqc_stream_s { xqc_usec_t send_cwnd_blk_duration; xqc_usec_t send_pacing_blk_duration; uint32_t retrans_pkt_cnt; + uint32_t sent_pkt_cnt; + uint8_t max_pto_backoff; + uint32_t recov_pkt_cnt; + xqc_usec_t fst_rpr_time; + xqc_usec_t last_rpr_time; } stream_stats; xqc_path_metrics_t paths_info[XQC_MAX_PATHS_COUNT]; uint8_t stream_mp_usage_schedule; uint8_t stream_mp_usage_reinject; + uint8_t stream_fec_blk_mode; uint64_t recv_rate_bytes_per_sec; @@ -207,6 +213,8 @@ void xqc_stream_ready_to_read(xqc_stream_t *stream); void xqc_stream_shutdown_read(xqc_stream_t *stream); +xqc_bool_t xqc_stream_is_terminal_state(xqc_stream_t *stream); + void xqc_stream_maybe_need_close(xqc_stream_t *stream); xqc_stream_t *xqc_find_stream_by_id(xqc_stream_id_t stream_id, xqc_id_hash_table_t *streams_hash); diff --git a/src/transport/xqc_timer.c b/src/transport/xqc_timer.c index 6843fb3a5..840eb99ff 100644 --- a/src/transport/xqc_timer.c +++ b/src/transport/xqc_timer.c @@ -240,48 +240,56 @@ xqc_timer_retire_cid_timeout(xqc_timer_type_t type, xqc_usec_t now, void *user_d xqc_usec_t next_time = XQC_MAX_UINT64_VALUE; xqc_usec_t interval = 0; - xqc_list_for_each_safe(pos, next, &conn->scid_set.cid_set.list_head) { - inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - - if (inner_cid->state == XQC_CID_RETIRED) { - - if (inner_cid->retired_ts < now) { - /* MP关闭主路后如果删除对应的cid映射,对外接口通过engine和cid无法找到conn,暂时注释掉 */ - /* TODO: 1. MP切换主路后通知上层更换cid; 2. 重新设计接口,改用conn而不是engine和cid */ - // /* switch state to REMOVED & delete from cid_set */ - // if (xqc_find_conns_hash(conn->engine->conns_hash, conn, - // inner_cid->cid.cid_buf, inner_cid->cid.cid_len)) - // { - // xqc_remove_conns_hash(conn->engine->conns_hash, conn, - // inner_cid->cid.cid_buf, inner_cid->cid.cid_len); - // } - - ret = xqc_cid_switch_to_next_state(&conn->scid_set.cid_set, inner_cid, XQC_CID_REMOVED); - if (ret != XQC_OK) { - xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_switch_to_next_state error|"); - return; + xqc_cid_set_inner_t *inner_set; + xqc_list_head_t *pos_set, *next_set; + uint32_t to_be_retired_cnt = 0; + + xqc_list_for_each_safe(pos_set, next_set, &conn->scid_set.cid_set_list) { + inner_set = xqc_list_entry(pos_set, xqc_cid_set_inner_t, next); + + xqc_list_for_each_safe(pos, next, &inner_set->cid_list) { + inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list); + + if (inner_cid->state == XQC_CID_RETIRED) { + + if (inner_cid->retired_ts < now) { + /* MP关闭主路后如果删除对应的cid映射,对外接口通过engine和cid无法找到conn,暂时注释掉 */ + /* TODO: 1. MP切换主路后通知上层更换cid; 2. 重新设计接口,改用conn而不是engine和cid */ + // /* switch state to REMOVED & delete from cid_set */ + // if (xqc_find_conns_hash(conn->engine->conns_hash, conn, + // inner_cid->cid.cid_buf, inner_cid->cid.cid_len)) + // { + // xqc_remove_conns_hash(conn->engine->conns_hash, conn, + // inner_cid->cid.cid_buf, inner_cid->cid.cid_len); + // } + + ret = xqc_cid_switch_to_next_state(&conn->scid_set, inner_cid, XQC_CID_REMOVED, inner_cid->cid.path_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_switch_to_next_state error|"); + continue; + } + + xqc_log(conn->log, XQC_LOG_DEBUG, + "|retired->removed|cid:%s|seq:%ui|len:%d|", + xqc_scid_str(conn->engine, &inner_cid->cid), + inner_cid->cid.cid_seq_num, + inner_cid->cid.cid_len); + + // xqc_list_del(pos); + // xqc_free(inner_cid); + + } else { + /* record the earliest time that has not yet expired */ + if (inner_cid->retired_ts < next_time) { + next_time = inner_cid->retired_ts; + } + to_be_retired_cnt++; } - - xqc_log(conn->log, XQC_LOG_DEBUG, - "|retired->removed|cid:%s|seq:%ui|len:%d|", - xqc_scid_str(conn->engine, &inner_cid->cid), - inner_cid->cid.cid_seq_num, - inner_cid->cid.cid_len); - - // xqc_list_del(pos); - // xqc_free(inner_cid); - - } else { - /* record the earliest time that has not yet expired */ - if (inner_cid->retired_ts < next_time) { - next_time = inner_cid->retired_ts; - } - } } } - if (conn->scid_set.cid_set.retired_cnt > 0) { + if (to_be_retired_cnt > 0) { if (next_time == XQC_MAX_UINT64_VALUE) { xqc_log(conn->log, XQC_LOG_ERROR, "|next_time is not assigned a value|"); return; diff --git a/src/transport/xqc_transport_params.c b/src/transport/xqc_transport_params.c index 07abe1b3a..53412c75c 100644 --- a/src/transport/xqc_transport_params.c +++ b/src/transport/xqc_transport_params.c @@ -158,34 +158,23 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, } if (params->enable_multipath) { - if (params->multipath_version == XQC_MULTIPATH_06) { - /* enable_multipath (-draft06) is zero-length transport parameter */ - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06) + - xqc_put_varint_len(0); - - } else if (params->multipath_version == XQC_MULTIPATH_05) { - /* enable_multipath (-draft05) is zero-length transport parameter */ - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05) + - xqc_put_varint_len(0); - - } else { - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04) + - xqc_put_varint_len(xqc_put_varint_len(params->enable_multipath)) + - xqc_put_varint_len(params->enable_multipath); + if (params->multipath_version == XQC_MULTIPATH_10) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10) + + xqc_put_varint_len(xqc_put_varint_len(params->init_max_path_id)) + + xqc_put_varint_len(params->init_max_path_id); + } } if (params->close_dgram_redundancy == XQC_RED_SET_CLOSE) { len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY) + - xqc_put_varint_len(xqc_put_varint_len(params->close_dgram_redundancy)) + - xqc_put_varint_len(params->close_dgram_redundancy); + xqc_put_varint_len(xqc_put_varint_len(params->close_dgram_redundancy)) + + xqc_put_varint_len(params->close_dgram_redundancy); } #ifdef XQC_ENABLE_FEC - if (params->enable_encode_fec || params->enable_decode_fec) { - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_VERSION) + - xqc_put_varint_len(0); - } + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_VERSION_02) + + xqc_put_varint_len(0); /* * if enable_encode_fec, add fec related params' length: @@ -201,15 +190,10 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, preferred_fec_paramslen += xqc_put_varint_len(params->fec_encoder_schemes[i]); } len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES) + - xqc_put_varint_len(preferred_fec_paramslen) + preferred_fec_paramslen; - - len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_SIZE) + - xqc_put_varint_len(xqc_put_varint_len(params->fec_max_symbol_size)) + - xqc_put_varint_len(params->fec_max_symbol_size); - + xqc_put_varint_len(preferred_fec_paramslen) + preferred_fec_paramslen; len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM) + - xqc_put_varint_len(xqc_put_varint_len(params->fec_max_symbols_num)) + - xqc_put_varint_len(params->fec_max_symbols_num); + xqc_put_varint_len(xqc_put_varint_len(params->fec_max_symbols_num)) + + xqc_put_varint_len(params->fec_max_symbols_num); } /* * if enable_decode_fec, add fec related params' length: @@ -225,7 +209,7 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, preferred_fec_paramslen += xqc_put_varint_len(params->fec_decoder_schemes[i]); } len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES) + - xqc_put_varint_len(preferred_fec_paramslen) + preferred_fec_paramslen; + xqc_put_varint_len(preferred_fec_paramslen) + preferred_fec_paramslen; } #endif @@ -406,14 +390,9 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, } if (params->enable_multipath) { - if (params->multipath_version == XQC_MULTIPATH_06) { - p = xqc_put_zero_length_param(p, XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06); + if (params->multipath_version == XQC_MULTIPATH_10) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10, params->init_max_path_id); - } else if (params->multipath_version == XQC_MULTIPATH_05) { - p = xqc_put_zero_length_param(p, XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05); - - } else { - p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04, params->enable_multipath); } } @@ -432,9 +411,7 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, } #ifdef XQC_ENABLE_FEC - if (params->enable_encode_fec || params->enable_decode_fec) { - p = xqc_put_zero_length_param(p, XQC_TRANSPORT_PARAM_FEC_VERSION); - } + p = xqc_put_zero_length_param(p, XQC_TRANSPORT_PARAM_FEC_VERSION_02); if (params->enable_encode_fec && params->fec_encoder_schemes_num > 0 @@ -452,11 +429,8 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, for (xqc_int_t i = 0; i < params->fec_encoder_schemes_num; i++) { p = xqc_put_varint(p, params->fec_encoder_schemes[i]); } - p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_SIZE, - params->fec_max_symbol_size); - p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM, - params->fec_max_symbols_num); + params->fec_max_symbols_num); } if (params->enable_decode_fec @@ -720,22 +694,11 @@ static xqc_int_t xqc_decode_enable_multipath(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) { - if (param_type == XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06) { - /* enable_multipath param is a zero-length value, presentation means enable */ - params->enable_multipath = 1; - params->multipath_version = XQC_MULTIPATH_06; - return XQC_OK; - } else if (param_type == XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05) { - /* enable_multipath param is a zero-length value, presentation means enable */ + if (param_type == XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10) { params->enable_multipath = 1; - params->multipath_version = XQC_MULTIPATH_05; + params->multipath_version = XQC_MULTIPATH_10; + XQC_DECODE_VINT_VALUE(¶ms->init_max_path_id, p, end); return XQC_OK; - } else if (param_type == XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04) { - if (params->multipath_version > XQC_MULTIPATH_04) { - return XQC_OK; - } - params->multipath_version = XQC_MULTIPATH_04; - XQC_DECODE_VINT_VALUE(¶ms->enable_multipath, p, end); } return XQC_OK; } @@ -765,8 +728,8 @@ xqc_decode_fec_version(xqc_transport_params_t *params, xqc_transport_params_type const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) { switch (param_type) { - case XQC_TRANSPORT_PARAM_FEC_VERSION: - params->fec_version = XQC_FEC_01; + case XQC_TRANSPORT_PARAM_FEC_VERSION_02: + params->fec_version = XQC_FEC_02; break; default: @@ -777,12 +740,6 @@ xqc_decode_fec_version(xqc_transport_params_t *params, xqc_transport_params_type return XQC_OK; } -static xqc_int_t -xqc_decode_fec_max_symbol_size(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, - const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) -{ - XQC_DECODE_VINT_VALUE(¶ms->fec_max_symbol_size, p, end); -} static xqc_int_t xqc_decode_fec_max_symbols_num(xqc_transport_params_t *params, xqc_transport_params_type_t exttype, @@ -902,7 +859,6 @@ xqc_trans_param_decode_func xqc_trans_param_decode_func_list[] = { xqc_decode_fec_version, xqc_decode_encoder_schemes, xqc_decode_decoder_schemes, - xqc_decode_fec_max_symbol_size, xqc_decode_fec_max_symbols_num, #endif xqc_decode_no_crypto, @@ -934,9 +890,7 @@ xqc_trans_param_get_index(uint64_t param_type) case XQC_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID: return param_type; - case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04: - case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05: - case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06: + case XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10: return XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_PARSER; case XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE: @@ -947,6 +901,7 @@ xqc_trans_param_get_index(uint64_t param_type) #ifdef XQC_ENABLE_FEC case XQC_TRANSPORT_PARAM_FEC_VERSION: + case XQC_TRANSPORT_PARAM_FEC_VERSION_02: return XQC_TRANSPORT_PARAM_FEC_VERSION_PARSER; case XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES: @@ -955,15 +910,11 @@ xqc_trans_param_get_index(uint64_t param_type) case XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES: return XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES_PARSER; - case XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_SIZE: - return XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_SIZE_PARSER; - case XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM: return XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM_PARSER; #endif - // 验证一下编译开关关闭时候是否有问题 case XQC_TRANSPORT_PARAM_NO_CRYPTO: return XQC_TRANSPORT_PARAM_PROTOCOL_MAX; @@ -1059,12 +1010,12 @@ xqc_decode_transport_params(xqc_transport_params_t *params, params->enable_multipath = 0; params->multipath_version = XQC_ERR_MULTIPATH_VERSION; + params->init_max_path_id = 0; /* init fec params value */ params->enable_encode_fec = 0; params->enable_decode_fec = 0; params->fec_version = XQC_ERR_FEC_VERSION; - params->fec_max_symbol_size = 0; params->fec_max_symbols_num = 0; params->fec_encoder_schemes_num = 0; params->fec_decoder_schemes_num = 0; diff --git a/src/transport/xqc_transport_params.h b/src/transport/xqc_transport_params.h index 637962eb5..083c2ebef 100644 --- a/src/transport/xqc_transport_params.h +++ b/src/transport/xqc_transport_params.h @@ -23,6 +23,9 @@ /* max buffer length of encoded transport parameter */ #define XQC_MAX_TRANSPORT_PARAM_BUF_LEN 512 +/* default value for max_path_id */ +#define XQC_DEFAULT_INIT_MAX_PATH_ID 8 + /** @@ -70,8 +73,7 @@ typedef enum { XQC_TRANSPORT_PARAM_FEC_VERSION_PARSER = 0x0014, XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES_PARSER = 0x0015, XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES_PARSER = 0x0016, - XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_SIZE_PARSER = 0x0017, - XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM_PARSER = 0x0018, + XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM_PARSER = 0x0017, #endif /* upper limit of params defined in [Transport] */ XQC_TRANSPORT_PARAM_PROTOCOL_MAX, @@ -84,18 +86,16 @@ typedef enum { XQC_TRANSPORT_PARAM_NO_CRYPTO = 0x1000, /* multipath quic attributes */ - XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04 = 0x0f739bbc1b666d04, - XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05 = 0x0f739bbc1b666d05, - XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06 = 0x0f739bbc1b666d06, + XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10 = 0x0f739bbc1b666d09, /* google connection options */ XQC_TRANSPORT_PARAM_GOOGLE_CO = 0x3128, #ifdef XQC_ENABLE_FEC /* fec attributes */ XQC_TRANSPORT_PARAM_FEC_VERSION = 0xfec001, + XQC_TRANSPORT_PARAM_FEC_VERSION_02 = 0xfec002, XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES = 0xfece01, XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES = 0xfecd02, - XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_SIZE = 0xfecb01, XQC_TRANSPORT_PARAM_FEC_MAX_SYMBOL_NUM = 0xfecb02, #endif /* upper limit of params defined by xquic */ @@ -168,17 +168,16 @@ typedef struct { * NOTICE: enable_multipath MIGHT be modified or removed as it is not an official parameter */ uint64_t enable_multipath; + xqc_multipath_version_t multipath_version; + uint64_t init_max_path_id; - xqc_multipath_version_t multipath_version; - - uint32_t conn_options[XQC_CO_MAX_NUM]; - uint8_t conn_option_num; + uint32_t conn_options[XQC_CO_MAX_NUM]; + uint8_t conn_option_num; xqc_fec_version_t fec_version; uint64_t enable_encode_fec; uint64_t enable_decode_fec; - uint64_t fec_max_symbol_size; uint64_t fec_max_symbols_num; xqc_fec_schemes_e fec_encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; xqc_fec_schemes_e fec_decoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; diff --git a/src/transport/xqc_utils.c b/src/transport/xqc_utils.c index b1ae87e1b..ac66bf9d7 100644 --- a/src/transport/xqc_utils.c +++ b/src/transport/xqc_utils.c @@ -12,15 +12,14 @@ int -xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_ms) +xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_us) { - xqc_conns_pq_elem_t *elem = (xqc_conns_pq_elem_t *)xqc_pq_push(pq, time_ms); + xqc_conns_pq_elem_t *elem = (xqc_conns_pq_elem_t *)xqc_pq_push(pq, time_us, &conn); if (!elem) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_pq_push error|count:%uz|capacity:%uz|", pq->count, pq->capacity); return -XQC_EMALLOC; } - elem->conn = conn; - return 0; + return XQC_OK; } void @@ -35,6 +34,27 @@ xqc_conns_pq_top(xqc_pq_t *pq) return (xqc_conns_pq_elem_t *)xqc_pq_top(pq); } +xqc_connection_t * +xqc_conns_pq_pop_top_conn(xqc_pq_t *pq) +{ + /* used to traverse conns_pq */ + xqc_conns_pq_elem_t *el = xqc_conns_pq_top(pq); + if (XQC_UNLIKELY(el == NULL || el->conn == NULL)) { + xqc_conns_pq_pop(pq); + return NULL; + } + + xqc_connection_t *conn = el->conn; + xqc_conns_pq_pop(pq); + return conn; +} + +void +xqc_conns_pq_remove(xqc_pq_t *pq, xqc_connection_t *conn) +{ + xqc_pq_remove(pq, conn->wakeup_pq_index); +} + int xqc_insert_conns_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, const uint8_t *data, size_t len) diff --git a/src/transport/xqc_utils.h b/src/transport/xqc_utils.h index 0a4be3770..d60839344 100644 --- a/src/transport/xqc_utils.h +++ b/src/transport/xqc_utils.h @@ -9,16 +9,20 @@ #include "src/common/xqc_priority_q.h" typedef struct xqc_conns_pq_elem_s { - xqc_pq_key_t time_ms; + xqc_pq_key_t time_us; xqc_connection_t *conn; } xqc_conns_pq_elem_t; -int xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_ms); +int xqc_conns_pq_push(xqc_pq_t *pq, xqc_connection_t *conn, uint64_t time_us); void xqc_conns_pq_pop(xqc_pq_t *pq); xqc_conns_pq_elem_t *xqc_conns_pq_top(xqc_pq_t *pq); +xqc_connection_t *xqc_conns_pq_pop_top_conn(xqc_pq_t *pq); + +void xqc_conns_pq_remove(xqc_pq_t *pq, xqc_connection_t *conn); + int xqc_insert_conns_hash(xqc_str_hash_table_t *conns_hash, xqc_connection_t *conn, const uint8_t *data, size_t len); diff --git a/src/transport/xqc_wakeup_pq.h b/src/transport/xqc_wakeup_pq.h deleted file mode 100644 index 8d818cc98..000000000 --- a/src/transport/xqc_wakeup_pq.h +++ /dev/null @@ -1,235 +0,0 @@ -/** - * @copyright Copyright (c) 2022, Alibaba Group Holding Limited - */ - -#ifndef _XQC_WAKEUP_PQ_H_INCLUDED_ -#define _XQC_WAKEUP_PQ_H_INCLUDED_ - -#include "src/transport/xqc_conn.h" -#include "src/common/xqc_malloc.h" -#include - -typedef uint64_t xqc_pq_wakeup_time_t; - -typedef struct { - xqc_pq_wakeup_time_t wakeup_time; - struct xqc_connection_s *conn; -} xqc_wakeup_pq_elem_t; - -/* element compare function */ -typedef int (*xqc_wakeup_pq_compare_ptr)(xqc_pq_wakeup_time_t a, xqc_pq_wakeup_time_t b); - -/* - * default element compare function, priority: a < b - * higher priority first - */ -static inline int -xqc_wakeup_pq_default_cmp(xqc_pq_wakeup_time_t a, xqc_pq_wakeup_time_t b) -{ - return (a < b) ? 1 : 0; -} - -/* - * inverse element compare function, priority: a > b - * lower priority first - */ -static inline int -xqc_wakeup_pq_revert_cmp(xqc_pq_wakeup_time_t a, xqc_pq_wakeup_time_t b) -{ - return (b < a) ? 1 : 0; -} - -typedef struct xqc_wakeup_pq_s { - char *elements; /* elements */ - size_t element_size; /* memory size of element objects */ - size_t count; /* number of elements */ - size_t capacity; /* element capacity */ - xqc_allocator_t a; /* memory allocator */ - xqc_wakeup_pq_compare_ptr cmp; /* compare function */ -} xqc_wakeup_pq_t; - - -#define xqc_wakeup_pq_element(pq, index) ((xqc_wakeup_pq_elem_t*)&(pq)->elements[(index) * (pq)->element_size]) -#define xqc_wakeup_pq_element_copy(pq, dst, src) memmove(xqc_wakeup_pq_element((pq), (dst)), xqc_wakeup_pq_element((pq), (src)), (pq)->element_size) -#define xqc_wakeup_pq_default_capacity 16 - -static inline int -xqc_wakeup_pq_init(xqc_wakeup_pq_t *pq, size_t capacity, xqc_allocator_t a, xqc_wakeup_pq_compare_ptr cmp) -{ - size_t element_size = sizeof(xqc_wakeup_pq_elem_t); - if (capacity == 0) { - return -1; - } - - pq->elements = a.malloc(a.opaque, element_size * capacity); - if (pq->elements == NULL) { - return -2; - } - - pq->element_size = element_size; - pq->count = 0; - pq->capacity = capacity; - pq->a = a; - pq->cmp = cmp; - - return 0; -} - -static inline int -xqc_wakeup_pq_init_default(xqc_wakeup_pq_t *pq, xqc_allocator_t a, xqc_wakeup_pq_compare_ptr cmp) -{ - return xqc_wakeup_pq_init(pq, xqc_wakeup_pq_default_capacity, a, cmp); -} - -static inline void -xqc_wakeup_pq_destroy(xqc_wakeup_pq_t *pq) -{ - pq->a.free(pq->a.opaque, pq->elements); - pq->elements = NULL; - pq->element_size = 0; - pq->count = 0; - pq->capacity = 0; -} - -static inline void -xqc_wakeup_pq_element_swap(xqc_wakeup_pq_t *pq, size_t i, size_t j) -{ -#if !defined(XQC_SYS_WINDOWS) || defined(XQC_ON_MINGW) - char buf[pq->element_size]; -#else - char *buf = (char *)_alloca(pq->element_size); -#endif - - xqc_wakeup_pq_elem_t* p; - p = xqc_wakeup_pq_element(pq, i); - p->conn->wakeup_pq_index = j; - p = xqc_wakeup_pq_element(pq, j); - p->conn->wakeup_pq_index = i; - - memcpy(buf, xqc_wakeup_pq_element(pq, j), pq->element_size); - memcpy(xqc_wakeup_pq_element(pq, j), xqc_wakeup_pq_element(pq, i), pq->element_size); - memcpy(xqc_wakeup_pq_element(pq, i), buf, pq->element_size); -} - -static inline xqc_wakeup_pq_elem_t * -xqc_wakeup_pq_push(xqc_wakeup_pq_t *pq, xqc_pq_wakeup_time_t wakeup_time, struct xqc_connection_s *conn) -{ - if (pq->count == pq->capacity) { - size_t capacity = pq->capacity * 2; - size_t size = capacity * pq->element_size; - void* buf = pq->a.malloc(pq->a.opaque, size); - if (buf == NULL) { - return NULL; - } - memcpy(buf, pq->elements, pq->capacity * pq->element_size); - pq->a.free(pq->a.opaque, pq->elements); - pq->elements = buf; - pq->capacity = capacity; - } - - xqc_wakeup_pq_elem_t* p = xqc_wakeup_pq_element(pq, pq->count); - p->wakeup_time = wakeup_time; - p->conn = conn; - conn->wakeup_pq_index = pq->count; - - size_t i = pq->count++; - while (i != 0) { - int j = (i - 1) / 2; - if (!pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, i)->wakeup_time)) - break; - - xqc_wakeup_pq_element_swap(pq, i, j); - - i = j; - } - - return xqc_wakeup_pq_element(pq, i); -} - -static inline xqc_wakeup_pq_elem_t * -xqc_wakeup_pq_top(xqc_wakeup_pq_t *pq) -{ - if (pq->count == 0) { - return NULL; - } - return xqc_wakeup_pq_element(pq, 0); -} - -static inline int -xqc_wakeup_pq_empty(xqc_wakeup_pq_t *pq) -{ - return pq->count == 0 ? 1 : 0; -} - -static inline void -xqc_wakeup_pq_pop(xqc_wakeup_pq_t *pq) -{ - if (pq->count == 0 || --pq->count == 0) { - return; - } - - xqc_wakeup_pq_element_copy(pq, 0, pq->count); - xqc_wakeup_pq_elem_t* p = xqc_wakeup_pq_element(pq, 0); - p->conn->wakeup_pq_index = 0; - - int i = 0, j = 2 * i + 1; - while (j <= pq->count - 1) { - if (j < pq->count - 1 && pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, j+1)->wakeup_time)) { - ++j; - } - - if (!pq->cmp(xqc_wakeup_pq_element(pq, i)->wakeup_time, xqc_wakeup_pq_element(pq, j)->wakeup_time)) { - break; - } - - xqc_wakeup_pq_element_swap(pq, i, j); - - i = j; - j = 2 * i + 1; - } -} - -static inline void -xqc_wakeup_pq_remove(xqc_wakeup_pq_t *pq, struct xqc_connection_s *conn) -{ - unsigned pq_index = conn->wakeup_pq_index; - if (pq_index >= pq->count || pq->count == 0 || --pq->count == 0) { - return; - } - - xqc_wakeup_pq_element_copy(pq, pq_index, pq->count); - xqc_wakeup_pq_elem_t* p = xqc_wakeup_pq_element(pq, pq_index); - p->conn->wakeup_pq_index = pq_index; - - int i = pq_index, j = 2 * i + 1; - while (j <= pq->count - 1) { - if (j < pq->count - 1 && pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, j+1)->wakeup_time)) { - ++j; - } - - if (!pq->cmp(xqc_wakeup_pq_element(pq, i)->wakeup_time, xqc_wakeup_pq_element(pq, j)->wakeup_time)) { - break; - } - - xqc_wakeup_pq_element_swap(pq, i, j); - - i = j; - j = 2 * i + 1; - } - - i = pq_index; - while (i != 0) { - j = (i - 1)/2; - if (!pq->cmp(xqc_wakeup_pq_element(pq, j)->wakeup_time, xqc_wakeup_pq_element(pq, i)->wakeup_time)) { - break; - } - - xqc_wakeup_pq_element_swap(pq, i, j); - i = j; - } -} - -#undef xqc_wakeup_pq_element -#undef xqc_wakeup_pq_element_copy - -#endif /* _XQC_WAKEUP_PQ_H_INCLUDED_ */ diff --git a/tests/platform.h b/tests/platform.h index 9b50e0845..d3435932d 100644 --- a/tests/platform.h +++ b/tests/platform.h @@ -20,7 +20,7 @@ * * @return int */ -int get_sys_errno() +static inline int get_sys_errno() { int err = 0; #ifdef XQC_SYS_WINDOWS @@ -31,7 +31,7 @@ int get_sys_errno() return err; } -void set_sys_errno(int err) +static inline void set_sys_errno(int err) { #ifdef XQC_SYS_WINDOWS WSASetLastError(err); @@ -44,7 +44,7 @@ void set_sys_errno(int err) * @brief init platform env if necessary * */ -void xqc_platform_init_env() +static inline void xqc_platform_init_env() { int result = 0; diff --git a/tests/test_client.c b/tests/test_client.c index 7d64dd164..ad92af81f 100644 --- a/tests/test_client.c +++ b/tests/test_client.c @@ -28,7 +28,6 @@ #pragma comment(lib,"ws2_32.lib") #pragma comment(lib,"event.lib") #pragma comment(lib, "Iphlpapi.lib") -#pragma comment(lib, "Bcrypt.lib") #include "getopt.h" #endif @@ -256,7 +255,7 @@ char g_headers[MAX_HEADER][256]; int g_header_cnt = 0; int g_ping_id = 1; int g_enable_multipath = 0; -xqc_multipath_version_t g_multipath_version = XQC_MULTIPATH_04; +xqc_multipath_version_t g_multipath_version = XQC_MULTIPATH_10; int g_enable_fec = 0; int g_enable_reinjection = 0; int g_verify_cert = 0; @@ -1464,6 +1463,7 @@ xqc_convert_addr_text_to_sockaddr(int type, { if (type == AF_INET6) { *saddr = calloc(1, sizeof(struct sockaddr_in6)); + memset(*saddr, 0, sizeof(struct sockaddr_in6)); struct sockaddr_in6 *addr_v6 = (struct sockaddr_in6 *)(*saddr); inet_pton(type, addr_text, &(addr_v6->sin6_addr.s6_addr)); addr_v6->sin6_family = type; @@ -1472,6 +1472,7 @@ xqc_convert_addr_text_to_sockaddr(int type, } else { *saddr = calloc(1, sizeof(struct sockaddr_in)); + memset(*saddr, 0, sizeof(struct sockaddr_in)); struct sockaddr_in *addr_v4 = (struct sockaddr_in *)(*saddr); inet_pton(type, addr_text, &(addr_v4->sin_addr.s_addr)); addr_v4->sin_family = type; @@ -1492,10 +1493,12 @@ xqc_client_init_addr(user_conn_t *user_conn, if (ip_type == AF_INET6) { user_conn->local_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in6)); + memset(user_conn->local_addr, 0, sizeof(struct sockaddr_in6)); user_conn->local_addrlen = sizeof(struct sockaddr_in6); } else { user_conn->local_addr = (struct sockaddr *)calloc(1, sizeof(struct sockaddr_in)); + memset(user_conn->local_addr, 0, sizeof(struct sockaddr_in)); user_conn->local_addrlen = sizeof(struct sockaddr_in); } } @@ -2473,6 +2476,27 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream header_size++; } + if (g_enable_fec) { + xqc_h3_priority_t h3_prio = { + .fec = XQC_DEFAULT_SIZE_REQ + }; + xqc_h3_request_set_priority(h3_request, &h3_prio); + + ret = xqc_write_http_priority(&h3_prio, g_priority, 64); + if (ret < 0) { + printf("xqc_write_http_priority error %zd\n", ret); + return ret; + } + + xqc_http_header_t priority_hdr = { + .name = {.iov_base = "priority", .iov_len = 8}, + .value = {.iov_base = g_priority, .iov_len = strlen(g_priority)}, + .flags = 0, + }; + header[header_size] = priority_hdr; + header_size++; + } + if (g_mp_request_accelerate) { /* set local h3 priority */ xqc_h3_priority_t h3_prio = { @@ -2480,6 +2504,7 @@ xqc_client_request_send(xqc_h3_request_t *h3_request, user_stream_t *user_stream .incremental = 1, .schedule = 1, .reinject = 1, + .fec = XQC_DEFAULT_SIZE_REQ, }; xqc_h3_request_set_priority(h3_request, &h3_prio); @@ -2914,6 +2939,8 @@ xqc_client_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_ stats.send_body_size, stats.recv_body_size); printf("test_result_speed: %"PRIu64" Kbit/s. request_cnt: %d.\n", (stats.send_body_size + stats.recv_body_size)*8000/(now_us - user_stream->start_time), g_req_cnt); + printf("retx:%u, sent:%u, max_pto:%u\n", stats.retrans_cnt, stats.sent_pkt_cnt, stats.max_pto_backoff); + printf("[rr_benchmark]|request_time:%"PRIu64"|" "request_size:%zu|response_size:%zu|\n", now_us - user_stream->start_time, @@ -2960,6 +2987,8 @@ xqc_client_request_close_notify(xqc_h3_request_t *h3_request, void *user_data) stats.mp_standby_path_send_weight, stats.mp_standby_path_recv_weight, stats.stream_info); + printf("retx:%u, sent:%u, max_pto:%u\n", stats.retrans_cnt, stats.sent_pkt_cnt, stats.max_pto_backoff); + if (g_echo_check) { int pass = 0; if (user_stream->recv_fin && user_stream->send_body_len == user_stream->recv_body_len @@ -3360,6 +3389,7 @@ xqc_client_timeout_callback(int fd, short what, void *arg) restart_after_a_while--; //we don't care the memory leak caused by user_stream. It's just for one-shot testing. :D user_stream_t *user_stream = calloc(1, sizeof(user_stream_t)); + memset(user_stream, 0, sizeof(user_stream_t)); user_stream->user_conn = user_conn; printf("gtest 15: restart from idle!\n"); user_stream->stream = xqc_stream_create(ctx.engine, &(user_conn->cid), NULL, user_stream); @@ -3735,7 +3765,7 @@ xqc_client_ready_to_create_path(const xqc_cid_t *cid, } } - if (g_mp_backup_mode) { + if (g_mp_backup_mode || g_enable_fec) { ret = xqc_conn_mark_path_standby(ctx.engine, &(user_conn->cid), path_id); if (ret < 0) { printf("xqc_conn_mark_path_standby err = %d\n", ret); @@ -3952,8 +3982,8 @@ xqc_client_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out) case XQC_XOR_CODE: *out = XQC_XOR_CODE; return XQC_OK; - case XQC_PACKET_MASK: - *out = XQC_PACKET_MASK; + case XQC_PACKET_MASK_CODE: + *out = XQC_PACKET_MASK_CODE; return XQC_OK; default: break; @@ -4279,11 +4309,8 @@ int main(int argc, char *argv[]) { case 'v': /* Negotiate multipath version. 4: Multipath-04. 5: Multipath-05*/ printf("option multipath version: %s\n", optarg); - if (atoi(optarg) == 4) { - g_multipath_version = XQC_MULTIPATH_04; - - } else if (atoi(optarg) == 5) { - g_multipath_version = XQC_MULTIPATH_05; + if (atoi(optarg) == 10) { + g_multipath_version = XQC_MULTIPATH_10; } break; case 'R': @@ -4731,7 +4758,7 @@ int main(int argc, char *argv[]) { if (g_test_case == 44) { // turn off the log switch - config.log_disable = 1; + xqc_log_disable(XQC_TRUE); } ctx.engine = xqc_engine_create(XQC_ENGINE_CLIENT, &config, &engine_ssl_config, @@ -4741,12 +4768,6 @@ int main(int argc, char *argv[]) { return -1; } - if (g_test_case == 44) { - // test the API - xqc_log_disable(ctx.engine, 0); - xqc_log_disable(ctx.engine, 1); - } - xqc_h3_callbacks_t h3_cbs = { .h3c_cbs = { .h3_conn_create_notify = xqc_client_h3_conn_create_notify, @@ -4923,7 +4944,11 @@ int main(int argc, char *argv[]) { xqc_fec_params_t fec_params; if (xqc_client_set_fec_scheme(fec_encoder_scheme, &fec_params.fec_encoder_schemes[0]) == XQC_OK) { fec_params.fec_encoder_schemes_num = 1; - + // limit repair number if fec scheme is xor + fec_params.fec_code_rate = 0.1; + fec_params.fec_max_symbol_num_per_block = 3; + fec_params.fec_mp_mode = XQC_FEC_MP_USE_STB; + } else { conn_settings.enable_encode_fec = 0; } @@ -4956,6 +4981,10 @@ int main(int argc, char *argv[]) { conn_settings.standby_path_probe_timeout = 500; } + if (g_enable_fec) { + conn_settings.scheduler_callback = xqc_backup_fec_scheduler_cb; + } + unsigned char token[XQC_MAX_TOKEN_LEN]; int token_len = XQC_MAX_TOKEN_LEN; token_len = xqc_client_read_token(token, token_len); diff --git a/tests/test_server.c b/tests/test_server.c index 88ed65c75..7f7fd0274 100644 --- a/tests/test_server.c +++ b/tests/test_server.c @@ -27,7 +27,6 @@ #include "getopt.h" #pragma comment(lib,"ws2_32.lib") #pragma comment(lib, "Iphlpapi.lib") -#pragma comment(lib, "Bcrypt.lib") #endif #define XQC_FIRST_OCTET 1 @@ -151,7 +150,6 @@ int g_ipv6; int g_batch=0; int g_lb_cid_encryption_on = 0; int g_enable_multipath = 0; -// xqc_multipath_version_t g_multipath_version = XQC_MULTIPATH_05; int g_enable_reinjection = 0; int g_spec_local_addr = 0; int g_mpshell = 0; @@ -2498,16 +2496,24 @@ int main(int argc, char *argv[]) { conn_settings.scheduler_callback = xqc_backup_scheduler_cb; } + if (g_enable_fec) { + conn_settings.scheduler_callback = xqc_backup_fec_scheduler_cb; + } + if (g_enable_fec) { xqc_fec_params_t fec_params; - xqc_fec_schemes_e fec_schemes[XQC_FEC_MAX_SCHEME_NUM] = {XQC_XOR_CODE, XQC_REED_SOLOMON_CODE}; - for (xqc_int_t i = 0; i < XQC_FEC_MAX_SCHEME_NUM; i++) { + memset(&fec_params, 0, sizeof(xqc_fec_params_t)); + xqc_fec_schemes_e fec_schemes[XQC_FEC_MAX_SCHEME_NUM] = {XQC_XOR_CODE, XQC_REED_SOLOMON_CODE, XQC_PACKET_MASK_CODE}; + for (xqc_int_t i = 0; i < 3; i++) { fec_params.fec_encoder_schemes[i] = fec_schemes[i]; fec_params.fec_decoder_schemes[i] = fec_schemes[i]; } - fec_params.fec_encoder_schemes_num = 2; - fec_params.fec_decoder_schemes_num = 2; + fec_params.fec_encoder_schemes_num = 3; + fec_params.fec_decoder_schemes_num = 3; fec_params.fec_max_window_size = 8; + fec_params.fec_code_rate = 0.1; + fec_params.fec_max_symbol_num_per_block = 39; + fec_params.fec_mp_mode = XQC_FEC_MP_USE_STB; conn_settings.fec_params = fec_params; } diff --git a/tests/unittest/main.c b/tests/unittest/main.c index 6b4a028e1..7825bf973 100644 --- a/tests/unittest/main.c +++ b/tests/unittest/main.c @@ -18,7 +18,6 @@ #include "xqc_cubic_test.h" #include "xqc_packet_test.h" #include "xqc_stream_frame_test.h" -#include "xqc_wakeup_pq_test.h" #include "xqc_process_frame_test.h" #include "xqc_tp_test.h" #include "xqc_tls_test.h" @@ -76,7 +75,6 @@ main() || !CU_add_test(pSuite, "xqc_test_empty_pkt", xqc_test_empty_pkt) || !CU_add_test(pSuite, "xqc_test_engine_packet_process", xqc_test_engine_packet_process) || !CU_add_test(pSuite, "xqc_test_stream_frame", xqc_test_stream_frame) - || !CU_add_test(pSuite, "xqc_test_wakeup_pq", xqc_test_wakeup_pq) || !CU_add_test(pSuite, "xqc_test_process_frame", xqc_test_process_frame) || !CU_add_test(pSuite, "xqc_test_parse_padding_frame", xqc_test_parse_padding_frame) || !CU_add_test(pSuite, "xqc_test_large_ack_frame", xqc_test_large_ack_frame) diff --git a/tests/unittest/xqc_cid_test.c b/tests/unittest/xqc_cid_test.c index 1d3587776..ab1f2dd3b 100644 --- a/tests/unittest/xqc_cid_test.c +++ b/tests/unittest/xqc_cid_test.c @@ -25,35 +25,31 @@ xqc_test_cid_basic() ret = xqc_generate_cid(conn->engine, NULL, &test_scid, 1); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->scid_set.cid_set, &test_scid, XQC_CID_UNUSED, conn->remote_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->scid_set, &test_scid, XQC_CID_UNUSED, conn->remote_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set.cid_set, &test_scid) != NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->scid_set.cid_set, 1), &test_scid) == XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set, &test_scid, 0) != NULL); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_delete_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_cid_set_delete_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set.cid_set, &test_scid) == NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->scid_set.cid_set, 1), &test_scid) != XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->scid_set, &test_scid, 0) == NULL); ret = xqc_generate_cid(conn->engine, NULL, &test_dcid, 1); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &test_dcid) != NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->dcid_set.cid_set, 1), &test_dcid) == XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set, &test_dcid, 0) != NULL); - ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &test_dcid); + ret = xqc_get_unused_cid(&conn->dcid_set, &test_dcid, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_delete_cid(&conn->dcid_set.cid_set, &test_dcid); + ret = xqc_cid_set_delete_cid(&conn->dcid_set, &test_dcid, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &test_dcid) == NULL); - CU_ASSERT(xqc_cid_is_equal(xqc_get_cid_by_seq(&conn->dcid_set.cid_set, 1), &test_dcid) != XQC_OK) + CU_ASSERT(xqc_cid_in_cid_set(&conn->dcid_set, &test_dcid, 0) == NULL); xqc_engine_destroy(conn->engine); } @@ -71,11 +67,11 @@ xqc_test_new_cid() /* New Conn ID */ ret = xqc_write_new_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(conn->scid_set.cid_set.unused_cnt == 1); + CU_ASSERT(xqc_cid_set_get_unused_cnt(&conn->scid_set, 0) == 1); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); - CU_ASSERT(conn->scid_set.cid_set.unused_cnt == 0); + CU_ASSERT(xqc_cid_set_get_unused_cnt(&conn->scid_set, 0) == 0); xqc_engine_destroy(conn->engine); } @@ -96,7 +92,7 @@ xqc_test_retire_cid() ret = xqc_generate_cid(conn->engine, NULL, &test_dcid, 1); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->dcid_set, &test_dcid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); ret = xqc_write_retire_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); @@ -116,7 +112,7 @@ xqc_test_recv_retire_cid() ret = xqc_write_new_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); xqc_cid_t ori_cid; @@ -135,7 +131,7 @@ xqc_test_recv_retire_cid() CU_ASSERT(packet_in.pi_frame_types == XQC_FRAME_BIT_RETIRE_CONNECTION_ID); /* ori_scid retired */ - xqc_cid_inner_t *ori_inner_cid = xqc_cid_in_cid_set(&conn->scid_set.cid_set, &ori_cid); + xqc_cid_inner_t *ori_inner_cid = xqc_cid_in_cid_set(&conn->scid_set, &ori_cid, 0); CU_ASSERT(ori_inner_cid != NULL); CU_ASSERT(ori_inner_cid->state == XQC_CID_RETIRED); @@ -168,7 +164,7 @@ xqc_test_retire_cid_with_odcid_in_set() ret = xqc_generate_cid(conn->engine, NULL, &test_odcid, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_cid_set_insert_cid(&conn->scid_set.cid_set, &test_odcid, XQC_CID_USED, conn->remote_settings.active_connection_id_limit); + ret = xqc_cid_set_insert_cid(&conn->scid_set, &test_odcid, XQC_CID_USED, conn->remote_settings.active_connection_id_limit, 0); CU_ASSERT(ret == XQC_OK); /* generate new cid with default cid_len:8 */ @@ -178,7 +174,7 @@ xqc_test_retire_cid_with_odcid_in_set() ret = xqc_write_new_conn_id_frame_to_packet(conn, 0); CU_ASSERT(ret == XQC_OK); - ret = xqc_get_unused_cid(&conn->scid_set.cid_set, &test_scid); + ret = xqc_get_unused_cid(&conn->scid_set, &test_scid, 0); CU_ASSERT(ret == XQC_OK); /* retire user_scid */ diff --git a/tests/unittest/xqc_fec_scheme_test.c b/tests/unittest/xqc_fec_scheme_test.c index 5a2cc8596..daafa7c34 100644 --- a/tests/unittest/xqc_fec_scheme_test.c +++ b/tests/unittest/xqc_fec_scheme_test.c @@ -12,12 +12,16 @@ #include "src/transport/xqc_packet_out.h" #include "src/transport/xqc_packet_in.h" #include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_fec.h" #include "src/transport/fec_schemes/xqc_xor.h" #include "xqc_common_test.h" +#include "src/transport/fec_schemes/xqc_packet_mask.h" +#include "include/xquic/xqc_errno.h" char XQC_TEST_SID_FRAME[] = {0x80, 0x00, 0xfe, 0xc5, 0x00, 0x00, 0x00, 0x00}; char XQC_TEST_RPR_FRAME[] = {0x80, 0x00, 0xfe, 0xc6, 0x00, 0x00, 0x00, 0x00}; char XQC_TEST_STREAM[] = {0x01, 0x00, 0x00, 0x00, 0x00}; +char XQC_TEST_REPAIR_KEY[] = {0x00}; const xqc_cid_t * @@ -56,6 +60,17 @@ test_engine_connect_fec() return conn; } +xqc_connection_t * +test_engine_connect_fec_server() +{ + xqc_engine_t *engine = test_create_engine_server(); + if (engine == NULL) { + return NULL; + } + xqc_connection_t *conn = test_fec_connect(engine); + return conn; +} + void xqc_test_fec_frame_err() { @@ -65,35 +80,32 @@ xqc_test_fec_frame_err() packet_in.pos = XQC_TEST_SID_FRAME; packet_in.last = packet_in.pos + sizeof(XQC_TEST_SID_FRAME); int ret = xqc_process_frames(conn, &packet_in); - CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); + CU_ASSERT(ret == -XQC_EIGNORE_PKT); packet_in.pos = XQC_TEST_RPR_FRAME; packet_in.last = packet_in.pos + sizeof(XQC_TEST_RPR_FRAME); ret = xqc_process_frames(conn, &packet_in); - CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); + CU_ASSERT(ret == -XQC_EIGNORE_PKT); xqc_engine_destroy(conn->engine); } void xqc_test_invalid_encoder_params() -{ +{ xqc_int_t ret; xqc_connection_t *conn = test_engine_connect_fec(); CU_ASSERT(conn != NULL); conn->conn_settings.fec_params.fec_max_symbol_num_per_block = 4; - conn->conn_settings.fec_params.fec_code_rate = 2; - ret = xqc_fec_encoder(conn, XQC_TEST_STREAM); + conn->fec_ctl->fec_send_required_repair_num[0] = 8; + ret = xqc_check_fec_params(conn, conn->conn_settings.fec_params.fec_max_symbol_num_per_block, + conn->fec_ctl->fec_send_required_repair_num[0], XQC_SYMBOL_CACHE_LEN, 5); CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); - conn->conn_settings.fec_params.fec_code_rate = 1; - ret = xqc_fec_encoder(conn, XQC_TEST_STREAM); - CU_ASSERT(ret == XQC_OK); - - conn->conn_settings.fec_params.fec_code_rate = 0.75; + conn->fec_ctl->fec_send_required_repair_num[0] = 1; conn->conn_settings.fec_encode_callback.xqc_fec_encode = NULL; - ret = xqc_fec_encoder(conn, XQC_TEST_STREAM); + ret = xqc_fec_encoder(conn, XQC_TEST_STREAM, 5, 0); CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); xqc_engine_destroy(conn->engine); @@ -102,42 +114,161 @@ xqc_test_invalid_encoder_params() void xqc_test_invalid_decoder_params() { - xqc_int_t ret; + xqc_int_t ret, symbol_size; + xqc_list_head_t *symbol_list; xqc_connection_t *conn = test_engine_connect_fec(); + xqc_fec_rpr_syb_t *rpr_symbol; + CU_ASSERT(conn != NULL); // when fec_recv_symbols_num is smaller than expected, should return error; - conn->fec_ctl->fec_recv_symbols_num[0] = 0; - conn->remote_settings.fec_max_symbols_num = 3; - ret = xqc_fec_decoder(conn, 0); - CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + // conn->remote_settings.fec_max_symbols_num = 3; + // ret = xqc_fec_bc_decoder(conn, 0, 1); + // CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + // when fec_processed_blk_num overflow, it should process it properly; + conn->remote_settings.fec_max_symbols_num = 0; + conn->fec_ctl->fec_processed_blk_num = XQC_MAX_UINT32_VALUE; + ret = xqc_fec_bc_decoder(conn, 0, 0); + CU_ASSERT(ret == XQC_OK && conn->fec_ctl->fec_processed_blk_num == 0); + // when decoder function is NULL, should return error; conn->conn_settings.fec_decode_callback.xqc_fec_decode = NULL; - conn->fec_ctl->fec_recv_symbols_num[0] = 3; - conn->fec_ctl->fec_recv_symbols_flag[0] = 0xe; conn->remote_settings.fec_max_symbols_num = 3; - ret = xqc_fec_decoder(conn, 0); + symbol_size = 5; + symbol_list = &conn->fec_ctl->fec_recv_src_syb_list; + // 给recv symbol list加入一些节点 + for (xqc_int_t i = 0; i < 2; i++) { + ret = xqc_insert_src_symbol_by_seq(conn, symbol_list, 0, i, &conn->fec_ctl->fec_src_syb_num, XQC_TEST_STREAM, symbol_size); + } + symbol_list = &conn->fec_ctl->fec_recv_rpr_syb_list; + xqc_fec_rpr_syb_t tmp_rpr_symbol = { + .block_id = 0, + .payload = XQC_TEST_STREAM, + .payload_size = symbol_size, + .repair_key = XQC_TEST_REPAIR_KEY, + .repair_key_size = 1 + }; + for (xqc_int_t i = 0; i < 1; i++) { + tmp_rpr_symbol.symbol_idx = i; + rpr_symbol = NULL; + xqc_insert_rpr_symbol_by_seq(conn, symbol_list, &tmp_rpr_symbol, &conn->fec_ctl->fec_rpr_syb_num, &rpr_symbol); + } + ret = xqc_fec_bc_decoder(conn, 0, 1); CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); - // when fec_processed_blk_num overflow, it should process it properly; - conn->fec_ctl->fec_recv_symbols_flag[0] = 0xf; - conn->fec_ctl->fec_processed_blk_num = XQC_MAX_UINT32_VALUE; - ret = xqc_fec_decoder(conn, 0); - CU_ASSERT(ret == XQC_OK && conn->fec_ctl->fec_processed_blk_num == 1); // when recovered_failed_cnt overflow, it should process it properly; conn->conn_settings.fec_decode_callback.xqc_fec_decode = xqc_xor_decode; - conn->fec_ctl->fec_recv_symbols_num[0] = 3; - conn->fec_ctl->fec_recv_symbols_flag[0] = 0xe; - conn->remote_settings.fec_max_symbols_num = 3; conn->fec_ctl->fec_recover_failed_cnt = XQC_MAX_UINT32_VALUE; - for (xqc_int_t i = 1; i < 3; i++) { - conn->fec_ctl->fec_recv_symbols_buff[0][i].is_valid = 1; - } - ret = xqc_fec_decoder(conn, 0); - CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR && conn->fec_ctl->fec_recover_failed_cnt == 1); + ret = xqc_fec_bc_decoder(conn, 0, 0); + CU_ASSERT(ret == XQC_OK); + + xqc_engine_destroy(conn->engine); +} + + +void +xqc_test_fec_xor_decode() +{ + size_t size; + xqc_int_t ret; + unsigned char *output[1], *pm; + xqc_connection_t *conn = test_engine_connect_fec(); + + output[0] = xqc_malloc(XQC_MAX_SYMBOL_SIZE); + size = 0; + + // empty list + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + // repair symbol size error + xqc_fec_rpr_syb_t tmp_rpr_symbol = { + .block_id = 1, + .symbol_idx = 0, + .payload = XQC_TEST_STREAM, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1, + }; + xqc_init_list_head(&tmp_rpr_symbol.fec_list); + xqc_list_add(&tmp_rpr_symbol.fec_list, &conn->fec_ctl->fec_recv_rpr_syb_list); + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // rpr block idx err + tmp_rpr_symbol.payload_size = 5; + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // src syb size err + xqc_fec_src_syb_t tmp_src_symbol = { + .block_id = 0, + .symbol_idx = 0, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1 + }; + tmp_rpr_symbol.block_id = 0; + xqc_init_list_head(&tmp_src_symbol.fec_list); + xqc_list_add(&tmp_src_symbol.fec_list, &conn->fec_ctl->fec_recv_src_syb_list); + ret = xqc_xor_decode(conn, output, &size, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + xqc_list_del(&tmp_src_symbol.fec_list); + xqc_list_del(&tmp_rpr_symbol.fec_list); + xqc_free(output[0]); + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_fec_pm_decode() +{ + xqc_int_t ret; + unsigned char *output, *pm; + xqc_connection_t *conn = test_engine_connect_fec(); + + output = xqc_malloc(XQC_MAX_SYMBOL_SIZE); + pm = xqc_malloc(XQC_MAX_RPR_KEY_SIZE); + // output is NULL + ret = xqc_packet_mask_decode_one(conn, NULL, 0, 0); + CU_ASSERT(ret == -XQC_EPARAM); + // no repair symbol + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + // repair symbol size error + xqc_fec_rpr_syb_t tmp_rpr_symbol = { + .block_id = 0, + .symbol_idx = 0, + .payload = output, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1, + .recv_mask = pm + }; + xqc_init_list_head(&tmp_rpr_symbol.fec_list); + xqc_list_add(&tmp_rpr_symbol.fec_list, &conn->fec_ctl->fec_recv_rpr_syb_list); + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // src symbol idx err + tmp_rpr_symbol.payload_size = XQC_MAX_SYMBOL_SIZE; + xqc_fec_src_syb_t tmp_src_symbol = { + .block_id = 0, + .symbol_idx = 80, + .payload_size = XQC_MAX_SYMBOL_SIZE + 1 + }; + xqc_init_list_head(&tmp_src_symbol.fec_list); + xqc_list_add(&tmp_src_symbol.fec_list, &conn->fec_ctl->fec_recv_src_syb_list); + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + // src symbol size err + tmp_src_symbol.symbol_idx = 0; + ret = xqc_packet_mask_decode_one(conn, output, 0, 0); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + xqc_list_del(&tmp_src_symbol.fec_list); + xqc_list_del(&tmp_rpr_symbol.fec_list); + xqc_free(output); + xqc_free(pm); xqc_engine_destroy(conn->engine); } @@ -146,4 +277,6 @@ void xqc_test_fec_scheme() xqc_test_fec_frame_err(); xqc_test_invalid_encoder_params(); xqc_test_invalid_decoder_params(); + xqc_test_fec_xor_decode(); + xqc_test_fec_pm_decode(); } diff --git a/tests/unittest/xqc_fec_scheme_test.h b/tests/unittest/xqc_fec_scheme_test.h index 2afa73eff..62eceec7d 100644 --- a/tests/unittest/xqc_fec_scheme_test.h +++ b/tests/unittest/xqc_fec_scheme_test.h @@ -15,5 +15,6 @@ void xqc_test_fec_scheme(); const xqc_cid_t *test_cid_connect_fec(xqc_engine_t *engine); static xqc_connection_t *test_fec_connect(xqc_engine_t *engine); xqc_connection_t *test_engine_connect_fec(); +xqc_connection_t *test_engine_connect_fec_server(); -#endif /* _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ */ +#endif diff --git a/tests/unittest/xqc_fec_test.c b/tests/unittest/xqc_fec_test.c index 0d4e38dd5..b9aa64c4b 100644 --- a/tests/unittest/xqc_fec_test.c +++ b/tests/unittest/xqc_fec_test.c @@ -11,7 +11,7 @@ #include "src/transport/xqc_packet_out.h" #include "xqc_common_test.h" -xqc_fec_schemes_e fec_schemes[XQC_FEC_MAX_SCHEME_NUM] = {0, XQC_XOR_CODE, XQC_REED_SOLOMON_CODE, XQC_PACKET_MASK}; +xqc_fec_schemes_e fec_schemes[XQC_FEC_MAX_SCHEME_NUM] = {0, XQC_XOR_CODE, XQC_REED_SOLOMON_CODE, XQC_PACKET_MASK_CODE}; void xqc_test_fec_scheme_setter() @@ -28,42 +28,43 @@ xqc_test_fec_negotiation() { xqc_int_t ret; xqc_connection_t *conn = test_engine_connect_fec(); + xqc_connection_t *conn_server = test_engine_connect_fec_server(); xqc_transport_params_t params; xqc_trans_settings_t *ls = &conn->local_settings; params.fec_version = XQC_ERR_FEC_VERSION; + ret = xqc_negotiate_fec_schemes(conn, params); + CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); + + params.fec_version = XQC_FEC_02; + params.enable_encode_fec = 1; + params.enable_decode_fec = 1; + ls->enable_encode_fec = 1; + ls->enable_decode_fec = 1; + params.fec_encoder_schemes_num = 2; + params.fec_decoder_schemes_num = 2; ret = xqc_negotiate_fec_schemes(conn, params); CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); - xqc_engine_destroy(conn->engine); -} -void -xqc_test_flush_num() -{ - xqc_connection_t *conn = test_engine_connect_fec(); - conn->fec_ctl->fec_flush_blk_cnt = XQC_MAX_UINT32_VALUE; - conn->fec_ctl->fec_ignore_blk_cnt = XQC_MAX_UINT32_VALUE; - conn->conn_settings.fec_params.fec_max_window_size = 3; - conn->fec_ctl->fec_recv_symbols_num[0] = 3; - conn->fec_ctl->fec_recv_block_idx[0] = 0; - xqc_fec_record_flush_blk(conn, 6); - CU_ASSERT(conn->fec_ctl->fec_flush_blk_cnt == 1 && conn->fec_ctl->fec_ignore_blk_cnt == 1); xqc_engine_destroy(conn->engine); -} -void -xqc_test_process_fec_packet() -{ - xqc_int_t ret; - xqc_connection_t *conn = test_engine_connect_fec(); - xqc_packet_out_t po; - po.po_frame_types = 0; - ret = xqc_process_fec_protected_packet(conn, &po); + params.fec_encoder_schemes[0] = 20; + params.fec_decoder_schemes[0] = 20; + params.fec_encoder_schemes_num = 1; + params.fec_decoder_schemes_num = 1; + + ls->fec_encoder_schemes[0] = 8; + ls->fec_decoder_schemes[0] = 8; + ls->fec_encoder_schemes_num = 1; + ls->fec_decoder_schemes_num = 1; + ret = xqc_negotiate_fec_schemes(conn_server, params); CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); - xqc_engine_destroy(conn->engine); + + xqc_engine_destroy(conn_server->engine); } + void xqc_test_write_repair_packet() { @@ -71,16 +72,14 @@ xqc_test_write_repair_packet() xqc_list_head_t *prev = NULL; xqc_connection_t *conn = test_engine_connect_fec(); - conn->fec_ctl->fec_send_repair_symbols_num = 0; - ret = xqc_write_repair_packets(conn, 0, prev); + ret = xqc_write_repair_packets(conn, 0, prev, 0, 0); CU_ASSERT(ret == XQC_OK); conn->conn_settings.fec_params.fec_max_symbol_num_per_block = 4; conn->conn_settings.fec_params.fec_code_rate = 1; - conn->fec_ctl->fec_send_src_symbols_num = 3; - conn->fec_ctl->fec_send_repair_symbols_num = 1; - ret = xqc_write_repair_packets(conn, 0, prev); - CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + conn->fec_ctl->fec_send_symbol_num[0] = 3; + ret = xqc_write_repair_packets(conn, 0, prev, 1, 0); + CU_ASSERT(ret == XQC_OK); xqc_engine_destroy(conn->engine); } @@ -90,39 +89,79 @@ xqc_test_gen_fec_frames() { xqc_int_t ret, padding_len, limit; xqc_connection_t *conn = test_engine_connect_fec(); - xqc_packet_out_t packet_out; - packet_out.po_used_size = 1000; + xqc_packet_out_t* packet_out = xqc_packet_out_create(XQC_QUIC_MAX_MSS); + packet_out->po_used_size = 1000; padding_len = 500; limit = 1200; - ret = xqc_gen_padding_frame_with_len(conn, &packet_out, padding_len, limit); + ret = xqc_gen_padding_frame_with_len(conn, packet_out, padding_len, limit); CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); - packet_out.po_used_size = XQC_QUIC_MAX_MSS + 1; - ret = xqc_gen_sid_frame(conn, &packet_out); - CU_ASSERT(ret == -XQC_ENOBUF); + // invalid po_used_size + packet_out->po_used_size = XQC_QUIC_MAX_MSS + 1; + ret = xqc_gen_sid_frame(conn, packet_out); + CU_ASSERT(ret == -XQC_EPARAM); - conn->fec_ctl->fec_send_src_symbols_num = XQC_FEC_MAX_SYMBOL_PAYLOAD_ID; - packet_out.po_used_size = 0; - ret = xqc_gen_sid_frame(conn, &packet_out); + // invalid fec_send_block_num + conn->fec_ctl->fec_send_block_num[0] = XQC_FEC_MAX_BLOCK_NUM + 1; + packet_out->po_reserved_size = 12; + packet_out->po_used_size = 0; + ret = xqc_gen_sid_frame(conn, packet_out); CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); ret = xqc_gen_repair_frame(conn, NULL, 0, 0, 0); CU_ASSERT(ret == -XQC_EPARAM); conn->conn_settings.fec_params.fec_ele_bit_size = 0; - ret = xqc_gen_repair_frame(conn, &packet_out, 0, 0, 0); + ret = xqc_gen_repair_frame(conn, packet_out, 0, 0, 0); + CU_ASSERT(ret == -XQC_EPARAM); + + xqc_packet_out_destroy(packet_out); + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_chk_fec_param() +{ + xqc_int_t ret; + xqc_connection_t *conn = test_engine_connect_fec(); + + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, XQC_REPAIR_LEN + 1, XQC_SYMBOL_CACHE_LEN, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK + 1, XQC_REPAIR_LEN, XQC_SYMBOL_CACHE_LEN, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, XQC_REPAIR_LEN, XQC_SYMBOL_CACHE_LEN + 1, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + ret = xqc_check_fec_params(conn, XQC_FEC_MAX_SYMBOL_NUM_PBLOCK, XQC_REPAIR_LEN, XQC_SYMBOL_CACHE_LEN + 1, XQC_MAX_SYMBOL_SIZE + 1); CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); xqc_engine_destroy(conn->engine); } +void +xqc_test_encoder_chk_param() +{ + xqc_int_t ret, rpr_syb_num; + xqc_connection_t *conn = test_engine_connect_fec(); + + ret = xqc_fec_encoder_check_params(conn, 2, XQC_XOR_CODE, XQC_MAX_SYMBOL_SIZE); + CU_ASSERT(ret == -XQC_EPARAM); + + ret = xqc_fec_encoder_check_params(conn, 1, XQC_XOR_CODE, XQC_MAX_SYMBOL_SIZE + 1); + CU_ASSERT(ret == -XQC_EPARAM); + + xqc_engine_destroy(conn->engine); +} + void xqc_test_fec() { xqc_test_fec_scheme_setter(); xqc_test_fec_negotiation(); - xqc_test_process_fec_packet(); - xqc_test_flush_num(); xqc_test_write_repair_packet(); xqc_test_gen_fec_frames(); + xqc_test_chk_fec_param(); + xqc_test_encoder_chk_param(); } \ No newline at end of file diff --git a/tests/unittest/xqc_fec_test.h b/tests/unittest/xqc_fec_test.h index 1a1775312..a47f97ed9 100644 --- a/tests/unittest/xqc_fec_test.h +++ b/tests/unittest/xqc_fec_test.h @@ -7,4 +7,4 @@ void xqc_test_fec(); -#endif /* _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ */ +#endif diff --git a/tests/unittest/xqc_pq_test.c b/tests/unittest/xqc_pq_test.c index 52bc807c3..bb1247caf 100644 --- a/tests/unittest/xqc_pq_test.c +++ b/tests/unittest/xqc_pq_test.c @@ -11,14 +11,14 @@ xqc_test_pq() { xqc_pq_t pq; memset(&pq, 0, sizeof(pq)); - int i = xqc_pq_init(&pq, sizeof(xqc_pq_key_t), 4, xqc_default_allocator, xqc_pq_default_cmp); + int i = xqc_pq_init(&pq, sizeof(xqc_pq_key_t), 4, xqc_default_allocator, xqc_pq_default_cmp, NULL); CU_ASSERT(i == 0); - xqc_pq_push(&pq, 4); - xqc_pq_push(&pq, 5); - xqc_pq_push(&pq, 1); - xqc_pq_push(&pq, 3); - xqc_pq_push(&pq, 2); + xqc_pq_push(&pq, 4, NULL); + xqc_pq_push(&pq, 5, NULL); + xqc_pq_push(&pq, 1, NULL); + xqc_pq_push(&pq, 3, NULL); + xqc_pq_push(&pq, 2, NULL); xqc_pq_key_t key = (xqc_pq_key_t) -1; diff --git a/tests/unittest/xqc_wakeup_pq_test.c b/tests/unittest/xqc_wakeup_pq_test.c deleted file mode 100644 index e53548f8b..000000000 --- a/tests/unittest/xqc_wakeup_pq_test.c +++ /dev/null @@ -1,49 +0,0 @@ -/** - * @copyright Copyright (c) 2022, Alibaba Group Holding Limited - */ - -#include -#include "xqc_wakeup_pq_test.h" -#include "src/transport/xqc_wakeup_pq.h" - - -void -xqc_test_wakeup_pq() -{ - int ret; - xqc_wakeup_pq_t pq; - memset(&pq, 0, sizeof(pq)); - ret = xqc_wakeup_pq_init(&pq, 4, xqc_default_allocator, xqc_wakeup_pq_revert_cmp); - CU_ASSERT(ret == 0); - - xqc_wakeup_pq_elem_t *elem; - xqc_connection_t *conn = (xqc_connection_t *)malloc(5 * sizeof(xqc_connection_t)); - - elem = xqc_wakeup_pq_push(&pq, 3, &conn[0]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 1, &conn[1]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 4, &conn[2]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 2, &conn[3]); - CU_ASSERT(elem != NULL); - - elem = xqc_wakeup_pq_push(&pq, 5, &conn[4]); - CU_ASSERT(elem != NULL); - - - xqc_wakeup_pq_remove(&pq, &conn[0]); - - while (!xqc_wakeup_pq_empty(&pq)) { - elem = xqc_wakeup_pq_top(&pq); - //printf("key:%llu\n", elem->wakeup_time); - xqc_wakeup_pq_pop(&pq); - } - - free(conn); - - xqc_wakeup_pq_destroy(&pq); -} \ No newline at end of file diff --git a/tests/unittest/xqc_wakeup_pq_test.h b/tests/unittest/xqc_wakeup_pq_test.h deleted file mode 100644 index 28a3a227f..000000000 --- a/tests/unittest/xqc_wakeup_pq_test.h +++ /dev/null @@ -1,10 +0,0 @@ -/** - * @copyright Copyright (c) 2022, Alibaba Group Holding Limited - */ - -#ifndef _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ -#define _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ - -void xqc_test_wakeup_pq(); - -#endif /* _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ */ diff --git a/xqc_configure.h.in b/xqc_configure.h.in index 94d6ac24d..b9b91c117 100644 --- a/xqc_configure.h.in +++ b/xqc_configure.h.in @@ -12,4 +12,5 @@ #cmakedefine XQC_COMPAT_DUPLICATE #cmakedefine XQC_ENABLE_FEC #cmakedefine XQC_ENABLE_XOR -#cmakedefine XQC_ENABLE_RSC \ No newline at end of file +#cmakedefine XQC_ENABLE_RSC +#cmakedefine XQC_ENABLE_PKM \ No newline at end of file From 131ab46f0e62c7ba74868ee17ca76880068eb153 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Thu, 24 Oct 2024 16:44:07 +0800 Subject: [PATCH 02/12] [=] fix diff/compile err --- CMakeLists.txt | 15 ++++++++++++--- CMakeOptions.txt | 2 +- cmake/CMakeLists.txt | 28 ++++++++++++++++++++++++---- scripts/xquic.lds | 4 ++++ scripts/xquic_test.sh | 2 +- tests/CMakeLists.txt | 15 +-------------- tests/unittest/main.c | 2 +- 7 files changed, 44 insertions(+), 24 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 9ec379d30..597683280 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,6 +18,7 @@ option (XQC_COMPAT_DUPLICATE "qpack compat dup" OFF) option (XQC_ENABLE_FEC "enable fec" OFF) option (XQC_ENABLE_XOR "enable fec scheme xor" OFF) option (XQC_ENABLE_RSC "enable fec scheme reed-solomon code" OFF) +option (XQC_ENABLE_PKM "enable fec scheme packet mask" OFF) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -114,7 +115,7 @@ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0 -std=gnu11 -Wall ${CMAKE_C_FLAG if(CMAKE_SYSTEM_NAME MATCHES "Windows") add_definitions(-DXQC_SYS_WINDOWS=1) - set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Zi") + set(CMAKE_C_FLAGS_OPTION " ") endif() @@ -137,7 +138,6 @@ if(XQC_PRINT_SECRET) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_PRINT_SECRET") endif() - # compat with the stateless reset before version v1.6.0 if(XQC_COMPAT_GENERATE_SR_PKT) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_COMPAT_GENERATE_SR_PKT") @@ -227,6 +227,7 @@ set( "src/transport/scheduler/xqc_scheduler_minrtt.c" "src/transport/scheduler/xqc_scheduler_common.c" "src/transport/scheduler/xqc_scheduler_backup.c" + "src/transport/scheduler/xqc_scheduler_backup_fec.c" "src/transport/scheduler/xqc_scheduler_rap.c" ) @@ -238,6 +239,7 @@ if(XQC_ENABLE_MP_INTEROP) ) endif() + # fec framework set( FEC_FRAMEWORK_SOURCE @@ -262,6 +264,14 @@ if(XQC_ENABLE_RSC) ) endif() +if(XQC_ENABLE_PKM) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_packet_mask.c" + ) +endif() + if(XQC_ENABLE_FEC) set( TRANSPORT_SOURCES @@ -392,7 +402,6 @@ if(PLATFORM MATCHES "mac") ${SSL_LIB_PATH} "-Wl" -lpthread - -lstdc++ ) else() target_link_libraries( diff --git a/CMakeOptions.txt b/CMakeOptions.txt index b8373c909..c8bff1f14 100644 --- a/CMakeOptions.txt +++ b/CMakeOptions.txt @@ -6,4 +6,4 @@ option(SSL_TYPE "Using BoringSSL" boringssl) option(SSL_DYNAMIC "Use dynamic libssl" OFF) option(XQC_ENABLE_TESTING "Enable Testing" OFF) option(XQC_BUILD_SAMPLE "Build Sample" OFF) -option(GCOV "Test Coverage" OFF) +option(GCOV "Test Coverage" OFF) \ No newline at end of file diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 760ea629c..f2623c221 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -75,9 +75,10 @@ if (XQC_ENABLE_EVENT_LOG) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_ENABLE_EVENT_LOG ") endif() -if (DISABLE_WARNINGS) - add_compile_options("-Wno-error") -endif () +# sendmmsg +if(XQC_SUPPORT_SENDMMSG_BUILD) + add_definitions(-DXQC_SUPPORT_SENDMMSG) +endif() if(ANDROID) set(DYMAMIC_LINK_OPTION @@ -197,6 +198,7 @@ set( "src/transport/scheduler/xqc_scheduler_minrtt.c" "src/transport/scheduler/xqc_scheduler_common.c" "src/transport/scheduler/xqc_scheduler_backup.c" + "src/transport/scheduler/xqc_scheduler_backup_fec.c" "src/transport/scheduler/xqc_scheduler_rap.c" ) @@ -233,6 +235,14 @@ if(XQC_ENABLE_RSC) ) endif() +if(XQC_ENABLE_PKM) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_packet_mask.c" + ) +endif() + if(XQC_ENABLE_FEC) set( TRANSPORT_SOURCES @@ -329,7 +339,16 @@ if(XQC_ENABLE_UNLIMITED) ) endif() - +# add tunnel +if(XQC_ENABLE_TH3 OR XQC_ENABLE_TUNNEL) + set( + XQC_SOURCE + ) + if(XQC_ENABLE_TNL_DG) + set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_ENABLE_TNL_DG ") + endif() + add_subdirectory(tunnel) +endif() if (XQC_NO_SHARED) set(XQC_BINARY_TYPE STATIC) @@ -343,6 +362,7 @@ add_library( ${TLS_SOURCE} ${COMMON_SOURCES} ${CONGESTION_CONTROL_SOURCES} + ${XQC_SOURCE} ) add_dependencies(xquic xquic_global) diff --git a/scripts/xquic.lds b/scripts/xquic.lds index da8b38ce5..529413d9d 100644 --- a/scripts/xquic.lds +++ b/scripts/xquic.lds @@ -28,6 +28,7 @@ XQUIC_VERS_1.0 { xqc_h3_request_send_body; xqc_h3_request_recv_headers; xqc_h3_request_recv_body; + xqc_h3_priority_init; xqc_write_http_priority; xqc_parse_http_priority; xqc_h3_request_set_priority; @@ -52,6 +53,7 @@ XQUIC_VERS_1.0 { xqc_stream_send; xqc_engine_packet_process; xqc_engine_finish_recv; + xqc_engine_finish_send; xqc_engine_recv_batch; xqc_engine_main_logic; xqc_engine_get_default_config; @@ -68,6 +70,7 @@ XQUIC_VERS_1.0 { xqc_minrtt_scheduler_cb; xqc_interop_scheduler_cb; xqc_backup_scheduler_cb; + xqc_backup_fec_scheduler_cb; xqc_rap_scheduler_cb; xqc_conn_is_ready_to_send_early_data; xqc_h3_conn_send_ping; @@ -124,6 +127,7 @@ XQUIC_VERS_1.0 { xqc_stream_update_settings; xqc_reed_solomon_code_cb; xqc_xor_code_cb; + xqc_packet_mask_code_cb; local: *; }; diff --git a/scripts/xquic_test.sh b/scripts/xquic_test.sh index d8556818a..ed71fc533 100644 --- a/scripts/xquic_test.sh +++ b/scripts/xquic_test.sh @@ -57,7 +57,7 @@ function do_compile() { fi #turn on Code Coverage - cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 -DXQC_ENABLE_FEC=1 -DXQC_ENABLE_XOR=1 -DXQC_ENABLE_RSC=1 .. + cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 .. make -j if [ $? -ne 0 ]; then diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index 09c4f93c0..f340cbd1f 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -50,7 +50,6 @@ endif() add_executable(test_server ${TEST_SERVER_SOURCES}) add_executable(test_client ${TEST_CLIENT_SOURCES}) - # link libraries if(CMAKE_SYSTEM_NAME MATCHES "Windows") set(APP_DEPEND_LIBS @@ -59,21 +58,11 @@ if(CMAKE_SYSTEM_NAME MATCHES "Windows") ${LIBEVENT_LIBRARY} -lm CACHE STRING "xquic app depend libs") -elseif(CMAKE_SYSTEM_NAME MATCHES "Darwin") - set(APP_DEPEND_LIBS - xquic-static - ${SSL_LIB_PATH} - ${LIBEVENT_LIBRARY} - m - dl - pthread - CACHE STRING "xquic app depend libs") else() set(APP_DEPEND_LIBS xquic-static ${SSL_LIB_PATH} ${LIBEVENT_LIBRARY} - stdc++ m dl pthread @@ -103,7 +92,6 @@ if(HAVE_CUNIT) ${UNIT_TEST_DIR}/xqc_reno_test.c ${UNIT_TEST_DIR}/xqc_cubic_test.c ${UNIT_TEST_DIR}/xqc_stream_frame_test.c - ${UNIT_TEST_DIR}/xqc_wakeup_pq_test.c ${UNIT_TEST_DIR}/xqc_process_frame_test.c ${UNIT_TEST_DIR}/xqc_tp_test.c ${UNIT_TEST_DIR}/xqc_tls_test.c @@ -125,7 +113,7 @@ if(HAVE_CUNIT) ${UNIT_TEST_DIR}/xqc_h3_ext_test.c ) - if(XQC_ENABLE_FEC) + if(XQC_ENABLE_FEC AND XQC_ENABLE_PKM) set( test_SOURCES ${test_SOURCES} @@ -156,7 +144,6 @@ if(HAVE_CUNIT) xquic-static ${CUNIT_LIBRARIES} ${SSL_LIB_PATH} - stdc++ m dl pthread diff --git a/tests/unittest/main.c b/tests/unittest/main.c index 7825bf973..2c5073d19 100644 --- a/tests/unittest/main.c +++ b/tests/unittest/main.c @@ -99,7 +99,7 @@ main() || !CU_add_test(pSuite, "xqc_test_retry", xqc_test_retry) || !CU_add_test(pSuite, "xqc_test_receive_invalid_dgram", xqc_test_receive_invalid_dgram) || !CU_add_test(pSuite, "xqc_test_h3_ext_frame", xqc_test_h3_ext_frame) -#ifdef XQC_ENABLE_FEC +#if ( defined XQC_ENABLE_FEC ) && ( defined XQC_ENABLE_PKM ) || !CU_add_test(pSuite, "xqc_test_galois_calculation", xqc_test_galois_calculation) || !CU_add_test(pSuite, "xqc_test_fec_scheme", xqc_test_fec_scheme) || !CU_add_test(pSuite, "xqc_test_fec", xqc_test_fec) From ef80a6a66666d8fdc34b521da9221a5e4950f75b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Fri, 25 Oct 2024 11:40:13 +0800 Subject: [PATCH 03/12] [~] fix unit link err --- tests/CMakeLists.txt | 2 ++ 1 file changed, 2 insertions(+) diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index f340cbd1f..bcd2b0e2d 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -65,6 +65,7 @@ else() ${LIBEVENT_LIBRARY} m dl + stdc++ pthread CACHE STRING "xquic app depend libs") endif() @@ -145,6 +146,7 @@ if(HAVE_CUNIT) ${CUNIT_LIBRARIES} ${SSL_LIB_PATH} m + stdc++ dl pthread CACHE STRING "xquic unit test depend libs") From a0fc5759495f81da5b058354499412a1ce3970a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Fri, 25 Oct 2024 12:55:04 +0800 Subject: [PATCH 04/12] [~] fix casetest err --- .github/workflows/build.yml | 4 ++-- .github/workflows/codeql-analysis.yml | 2 +- xqc_build.sh | 8 +------- 3 files changed, 4 insertions(+), 10 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index ecf7f425e..c6e0402d9 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: - name: Build BoringSSL run: | - git clone https://github.com/google/boringssl.git ./third_party/boringssl + git clone --depth 1 --branch fips-20220613 https://github.com/google/boringssl.git ./third_party/boringssl cd ./third_party/boringssl mkdir -p build cd build @@ -61,7 +61,7 @@ jobs: SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/ssl/libssl.a;${PWD}/third_party/boringssl/build/crypto/libcrypto.a" mkdir -p build cd build - cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 -DXQC_ENABLE_FEC=1 -DXQC_ENABLE_XOR=1 -DXQC_ENABLE_RSC=1 .. + cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 -DXQC_ENABLE_FEC=1 -DXQC_ENABLE_XOR=1 -DXQC_ENABLE_RSC=1 -DXQC_ENABLE_PKM=1 .. make -j - name: Test diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 343aff1d1..59802d57e 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -60,7 +60,7 @@ jobs: SSL_LIB_PATH_STR="${PWD}/third_party/boringssl/build/ssl/libssl.a;${PWD}/third_party/boringssl/build/crypto/libcrypto.a" mkdir -p build cd build - cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 -DXQC_ENABLE_FEC=1 -DXQC_ENABLE_XOR=1 -DXQC_ENABLE_RSC=1 .. + cmake -DGCOV=on -DCMAKE_BUILD_TYPE=Debug -DXQC_ENABLE_TESTING=1 -DXQC_PRINT_SECRET=1 -DXQC_SUPPORT_SENDMMSG_BUILD=1 -DXQC_ENABLE_EVENT_LOG=1 -DXQC_ENABLE_BBR2=1 -DXQC_ENABLE_RENO=1 -DSSL_TYPE=${SSL_TYPE_STR} -DSSL_PATH=${SSL_PATH_STR} -DXQC_ENABLE_UNLIMITED=1 -DXQC_ENABLE_COPA=1 -DXQC_COMPAT_DUPLICATE=1 -DXQC_ENABLE_FEC=1 -DXQC_ENABLE_XOR=1 -DXQC_ENABLE_RSC=1 -DXQC_ENABLE_PKM=1 .. make -j - name: Perform CodeQL Analysis diff --git a/xqc_build.sh b/xqc_build.sh index a9f1e85b0..d085f592f 100755 --- a/xqc_build.sh +++ b/xqc_build.sh @@ -68,9 +68,6 @@ if [ x"$platform" == xios ] ; then -DXQC_ENABLE_COPA=OFF -DXQC_ENABLE_UNLIMITED=OFF -DXQC_ENABLE_MP_INTEROP=OFF - -DXQC_ENABLE_FEC=OFF - -DXQC_ENABLE_XOR=OFF - -DXQC_ENABLE_RSC=OFF -DXQC_DISABLE_LOG=OFF -DXQC_ONLY_ERROR_LOG=ON -DXQC_COMPAT_GENERATE_SR_PKT=ON" @@ -99,10 +96,7 @@ elif [ x"$platform" == xandroid ] ; then -DXQC_DISABLE_LOG=OFF -DXQC_ONLY_ERROR_LOG=ON -DXQC_ENABLE_TH3=ON - -DXQC_COMPAT_GENERATE_SR_PKT=ON - -DXQC_ENABLE_FEC=OFF - -DXQC_ENABLE_XOR=OFF - -DXQC_ENABLE_RSC=OFF" + -DXQC_COMPAT_GENERATE_SR_PKT=ON" elif [ x"$platform" == xharmony ] ; then if [ x"$HMOS_CMAKE_TOOLCHAIN" == x ] ; then echo "HMOS_CMAKE_TOOLCHAIN MUST be defined" From 7370637e422f0d47b6dc6a86c0d391e562ca3aec Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Fri, 25 Oct 2024 14:27:38 +0800 Subject: [PATCH 05/12] [=] fix compile error --- .github/workflows/build.yml | 2 +- CMakeLists.txt | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index c6e0402d9..9bf79beeb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -46,7 +46,7 @@ jobs: - name: Build BoringSSL run: | - git clone --depth 1 --branch fips-20220613 https://github.com/google/boringssl.git ./third_party/boringssl + git clone https://github.com/google/boringssl.git ./third_party/boringssl cd ./third_party/boringssl mkdir -p build cd build diff --git a/CMakeLists.txt b/CMakeLists.txt index 597683280..963d08a19 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -402,6 +402,7 @@ if(PLATFORM MATCHES "mac") ${SSL_LIB_PATH} "-Wl" -lpthread + -lstdc++ ) else() target_link_libraries( From 13e27cfe05eb0f29a44edc746c1d50dd0f849b9b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Fri, 25 Oct 2024 17:59:22 +0800 Subject: [PATCH 06/12] [=] fix casetest error --- scripts/case_test.sh | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/scripts/case_test.sh b/scripts/case_test.sh index db930b43e..b4d2ed472 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -4575,9 +4575,7 @@ else case_print_result "fec_recovered_function_of_datagram_rsc_and_xor" "fail" fi - -clear_log -rm -rf tp_localhost test_session xqc_token +sudo rm -rf tp_localhost test_session xqc_token slog clog echo -e "qlog disable ...\c" killall test_server ${SERVER_BIN} -l d -e -x 1 --qlog_disable > slog & From 9053658ea308884fc9e3e7fd46cbe780fd341ba1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Fri, 25 Oct 2024 18:03:44 +0800 Subject: [PATCH 07/12] [=] fix casetest --- scripts/case_test.sh | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/scripts/case_test.sh b/scripts/case_test.sh index b4d2ed472..5468df084 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -4419,7 +4419,7 @@ sleep 1 rm -rf tp_localhost test_session xqc_token echo -e "negotiate_encoder_fec_schemes ...\c" -sudo ${CLIENT_BIN} -l d -g > stdlog +${CLIENT_BIN} -l d -g >> stdlog clog_res1=`grep "|xqc_negotiate_fec_schemes|set final encoder fec scheme: XOR" clog` slog_res1=`grep "|xqc_negotiate_fec_schemes|set final encoder fec scheme: XOR" slog` errlog=`grep_err_log` @@ -4434,7 +4434,7 @@ fi rm -rf tp_localhost test_session xqc_token echo -e "negotiate_decoder_fec_schemes ...\c" -sudo ${CLIENT_BIN} -l d -g > stdlog +${CLIENT_BIN} -l d -g >> stdlog clog_res2=`grep "|xqc_negotiate_fec_schemes|set final decoder fec scheme: XOR" clog` slog_res2=`grep "|xqc_negotiate_fec_schemes|set final decoder fec scheme: XOR" slog` errlog=`grep_err_log` @@ -4454,7 +4454,7 @@ sleep 1 rm -rf tp_localhost test_session xqc_token echo -e "check fec recovery function of stream using XOR ...\c" -sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo > stdlog +${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4472,7 +4472,7 @@ sleep 1 rm -rf tp_localhost test_session xqc_token echo -e "check fec recovery function of stream using RSC ...\c" -sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 8 --fec_decoder 8 > stdlog +${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 8 --fec_decoder 8 >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4490,7 +4490,7 @@ sleep 1 rm -rf tp_localhost test_session xqc_token echo -e "check fec recovery function of stream using PM ...\c" -sudo ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 > stdlog +${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4508,10 +4508,9 @@ ${SERVER_BIN} -l d -Q 65535 -e -U 1 -s 1 --dgram_qos 3 -f > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token - clear_log echo -e "check fec recovery function of datagram with XOR fec scheme ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g > stdlog +${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g >> stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4522,9 +4521,10 @@ else case_print_result "fec_recovered_function_of_datagram_xor" "fail" fi +rm -rf tp_localhost test_session xqc_token clear_log echo -e "check fec recovery function of datagram with RSC fec scheme ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 8 > stdlog +${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 8 >> stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4537,7 +4537,7 @@ fi clear_log echo -e "check fec recovery function of datagram with Packet Mask scheme ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 12 --fec_decoder 12 > stdlog +${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 12 --fec_decoder 12 >> stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4548,9 +4548,10 @@ else case_print_result "fec_recovered_function_of_datagram_pm" "fail" fi +rm -rf tp_localhost test_session xqc_token clear_log echo -e "check fec recovery function of datagram with XOR(encoder) and RSC(decoder) fec schemes ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 11 > stdlog +${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 8 --fec_decoder 11 >> stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4562,9 +4563,10 @@ else fi +rm -rf tp_localhost test_session xqc_token clear_log echo -e "check fec recovery function of datagram with XOR(decoder) and RSC(encoder) fec schemes ...\c" -sudo ${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 11 --fec_decoder 8 > stdlog +${CLIENT_BIN} -l d -T 1 -s 10000 -U 1 -Q 65535 -E -x 205 -N -1 -t 1 --dgram_qos 3 -g --fec_encoder 11 --fec_decoder 8 >> stdlog slog_res1=`grep '|process packet of block 0 successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then From c2eddf7940399476ebd80d8a98027d8134d45699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Mon, 28 Oct 2024 10:56:20 +0800 Subject: [PATCH 08/12] [=] fix gcovr parse error --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bf79beeb..00769ef94 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,7 +72,7 @@ jobs: openssl req -newkey rsa:2048 -x509 -nodes -keyout "$keyfile" -new -out "$certfile" -subj /CN=test.xquic.com ./tests/run_tests | tee -a ../xquic_test.log ../scripts/case_test.sh | tee -a ../xquic_test.log - gcovr -r .. --xml -o ../coverage.xml + gcovr -r .. --xml --gcov-ignore-parse-errors=negative_hits.warn -o ../coverage.xml - name: Check Test Result run: | From a2958b4c2bf0a69bfda865b831e10a4c6040edb9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Mon, 28 Oct 2024 11:01:10 +0800 Subject: [PATCH 09/12] [~] fix fec testcase error --- scripts/case_test.sh | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/scripts/case_test.sh b/scripts/case_test.sh index 5468df084..460d8de7d 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -4449,7 +4449,7 @@ fi clear_log killall test_server 2> /dev/null -stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & +${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & sleep 1 rm -rf tp_localhost test_session xqc_token @@ -4466,10 +4466,6 @@ else fi clear_log -killall test_server 2> /dev/null -stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & -sleep 1 - rm -rf tp_localhost test_session xqc_token echo -e "check fec recovery function of stream using RSC ...\c" ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 8 --fec_decoder 8 >> stdlog @@ -4484,10 +4480,6 @@ else fi clear_log -killall test_server 2> /dev/null -stdbuf -oL ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & -sleep 1 - rm -rf tp_localhost test_session xqc_token echo -e "check fec recovery function of stream using PM ...\c" ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 >> stdlog From 0581bd80ed5e090ed66dbf9f0f29cc9665bf5519 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Mon, 28 Oct 2024 13:29:01 +0800 Subject: [PATCH 10/12] [~] skip priority if fec not compiled --- .github/workflows/build.yml | 2 +- scripts/case_test.sh | 11 +++++------ src/http3/xqc_h3_request.c | 4 ++-- src/http3/xqc_h3_stream.c | 9 ++++++--- 4 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 00769ef94..b02ecf9df 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -72,7 +72,7 @@ jobs: openssl req -newkey rsa:2048 -x509 -nodes -keyout "$keyfile" -new -out "$certfile" -subj /CN=test.xquic.com ./tests/run_tests | tee -a ../xquic_test.log ../scripts/case_test.sh | tee -a ../xquic_test.log - gcovr -r .. --xml --gcov-ignore-parse-errors=negative_hits.warn -o ../coverage.xml + gcovr -r .. --xml --gcov-ignore-parse-errors -o ../coverage.xml - name: Check Test Result run: | diff --git a/scripts/case_test.sh b/scripts/case_test.sh index 460d8de7d..05c5476a0 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -4412,12 +4412,11 @@ else case_print_result "h3_engine_set_settings_api_h3_ext_more" "fail" fi -sudo rm -rf tp_localhost test_session xqc_token clog slog +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog killall test_server 2> /dev/null ${SERVER_BIN} -l d -e -f > /dev/null & sleep 1 -rm -rf tp_localhost test_session xqc_token echo -e "negotiate_encoder_fec_schemes ...\c" ${CLIENT_BIN} -l d -g >> stdlog clog_res1=`grep "|xqc_negotiate_fec_schemes|set final encoder fec scheme: XOR" clog` @@ -4432,7 +4431,7 @@ else fi -rm -rf tp_localhost test_session xqc_token +sudo rm -rf tp_localhost test_session xqc_token stdlog echo -e "negotiate_decoder_fec_schemes ...\c" ${CLIENT_BIN} -l d -g >> stdlog clog_res2=`grep "|xqc_negotiate_fec_schemes|set final decoder fec scheme: XOR" clog` @@ -4452,7 +4451,7 @@ killall test_server 2> /dev/null ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & sleep 1 -rm -rf tp_localhost test_session xqc_token +sudo rm -rf tp_localhost test_session xqc_token stdlog echo -e "check fec recovery function of stream using XOR ...\c" ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` @@ -4466,7 +4465,7 @@ else fi clear_log -rm -rf tp_localhost test_session xqc_token +sudo rm -rf tp_localhost test_session xqc_token stdlog echo -e "check fec recovery function of stream using RSC ...\c" ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 8 --fec_decoder 8 >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` @@ -4480,7 +4479,7 @@ else fi clear_log -rm -rf tp_localhost test_session xqc_token +sudo rm -rf tp_localhost test_session xqc_token stdlog echo -e "check fec recovery function of stream using PM ...\c" ${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` diff --git a/src/http3/xqc_h3_request.c b/src/http3/xqc_h3_request.c index d9bb2b28d..f72755afc 100644 --- a/src/http3/xqc_h3_request.c +++ b/src/http3/xqc_h3_request.c @@ -954,12 +954,12 @@ xqc_write_http_priority(xqc_h3_priority_t *prio, xqc_memcpy(dst, XQC_PRIORITY_REINJECT, XQC_PRIORITY_REINJECT_LEN); dst += XQC_PRIORITY_REINJECT_LEN; *dst++ = '0' + prio->reinject; - +#ifdef XQC_ENABLE_FEC xqc_memcpy(dst, XQC_PRIORITY_FEC, XQC_PRIORITY_FEC_LEN); dst += XQC_PRIORITY_FEC_LEN; xqc_memcpy(dst, &prio->fec, 4); dst += 4; - +#endif return dst - begin; } diff --git a/src/http3/xqc_h3_stream.c b/src/http3/xqc_h3_stream.c index 0c184e53c..2e876ac12 100644 --- a/src/http3/xqc_h3_stream.c +++ b/src/http3/xqc_h3_stream.c @@ -2077,7 +2077,7 @@ xqc_h3_stream_get_path_info(xqc_h3_stream_t *h3s) } } } - +#ifdef XQC_ENABLE_FEC uint8_t xqc_set_stream_fec_block_mode(uint32_t fec_size) { @@ -2097,7 +2097,7 @@ xqc_set_stream_fec_block_mode(uint32_t fec_size) return XQC_LARGE_SIZE_REQ; } } - +#endif void xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) { @@ -2108,15 +2108,18 @@ xqc_h3_stream_set_priority(xqc_h3_stream_t *h3s, xqc_h3_priority_t *prio) h3s->priority.incremental = prio->incremental; h3s->priority.schedule = prio->schedule; h3s->priority.reinject = prio->reinject; +#ifdef XQC_ENABLE_FEC h3s->priority.fec = prio->fec; - +#endif if (h3s->stream == NULL) { xqc_log(h3s->log, XQC_LOG_ERROR, "|transport stream was NULL|stream_id:%ui|", h3s->stream_id); return; } xqc_stream_set_multipath_usage(h3s->stream, h3s->priority.schedule, h3s->priority.reinject); +#ifdef XQC_ENABLE_FEC h3s->stream->stream_fec_blk_mode = xqc_set_stream_fec_block_mode(h3s->priority.fec); h3s->h3r->block_size_mode = h3s->stream->stream_fec_blk_mode; +#endif } } From a9d96b608bcb47e711c1be534c56db456b9274be Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Mon, 28 Oct 2024 13:31:40 +0800 Subject: [PATCH 11/12] [=] fix window compile diff --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 963d08a19..7129ac57c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS} -g -O0 -std=gnu11 -Wall ${CMAKE_C_FLAG if(CMAKE_SYSTEM_NAME MATCHES "Windows") add_definitions(-DXQC_SYS_WINDOWS=1) - set(CMAKE_C_FLAGS_OPTION " ") + set(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} /Zi") endif() From de4dc87e6d4838e03708e3a78c54772a44748829 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E5=B2=81=E4=B8=80?= Date: Mon, 28 Oct 2024 14:48:12 +0800 Subject: [PATCH 12/12] [=] fix casetest error --- scripts/case_test.sh | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/scripts/case_test.sh b/scripts/case_test.sh index 05c5476a0..d1fdc735a 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -4446,14 +4446,14 @@ else fi -clear_log +sudo rm -rf clog slog killall test_server 2> /dev/null ${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & sleep 1 sudo rm -rf tp_localhost test_session xqc_token stdlog echo -e "check fec recovery function of stream using XOR ...\c" -${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo >> stdlog +${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4464,10 +4464,14 @@ else case_print_result "fec_recovered_function_of_stream_xor" "fail" fi -clear_log +sudo rm -rf clog slog +killall test_server 2> /dev/null +${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & +sleep 1 + sudo rm -rf tp_localhost test_session xqc_token stdlog echo -e "check fec recovery function of stream using RSC ...\c" -${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 8 --fec_decoder 8 >> stdlog +${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g --fec_encoder 8 --fec_decoder 8 >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then @@ -4478,10 +4482,14 @@ else case_print_result "fec_recovered_function_of_stream_rsc" "fail" fi -clear_log +sudo rm -rf clog slog +killall test_server 2> /dev/null +${SERVER_BIN} -l d -e -f -x 1 -M > /dev/null & +sleep 1 + sudo rm -rf tp_localhost test_session xqc_token stdlog echo -e "check fec recovery function of stream using PM ...\c" -${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g -M -i lo -i lo --fec_encoder 12 --fec_decoder 12 >> stdlog +${CLIENT_BIN} -s 5120000 -l e -E -d 30 -g --fec_encoder 12 --fec_decoder 12 >> stdlog slog_res1=`grep '|process packet of block .\{1,3\} successfully' slog` errlog=`grep_err_log` if [ -z "$errlog" ] && [ -n "$slog_res1" ]; then