diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 0b9665755..ecf7f425e 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -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_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} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. + 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 .. make -j - name: Test diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index 24438c5af..343aff1d1 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_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} -DSSL_INC_PATH=${SSL_INC_PATH_STR} -DSSL_LIB_PATH=${SSL_LIB_PATH_STR} .. + 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 .. make -j - name: Perform CodeQL Analysis diff --git a/CMakeLists.txt b/CMakeLists.txt index f76b3b973..9ec379d30 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -14,6 +14,10 @@ option (XQC_ENABLE_UNLIMITED "enable unlimited cc" OFF) option (XQC_ENABLE_MP_INTEROP "enable MPQUIC interop" OFF) option (XQC_NO_PID_PACKET_PROCESS "do not expose path_id in xqc_engine_packet_process" OFF) option (XQC_PROTECT_POOL_MEM "enable write protection for pool memory (for debug)" OFF) +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) if(NOT CMAKE_BUILD_TYPE) set(CMAKE_BUILD_TYPE Release) @@ -133,10 +137,6 @@ if(XQC_PRINT_SECRET) set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_PRINT_SECRET") endif() -# compat with the duplicate instruction of HTTP/3 module before version v1.1.0 -if(XQC_COMPAT_DUPLICATE) - set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_COMPAT_DUPLICATE") -endif() # compat with the stateless reset before version v1.6.0 if(XQC_COMPAT_GENERATE_SR_PKT) @@ -238,6 +238,38 @@ if(XQC_ENABLE_MP_INTEROP) ) endif() +# fec framework +set( + FEC_FRAMEWORK_SOURCE + "src/transport/xqc_fec.c" + "src/transport/xqc_fec_scheme.c" + "src/transport/fec_schemes/xqc_galois_calculation.c" +) + +if(XQC_ENABLE_XOR) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_xor.c" + ) +endif() + +if(XQC_ENABLE_RSC) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_reed_solomon.c" + ) +endif() + +if(XQC_ENABLE_FEC) + set( + TRANSPORT_SOURCES + ${TRANSPORT_SOURCES} + ${FEC_FRAMEWORK_SOURCE} + ) +endif() + # TLS source set ( TLS_SOURCE diff --git a/cmake/CMakeLists.txt b/cmake/CMakeLists.txt index 30a0b6531..760ea629c 100644 --- a/cmake/CMakeLists.txt +++ b/cmake/CMakeLists.txt @@ -208,6 +208,39 @@ if(XQC_ENABLE_MP_INTEROP) ) endif() + +# fec framework +set( + FEC_FRAMEWORK_SOURCE + "src/transport/xqc_fec.c" + "src/transport/xqc_fec_scheme.c" + "src/transport/fec_schemes/xqc_galois_calculation.c" +) + +if(XQC_ENABLE_XOR) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_xor.c" + ) +endif() + +if(XQC_ENABLE_RSC) + set( + FEC_FRAMEWORK_SOURCE + ${FEC_FRAMEWORK_SOURCE} + "src/transport/fec_schemes/xqc_reed_solomon.c" + ) +endif() + +if(XQC_ENABLE_FEC) + set( + TRANSPORT_SOURCES + ${TRANSPORT_SOURCES} + ${FEC_FRAMEWORK_SOURCE} + ) +endif() + # TLS source set ( TLS_SOURCE diff --git a/demo/demo_client.c b/demo/demo_client.c index ad1ccb66b..b0257bf31 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -610,6 +610,24 @@ xqc_demo_cli_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, v } } +void +xqc_demo_cli_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data) +{ + xqc_demo_cli_ctx_t *ctx = (xqc_demo_cli_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + return; + } + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + } +} + int xqc_demo_cli_open_keylog_file(xqc_demo_cli_ctx_t *ctx) @@ -2314,7 +2332,8 @@ xqc_demo_cli_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t static xqc_engine_callback_t callback = { .log_callbacks = { .xqc_log_write_err = xqc_demo_cli_write_log_file, - .xqc_log_write_stat = xqc_demo_cli_write_log_file + .xqc_log_write_stat = xqc_demo_cli_write_log_file, + .xqc_qlog_event_write = xqc_demo_cli_write_qlog_file, }, .keylog_cb = xqc_demo_cli_keylog_cb, .set_event_timer = xqc_demo_cli_set_event_timer, @@ -2461,12 +2480,15 @@ xqc_demo_cli_init_xquic_connection(xqc_demo_cli_user_conn_t *user_conn, memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); } else { - user_conn->hqc_handle = xqc_hq_connect(user_conn->ctx->engine, &conn_settings, + const xqc_cid_t *cid = xqc_hq_connect(user_conn->ctx->engine, &conn_settings, args->quic_cfg.token, args->quic_cfg.token_len, args->net_cfg.host, args->quic_cfg.no_encryption, &conn_ssl_config, (struct sockaddr*)&args->net_cfg.addr, args->net_cfg.addr_len, user_conn); - if (user_conn->hqc_handle == NULL) { + + if (cid == NULL) { return -1; } + + memcpy(&user_conn->cid, cid, sizeof(xqc_cid_t)); } if (conn_settings.enable_multipath diff --git a/demo/demo_server.c b/demo/demo_server.c index ad40df291..f1670453a 100644 --- a/demo/demo_server.c +++ b/demo/demo_server.c @@ -304,6 +304,24 @@ xqc_demo_svr_write_log_file(xqc_log_level_t lvl, const void *buf, size_t size, v } } +void +xqc_demo_svr_write_qlog_file(qlog_event_importance_t imp, const void *buf, size_t size, void *eng_user_data) +{ + xqc_demo_svr_ctx_t *ctx = (xqc_demo_svr_ctx_t*)eng_user_data; + if (ctx->log_fd <= 0) { + return; + } + + int write_len = write(ctx->log_fd, buf, size); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + return; + } + write_len = write(ctx->log_fd, line_break, 1); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", get_sys_errno()); + } +} /** * start of server keylog functions @@ -1398,7 +1416,8 @@ xqc_demo_svr_init_callback(xqc_engine_callback_t *cb, xqc_transport_callbacks_t .set_event_timer = xqc_demo_svr_set_event_timer, .log_callbacks = { .xqc_log_write_err = xqc_demo_svr_write_log_file, - .xqc_log_write_stat = xqc_demo_svr_write_log_file + .xqc_log_write_stat = xqc_demo_svr_write_log_file, + .xqc_qlog_event_write = xqc_demo_svr_write_qlog_file }, .keylog_cb = xqc_demo_svr_keylog_cb, }; @@ -1446,7 +1465,7 @@ xqc_demo_svr_init_ssl_config(xqc_engine_ssl_config_t *cfg, xqc_demo_svr_args_t * } void -xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args) +xqc_demo_svr_init_conn_settings(xqc_engine_t *engine, xqc_demo_svr_args_t *args) { xqc_cong_ctrl_callback_t ccc = {0}; switch (args->net_cfg.cc) { @@ -1509,7 +1528,7 @@ xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args) .anti_amplification_limit = 3, }; - xqc_server_set_conn_settings(&conn_settings); + xqc_server_set_conn_settings(engine, &conn_settings); } @@ -1576,9 +1595,6 @@ xqc_demo_svr_init_xquic_engine(xqc_demo_svr_ctx_t *ctx, xqc_demo_svr_args_t *arg xqc_transport_callbacks_t transport_cbs; xqc_demo_svr_init_callback(&callback, &transport_cbs, args); - /* init server connection settings */ - xqc_demo_svr_init_conn_settings(args); - /* init engine config */ xqc_config_t config; if (xqc_engine_get_default_config(&config, XQC_ENGINE_CLIENT) < 0) { @@ -1613,6 +1629,9 @@ xqc_demo_svr_init_xquic_engine(xqc_demo_svr_ctx_t *ctx, xqc_demo_svr_args_t *arg return -1; } + /* init server connection settings */ + xqc_demo_svr_init_conn_settings(ctx->engine, args); + if (xqc_demo_svr_init_alpn_ctx(ctx) < 0) { printf("init alpn ctx error!"); return -1; diff --git a/demo/xqc_hq.h b/demo/xqc_hq.h index 6b302d712..95d0e5e4f 100644 --- a/demo/xqc_hq.h +++ b/demo/xqc_hq.h @@ -99,7 +99,7 @@ xqc_hq_ctx_destroy(xqc_engine_t *engine); * @brief hq connection functions */ -xqc_hq_conn_t * +const xqc_cid_t * xqc_hq_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_settings, const unsigned char *token, unsigned token_len, const char *server_host, int no_crypto_flag, const xqc_conn_ssl_config_t *conn_ssl_config, const struct sockaddr *peer_addr, diff --git a/demo/xqc_hq_conn.c b/demo/xqc_hq_conn.c index 035cfc231..653c25d39 100644 --- a/demo/xqc_hq_conn.c +++ b/demo/xqc_hq_conn.c @@ -11,18 +11,6 @@ #include "src/transport/xqc_conn.h" -typedef struct xqc_hq_conn_s { - xqc_hq_conn_callbacks_t *hqc_cbs; - - xqc_connection_t *conn; - - xqc_log_t *log; - - void *user_data; - -} xqc_hq_conn_s; - - xqc_hq_conn_t * xqc_hq_conn_create(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data) { @@ -31,7 +19,12 @@ xqc_hq_conn_create(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data return NULL; } - if (xqc_hq_ctx_get_conn_callbacks(&hqc->hqc_cbs) != XQC_OK) { + xqc_hq_callbacks_t *hq_cbs = NULL; + xqc_int_t ret; + + ret = xqc_hq_ctx_get_callbacks(conn->engine, conn->alpn, conn->alpn_len, &hq_cbs); + + if (ret != XQC_OK || hq_cbs == NULL) { PRINT_LOG("|create hq conn failed"); xqc_free(hqc); return NULL; @@ -40,6 +33,10 @@ xqc_hq_conn_create(xqc_connection_t *conn, const xqc_cid_t *cid, void *user_data hqc->user_data = user_data; hqc->log = conn->log; hqc->conn = conn; + hqc->hqc_cbs = hq_cbs->hqc_cbs; + hqc->hqr_cbs = hq_cbs->hqr_cbs; + + xqc_conn_set_alp_user_data(conn, hqc); return hqc; } @@ -53,22 +50,7 @@ xqc_hq_conn_destroy(xqc_hq_conn_t *hqc) } } - -xqc_hq_conn_t * -xqc_hq_conn_create_passive(xqc_connection_t *conn, const xqc_cid_t *cid) -{ - xqc_hq_conn_t *hqc = xqc_hq_conn_create(conn, cid, NULL); - if (NULL == hqc) { - PRINT_LOG("|create hq conn failed"); - return NULL; - } - - xqc_conn_set_alp_user_data(conn, hqc); - return hqc; -} - - -xqc_hq_conn_t * +const xqc_cid_t* xqc_hq_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_settings, const unsigned char *token, unsigned token_len, const char *server_host, int no_crypto_flag, const xqc_conn_ssl_config_t *conn_ssl_config, const struct sockaddr *peer_addr, @@ -78,18 +60,8 @@ xqc_hq_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_settings, const xqc_cid_t *cid = xqc_connect(engine, conn_settings, token, token_len, server_host, no_crypto_flag, conn_ssl_config, peer_addr, peer_addrlen, xqc_hq_alpn[conn_settings->proto_version], user_data); - if (cid == NULL) { - return NULL; - } - - xqc_hq_conn_t *hqc = xqc_hq_conn_create(xqc_engine_conns_hash_find(engine, cid, 's'), - cid, user_data); - if (NULL == hqc) { - xqc_conn_close(engine, cid); - return NULL; - } - return hqc; + return cid; } @@ -125,12 +97,9 @@ xqc_hq_conn_create_notify(xqc_connection_t *conn, const xqc_cid_t *cid, return -XQC_EMALLOC; } - /* set hqc as conn's application-layer-protocol user_data */ - xqc_conn_set_alp_user_data(conn, hqc); - - if (hqc->hqc_cbs->conn_create_notify) { + if (hqc->hqc_cbs.conn_create_notify) { /* NOTICE: if hqc is created passively, hqc->user_data is NULL */ - return hqc->hqc_cbs->conn_create_notify(hqc, cid, hqc->user_data); + return hqc->hqc_cbs.conn_create_notify(hqc, cid, hqc->user_data); } return XQC_OK; @@ -143,8 +112,8 @@ xqc_hq_conn_close_notify(xqc_connection_t *conn, const xqc_cid_t *cid, xqc_int_t ret = XQC_OK; xqc_hq_conn_t *hqc = (xqc_hq_conn_t *)conn_proto_data; - if (hqc->hqc_cbs->conn_close_notify) { - ret = hqc->hqc_cbs->conn_close_notify(hqc, cid, hqc->user_data); + if (hqc->hqc_cbs.conn_close_notify) { + ret = hqc->hqc_cbs.conn_close_notify(hqc, cid, hqc->user_data); if (ret != XQC_OK) { return ret; } diff --git a/demo/xqc_hq_conn.h b/demo/xqc_hq_conn.h index 722605aae..bef782e2e 100644 --- a/demo/xqc_hq_conn.h +++ b/demo/xqc_hq_conn.h @@ -7,6 +7,19 @@ #include "xqc_hq.h" +typedef struct xqc_hq_conn_s { + + xqc_hq_conn_callbacks_t hqc_cbs; + xqc_hq_request_callbacks_t hqr_cbs; + + xqc_connection_t *conn; + + xqc_log_t *log; + + void *user_data; + +} xqc_hq_conn_s; + extern const xqc_conn_callbacks_t hq_conn_callbacks; #endif \ No newline at end of file diff --git a/demo/xqc_hq_ctx.c b/demo/xqc_hq_ctx.c index efd30465a..e6b2c1cc9 100644 --- a/demo/xqc_hq_ctx.c +++ b/demo/xqc_hq_ctx.c @@ -15,9 +15,18 @@ typedef struct xqc_hq_ctx_s { xqc_hq_callbacks_t hq_cbs; } xqc_hq_ctx_t; +xqc_hq_ctx_t* +xqc_hq_ctx_create(xqc_hq_callbacks_t *hq_cbs) +{ + xqc_hq_ctx_t *hq_ctx = NULL; -xqc_hq_ctx_t *hq_ctx = NULL; + hq_ctx = xqc_malloc(sizeof(xqc_hq_callbacks_t)); + if (hq_ctx) { + hq_ctx->hq_cbs = *hq_cbs; + } + return hq_ctx; +} xqc_int_t xqc_hq_ctx_init(xqc_engine_t *engine, xqc_hq_callbacks_t *hq_cbs) @@ -26,65 +35,77 @@ xqc_hq_ctx_init(xqc_engine_t *engine, xqc_hq_callbacks_t *hq_cbs) return -XQC_EPARAM; } - if (hq_ctx == NULL) { - hq_ctx = xqc_malloc(sizeof(xqc_hq_callbacks_t)); - if (NULL == hq_ctx) { - return -XQC_EMALLOC; - } - } - - hq_ctx->hq_cbs = *hq_cbs; - + xqc_hq_ctx_t *hq_ctx; + xqc_int_t ret = XQC_OK; xqc_app_proto_callbacks_t ap_cbs = { .conn_cbs = hq_conn_callbacks, .stream_cbs = hq_stream_callbacks }; + hq_ctx = xqc_hq_ctx_create(hq_cbs); + if (hq_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + /* register ALPN and Application-Layer-Protocol callbacks */ - if (xqc_engine_register_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN, &ap_cbs) != XQC_OK - || xqc_engine_register_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN, &ap_cbs) != XQC_OK) - { - xqc_hq_ctx_destroy(engine); - return -XQC_EFATAL; + if (xqc_engine_register_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN, &ap_cbs, hq_ctx) != XQC_OK) { + xqc_free(hq_ctx); + ret = -XQC_EFATAL; + goto error; } - return XQC_OK; + hq_ctx = xqc_hq_ctx_create(hq_cbs); + if (hq_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + + /* register ALPN and Application-Layer-Protocol callbacks */ + if (xqc_engine_register_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN, &ap_cbs, hq_ctx) != XQC_OK) { + xqc_free(hq_ctx); + ret = -XQC_EFATAL; + goto error; + } + + return ret; +error: + xqc_hq_ctx_destroy(engine); + return ret; } xqc_int_t xqc_hq_ctx_destroy(xqc_engine_t *engine) { - xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); - xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN); + xqc_hq_ctx_t *hq_ctx; + hq_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); if (hq_ctx) { xqc_free(hq_ctx); - hq_ctx = NULL; } - return XQC_OK; -} - -xqc_int_t -xqc_hq_ctx_get_conn_callbacks(xqc_hq_conn_callbacks_t **hqc_cbs) -{ - if (NULL == hq_ctx || NULL == hqc_cbs) { - return -XQC_EFATAL; + hq_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN); + if (hq_ctx) { + xqc_free(hq_ctx); } - *hqc_cbs = &hq_ctx->hq_cbs.hqc_cbs; + xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); + xqc_engine_unregister_alpn(engine, XQC_ALPN_HQ_INTEROP, XQC_ALPN_HQ_INTEROP_LEN); return XQC_OK; } - xqc_int_t -xqc_hq_ctx_get_request_callbacks(xqc_hq_request_callbacks_t **hqr_cbs) +xqc_hq_ctx_get_callbacks(xqc_engine_t *engine, char *alpn, size_t alpn_len, xqc_hq_callbacks_t **hq_cbs) { - if (NULL == hq_ctx || NULL == hqr_cbs) { + xqc_hq_ctx_t *hq_ctx; + + hq_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_HQ_29, XQC_ALPN_HQ_29_LEN); + + if (hq_ctx == NULL) { return -XQC_EFATAL; } - *hqr_cbs = &hq_ctx->hq_cbs.hqr_cbs; + *hq_cbs = &hq_ctx->hq_cbs; return XQC_OK; -} +} \ No newline at end of file diff --git a/demo/xqc_hq_ctx.h b/demo/xqc_hq_ctx.h index d0bf43ad7..961e6fca2 100644 --- a/demo/xqc_hq_ctx.h +++ b/demo/xqc_hq_ctx.h @@ -7,11 +7,7 @@ #include "xqc_hq.h" -xqc_int_t -xqc_hq_ctx_get_conn_callbacks(xqc_hq_conn_callbacks_t **hqc_cbs); - -xqc_int_t -xqc_hq_ctx_get_request_callbacks(xqc_hq_request_callbacks_t **hqr_cbs); +xqc_int_t xqc_hq_ctx_get_callbacks(xqc_engine_t *engine, char *alpn, size_t alpn_len, xqc_hq_callbacks_t **hq_cbs); #endif diff --git a/demo/xqc_hq_request.c b/demo/xqc_hq_request.c index 8c7bec2f5..3eede95a6 100644 --- a/demo/xqc_hq_request.c +++ b/demo/xqc_hq_request.c @@ -78,11 +78,7 @@ xqc_hq_request_create(xqc_engine_t *engine, xqc_hq_conn_t *hqc, const xqc_cid_t return NULL; } - /* init app-level callbacks */ - if (xqc_hq_ctx_get_request_callbacks(&hqr->hqr_cbs) != XQC_OK) { - PRINT_LOG("get app-level request callbacks error\n"); - goto fail; - } + hqr->hqr_cbs = &hqc->hqr_cbs; /* create stream, make hqr the user_data of xqc_stream_t */ stream = xqc_stream_create(engine, cid, NULL, hqr); @@ -114,12 +110,9 @@ xqc_hq_request_create_passive(xqc_stream_t *stream) return NULL; } - /* init app-level callbacks */ - if (xqc_hq_ctx_get_request_callbacks(&hqr->hqr_cbs) != XQC_OK) { - PRINT_LOG("get app-level request callbacks error"); - xqc_hq_request_destroy(hqr); - return NULL; - } + xqc_hq_conn_t *hqc = xqc_get_conn_alp_user_data_by_stream(stream); + + hqr->hqr_cbs = &hqc->hqr_cbs; /* make hqr the user_data of xqc_stream_t */ xqc_stream_set_user_data(stream, hqr); diff --git a/include/xquic/xqc_errno.h b/include/xquic/xqc_errno.h index b64f21a8a..e314d6338 100644 --- a/include/xquic/xqc_errno.h +++ b/include/xquic/xqc_errno.h @@ -131,6 +131,10 @@ typedef enum { 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_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_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 e1967bf0a..0c1f783f9 100644 --- a/include/xquic/xqc_http3.h +++ b/include/xquic/xqc_http3.h @@ -412,7 +412,8 @@ xqc_int_t xqc_h3_ctx_destroy(xqc_engine_t *engine); /** - * @brief set max h3 max dynamic table capacity + * @brief set max h3 max dynamic table capacity. It MUST only be called after + * xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param value capacity of dynamic table, 0 for disable dynamic table @@ -421,7 +422,8 @@ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_max_dtable_capacity(xqc_engine_t *engine, size_t capacity); /** - * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead + * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead. + * It MUST only be called after xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param value 0:disable dynamic table @@ -430,7 +432,8 @@ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_dec_max_dtable_capacity(xqc_engine_t *engine, size_t value); /** - * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead + * @brief @deprecated use xqc_h3_engine_set_max_dtable_capacity instead. + * It MUST only be called after xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param value 0:disable dynamic table @@ -439,7 +442,8 @@ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_enc_max_dtable_capacity(xqc_engine_t *engine, size_t value); /** - * @brief set max h3 field section size + * @brief set max h3 field section size. + * It MUST only be called after xqc_h3_ctx_init. * * @param engine the engine handler created by xqc_engine_create * @param size size of field section size @@ -447,12 +451,38 @@ void xqc_h3_engine_set_enc_max_dtable_capacity(xqc_engine_t *engine, size_t valu XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_max_field_section_size(xqc_engine_t *engine, size_t size); +/** + * @brief set the limit for qpack blocked streams. + * It MUST only be called after xqc_h3_ctx_init. + * + * @param engine + * @param value + * @return XQC_EXPORT_PUBLIC_API + */ +XQC_EXPORT_PUBLIC_API +void xqc_h3_engine_set_qpack_blocked_streams(xqc_engine_t *engine, size_t value); + #ifdef XQC_COMPAT_DUPLICATE +/** + * @brief It MUST only be called after xqc_h3_ctx_init. + * + * @param engine the engine handler created by xqc_engine_create + * @param cmpt value + * @return XQC_EXPORT_PUBLIC_API + */ XQC_EXPORT_PUBLIC_API void xqc_h3_engine_set_qpack_compat_duplicate(xqc_engine_t *engine, xqc_bool_t cmpt); #endif + +/** + * User can set h3 settings when h3_conn_create_notify callbacks + */ +XQC_EXPORT_PUBLIC_API +void xqc_h3_engine_set_local_settings(xqc_engine_t *engine, + const xqc_h3_conn_settings_t *h3_conn_settings); + /** * @brief create and http3 connection * @@ -539,13 +569,6 @@ XQC_EXPORT_PUBLIC_API void *xqc_h3_conn_get_user_data(xqc_h3_conn_t *h3_conn); -/** - * User can set h3 settings when h3_conn_create_notify callbacks - */ -XQC_EXPORT_PUBLIC_API -void xqc_h3_conn_set_settings(xqc_h3_conn_t *h3c, - const xqc_h3_conn_settings_t *h3_conn_settings); - /** * @brief get peer address information, server should call this when h3_conn_create_notify triggers diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index 18489e0c0..da8510f5b 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -74,6 +74,8 @@ typedef enum xqc_proto_version_s { #define XQC_CO_MAX_NUM 16 #define XQC_CO_STR_MAX_LEN (5 * XQC_CO_MAX_NUM) +#define XQC_FEC_MAX_SCHEME_NUM 5 + /** * @brief get timestamp callback function. this might be useful on different platforms @@ -129,7 +131,8 @@ typedef struct xqc_log_callbacks_s { * * trace log including XQC_LOG_FATAL, XQC_LOG_ERROR, XQC_LOG_WARN, XQC_LOG_STATS, XQC_LOG_INFO, * XQC_LOG_DEBUG, xquic will output logs with the level higher or equal to the level configured - * in xqc_congit_t. + * in xqc_log_init. Besides, when qlog enable and EVENT_IMPORTANCE_SELECTED importance is set, some + * event log will output log by xqc_log_write_err callback. */ void (*xqc_log_write_err)(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data); @@ -141,6 +144,18 @@ typedef struct xqc_log_callbacks_s { */ void (*xqc_log_write_stat)(xqc_log_level_t lvl, const void *buf, size_t size, void *engine_user_data); + /** + * qlog event callback function + * + * qlog event importance including EVENT_IMPORTANCE_SELECTED, EVENT_IMPORTANCE_CORE, EVENT_IMPORTANCE_BASE, + * EVENT_IMPORTANCE_EXTRA and EVENT_IMPORTANCE_REMOVED. + * EVENT_IMPORTANCE_CORE, EVENT_IMPORTANCE_BASE and EVENT_IMPORTANCE_EXTRA follow the defination of qlog draft. + * EVENT_IMPORTANCE_SELECTED works by xqc_log_write_err + * EVENT_IMPORTANCE_REMOVED exits, because the last qlog draft remove some qlog event, but the current qvis tool + * still need them. + */ + void (*xqc_qlog_event_write)(qlog_event_importance_t imp, const void *buf, size_t size, void *engine_user_data); + } xqc_log_callbacks_t; @@ -849,6 +864,29 @@ typedef struct xqc_scheduler_params_u { uint32_t pto_cnt_thr; } xqc_scheduler_params_t; +typedef enum { + XQC_REED_SOLOMON_CODE = 8, + XQC_XOR_CODE = 11, /* 测试用,没有在IANA登记过*/ + XQC_PACKET_MASK = 12, +} xqc_fec_schemes_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_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_params_t; + typedef struct xqc_congestion_control_callback_s { /* Callback on initialization, for memory allocation */ size_t (*xqc_cong_ctl_size)(void); @@ -965,6 +1003,15 @@ XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_reinj_ctl_callback_t xqc_default_rein XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_reinj_ctl_callback_t xqc_deadline_reinj_ctl_cb; XQC_EXPORT_PUBLIC_API XQC_EXTERN const xqc_reinj_ctl_callback_t xqc_dgram_reinj_ctl_cb; +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_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; /** * @struct xqc_config_t @@ -977,6 +1024,9 @@ typedef struct xqc_config_s { /* enable log based on event or not, non-zero for enable, 0 for not */ xqc_flag_t cfg_log_event; + /* qlog evnet importance */ + qlog_event_importance_t cfg_qlog_importance; + /* print timestamp in log or not, non-zero for print, 0 for not */ xqc_flag_t cfg_log_timestamp; @@ -1034,6 +1084,12 @@ typedef struct xqc_config_s { * */ uint8_t enable_h3_ext; + + /** + * @brief disable or enable logging (default: 0, enable) + * + */ + xqc_bool_t log_disable; } xqc_config_t; @@ -1083,6 +1139,11 @@ typedef enum { XQC_TLS_CERT_FLAG_ALLOW_SELF_SIGNED = 1 << 1, } xqc_cert_verify_flag_e; +typedef enum { + XQC_RED_NOT_USE = 0, + XQC_RED_SET_CLOSE = 1, +} xqc_dgram_red_setting_e; + /** * @brief connection tls config for client */ @@ -1128,6 +1189,10 @@ typedef enum { XQC_MULTIPATH_06 = 0x06, } xqc_multipath_version_t; +typedef enum { + XQC_ERR_FEC_VERSION = 0x00, + XQC_FEC_01 = 0x01, +} xqc_fec_version_t; typedef struct xqc_conn_settings_s { int pacing_on; /* default: 0 */ @@ -1279,6 +1344,19 @@ typedef struct xqc_conn_settings_s { */ xqc_usec_t initial_pto_duration; + /* + * fec option: + * 0: don't support fec + * 1: supports fec + */ + uint64_t enable_encode_fec; + uint64_t enable_decode_fec; + xqc_fec_params_t fec_params; + xqc_fec_code_callback_t fec_encode_callback; + xqc_fec_code_callback_t fec_decode_callback; + + xqc_dgram_red_setting_e close_dgram_redundancy; + } xqc_conn_settings_t; @@ -1316,10 +1394,10 @@ typedef struct xqc_conn_stats_s { uint32_t lost_count; uint32_t tlp_count; uint32_t spurious_loss_count; - uint32_t lost_dgram_count; /*how many datagram frames (pkts) are lost*/ - 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 */ + uint32_t lost_dgram_count; /* how many datagram frames (pkts) are lost */ + 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_0rtt_flag_t early_data_flag; uint32_t recv_count; int spurious_loss_detect_on; @@ -1398,11 +1476,12 @@ void xqc_engine_destroy(xqc_engine_t *engine); * @param alpn Application-Layer-Protocol, for example, h3, hq-interop, or self-defined * @param alpn_len length of Application-Layer-Protocol string * @param ap_cbs connection and stream event callback functions for application-layer-protocol + * @param alp_ctx the context of the upper layer protocol (e.g. the callback functions and default settings of the upper layer protocol) * @return XQC_EXPORT_PUBLIC_API */ XQC_EXPORT_PUBLIC_API xqc_int_t xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, - xqc_app_proto_callbacks_t *ap_cbs); + xqc_app_proto_callbacks_t *ap_cbs, void *alp_ctx); /** @@ -1416,6 +1495,35 @@ xqc_int_t xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_ XQC_EXPORT_PUBLIC_API xqc_int_t xqc_engine_unregister_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len); +/** + * @brief get the context an application layer protocol + * + * @param engine engine handler + * @param alpn Application-Layer-Protocol, for example, h3, hq-interop, or self-defined + * @param alpn_len length of alpn + * @return the context + */ +XQC_EXPORT_PUBLIC_API +void* xqc_engine_get_alpn_ctx(xqc_engine_t *engine, const char *alpn, size_t alpn_len); + +/** + * @brief get the private context + * + * @param engine + * @return XQC_EXPORT_PUBLIC_API* + */ +XQC_EXPORT_PUBLIC_API +void* xqc_engine_get_priv_ctx(xqc_engine_t *engine); + +/** + * @brief save the private context + * + * @param engine + * @param priv_ctx + * @return XQC_EXPORT_PUBLIC_API + */ +XQC_EXPORT_PUBLIC_API +xqc_int_t xqc_engine_set_priv_ctx(xqc_engine_t *engine, void *priv_ctx); /** * Pass received UDP packet payload into xquic engine. @@ -1458,7 +1566,7 @@ xqc_int_t xqc_engine_set_config(xqc_engine_t *engine, const xqc_config_t *engine * new created connections */ XQC_EXPORT_PUBLIC_API -void xqc_server_set_conn_settings(const xqc_conn_settings_t *settings); +void xqc_server_set_conn_settings(xqc_engine_t *engine, const xqc_conn_settings_t *settings); /** @@ -1473,10 +1581,10 @@ void xqc_engine_set_log_level(xqc_engine_t *engine, xqc_log_level_t log_level); /** * @brief enable/disable the log module of xquic * - * @param enable XQC_TRUE for enable, XQC_FALSE for disable + * @param enable XQC_TRUE for disable, XQC_FALSE for enable */ XQC_EXPORT_PUBLIC_API -void xqc_log_enable(xqc_bool_t enable); +void xqc_log_disable(xqc_engine_t *engine, xqc_bool_t disable); /** @@ -1794,10 +1902,10 @@ xqc_int_t xqc_cid_is_equal(const xqc_cid_t *dst, const xqc_cid_t *src); * @return user should copy return buffer to your own memory if you will access in the future */ XQC_EXPORT_PUBLIC_API -unsigned char *xqc_scid_str(const xqc_cid_t *scid); +unsigned char *xqc_scid_str(xqc_engine_t *engine, const xqc_cid_t *scid); XQC_EXPORT_PUBLIC_API -unsigned char *xqc_dcid_str(const xqc_cid_t *dcid); +unsigned char *xqc_dcid_str(xqc_engine_t *engine, const xqc_cid_t *dcid); XQC_EXPORT_PUBLIC_API unsigned char *xqc_dcid_str_by_scid(xqc_engine_t *engine, const xqc_cid_t *scid); diff --git a/include/xquic/xquic_typedef.h b/include/xquic/xquic_typedef.h index bb4a905b0..ce45eb1a8 100644 --- a/include/xquic/xquic_typedef.h +++ b/include/xquic/xquic_typedef.h @@ -138,6 +138,15 @@ typedef enum xqc_log_level_s { XQC_LOG_DEBUG, } xqc_log_level_t; +/* qlog Importance level definition */ +typedef enum qlog_event_importance_s { + EVENT_IMPORTANCE_SELECTED, /* qlog will be emitted selectly */ + EVENT_IMPORTANCE_CORE, + EVENT_IMPORTANCE_BASE, + EVENT_IMPORTANCE_EXTRA, + EVENT_IMPORTANCE_REMOVED, /* Currently, some events have been removed in the latest qlog draft. But old qvis need them! */ +} qlog_event_importance_t; + #define XQC_BBR_RTTVAR_COMPENSATION_ENABLED 0 typedef enum { XQC_BBR_FLAG_NONE = 0x00, diff --git a/scripts/case_test.sh b/scripts/case_test.sh index f93ae843a..6fd575260 100755 --- a/scripts/case_test.sh +++ b/scripts/case_test.sh @@ -14,11 +14,6 @@ CLIENT_BIN="tests/test_client" SERVER_BIN="tests/test_server" -# start test_server -killall test_server 2> /dev/null -${SERVER_BIN} -l d -e > /dev/null & -sleep 1 - clear_log() { >clog >slog @@ -42,11 +37,17 @@ function case_print_result() { } +# start test_server +rm -rf tp_localhost test_session xqc_token +killall test_server 2> /dev/null +${SERVER_BIN} -l d -e > /dev/null & +sleep 1 + clear_log echo -e "log switch off ...\c" ${CLIENT_BIN} -s 1024000 -l d -t 1 -E -x 44 >> stdlog -log_size=`wc -c clog | awk -F ' ' '{print $1}'` -if [ $log_size -eq 0 ]; then +log_size=`wc -l clog | awk -F ' ' '{print $1}'` +if [ $log_size -eq 1 ]; then echo ">>>>>>>> pass:1" case_print_result "log_switch_off" "pass" else @@ -54,7 +55,7 @@ else case_print_result "log_switch_off" "fail" fi -clear_log + echo -e "server refuse ...\c" ${CLIENT_BIN} -x 46 -t 10 >> stdlog result=`grep "conn close notified by refuse" slog` @@ -779,7 +780,7 @@ clear_log echo -e "GET request ...\c" result=`${CLIENT_BIN} -l d -t 1 -E -G|grep ">>>>>>>> pass"` errlog=`grep_err_log` -alpn_res=`grep "|select alpn|h3|" slog` +alpn_res=`grep "|selected_alpn:h3|" slog` echo "$result" if [ -z "$errlog" ] && [ -n "$alpn_res" ] && [ "$result" == ">>>>>>>> pass:1" ]; then case_print_result "GET_request" "pass" @@ -792,7 +793,7 @@ clear_log rm -f test_session xqc_token tp_localhost echo -e "new client 29 - new server ...\c" result=`${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 17 |grep ">>>>>>>> pass"` -alpn_res=`grep "select alpn|h3-29|" slog` +alpn_res=`grep "selected_alpn:h3-29" slog` errlog=`grep_err_log` echo "$result" if [ -z "$errlog" ] && [ -n "$alpn_res" ] && [ "$result" == ">>>>>>>> pass:1" ]; then @@ -1200,7 +1201,7 @@ sleep 1 client_print_res=`${CLIENT_BIN} -s 1024000 -l d -t 1 -x 22 -E | grep ">>>>>>>> pass"` errlog=`grep_err_log` server_log_res=`grep "decrypt payload error" slog` -server_conn_cnt=`grep "xqc_conn_create" slog | grep -v "tra_parameters_set" | grep -v "mempool" | wc -l` +server_conn_cnt=`grep "xqc_conn_create" slog | grep -v "tra_parameters_set" | grep -v "mempool" | grep -v "connection_state_updated" | grep -v "path_assigned" | wc -l` echo "$client_print_res" if [ "$client_print_res" != "" ] && [ "$server_log_res" != "" ] && [ $server_conn_cnt -eq 2 ]; then case_print_result "client_initial_dcid_corruption" "pass" @@ -1550,12 +1551,12 @@ grep_err_log clear_log echo -e "MPNS multipath close initial path ...\c" -sudo ${CLIENT_BIN} -s 1024000 -l d -t 3 -M -i lo -i lo -E -x 100 > stdlog +sudo ${CLIENT_BIN} -s 10240 -l d -t 5 -M -i lo -i lo -E -x 100 -e 10 --epoch_timeout 1000000 > stdlog result=`grep ">>>>>>>> pass" stdlog` svr_res=`grep "|path closed|path:0|" slog` cli_res=`grep "|path closed|path:0|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_close_initial_path" "pass" else @@ -1566,12 +1567,12 @@ grep_err_log clear_log echo -e "MPNS multipath 30 percent loss close initial path ...\c" -sudo ${CLIENT_BIN} -s 10240000 -t 5 -l d -E -d 300 -M -i lo -i lo -x 100 > stdlog +sudo ${CLIENT_BIN} -s 10240 -t 6 -l d -E -d 300 -M -i lo -i lo -x 100 -e 10 --epoch_timeout 1000000 > stdlog result=`grep ">>>>>>>> pass" stdlog` svr_res=`grep "|path closed|path:0|" slog` cli_res=`grep "|path closed|path:0|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_30_percent_loss_close_initial_path" "pass" else @@ -1580,14 +1581,16 @@ else fi grep_err_log + + clear_log echo -e "MPNS multipath close new path ...\c" -sudo ${CLIENT_BIN} -s 1024000 -l d -t 3 -M -A -i lo -i lo -E -x 101 >> clog +sudo ${CLIENT_BIN} -s 10240 -l d -t 5 -M -A -i lo -i lo -E -x 101 -e 10 --epoch_timeout 1000000 >> clog result=`grep ">>>>>>>> pass" clog` svr_res=`grep "|path closed|path:1|" slog` cli_res=`grep "|path closed|path:1|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_close_new_path" "pass" else @@ -1598,12 +1601,12 @@ grep_err_log clear_log echo -e "MPNS multipath 30 percent loss close new path ...\c" -sudo ${CLIENT_BIN} -s 10240000 -t 5 -l d -E -d 300 -M -i lo -i lo -x 101 > stdlog +sudo ${CLIENT_BIN} -s 10240 -t 6 -l d -E -d 300 -M -i lo -i lo -x 101 -e 10 --epoch_timeout 1000000 > stdlog result=`grep ">>>>>>>> pass" stdlog` svr_res=`grep "|path closed|path:1|" slog` cli_res=`grep "|path closed|path:1|" clog` errlog=`grep_err_log` -if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then +if [ -z "$errlog" ] && [ -n "$result" ] && [ "$svr_res" != "" ] && [ "$cli_res" != "" ]; then echo ">>>>>>>> pass:1" case_print_result "MPNS_multipath_30_percent_loss_close_new_path" "pass" else @@ -2519,6 +2522,25 @@ else case_print_result "0RTT_datagram_send_multiple_redundancy" "fail" fi +killall test_server +rm -rf tp_localhost test_session xqc_token +clear_log +stdbuf -oL ${SERVER_BIN} -l d -Q 65535 -x 208 -e -U 1 > svr_stdlog & +sleep 1 + +echo -e "stop_datagram_send_redundancy_after_negotiation...\c" +${CLIENT_BIN} -l d -T 1 -s 2000 -U 2 -Q 65535 -x 208 --close_dg_red 1 > stdlog +cli_res=`grep "|stop sending datagram redundancy." clog` +svr_res=`grep "|stop sending datagram redundancy." slog` +errlog=`grep_err_log` +if [ -n "$cli_res" ] && [ -n "$svr_res" ] && [ -z "$errlog" ]; then + echo ">>>>>>>> pass:1" + case_print_result "stop_datagram_send_redundancy_after_negotiation" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "stop_datagram_send_redundancy_after_negotiation" "fail" +fi + killall test_server ${SERVER_BIN} -l d -e -x 208 -Q 65535 -U 1 --dgram_qos 3 > /dev/null & @@ -4213,6 +4235,526 @@ else echo "$errlog" fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 150 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3 ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 150 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3" "fail" +fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 151 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_more ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 151 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_more" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_more" "fail" +fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 152 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_29 ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 152 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_29" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_29" "fail" +fi + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 153 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_29_more ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 153 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_29_more" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_29_more" "fail" +fi + + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 150 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_ext ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 150 -T 2 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_ext" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_ext" "fail" +fi + + +sudo rm -rf tp_localhost test_session xqc_token clog slog stdlog ckeys.log +killall test_server +${SERVER_BIN} -l d -e -x 151 > /dev/null & +sleep 1 + +clear_log +echo -e "h3_engine_set_settings_api_h3_ext_more ...\c" +${CLIENT_BIN} -s 1024 -l d -t 1 -E -x 151 -T 2 >> stdlog +sleep 1 +cli_pass=`grep ">>>>>>>> pass:1" stdlog` +cli_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" clog` +cli_log2=`grep -e "qpack_enc_compat_dup:1" clog` +cli_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" clog` +cli_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" clog` +cli_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" clog` +svr_log1=`grep -e "xqc_h3_conn_send_settings.*qpack_blocked_streams:32|qpack_max_table_capacity:4096|max_field_section_size:512" slog` +svr_log2=`grep -e "qpack_enc_compat_dup:1" slog` +svr_log3=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:7.*value:32" slog` +svr_log4=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:1.*value:4096" slog` +svr_log5=`grep -e "xqc_h3_conn_on_settings_entry_received.*id:6.*value:512" slog` +err_log=`grep_err_log` + +if [ -n "$cli_pass" ] && [ -n "$cli_log1" ] && [ -n "$cli_log2" ] && [ -n "$cli_log3" ] && [ -n "$cli_log4" ] && [ -n "$cli_log5" ] && \ + [ -z "$err_log" ] && [ -n "$svr_log1" ] && [ -n "$svr_log2" ] && [ -n "$svr_log3" ] && [ -n "$svr_log4" ] && [ -n "$svr_log5" ] ; then + echo ">>>>>>>> pass:1" + case_print_result "h3_engine_set_settings_api_h3_ext_more" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "h3_engine_set_settings_api_h3_ext_more" "fail" +fi + +rm -rf tp_localhost test_session xqc_token +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` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$clog_res1" ] && [ -n "$slog_res1" ]; then + echo ">>>>>>>> pass:1" + case_print_result "negotiate_encoder_fec_scheme" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "negotiate_encoder_fec_scheme" "fail" +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` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$clog_res2" ] && [ -n "$slog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "negotiate_decoder_fec_scheme" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "negotiate_decoder_fec_scheme" "fail" +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` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ -n "$clog_res2" ] && [ -n "$slog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "negotiate_fec_schemes_fail" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "negotiate_fec_schemes_fail" "fail" +fi + + +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 +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" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_stream" "fail" +fi + +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 ">>>>>>>> pass:1" + case_print_result "repair_num_is_zero" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "repair_num_is_zero" "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 + +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 +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_xor" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_xor" "fail" +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 +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_rsc" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_rsc" "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 +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_xor_and_rsc" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_xor_and_rsc" "fail" +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 +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_rsc_and_xor" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "fec_recovered_function_of_datagram_rsc_and_xor" "fail" +fi + + +clear_log +rm -rf tp_localhost test_session xqc_token +echo -e "qlog disable ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_disable > slog & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_disable >> clog +result=`grep ">>>>>>>> pass:1" clog` +svr_qlog_res1=`grep "\[packet_received\]" slog` +svr_qlog_res2=`grep "\[packet_sent\]" slog` +cli_qlog_res1=`grep "\[packet_received\]" clog` +cli_qlog_res2=`grep "\[packet_sent\]" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -z "$svr_qlog_res1" ] && [ -z "$svr_qlog_res2" ] \ + && [ -z "$cli_qlog_res1" ] && [ -z "$cli_qlog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_disable" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_disable" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance selected 1 ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance s > slog & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance s >> clog +result=`grep ">>>>>>>> pass:1" clog` +svr_qlog_res1=`grep "\[packet_received\]" slog` +svr_qlog_res2=`grep "\[connection_started\]" slog` +cli_qlog_res1=`grep "\[packet_received\]" clog` +cli_qlog_res2=`grep "\[connection_started\]" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_selected_1" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_selected_1" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance selected 2 ...\c" +killall test_server +${SERVER_BIN} -l i -e -x 1 --qlog_importance s > slog & +sleep 1 +${CLIENT_BIN} -s 10240 -l i -t 1 -E --qlog_importance s >> clog +result=`grep ">>>>>>>> pass:1" clog` +svr_qlog_res1=`grep "\[packet_received\]" slog` +svr_qlog_res2=`grep "\[connection_started\]" slog` +cli_qlog_res1=`grep "\[packet_received\]" clog` +cli_qlog_res2=`grep "\[connection_started\]" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -z "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -z "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_selected_2" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_selected_2" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance removed ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance r > slog & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance r >> clog +result=`grep ">>>>>>>> pass:1" clog` +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -n "$svr_qlog_res3" ] && [ -n "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ] \ + && [ -n "$cli_qlog_res3" ] && [ -n "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_removed" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_removed" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance extra ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance e > slog & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance e >> clog +result=`grep ">>>>>>>> pass:1" clog` +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -n "$svr_qlog_res3" ] && [ -z "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ] \ + && [ -n "$cli_qlog_res3" ] && [ -z "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_extra" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_extra" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance base ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance b > slog & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance b >> clog +result=`grep ">>>>>>>> pass:1" clog` +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -n "$svr_qlog_res2" ] \ + && [ -z "$svr_qlog_res3" ] && [ -z "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -n "$cli_qlog_res2" ] \ + && [ -z "$cli_qlog_res3" ] && [ -z "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_base" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_base" "fail" + echo "$errlog" +fi + + +clear_log +echo -e "qlog importance core ...\c" +killall test_server +${SERVER_BIN} -l d -e -x 1 --qlog_importance c > slog & +sleep 1 +${CLIENT_BIN} -s 10240 -l d -t 1 -E --qlog_importance c >> clog +result=`grep ">>>>>>>> pass:1" clog` +svr_qlog_res1=`grep "\[packet_sent" slog` +svr_qlog_res2=`grep "\[connection_" slog` +svr_qlog_res3=`grep "\[datagram" slog` +svr_qlog_res4=`grep "\[qpack_" slog` +cli_qlog_res1=`grep "\[packet_sent" clog` +cli_qlog_res2=`grep "\[connection_" clog` +cli_qlog_res3=`grep "\[datagram" clog` +cli_qlog_res4=`grep "\[qpack_" clog` +errlog=`grep_err_log` +if [ -z "$errlog" ] && [ "$result" == ">>>>>>>> pass:1" ] && [ -n "$svr_qlog_res1" ] && [ -z "$svr_qlog_res2" ] \ + && [ -z "$svr_qlog_res3" ] && [ -z "$svr_qlog_res4" ] && [ -n "$cli_qlog_res1" ] && [ -z "$cli_qlog_res2" ] \ + && [ -z "$cli_qlog_res3" ] && [ -z "$cli_qlog_res4" ]; then + echo ">>>>>>>> pass:1" + case_print_result "qlog_importance_core" "pass" +else + echo ">>>>>>>> pass:0" + case_print_result "qlog_importance_core" "fail" + echo "$errlog" +fi + killall test_server -cd - +cd - \ No newline at end of file diff --git a/scripts/xquic.lds b/scripts/xquic.lds index dbf3badd6..da8b38ce5 100644 --- a/scripts/xquic.lds +++ b/scripts/xquic.lds @@ -4,6 +4,8 @@ XQUIC_VERS_1.0 { xqc_server_set_conn_settings; xqc_engine_create; xqc_engine_destroy; + xqc_engine_set_priv_ctx; + xqc_engine_get_priv_ctx; xqc_h3_connect; xqc_h3_conn_close; xqc_scid_str; @@ -18,7 +20,7 @@ XQUIC_VERS_1.0 { xqc_h3_request_get_stats; xqc_h3_request_stats_print; xqc_h3_request_set_user_data; - xqc_h3_conn_set_settings; + xqc_h3_engine_set_local_settings; xqc_h3_get_conn_user_data_by_request; xqc_h3_stream_id; xqc_h3_request_close; @@ -33,6 +35,7 @@ XQUIC_VERS_1.0 { xqc_h3_engine_set_enc_max_dtable_capacity; xqc_h3_engine_set_max_dtable_capacity; xqc_h3_engine_set_max_field_section_size; + xqc_h3_engine_set_qpack_blocked_streams; xqc_connect; xqc_conn_close; xqc_conn_get_errno; @@ -81,6 +84,7 @@ XQUIC_VERS_1.0 { xqc_h3_ctx_destroy; xqc_engine_register_alpn; xqc_engine_unregister_alpn; + xqc_engine_get_alpn_ctx; xqc_conn_set_alp_user_data; xqc_h3_request_finish; xqc_conn_close_with_error; @@ -115,9 +119,11 @@ XQUIC_VERS_1.0 { xqc_copa_cb; xqc_conn_get_conn_settings_template; xqc_conn_get_lastest_rtt; - xqc_log_enable; + xqc_log_disable; xqc_h3_request_update_settings; xqc_stream_update_settings; + xqc_reed_solomon_code_cb; + xqc_xor_code_cb; local: *; }; diff --git a/scripts/xquic_test.sh b/scripts/xquic_test.sh index 0739278b7..d8556818a 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} .. + 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 .. make -j if [ $? -ne 0 ]; then diff --git a/src/common/xqc_log.c b/src/common/xqc_log.c index b7b8850e0..2b7b00177 100644 --- a/src/common/xqc_log.c +++ b/src/common/xqc_log.c @@ -3,18 +3,17 @@ */ #include "xqc_log.h" +#include "src/transport/xqc_engine.h" #ifdef PRINT_MALLOC FILE *g_malloc_info_fp; #endif - -static xqc_bool_t xqc_log_switch = XQC_TRUE; - void -xqc_log_enable(xqc_bool_t enable) +xqc_log_disable(xqc_engine_t *engine, xqc_bool_t disable) { - xqc_log_switch = enable; + engine->log_disable = disable; + xqc_log(engine->log, XQC_LOG_DEBUG, "|log_disable:%d|", disable); } void @@ -58,58 +57,145 @@ xqc_log_type_2_level(xqc_log_type_t type) return XQC_LOG_ERROR; case GEN_WARN: return XQC_LOG_WARN; + case GEN_STATS: + return XQC_LOG_STATS; + case GEN_INFO: + return XQC_LOG_INFO; + case GEN_DEBUG: + return XQC_LOG_DEBUG; + default: + return XQC_LOG_DEBUG; + } +} + +qlog_event_importance_t +xqc_qlog_event_2_level(xqc_log_type_t type) +{ + switch (type) { + /* draft-ietf-quic-qlog-quic-events */ case CON_SERVER_LISTENING: + return EVENT_IMPORTANCE_EXTRA; case CON_CONNECTION_STARTED: case CON_CONNECTION_CLOSED: - case GEN_STATS: - return XQC_LOG_STATS; case CON_CONNECTION_ID_UPDATED: + case CON_SPIN_BIM_UPDATED: case CON_CONNECTION_STATE_UPDATED: - case SEC_KEY_UPDATED: - case SEC_KEY_RETIRED: + case CON_PATH_ASSIGNED: + return EVENT_IMPORTANCE_BASE; + + case CON_MTU_UPDATED: + return EVENT_IMPORTANCE_EXTRA; + case TRA_VERSION_INFORMATION: case TRA_ALPN_INFORMATION: case TRA_PARAMETERS_SET: + return EVENT_IMPORTANCE_CORE; + case TRA_PARAMETERS_RESTORED: + return EVENT_IMPORTANCE_BASE; + + case TRA_PACKET_SENT: + case TRA_PACKET_RECEIVED: + return EVENT_IMPORTANCE_CORE; + + case TRA_PACKET_DROPPED: + case TRA_PACKET_BUFFERED: + return EVENT_IMPORTANCE_BASE; + + case TRA_PACKETS_ACKED: + case TRA_DATAGRAM_DROPPED: case TRA_DATAGRAMS_SENT: case TRA_DATAGRAMS_RECEIVED: + return EVENT_IMPORTANCE_EXTRA; + case TRA_STREAM_STATE_UPDATED: - case TRA_STATELESS_RESET: + return EVENT_IMPORTANCE_BASE; + + case TRA_FRAMES_PROCESSED: + return EVENT_IMPORTANCE_EXTRA; + + case TRA_STREAM_DATA_MOVED: + case TRA_DATAGRAM_DATA_MOVED: + return EVENT_IMPORTANCE_BASE; + case REC_METRICS_UPDATED: + return EVENT_IMPORTANCE_EXTRA; + + case SEC_KEY_UPDATED: + case SEC_KEY_RETIRED: + return EVENT_IMPORTANCE_BASE; + case REC_PARAMETERS_SET: + return EVENT_IMPORTANCE_BASE; + case REC_CONGESTION_STATE_UPDATED: + return EVENT_IMPORTANCE_BASE; + + case REC_LOSS_TIMER_UPDATED: + return EVENT_IMPORTANCE_EXTRA; + + case REC_PACKET_LOST: + return EVENT_IMPORTANCE_CORE; + + case REC_MARKED_FOR_RETRANSMIT: + return EVENT_IMPORTANCE_EXTRA; + + /* draft-ietf-quic-qlog-h3-events */ case HTTP_PARAMETERS_SET: case HTTP_PARAMETERS_RESTORED: - case HTTP_SETTING_PARSED: case HTTP_STREAM_TYPE_SET: + case HTTP_PRIORITY_UPDATED: + return EVENT_IMPORTANCE_BASE; + case HTTP_FRAME_PARSED: + case HTTP_FRAME_CREATED: + return EVENT_IMPORTANCE_CORE; + + case HTTP_PUSH_RESOLVED: + return EVENT_IMPORTANCE_EXTRA; + + /* quic-qlog-h3-events have removed all qpack event definitions since draft 05*/ case QPACK_STATE_UPDATED: case QPACK_STREAM_STATE_UPDATED: - case GEN_INFO: - return XQC_LOG_INFO; - case CON_SPIN_BIM_UPDATED: - case TRA_PACKET_SENT: - case TRA_PACKET_RECEIVED: - case TRA_PACKET_DROPPED: - case TRA_PACKET_BUFFERED: + case QPACK_DYNAMIC_TABLE_UPDATED: + case QPACK_HEADERS_ENCODED: + case QPACK_HEADERS_DECODED: + case QPACK_INSTRUCTION_CREATED: + case QPACK_INSTRUCTION_PARSED: + return EVENT_IMPORTANCE_REMOVED; + default: + return EVENT_IMPORTANCE_EXTRA; + } +} + +xqc_log_level_t +qlog_importance_2_log_level(xqc_log_type_t type){ + if (type >= GEN_REPORT){ + return xqc_log_type_2_level(type); + } + switch (type) + { + /* datagrame, packet, frame level event should be xqc_log_debug */ + case HTTP_FRAME_PARSED: + case HTTP_FRAME_CREATED: case TRA_PACKETS_ACKED: case TRA_DATAGRAM_DROPPED: + case TRA_DATAGRAMS_SENT: + case TRA_DATAGRAMS_RECEIVED: + case TRA_PACKET_SENT: + case TRA_PACKET_RECEIVED: case TRA_FRAMES_PROCESSED: - case TRA_DATA_MOVED: + case TRA_STREAM_DATA_MOVED: + case TRA_DATAGRAM_DATA_MOVED: case REC_LOSS_TIMER_UPDATED: case REC_PACKET_LOST: case REC_MARKED_FOR_RETRANSMIT: - case HTTP_FRAME_CREATED: - case HTTP_PUSH_RESOLVED: - case QPACK_DYNAMIC_TABLE_UPDATED: - case QPACK_INSTRUCTION_CREATED: - case QPACK_INSTRUCTION_PARSED: - case QPACK_HEADERS_ENCODED: - case QPACK_HEADERS_DECODED: - case GEN_DEBUG: + case TRA_PACKET_DROPPED: + case TRA_PACKET_BUFFERED: return XQC_LOG_DEBUG; + default: - return XQC_LOG_DEBUG; + return XQC_LOG_INFO; } } @@ -123,6 +209,8 @@ xqc_log_type_str(xqc_log_type_t type) [CON_CONNECTION_ID_UPDATED] = "connection_id_updated", [CON_SPIN_BIM_UPDATED] = "spin_bin_updated", [CON_CONNECTION_STATE_UPDATED] = "connection_state_updated", + [CON_PATH_ASSIGNED] = "path_assigned", + [CON_MTU_UPDATED] = "mtu_updated", [SEC_KEY_UPDATED] = "key_updated", [SEC_KEY_RETIRED] = "key_retired", [TRA_VERSION_INFORMATION] = "version_information", @@ -139,7 +227,8 @@ xqc_log_type_str(xqc_log_type_t type) [TRA_DATAGRAM_DROPPED] = "datagram_dropped", [TRA_STREAM_STATE_UPDATED] = "stream_state_updated", [TRA_FRAMES_PROCESSED] = "frames_processed", - [TRA_DATA_MOVED] = "data_moved", + [TRA_STREAM_DATA_MOVED] = "stream_data_moved", + [TRA_DATAGRAM_DATA_MOVED] = "datagram_data_moved", [TRA_STATELESS_RESET] = "stateless_reset", [REC_PARAMETERS_SET] = "rec_parameters_set", [REC_METRICS_UPDATED] = "rec_metrics_updated", @@ -150,10 +239,10 @@ xqc_log_type_str(xqc_log_type_t type) [HTTP_PARAMETERS_SET] = "http_parameters_set", [HTTP_PARAMETERS_RESTORED] = "http_parameters_restored", [HTTP_STREAM_TYPE_SET] = "http_stream_type_set", + [HTTP_PRIORITY_UPDATED] = "http_priority_updated", [HTTP_FRAME_CREATED] = "http_frame_created", [HTTP_FRAME_PARSED] = "http_frame_parsed", [HTTP_PUSH_RESOLVED] = "push_resolved", - [HTTP_SETTING_PARSED] = "http_setting_parsed", [QPACK_STATE_UPDATED] = "qpack_state_updated", [QPACK_STREAM_STATE_UPDATED] = "qpack_stream_state_updated", [QPACK_DYNAMIC_TABLE_UPDATED] = "dynamic_table_updated", @@ -177,7 +266,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 (!xqc_log_switch) { + if (log->engine && log->engine->log_disable) { return; } @@ -233,6 +322,73 @@ xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const c /* if didn't set log callback, just return */ } +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) { + return; + } + + if (!log->log_event){ + return; + } + + qlog_event_importance_t event_imp = xqc_qlog_event_2_level(type); + /* EVENT_IMPORTANCE_SELECTED: events will be emitted based on their map log level and cur log level */ + xqc_log_level_t level = XQC_LOG_DEBUG; + if (log->qlog_importance == EVENT_IMPORTANCE_SELECTED) { + level = qlog_importance_2_log_level(type); + if (level > log->log_level) { + return; + } + } + + unsigned char buf[XQC_MAX_LOG_LEN] = {0}; + unsigned char *p = buf; + unsigned char *last = buf + sizeof(buf); + + /* do not need time & level if use outside log format */ + if (log->log_timestamp) { + /* time */ + char time[64]; + xqc_log_time(time, sizeof(time)); + p = xqc_sprintf(p, last, "[%s] ", time); + } + + if (log->log_level_name) { + /* qlog event */ + p = xqc_sprintf(p, last, "[%s] ", xqc_log_type_str(type)); + } + + if (log->scid != NULL) { + p = xqc_sprintf(p, last, "|scid:%s|%s", log->scid, func); + } else { + p = xqc_sprintf(p, last, "|%s", func); + } + + /* log */ + va_list args; + va_start(args, fmt); + p = xqc_vsprintf(p, last, fmt, args); + va_end(args); + + if (p + 1 < last) { + /* may use printf("%s") outside, add '\0' and don't count into size */ + *p = '\0'; + } + /* EVENT_IMPORTANCE_SELECTED: event logs output with xqc_log via xqc_log_write_err callback */ + if (log->qlog_importance == EVENT_IMPORTANCE_SELECTED) { + if (log->log_callbacks->xqc_log_write_err) { + log->log_callbacks->xqc_log_write_err(level, buf, p - buf, log->user_data); + } + } + else if(log->log_callbacks->xqc_qlog_event_write) { + log->log_callbacks->xqc_qlog_event_write(event_imp, buf, p - buf, log->user_data); + } +} + + void xqc_log_time(char *buf, size_t buf_len) { diff --git a/src/common/xqc_log.h b/src/common/xqc_log.h index f05b92ef2..63a99d52a 100644 --- a/src/common/xqc_log.h +++ b/src/common/xqc_log.h @@ -57,6 +57,9 @@ typedef enum { CON_CONNECTION_ID_UPDATED, CON_SPIN_BIM_UPDATED, CON_CONNECTION_STATE_UPDATED, + CON_PATH_ASSIGNED, + CON_MTU_UPDATED, + /* security event */ SEC_KEY_UPDATED, @@ -77,7 +80,8 @@ typedef enum { TRA_DATAGRAM_DROPPED, TRA_STREAM_STATE_UPDATED, TRA_FRAMES_PROCESSED, - TRA_DATA_MOVED, + TRA_STREAM_DATA_MOVED, + TRA_DATAGRAM_DATA_MOVED, TRA_STATELESS_RESET, /* recovery event */ @@ -92,10 +96,10 @@ typedef enum { HTTP_PARAMETERS_SET, HTTP_PARAMETERS_RESTORED, HTTP_STREAM_TYPE_SET, + HTTP_PRIORITY_UPDATED, HTTP_FRAME_CREATED, HTTP_FRAME_PARSED, HTTP_PUSH_RESOLVED, - HTTP_SETTING_PARSED, /* qpack event */ QPACK_STATE_UPDATED, @@ -119,17 +123,19 @@ typedef enum { typedef struct xqc_log_s { xqc_log_level_t log_level; + qlog_event_importance_t qlog_importance; xqc_flag_t log_event; /* 1:enable log event, 0:disable log event */ xqc_flag_t log_timestamp; /* 1:add timestamp before log, 0:don't need timestamp */ xqc_flag_t log_level_name; /* 1:add level name before log, 0:don't need level name */ unsigned char *scid; + xqc_engine_t *engine; xqc_log_callbacks_t *log_callbacks; void *user_data; } xqc_log_t; static inline xqc_log_t * -xqc_log_init(xqc_log_level_t log_level, xqc_flag_t log_event, xqc_flag_t log_timestamp, xqc_flag_t log_level_name, - xqc_log_callbacks_t *log_callbacks, void *user_data) +xqc_log_init(xqc_log_level_t log_level, xqc_flag_t log_event, qlog_event_importance_t qlog_imp, xqc_flag_t log_timestamp, xqc_flag_t log_level_name, + xqc_engine_t *engine, xqc_log_callbacks_t *log_callbacks, void *user_data) { xqc_log_t* log = xqc_malloc(sizeof(xqc_log_t)); if (log == NULL) { @@ -143,6 +149,8 @@ xqc_log_init(xqc_log_level_t log_level, xqc_flag_t log_event, xqc_flag_t log_tim log->log_timestamp = log_timestamp; log->log_level_name = log_level_name; log->log_callbacks = log_callbacks; + log->qlog_importance = qlog_imp; + log->engine = engine; return log; } @@ -159,6 +167,12 @@ xqc_log_level_set(xqc_log_t *log, xqc_log_level_t level); xqc_log_level_t xqc_log_type_2_level(xqc_log_type_t type); +qlog_event_importance_t +xqc_qlog_event_2_level(xqc_log_type_t type); + +xqc_log_level_t +qlog_importance_2_log_level(xqc_log_type_t type); + xqc_log_type_t xqc_log_event_type(xqc_log_level_t level); @@ -171,6 +185,8 @@ xqc_log_time(char *buf, size_t buf_len); void xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...); +void +xqc_qlog_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const char *fmt, ...); #ifndef XQC_DISABLE_LOG #ifndef XQC_ONLY_ERROR_LOG @@ -193,7 +209,9 @@ xqc_log_implement(xqc_log_t *log, xqc_log_type_t type, const char *func, const c #define xqc_log_event(log, type, ...) \ do { \ if ((log)->log_event) { \ - if ((log)->log_level >= xqc_log_type_2_level(type)) { \ + if ((log)->qlog_importance >= xqc_qlog_event_2_level(type) || \ + ((log)->qlog_importance == EVENT_IMPORTANCE_SELECTED && \ + (log)->log_level >= qlog_importance_2_log_level(type))) { \ xqc_log_##type##_callback(log, __FUNCTION__, __VA_ARGS__); \ } \ } \ diff --git a/src/common/xqc_log_event_callback.c b/src/common/xqc_log_event_callback.c index b5e9a0ee7..b420478e1 100644 --- a/src/common/xqc_log_event_callback.c +++ b/src/common/xqc_log_event_callback.c @@ -9,30 +9,75 @@ #include "src/congestion_control/xqc_bbr_common.h" #include "src/http3/xqc_h3_conn.h" +void +xqc_log_CON_SERVER_LISTENING_callback(xqc_log_t *log, const char *func, const struct sockaddr *peer_addr, + socklen_t peer_addrlen) +{ + struct sockaddr_in *sa_peer = (struct sockaddr_in *)peer_addr; + if(peer_addr->sa_family == AF_INET){ + xqc_qlog_implement(log, CON_SERVER_LISTENING, func, + "|ip_v4:%s|port_v4:%d|", + xqc_peer_addr_str(log->engine, (struct sockaddr*)sa_peer, peer_addrlen), + ntohs(sa_peer->sin_port)); + } + else{ + xqc_qlog_implement(log, CON_SERVER_LISTENING, func, + "|ip_v6:%s|port_v6:%d|", + xqc_peer_addr_str(log->engine, (struct sockaddr*)sa_peer, peer_addrlen), + ntohs(sa_peer->sin_port)); + } +} + void xqc_log_CON_CONNECTION_STARTED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local) { if (local == XQC_LOG_LOCAL_EVENT) { struct sockaddr_in *sa_local = (struct sockaddr_in *)conn->local_addr; - xqc_log_implement(log, CON_CONNECTION_STARTED, func, + xqc_qlog_implement(log, CON_CONNECTION_STARTED, func, "|local|src_ip:%s|src_port:%d|", - xqc_local_addr_str((struct sockaddr*)sa_local, conn->local_addrlen), + xqc_local_addr_str(conn->engine, (struct sockaddr*)sa_local, conn->local_addrlen), ntohs(sa_local->sin_port)); } else { struct sockaddr_in *sa_peer = (struct sockaddr_in *)conn->peer_addr; - xqc_log_implement(log, CON_CONNECTION_STARTED, func, + xqc_qlog_implement(log, CON_CONNECTION_STARTED, func, "|remote|dst_ip:%s|dst_port:%d|scid:%s|dcid:%s|", - xqc_peer_addr_str((struct sockaddr*)sa_peer, conn->peer_addrlen), - ntohs(sa_peer->sin_port), log->scid, xqc_dcid_str(&conn->dcid_set.current_dcid)); + xqc_peer_addr_str(conn->engine, (struct sockaddr*)sa_peer, conn->peer_addrlen), + ntohs(sa_peer->sin_port), log->scid, xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid)); } } void xqc_log_CON_CONNECTION_CLOSED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn) { - xqc_log_implement(log, CON_CONNECTION_CLOSED, func, - "|err_code:%d|", conn->conn_err); + if (conn->conn_err != 0){ + xqc_list_head_t *pos, *next; + xqc_path_ctx_t *path = NULL; + unsigned char log_buf[500]; + unsigned char *p = log_buf; + unsigned char *last = log_buf + sizeof(log_buf); + xqc_list_for_each_safe(pos, next, &conn->conn_paths_list) { + path = xqc_list_entry(pos, xqc_path_ctx_t, path_list); + uint8_t idx = path->path_send_ctl->ctl_cwndlim_update_idx; + p = xqc_sprintf(p, last, "", + path->path_id, + xqc_calc_delay(path->path_send_ctl->ctl_recent_cwnd_limitation_time[idx], conn->conn_create_time) / 1000, + xqc_calc_delay(path->path_send_ctl->ctl_recent_cwnd_limitation_time[(idx + 1) % 3], conn->conn_create_time) / 1000, + xqc_calc_delay(path->path_send_ctl->ctl_recent_cwnd_limitation_time[(idx + 2) % 3], conn->conn_create_time) / 1000 + ); + if (p != last) { + *p = '\0'; + } + } + xqc_qlog_implement(log, CON_CONNECTION_CLOSED, func, + "|err_code:%d|mtu_updatad_count:%d|pkt_dropped:%d|recent_congestion:%s|", + conn->conn_err, conn->MTU_updated_count, conn->packet_dropped_count, log_buf); + } + else{ + xqc_qlog_implement(log, CON_CONNECTION_CLOSED, func, + "|err_code:%d|mtu_updatad_count:%d|pkt_dropped:%d|", + conn->conn_err, conn->MTU_updated_count, conn->packet_dropped_count); + } } void @@ -41,26 +86,43 @@ xqc_log_CON_CONNECTION_ID_UPDATED_callback(xqc_log_t *log, const char *func, xqc unsigned char scid_str[XQC_MAX_CID_LEN * 2 + 1]; xqc_hex_dump(scid_str, conn->scid_set.user_scid.cid_buf, conn->scid_set.user_scid.cid_len); scid_str[conn->scid_set.user_scid.cid_len * 2] = '\0'; - xqc_log_implement(log, CON_CONNECTION_ID_UPDATED, func, + xqc_qlog_implement(log, CON_CONNECTION_ID_UPDATED, func, "|scid:%s|dcid:%s|", scid_str, conn->dcid_set.current_dcid_str); } void xqc_log_CON_CONNECTION_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn) { - xqc_log_implement(log, CON_CONNECTION_STATE_UPDATED, func, - "|state:%d|", conn->conn_state); + xqc_qlog_implement(log, CON_CONNECTION_STATE_UPDATED, func, + "|new:%s|", xqc_conn_state_2_str(conn->conn_state)); +} + +void +xqc_log_CON_PATH_ASSIGNED_callback(xqc_log_t *log, const char *func, + xqc_path_ctx_t *path, xqc_connection_t *conn) +{ + xqc_qlog_implement(log, CON_PATH_ASSIGNED, func, + "|path_id:%ui|local_addr:%s|peer_addr:%s|dcid:%s|scid:%s|", + path->path_id, xqc_conn_addr_str(conn), xqc_path_addr_str(path), + xqc_dcid_str(log->engine, &path->path_dcid), xqc_scid_str(log->engine, &path->path_scid)); +} + +void +xqc_log_CON_MTU_UPDATED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, int32_t is_done) +{ + xqc_qlog_implement(log, CON_MTU_UPDATED, func, + "|new:%uz|done:%d|max:%uz|", conn->pkt_out_size, is_done, conn->max_pkt_out_size); } void xqc_log_SEC_KEY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_engine_ssl_config_t ssl_config, xqc_int_t local) { if (local == XQC_LOG_LOCAL_EVENT) { - xqc_log_implement(log, SEC_KEY_UPDATED, func, + xqc_qlog_implement(log, SEC_KEY_UPDATED, func, "|local|ciphers:%s|", ssl_config.ciphers); } else { - xqc_log_implement(log, SEC_KEY_UPDATED, func, + xqc_qlog_implement(log, SEC_KEY_UPDATED, func, "|remote|ciphers:%s|", ssl_config.ciphers); } } @@ -87,35 +149,42 @@ xqc_log_TRA_VERSION_INFORMATION_callback(xqc_log_t *log, const char *func, uint3 *p = '\0'; } - xqc_log_implement(log, TRA_VERSION_INFORMATION, func, + xqc_qlog_implement(log, TRA_VERSION_INFORMATION, func, "|%s|choose:%d|", log_buf, choose); } void -xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, size_t local_count, uint8_t *local_alpn, - size_t remote_count, const uint8_t *remote_alpn, size_t alpn_len, const unsigned char *alpn) +xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, const unsigned char * server_alpn_list, + unsigned int server_alpn_list_len, const unsigned char *client_alpn_list, unsigned int client_alpn_list_len, + const char *selected_alpn, size_t selected_alpn_len) { unsigned char log_buf[XQC_MAX_LOG_LEN]; unsigned char *p = log_buf; unsigned char *last = log_buf + sizeof(log_buf); + p = xqc_sprintf(p, last, "client_alpn:"); - p = xqc_sprintf(p, last, "local_alpn:"); - for (size_t i = 0; i < local_count; ++i) { - p = xqc_sprintf(p, last, " %d", local_alpn[i]); - } + uint8_t alpn_len; + size_t alpn_write_len; - p = xqc_sprintf(p, last, "|remote_alpn:"); - for (size_t i = 0; i < remote_count; ++i) { - p = xqc_sprintf(p, last, " %d", remote_alpn[i]); + for (unsigned i = 0; i < client_alpn_list_len;) { + alpn_len = client_alpn_list[i]; + alpn_write_len = alpn_len; + p = xqc_sprintf(p, last, "%*s ", alpn_write_len, &client_alpn_list[i + 1]); + i += alpn_len; + i++; } + p = xqc_sprintf(p, last, "|server_alpn:"); - if (p != last) { - *p = '\0'; + for (unsigned i = 0; i < server_alpn_list_len;) { + alpn_len = server_alpn_list[i]; + alpn_write_len = alpn_len; + p = xqc_sprintf(p, last, "%*s ", alpn_write_len, &server_alpn_list[i + 1]); + i += alpn_len; + i++; } - - xqc_log_implement(log, TRA_ALPN_INFORMATION, func, - "|%s|choose:%*s|", log_buf, alpn_len, alpn); -} + xqc_qlog_implement(log, TRA_ALPN_INFORMATION, func, + "|%s|selected_alpn:%*s|", log_buf, selected_alpn_len, selected_alpn); + } void xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local) @@ -128,7 +197,7 @@ xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connec setting = &conn->remote_settings; } - xqc_log_implement(log, TRA_PARAMETERS_SET, func, + xqc_qlog_implement(log, TRA_PARAMETERS_SET, func, "|%s|migration:%d|max_idle_timeout:%d|max_udp_payload_size:%d|" "active_connection_id_limit:%d|max_data:%d|", local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", setting->disable_active_migration, @@ -139,50 +208,71 @@ xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connec void xqc_log_TRA_PACKET_RECEIVED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in) { - xqc_log_implement(log, TRA_PACKET_RECEIVED, func, - "|pkt_pns:%d|pkt_type:%d|pkt_num:%ui|len:%uz|frame_flag:%s|", - packet_in->pi_pkt.pkt_pns, packet_in->pi_pkt.pkt_type, packet_in->pi_pkt.pkt_num, - packet_in->buf_size, xqc_frame_type_2_str(packet_in->pi_frame_types)); + xqc_qlog_implement(log, TRA_PACKET_RECEIVED, func, + "|pkt_pns:%d|pkt_type:%s|pkt_num:%ui|len:%uz|frame_flag:%s|path_id:%ui|", + packet_in->pi_pkt.pkt_pns, xqc_pkt_type_2_str(packet_in->pi_pkt.pkt_type), packet_in->pi_pkt.pkt_num, + packet_in->buf_size, xqc_frame_type_2_str(log->engine, packet_in->pi_frame_types), packet_in->pi_path_id); } void -xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out) +xqc_log_TRA_PACKET_DROPPED_callback(xqc_log_t *log, const char *func, const char *trigger, xqc_int_t ret, + const char* pi_pkt_type, xqc_packet_number_t pi_pkt_num) { - xqc_log_implement(log, TRA_PACKET_SENT, func, - "|pkt_pns:%d|pkt_type:%d|pkt_num:%ui|size:%d|frame_flag:%s|", - packet_out->po_pkt.pkt_pns, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num, - packet_out->po_used_size, xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_qlog_implement(log, TRA_PACKET_DROPPED, func, + "|trigger:%s|ret:%d|pkt_type:%s|pkt_num:%ui|", + trigger, ret, pi_pkt_type, pi_pkt_num); +} + +void +xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, + xqc_packet_out_t *packet_out, xqc_path_ctx_t *path, xqc_usec_t send_time, ssize_t sent, xqc_bool_t with_pn) +{ + if (with_pn) { + xqc_qlog_implement(log, TRA_PACKET_SENT, func, + "|<==|conn:%p|path_id:%ui|pkt_pns:%d|pkt_type:%s|pkt_num:%ui|size:%d|frame_flag:%s|" + "sent:%z|inflight:%ud|now:%ui|stream_id:%ui|stream_offset:%ui|", + conn, path->path_id, packet_out->po_pkt.pkt_pns, + xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), packet_out->po_pkt.pkt_num, + packet_out->po_used_size, xqc_frame_type_2_str(log->engine, packet_out->po_frame_types), + sent, path->path_send_ctl->ctl_bytes_in_flight, send_time, + packet_out->po_stream_id, packet_out->po_stream_offset); + } else { + xqc_qlog_implement(log, TRA_PACKET_SENT, func, + "|<==|conn:%p|path_id:%ui|pkt_type:%s|pkt_pns:%d|frame_flag:%s|size:%ud|sent:%z|", + conn, path->path_id, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), packet_out->po_pkt.pkt_pns, + xqc_frame_type_2_str(log->engine, packet_out->po_frame_types), packet_out->po_used_size, sent); + } } void xqc_log_TRA_PACKET_BUFFERED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in) { - xqc_log_implement(log, TRA_PACKET_BUFFERED, func, - "|pkt_pns:%d|pkt_type:%d|len:%d|", - packet_in->pi_pkt.pkt_pns, packet_in->pi_pkt.pkt_type, packet_in->buf_size); + xqc_qlog_implement(log, TRA_PACKET_BUFFERED, func, + "|pkt_num:%ui|pkt_pns:%d|pkt_type:%d|len:%d|", + packet_in->pi_pkt.pkt_num, packet_in->pi_pkt.pkt_pns, packet_in->pi_pkt.pkt_type, packet_in->buf_size); } void xqc_log_TRA_PACKETS_ACKED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in, - xqc_packet_number_t high, xqc_packet_number_t low) + xqc_packet_number_t high, xqc_packet_number_t low, uint64_t path_id) { - xqc_log_implement(log, TRA_PACKETS_ACKED, func, - "|pkt_space:%d|high:%d|low:%d|", - packet_in->pi_pkt.pkt_pns, high, low); + xqc_qlog_implement(log, TRA_PACKETS_ACKED, func, + "|pkt_space:%d|high:%d|low:%d|path_id:%ui|", + packet_in->pi_pkt.pkt_pns, high, low, path_id); } void -xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size) +xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id) { - xqc_log_implement(log, TRA_DATAGRAMS_SENT, func, - "|size:%z|", size); + xqc_qlog_implement(log, TRA_DATAGRAMS_SENT, func, + "|size:%z|path_id:%ui|", size, path_id); } void -xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size) +xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id) { - xqc_log_implement(log, TRA_DATAGRAMS_RECEIVED, func, - "|size:%d|", size); + xqc_qlog_implement(log, TRA_DATAGRAMS_RECEIVED, func, + "|size:%d|path_id:%ui|", size, path_id); } void @@ -190,11 +280,11 @@ xqc_log_TRA_STREAM_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_ xqc_int_t stream_type, xqc_int_t state) { if (stream_type == XQC_LOG_STREAM_SEND) { - xqc_log_implement(log, TRA_STREAM_STATE_UPDATED, func, + xqc_qlog_implement(log, TRA_STREAM_STATE_UPDATED, func, "|stream_id:%d|send_stream|old:%d|new:%d|", stream->stream_id, stream->stream_state_send, state); } else { - xqc_log_implement(log, TRA_STREAM_STATE_UPDATED, func, + xqc_qlog_implement(log, TRA_STREAM_STATE_UPDATED, func, "|stream_id:%d|recv_stream|old:%d|new:%d|", stream->stream_id, stream->stream_state_recv, state); } @@ -209,13 +299,13 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) switch (frame_type) { case XQC_FRAME_PADDING: { uint32_t length = va_arg(args, uint32_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|length:%ui|", frame_type, length); break; } case XQC_FRAME_PING: - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|", frame_type); break; @@ -239,7 +329,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) *p = '\0'; } - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|ack_delay:%ui|ack_range:%s|", frame_type, ack_info->ack_delay, buf); break; @@ -249,7 +339,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t err_code = va_arg(args, uint64_t); uint64_t final_size = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|stream_id:%ui|err_code:%ui|final_size:%ui|", frame_type, stream_id, err_code, final_size); break; @@ -258,7 +348,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_STOP_SENDING: { xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t err_code = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|stream_id:%ui|err_code:%ui|", frame_type, stream_id, err_code); break; } @@ -266,7 +356,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_CRYPTO: { uint64_t offset = va_arg(args, uint64_t); uint64_t length = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|offset:%ui|length:%ui|", frame_type, offset, length); break; } @@ -274,14 +364,14 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_NEW_TOKEN: { uint64_t length = va_arg(args, uint64_t); unsigned char *token = va_arg(args, unsigned char *); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|token_length:%ui|token:%s|", frame_type, length, token); break; } case XQC_FRAME_STREAM: { xqc_stream_frame_t *frame = va_arg(args, xqc_stream_frame_t*); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|data_offset:%ui|data_length:%d|fin:%d|", frame_type, frame->data_offset, frame->data_length, frame->fin); break; @@ -289,14 +379,14 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_DATAGRAM: { uint64_t length = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|data_length:%ui|", frame_type, length); break; } case XQC_FRAME_MAX_DATA: { uint64_t max_data = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|max_data:%ui|", frame_type, max_data); break; } @@ -304,7 +394,7 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_MAX_STREAM_DATA: { xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t max_stream_data = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|stream_id:%ui|max_stream_data:%ui|", frame_type, stream_id, max_stream_data); break; @@ -313,13 +403,13 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) int bidirectional = va_arg(args, int); uint64_t max_streams = va_arg(args, uint64_t); if (bidirectional) { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|max_stream_data:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:bidirectional|maximum:%ui|", frame_type, max_streams); } else { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|unidirectional|max_stream_data:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:unidirectional|maximum:%ui|", frame_type, max_streams); } break; @@ -327,8 +417,8 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_DATA_BLOCKED: { uint64_t data_limit = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|data_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|bidirectional|limit:%ui|", frame_type, data_limit); break; } @@ -336,8 +426,8 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) case XQC_FRAME_STREAM_DATA_BLOCKED: { xqc_stream_id_t stream_id = va_arg(args, xqc_stream_id_t); uint64_t stream_data_limit = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|stream_id:%ui|stream_data_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|bidirectional|stream_id:%ui|limit:%ui|", frame_type, stream_id, stream_data_limit); break; } @@ -346,13 +436,13 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) int bidirectional = va_arg(args, int); uint64_t stream_limit = va_arg(args, uint64_t); if (bidirectional) { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|bidirectional|stream_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:bidirectional|limit:%ui|", frame_type, stream_limit); } else { - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|unidirectional|stream_limit:%ui|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|stream_type:unidirectional|limit:%ui|", frame_type, stream_limit); } break; @@ -364,21 +454,21 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) unsigned char scid_str[XQC_MAX_CID_LEN * 2 + 1]; xqc_hex_dump(scid_str, new_cid->cid_buf, new_cid->cid_len); scid_str[new_cid->cid_len * 2] = '\0'; - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, - "|type:%d|seq_num:%ui|retire_prior_to:%ui|cid_len:%d|cid:%s|", + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, + "|type:%d|sequence_number:%ui|retire_prior_to:%ui|connection_id_length:%d|connection_id:%s|", frame_type, new_cid->cid_seq_num, retire_prior_to, new_cid->cid_len, scid_str); break; } case XQC_FRAME_CONNECTION_CLOSE: { uint64_t err_code = va_arg(args, uint64_t); - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|err_code:%ui|", frame_type, err_code); break; } case XQC_FRAME_HANDSHAKE_DONE: - xqc_log_implement(log, TRA_FRAMES_PROCESSED, func, + xqc_qlog_implement(log, TRA_FRAMES_PROCESSED, func, "|type:%d|", frame_type); break; @@ -399,19 +489,56 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...) } +void +xqc_log_TRA_STREAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + xqc_bool_t is_recv, size_t read_or_write_size, size_t recv_buf_size, + uint8_t fin, int ret, int pkt_type, int buff_1rtt, size_t offset) +{ + if (is_recv) { + xqc_qlog_implement(log, TRA_STREAM_DATA_MOVED, func, + "|stream_id:%ui|read:%uz|recv_buf_size:%uz|fin:%d|stream_length:%ui|next_read_offset:%ui|conn:%p" + "|from:transport|to:application|", + stream->stream_id, read_or_write_size, recv_buf_size, fin, + stream->stream_data_in.stream_length, stream->stream_data_in.next_read_offset, + stream->stream_conn); + } + else{ + xqc_connection_t *conn = stream->stream_conn; + xqc_qlog_implement(log, TRA_STREAM_DATA_MOVED, func, + "|ret:%d|stream_id:%ui|stream_send_offset:%ui|pkt_type:%s|buff_1rtt:%d" + "|send_data_size:%uz|offset:%uz|fin:%d|stream_flag:%d|conn:%p|conn_state:%s|flag:%s" + "|from:application|to:transport|", + ret, stream->stream_id, stream->stream_send_offset, xqc_pkt_type_2_str(pkt_type), + buff_1rtt, read_or_write_size, offset, fin, stream->stream_flag, conn, + xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn, conn->conn_flag)); + } +} + +void +xqc_log_TRA_DATAGRAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + size_t moved_data_len, const char *from, const char *to) +{ + xqc_qlog_implement(log, TRA_STREAM_DATA_MOVED, func, + "|stream_id:%ui|length:%uz|from:%s|to:%s|", + stream->stream_id, moved_data_len, from, to); +} + void xqc_log_TRA_STATELESS_RESET_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn) { - xqc_log_implement(log, TRA_DATAGRAMS_SENT, func, "|stateless reset|cid:%s", + xqc_qlog_implement(log, TRA_STATELESS_RESET, func, "|stateless reset|cid:%s|", log->scid); } void -xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl) +xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl, uint8_t timer_granularity, + xqc_cc_params_t cc_params) { - xqc_log_implement(log, REC_PARAMETERS_SET, func, - "|reordering_packet_threshold:%d|reordering_time_threshold_shift:%d|", - send_ctl->ctl_reordering_packet_threshold, send_ctl->ctl_reordering_time_threshold_shift); + xqc_qlog_implement(log, REC_PARAMETERS_SET, func, + "|reordering_threshold:%ui|time_threshold:%d|timer_granularity:%d|initial_rtt:%ui|" + "initial_congestion_window:%d|minimum_congestion_window:%d|", + send_ctl->ctl_reordering_packet_threshold, send_ctl->ctl_reordering_time_threshold_shift, timer_granularity, send_ctl->ctl_srtt / 1000, + cc_params.init_cwnd, cc_params.min_cwnd); } void @@ -430,7 +557,7 @@ xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ xqc_cong_ctl_get_pacing_rate(send_ctl->ctl_cong); mode = send_ctl->ctl_cong_callback->xqc_cong_ctl_info_cb->mode(send_ctl->ctl_cong); min_rtt = send_ctl->ctl_cong_callback-> xqc_cong_ctl_info_cb->min_rtt(send_ctl->ctl_cong); - xqc_log_implement(log, REC_METRICS_UPDATED, func, + xqc_qlog_implement(log, REC_METRICS_UPDATED, func, "|cwnd:%ui|inflight:%ud|mode:%ud|applimit:%ud|pacing_rate:%ui|bw:%ui|srtt:%ui|" "latest_rtt:%ui|ctl_rttvar:%ui|pto_count:%ud|min_rtt:%ui|send:%ud|lost:%ud|tlp:%ud|recv:%ud|", cwnd, send_ctl->ctl_bytes_in_flight, mode, send_ctl->ctl_app_limited, pacing_rate, bw, send_ctl->ctl_srtt, @@ -438,7 +565,7 @@ xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ send_ctl->ctl_tlp_count, send_ctl->ctl_recv_count); } else { - xqc_log_implement(log, REC_METRICS_UPDATED, func, + xqc_qlog_implement(log, REC_METRICS_UPDATED, func, "|cwnd:%ui|inflight:%ud|applimit:%ud|srtt:%ui|latest_rtt:%ui|pto_count:%ud|" "send:%ud|lost:%ud|tlp:%ud|recv:%ud|", cwnd, send_ctl->ctl_bytes_in_flight, send_ctl->ctl_app_limited, send_ctl->ctl_srtt, send_ctl->ctl_latest_rtt, send_ctl->ctl_pto_count, @@ -449,7 +576,7 @@ xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ void xqc_log_REC_CONGESTION_STATE_UPDATED_callback(xqc_log_t *log, const char *func, char *new_state) { - xqc_log_implement(log, REC_CONGESTION_STATE_UPDATED, func, + xqc_qlog_implement(log, REC_CONGESTION_STATE_UPDATED, func, "|new_state:%s|", new_state); } @@ -457,28 +584,36 @@ void xqc_log_REC_LOSS_TIMER_UPDATED_callback(xqc_log_t *log, const char *func, xqc_timer_manager_t *timer_manager, xqc_usec_t inter_time, xqc_int_t type, xqc_int_t event) { + if (type != XQC_TIMER_LOSS_DETECTION){ + return ; + } if (event == XQC_LOG_TIMER_SET) { - xqc_log_implement(log, REC_LOSS_TIMER_UPDATED, func, - "|set|type:%s|expire:%ui|interv:%ui|", + xqc_qlog_implement(log, REC_LOSS_TIMER_UPDATED, func, + "|event_type:set|type:%s|expire:%ui|interv:%ui|", xqc_timer_type_2_str(type), timer_manager->timer[type].expire_time, inter_time); } else if (event == XQC_LOG_TIMER_EXPIRE) { - xqc_log_implement(log, REC_LOSS_TIMER_UPDATED, func, - "|expired|type:%s|expire_time:%ui|", + xqc_qlog_implement(log, REC_LOSS_TIMER_UPDATED, func, + "|event_type:expired|type:%s|expire_time:%ui|", xqc_timer_type_2_str(type), timer_manager->timer[type].expire_time); } else if (event == XQC_LOG_TIMER_CANCEL) { - xqc_log_implement(log, REC_LOSS_TIMER_UPDATED, func, - "|cancel|type:%s|", xqc_timer_type_2_str(type)); + xqc_qlog_implement(log, REC_LOSS_TIMER_UPDATED, func, + "|event_type:cancel|type:%s|", xqc_timer_type_2_str(type)); } } void -xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out) +xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out, + xqc_packet_number_t lost_pn, xqc_usec_t lost_send_time, xqc_usec_t loss_delay) { - xqc_log_implement(log, REC_PACKET_LOST, func, - "|pkt_pns:%d|pkt_type:%d|pkt_num:%d|", - packet_out->po_pkt.pkt_pns, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num); + xqc_qlog_implement(log, REC_PACKET_LOST, func, + "|pkt_pns:%d|pkt_type:%d|pkt_num:%d|lost_pn:%ui|po_sent_time:%ui|" + "lost_send_time:%ui|loss_delay:%ui|frame:%s|repair:%d|path_id:%ui|", + packet_out->po_pkt.pkt_pns, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num, + lost_pn, packet_out->po_sent_time, lost_send_time, loss_delay, + xqc_frame_type_2_str(log->engine, packet_out->po_frame_types), XQC_NEED_REPAIR(packet_out->po_frame_types), + packet_out->po_path_id); } void @@ -491,8 +626,8 @@ xqc_log_HTTP_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_h3_co } else { setting = &h3_conn->peer_h3_conn_settings; } - xqc_log_implement(log, HTTP_PARAMETERS_SET, func, - "|%s|max_field_section_size:%ui|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", + xqc_qlog_implement(log, HTTP_PARAMETERS_SET, func, + "|owner:%s|max_field_section_size:%ui|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", setting->max_field_section_size, setting->qpack_dec_max_table_capacity, setting->qpack_blocked_streams); } @@ -501,7 +636,7 @@ void xqc_log_HTTP_PARAMETERS_RESTORED_callback(xqc_log_t *log, const char *func, xqc_h3_conn_t *h3_conn) { xqc_h3_conn_settings_t *setting = &h3_conn->local_h3_conn_settings; - xqc_log_implement(log, HTTP_PARAMETERS_RESTORED, func, + xqc_qlog_implement(log, HTTP_PARAMETERS_RESTORED, func, "|max_field_section_size:%ui|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", setting->max_field_section_size, setting->qpack_dec_max_table_capacity, setting->qpack_blocked_streams); @@ -510,7 +645,7 @@ xqc_log_HTTP_PARAMETERS_RESTORED_callback(xqc_log_t *log, const char *func, xqc_ void xqc_log_HTTP_STREAM_TYPE_SET_callback(xqc_log_t *log, const char *func, xqc_h3_stream_t *h3_stream, xqc_int_t local) { - xqc_log_implement(log, HTTP_STREAM_TYPE_SET, func, + xqc_qlog_implement(log, HTTP_STREAM_TYPE_SET, func, "|%s|stream_id:%ui|stream_type:%d|", local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", h3_stream->stream_id, h3_stream->type); } @@ -527,7 +662,7 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) switch (type) { case XQC_H3_FRM_DATA: { uint64_t size = va_arg(args, uint64_t); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|size:%ui|", stream_id, type, size); break; } @@ -544,7 +679,7 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) p = xqc_sprintf(p, last, "{name:%*s}|", (size_t) header->name.iov_len, header->name.iov_base); } } - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|%s", stream_id, type, log_buf); break; } @@ -552,13 +687,13 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) case XQC_H3_FRM_GOAWAY: case XQC_H3_FRM_MAX_PUSH_ID: { uint64_t push_id = va_arg(args, uint64_t); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|push_id:%ui|", stream_id, type, push_id); break; } case XQC_H3_FRM_SETTINGS: { xqc_h3_conn_settings_t *settings = va_arg(args, xqc_h3_conn_settings_t*); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|max_field_section_size:%ui|max_pushes:%ui|" "|qpack_max_table_capacity:%ui|qpack_blocked_streams:%ui|", stream_id, type, settings->max_field_section_size, settings->max_pushes, @@ -568,7 +703,7 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...) case XQC_H3_FRM_PUSH_PROMISE: { uint64_t push_id = va_arg(args, uint64_t); xqc_http_headers_t *headers = va_arg(args, xqc_http_headers_t*); - xqc_log_implement(log, HTTP_FRAME_CREATED, func, + xqc_qlog_implement(log, HTTP_FRAME_CREATED, func, "|stream_id:%ui|type:%d|push_id:%ui|", stream_id, type, push_id); break; } @@ -587,29 +722,29 @@ xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stre case XQC_H3_FRM_DATA: case XQC_H3_FRM_HEADERS: case XQC_H3_FRM_SETTINGS: - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|", stream_id, frame->type, frame->len); break; case XQC_H3_FRM_CANCEL_PUSH: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.cancel_push.push_id.vi); break; } case XQC_H3_FRM_PUSH_PROMISE: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.push_promise.push_id.vi); break; } case XQC_H3_FRM_GOAWAY: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.goaway.stream_id.vi); break; } case XQC_H3_FRM_MAX_PUSH_ID: { - xqc_log_implement(log, HTTP_FRAME_PARSED, func, + xqc_qlog_implement(log, HTTP_FRAME_PARSED, func, "|stream_id:%ui|type:%d|length:%ui|push_id:%ui|", stream_id, frame->type, frame->len, frame->frame_payload.max_push_id.push_id.vi); break; @@ -620,15 +755,18 @@ xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stre } void -xqc_log_HTTP_SETTING_PARSED_callback(xqc_log_t *log, const char *func, uint64_t identifier, uint64_t value) +xqc_log_HTTP_PRIORITY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_h3_priority_t *prio, xqc_h3_stream_t *h3s) { - xqc_log_implement(log, HTTP_SETTING_PARSED, func, "|id:%ui|value:%d|", identifier, value); + xqc_qlog_implement(log, HTTP_PRIORITY_UPDATED, func, "|urgency:%ui|incremental:%ui|schedule:%ui|reinject:%ui|" + "stream_id:%ui|conn:%p|", + prio->urgency, prio->incremental, prio->schedule, prio->reinject, + h3s->stream_id, h3s->h3c->conn); } void xqc_log_QPACK_STREAM_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_h3_stream_t *h3_stream) { - xqc_log_implement(log, QPACK_STREAM_STATE_UPDATED, func, + xqc_qlog_implement(log, QPACK_STREAM_STATE_UPDATED, func, "|stream_id:%ui|%s|", h3_stream->stream_id, h3_stream->flags & XQC_HTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED ? "blocked" : "unblocked"); } @@ -641,7 +779,7 @@ xqc_log_QPACK_DYNAMIC_TABLE_UPDATED_callback(xqc_log_t *log, const char *func, . xqc_int_t type = va_arg(args, xqc_int_t); uint64_t index = va_arg(args, uint64_t); if (type == XQC_LOG_DTABLE_EVICTED) { - xqc_log_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, + xqc_qlog_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, "|evicted|index:%ui|", index); } else { @@ -649,7 +787,7 @@ xqc_log_QPACK_DYNAMIC_TABLE_UPDATED_callback(xqc_log_t *log, const char *func, . char *name = va_arg(args, char *); uint64_t vlen = va_arg(args, uint64_t); char *value = va_arg(args, char *); - xqc_log_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, + xqc_qlog_implement(log, QPACK_DYNAMIC_TABLE_UPDATED, func, "|inserted|index:%ui|name:%*s|value:%*s|", index, (size_t) nlen, name, (size_t) vlen, value); } va_end(args); @@ -666,7 +804,7 @@ xqc_log_QPACK_INSTRUCTION_CREATED_callback(xqc_log_t *log, const char *func, ... switch (type) { case XQC_INS_TYPE_ENC_SET_DTABLE_CAP: { uint64_t cap = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|set_dynamic_table_capacity|capacity:%ui|", cap); break; } @@ -675,7 +813,7 @@ xqc_log_QPACK_INSTRUCTION_CREATED_callback(xqc_log_t *log, const char *func, ... uint64_t name_index = va_arg(args, uint64_t); size_t value_len = va_arg(args, size_t); char *value = va_arg(args, char *); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|insert_with_name_reference|%s|name_index:%ui|value:%*s|", table_type == XQC_DTABLE_FLAG ? "dtable" : "stable", name_index, (size_t) value_len, value); @@ -686,14 +824,14 @@ xqc_log_QPACK_INSTRUCTION_CREATED_callback(xqc_log_t *log, const char *func, ... char *name = va_arg(args, char *); size_t value_len = va_arg(args, size_t); char *value = va_arg(args, char *); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|insert_without_name_reference|name:%*s|value:%*s|", (size_t) name_len, name, (size_t) value_len, value); break; } case XQC_INS_TYPE_ENC_DUP: { uint64_t index = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|duplicate|index:%ui|", index); break; } @@ -706,19 +844,19 @@ xqc_log_QPACK_INSTRUCTION_CREATED_callback(xqc_log_t *log, const char *func, ... switch (type) { case XQC_INS_TYPE_DEC_SECTION_ACK: { uint64_t stream_id = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|header_acknowledgement|stream_id:%ui|", stream_id); break; } case XQC_INS_TYPE_DEC_STREAM_CANCEL: { uint64_t stream_id = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|stream_cancellation|stream_id:%ui|", stream_id); break; } case XQC_INS_TYPE_DEC_INSERT_CNT_INC: { uint64_t increment = va_arg(args, uint64_t); - xqc_log_implement(log, QPACK_INSTRUCTION_CREATED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_CREATED, func, "|insert_count_increment|increment:%ui|", increment); break; } @@ -739,22 +877,22 @@ xqc_log_QPACK_INSTRUCTION_PARSED_callback(xqc_log_t *log, const char *func, ...) xqc_ins_enc_ctx_t *ctx = va_arg(args, xqc_ins_enc_ctx_t*); switch (ctx->type) { case XQC_INS_TYPE_ENC_SET_DTABLE_CAP: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|set_dynamic_table_capacity|capacity:%ui|", ctx->capacity.value); break; case XQC_INS_TYPE_ENC_INSERT_NAME_REF: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|insert_with_name_reference|name_index:%ui|value:%*s|", ctx->name_index.value, (size_t) ctx->value->value->data_len, ctx->value->value->data); break; case XQC_INS_TYPE_ENC_INSERT_LITERAL: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|insert_without_name_reference|name:%*s|value:%*s|", (size_t) ctx->name->value->data_len, ctx->name->value->data, (size_t) ctx->value->value->data_len, ctx->value->value->data); break; case XQC_INS_TYPE_ENC_DUP: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|duplicate|index:%ui|", ctx->name_index.value); break; } @@ -763,15 +901,15 @@ xqc_log_QPACK_INSTRUCTION_PARSED_callback(xqc_log_t *log, const char *func, ...) xqc_ins_dec_ctx_t *ctx = va_arg(args, xqc_ins_dec_ctx_t*); switch (ctx->type) { case XQC_INS_TYPE_DEC_SECTION_ACK: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|header_acknowledgement|stream_id:%ui|", ctx->stream_id.value); break; case XQC_INS_TYPE_DEC_STREAM_CANCEL: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|stream_cancellation|stream_id:%ui|", ctx->stream_id.value); break; case XQC_INS_TYPE_DEC_INSERT_CNT_INC: - xqc_log_implement(log, QPACK_INSTRUCTION_PARSED, func, + xqc_qlog_implement(log, QPACK_INSTRUCTION_PARSED, func, "|insert_count_increment|increment:%ui|", ctx->increment.value); break; } diff --git a/src/common/xqc_log_event_callback.h b/src/common/xqc_log_event_callback.h index ff0cf9d0e..b53ee3249 100644 --- a/src/common/xqc_log_event_callback.h +++ b/src/common/xqc_log_event_callback.h @@ -7,6 +7,8 @@ #include "src/common/xqc_log.h" +void xqc_log_CON_SERVER_LISTENING_callback(xqc_log_t *log, const char *func, const struct sockaddr *peer_addr, + socklen_t peer_addrlen); void xqc_log_CON_CONNECTION_STARTED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local); @@ -20,6 +22,12 @@ void xqc_log_CON_CONNECTION_ID_UPDATED_callback(xqc_log_t *log, const char *func void xqc_log_CON_CONNECTION_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn); +void xqc_log_CON_PATH_ASSIGNED_callback(xqc_log_t *log, const char *func, + xqc_path_ctx_t *path, xqc_connection_t *conn); + +void xqc_log_CON_MTU_UPDATED_callback(xqc_log_t *log, const char *func, + xqc_connection_t *conn, int32_t is_done); + void xqc_log_SEC_KEY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_engine_ssl_config_t ssl_config, xqc_int_t local); @@ -27,37 +35,48 @@ void xqc_log_TRA_VERSION_INFORMATION_callback(xqc_log_t *log, const char *func, uint32_t local_count, uint32_t *local_version, uint32_t remote_count, uint32_t *remote_version, uint32_t choose); -void xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, size_t local_count, - uint8_t *local_alpn, size_t remote_count, const uint8_t *remote_alpn, size_t alpn_len, - const unsigned char *alpn); +void xqc_log_TRA_ALPN_INFORMATION_callback(xqc_log_t *log, const char *func, const unsigned char * server_alpn_list, + unsigned int server_alpn_list_len, const unsigned char *client_alpn_list, unsigned int client_alpn_list_len, + const char *selected_alpn, size_t selected_alpn_len); void xqc_log_TRA_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, xqc_int_t local); +void xqc_log_TRA_PACKET_DROPPED_callback(xqc_log_t *log, const char *func, const char *trigger, xqc_int_t ret, + const char * pi_pkt_type, xqc_packet_number_t pi_pkt_num); + void xqc_log_TRA_PACKET_RECEIVED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in); -void xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, - xqc_packet_out_t *packet_out); +void xqc_log_TRA_PACKET_SENT_callback(xqc_log_t *log, const char *func, xqc_connection_t *conn, + xqc_packet_out_t *packet_out, xqc_path_ctx_t *path, xqc_usec_t send_time, ssize_t sent, xqc_bool_t with_pn); void xqc_log_TRA_PACKET_BUFFERED_callback(xqc_log_t *log, const char *func, xqc_packet_in_t *packet_in); void xqc_log_TRA_PACKETS_ACKED_callback(xqc_log_t *log, const char *func, - xqc_packet_in_t *packet_in, xqc_packet_number_t high, xqc_packet_number_t low); + xqc_packet_in_t *packet_in, xqc_packet_number_t high, xqc_packet_number_t low, uint64_t path_id); -void xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size); +void xqc_log_TRA_DATAGRAMS_SENT_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id); -void xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size); +void xqc_log_TRA_DATAGRAMS_RECEIVED_callback(xqc_log_t *log, const char *func, ssize_t size, uint64_t path_id); void xqc_log_TRA_STREAM_STATE_UPDATED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, xqc_int_t stream_type, xqc_int_t state); void xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...); +void xqc_log_TRA_STREAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + xqc_bool_t is_recv, size_t read_or_write_size, size_t recv_buf_size, uint8_t fin, int ret, + int pkt_type, int buff_1rtt, size_t offset); + +void xqc_log_TRA_DATAGRAM_DATA_MOVED_callback(xqc_log_t *log, const char *func, xqc_stream_t *stream, + size_t moved_data_len, const char *from, const char *to); + void xqc_log_TRA_STATELESS_RESET_callback(xqc_log_t *log, const char *func, xqc_connection_t *c); -void xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl); +void xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl, + uint8_t timer_granularity, xqc_cc_params_t cc_params); void xqc_log_REC_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl); @@ -67,8 +86,8 @@ void xqc_log_REC_CONGESTION_STATE_UPDATED_callback(xqc_log_t *log, const char *f void xqc_log_REC_LOSS_TIMER_UPDATED_callback(xqc_log_t *log, const char *func, xqc_timer_manager_t *timer_manager, xqc_usec_t inter_time, xqc_int_t type, xqc_int_t event); -void xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, - xqc_packet_out_t *packet_out); +void xqc_log_REC_PACKET_LOST_callback(xqc_log_t *log, const char *func, xqc_packet_out_t *packet_out, + xqc_packet_number_t lost_pn, xqc_usec_t lost_send_time, xqc_usec_t loss_delay); void xqc_log_HTTP_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_h3_conn_t *h3_conn, xqc_int_t local); @@ -84,8 +103,8 @@ void xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...); void xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stream_t *h3_stream); -void xqc_log_HTTP_SETTING_PARSED_callback(xqc_log_t *log, const char *func, uint64_t identifier, - uint64_t value); +void +xqc_log_HTTP_PRIORITY_UPDATED_callback(xqc_log_t *log, const char *func, xqc_h3_priority_t *prio, xqc_h3_stream_t *h3s); void xqc_log_QPACK_STATE_UPDATED_callback(xqc_log_t *log, const char *func, ...); diff --git a/src/common/xqc_str.c b/src/common/xqc_str.c index 33ab9fda5..fa0da5767 100644 --- a/src/common/xqc_str.c +++ b/src/common/xqc_str.c @@ -288,8 +288,8 @@ xqc_sprintf_num(unsigned char *buf, unsigned char *last, uint64_t ui64, unsigned */ size_t len; uint32_t ui32; - static unsigned char hex[] = "0123456789abcdef"; - static unsigned char HEX[] = "0123456789ABCDEF"; + static const unsigned char hex[] = "0123456789abcdef"; + static const unsigned char HEX[] = "0123456789ABCDEF"; p = temp + XQC_INT64_LEN; diff --git a/src/http3/qpack/xqc_encoder.c b/src/http3/qpack/xqc_encoder.c index a1056b22c..409911f0e 100644 --- a/src/http3/qpack/xqc_encoder.c +++ b/src/http3/qpack/xqc_encoder.c @@ -1216,5 +1216,6 @@ void xqc_encoder_compat_dup(xqc_encoder_t *enc, xqc_bool_t compat) { enc->compat_dup = compat; + xqc_log(enc->log, XQC_LOG_DEBUG, "|qpack_enc_compat_dup:%d|", compat); } #endif diff --git a/src/http3/xqc_h3_conn.c b/src/http3/xqc_h3_conn.c index 70400c382..878e7d28c 100644 --- a/src/http3/xqc_h3_conn.c +++ b/src/http3/xqc_h3_conn.c @@ -11,7 +11,7 @@ #include "src/transport/xqc_defs.h" -xqc_h3_conn_settings_t default_local_h3_conn_settings = { +const xqc_h3_conn_settings_t default_local_h3_conn_settings = { .max_pushes = 0, .max_field_section_size = XQC_H3_MAX_FIELD_SECTION_SIZE, .qpack_blocked_streams = XQC_QPACK_MAX_BLOCK_STREAM, @@ -22,7 +22,7 @@ xqc_h3_conn_settings_t default_local_h3_conn_settings = { #endif }; -xqc_h3_conn_settings_t default_peer_h3_conn_settings = { +const xqc_h3_conn_settings_t default_peer_h3_conn_settings = { .max_pushes = XQC_H3_SETTINGS_UNSET, .max_field_section_size = XQC_H3_SETTINGS_UNSET, .qpack_blocked_streams = XQC_H3_SETTINGS_UNSET, @@ -74,33 +74,125 @@ xqc_h3_conn_destroy_blocked_stream_list(xqc_h3_conn_t *h3c); void xqc_h3_engine_set_dec_max_dtable_capacity(xqc_engine_t *engine, size_t value) { - default_local_h3_conn_settings.qpack_dec_max_table_capacity = value; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_dec_max_table_capacity = value; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_dec_max_table_capacity = value; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_dec_max_table_capacity = value; + } + } } void xqc_h3_engine_set_enc_max_dtable_capacity(xqc_engine_t *engine, size_t value) { - default_local_h3_conn_settings.qpack_enc_max_table_capacity = value; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = value; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = value; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = value; + } + } } void xqc_h3_engine_set_max_dtable_capacity(xqc_engine_t *engine, size_t capacity) { - default_local_h3_conn_settings.qpack_dec_max_table_capacity = capacity; - default_local_h3_conn_settings.qpack_enc_max_table_capacity = capacity; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = capacity; + settings->qpack_dec_max_table_capacity = capacity; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = capacity; + settings->qpack_dec_max_table_capacity = capacity; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_enc_max_table_capacity = capacity; + settings->qpack_dec_max_table_capacity = capacity; + } + } } void xqc_h3_engine_set_max_field_section_size(xqc_engine_t *engine, size_t size) { - default_local_h3_conn_settings.max_field_section_size = size; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->max_field_section_size = size; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->max_field_section_size = size; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->max_field_section_size = size; + } + } +} + +void +xqc_h3_engine_set_qpack_blocked_streams(xqc_engine_t *engine, size_t value) +{ + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_blocked_streams = value; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_blocked_streams = value; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_blocked_streams = value; + } + } } #ifdef XQC_COMPAT_DUPLICATE void xqc_h3_engine_set_qpack_compat_duplicate(xqc_engine_t *engine, xqc_bool_t cmpt) { - default_local_h3_conn_settings.qpack_compat_duplicate = cmpt; + xqc_h3_conn_settings_t *settings; + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + settings->qpack_compat_duplicate = cmpt; + } + + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + settings->qpack_compat_duplicate = cmpt; + } + + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + settings->qpack_compat_duplicate = cmpt; + } + } } #endif @@ -166,37 +258,25 @@ xqc_h3_conn_set_user_data(xqc_h3_conn_t *h3_conn, } -void -xqc_h3_conn_set_settings(xqc_h3_conn_t *h3_conn, const xqc_h3_conn_settings_t *h3_conn_settings) +void +xqc_h3_engine_set_local_settings(xqc_engine_t *engine, + const xqc_h3_conn_settings_t *h3_conn_settings) { - xqc_h3_conn_settings_t *settings = &h3_conn->local_h3_conn_settings; - - if (h3_conn_settings->max_field_section_size) { - settings->max_field_section_size = h3_conn_settings->max_field_section_size; - } + xqc_h3_conn_settings_t *settings; - if (h3_conn_settings->max_pushes) { - settings->max_pushes = h3_conn_settings->max_pushes; + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &settings) == XQC_OK) { + *settings = *h3_conn_settings; } - if (h3_conn_settings->qpack_enc_max_table_capacity) { - settings->qpack_enc_max_table_capacity = h3_conn_settings->qpack_enc_max_table_capacity; + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &settings) == XQC_OK) { + *settings = *h3_conn_settings; } - if (h3_conn_settings->qpack_dec_max_table_capacity) { - settings->qpack_dec_max_table_capacity = h3_conn_settings->qpack_dec_max_table_capacity; + if (engine->config->enable_h3_ext) { + if (xqc_h3_ctx_get_default_conn_settings(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &settings) == XQC_OK) { + *settings = *h3_conn_settings; + } } - - if (h3_conn_settings->qpack_blocked_streams) { - settings->qpack_blocked_streams = h3_conn_settings->qpack_blocked_streams; - } - -#ifdef XQC_COMPAT_DUPLICATE - settings->qpack_compat_duplicate = h3_conn_settings->qpack_compat_duplicate; - xqc_qpack_set_compat_dup(h3_conn->qpack, settings->qpack_compat_duplicate); -#endif - - xqc_log_event(h3_conn->log, HTTP_PARAMETERS_SET, h3_conn, XQC_LOG_LOCAL_EVENT); } @@ -303,21 +383,50 @@ const xqc_qpack_ins_cb_t xqc_h3_qpack_ins_cb = { xqc_int_t xqc_h3_conn_init_callbacks(xqc_h3_conn_t *h3c) { + if (h3c->conn->alpn == NULL) { + xqc_log(h3c->log, XQC_LOG_ERROR, "|alpn is null|"); + return -XQC_EFATAL; + } + xqc_h3_callbacks_t *h3_cbs = NULL; - xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(&h3_cbs); + xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(h3c->conn->engine, h3c->conn->alpn, h3c->conn->alpn_len, &h3_cbs); if (XQC_OK != ret || h3_cbs == NULL) { xqc_log(h3c->log, XQC_LOG_ERROR, "|can't get app callbacks, not initialized?"); return -XQC_EFATAL; } h3c->h3_conn_callbacks = h3_cbs->h3c_cbs; + h3c->h3_request_callbacks = h3_cbs->h3r_cbs; + if (h3c->flags & XQC_H3_CONN_FLAG_EXT_ENABLED) { + h3c->h3_ext_bs_callbacks = h3_cbs->h3_ext_bs_cbs; h3c->h3_ext_dgram_callbacks = h3_cbs->h3_ext_dgram_cbs; } return XQC_OK; } +xqc_int_t +xqc_h3_conn_init_settings(xqc_h3_conn_t *h3c) +{ + if (h3c->conn->alpn == NULL) { + xqc_log(h3c->log, XQC_LOG_ERROR, "|alpn is null|"); + return -XQC_EFATAL; + } + + xqc_h3_conn_settings_t *local_settings = NULL; + xqc_int_t ret = xqc_h3_ctx_get_default_conn_settings(h3c->conn->engine, h3c->conn->alpn, h3c->conn->alpn_len, &local_settings); + if (XQC_OK != ret) { + xqc_log(h3c->log, XQC_LOG_ERROR, "|can't get the default local h3 conn settings|"); + return -XQC_EFATAL; + } + + h3c->local_h3_conn_settings = *local_settings; + h3c->peer_h3_conn_settings = default_peer_h3_conn_settings; + + return XQC_OK; +} + xqc_h3_conn_t * xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) @@ -334,6 +443,14 @@ xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) h3c->control_stream_out = NULL; + /* avoid error handling in this function leads to crash */ + h3c->qdec_stream = NULL; + h3c->qenc_stream = NULL; + + /* blocked streams list */ + xqc_init_list_head(&h3c->block_stream_head); + h3c->block_stream_count = 0; + if (conn->engine->config->enable_h3_ext) { h3c->flags |= XQC_H3_CONN_FLAG_EXT_ENABLED; } @@ -341,10 +458,14 @@ xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) /* set callback functions from application layer to http3 layer */ if (xqc_h3_conn_init_callbacks(h3c) != XQC_OK) { h3c->flags &= ~XQC_H3_CONN_FLAG_EXT_ENABLED; + goto fail; } - h3c->local_h3_conn_settings = default_local_h3_conn_settings; - h3c->peer_h3_conn_settings = default_peer_h3_conn_settings; + + if (xqc_h3_conn_init_settings(h3c) != XQC_OK) { + h3c->flags &= ~XQC_H3_CONN_FLAG_EXT_ENABLED; + goto fail; + } /* create qpack */ h3c->qpack = xqc_qpack_create(h3c->local_h3_conn_settings.qpack_enc_max_table_capacity, @@ -359,12 +480,7 @@ xqc_h3_conn_create(xqc_connection_t *conn, void *user_data) xqc_qpack_set_compat_dup(h3c->qpack, h3c->local_h3_conn_settings.qpack_compat_duplicate); #endif - h3c->qdec_stream = NULL; - h3c->qenc_stream = NULL; - - /* blocked streams list */ - xqc_init_list_head(&h3c->block_stream_head); - h3c->block_stream_count = 0; + xqc_log_event(h3c->log, HTTP_PARAMETERS_SET, h3c, XQC_LOG_LOCAL_EVENT); /* creation callback */ if (h3c->h3_conn_callbacks.h3_conn_create_notify) { @@ -538,7 +654,6 @@ xqc_h3_conn_on_settings_entry_received(uint64_t identifier, uint64_t value, void xqc_h3_conn_t *h3c = (xqc_h3_conn_t *) user_data; xqc_log(h3c->log, XQC_LOG_DEBUG, "|id:%ui|value:%ui|", identifier, value); - xqc_log_event(h3c->log, HTTP_SETTING_PARSED, identifier, value); switch (identifier) { case XQC_H3_SETTINGS_MAX_FIELD_SECTION_SIZE: diff --git a/src/http3/xqc_h3_conn.h b/src/http3/xqc_h3_conn.h index 30f63fe6e..6969ee474 100644 --- a/src/http3/xqc_h3_conn.h +++ b/src/http3/xqc_h3_conn.h @@ -73,7 +73,8 @@ typedef struct xqc_h3_conn_s { /* h3 connection callback functions for user */ xqc_h3_conn_callbacks_t h3_conn_callbacks; - + xqc_h3_request_callbacks_t h3_request_callbacks; + xqc_h3_ext_bytestream_callbacks_t h3_ext_bs_callbacks; /* h3 datagram callback functions for user */ xqc_h3_ext_dgram_callbacks_t h3_ext_dgram_callbacks; diff --git a/src/http3/xqc_h3_ctx.c b/src/http3/xqc_h3_ctx.c index 59a72c392..e02fb65cd 100644 --- a/src/http3/xqc_h3_ctx.c +++ b/src/http3/xqc_h3_ctx.c @@ -9,13 +9,22 @@ #include "xqc_h3_ext_dgram.h" #include "src/transport/xqc_engine.h" -/* 应用层注册回调,放到engine */ -typedef struct xqc_h3_ctx_s { - xqc_h3_callbacks_t h3_cbs; -} xqc_h3_ctx_t; +xqc_h3_ctx_t* +xqc_h3_ctx_create(xqc_h3_callbacks_t *h3_cbs) +{ + xqc_h3_ctx_t *h3_ctx = NULL; + + h3_ctx = xqc_calloc(1, sizeof(xqc_h3_ctx_t)); -xqc_h3_ctx_t *h3_ctx = NULL; + if (h3_ctx) { + /* save h3 callbacks */ + h3_ctx->h3_cbs = *h3_cbs; + h3_ctx->h3c_def_local_settings = default_local_h3_conn_settings; + } + + return h3_ctx; +} xqc_int_t xqc_h3_ctx_init(xqc_engine_t *engine, xqc_h3_callbacks_t *h3_cbs) @@ -24,15 +33,8 @@ xqc_h3_ctx_init(xqc_engine_t *engine, xqc_h3_callbacks_t *h3_cbs) return -XQC_EPARAM; } - if (NULL == h3_ctx) { - h3_ctx = xqc_malloc(sizeof(xqc_h3_ctx_t)); - if (NULL == h3_ctx) { - return -XQC_EMALLOC; - } - } - - /* save h3 callbacks */ - h3_ctx->h3_cbs = *h3_cbs; + xqc_h3_ctx_t *h3_ctx = NULL; + xqc_int_t ret = XQC_OK; /* init http3 layer callbacks */ xqc_app_proto_callbacks_t ap_cbs = { @@ -40,53 +42,120 @@ xqc_h3_ctx_init(xqc_engine_t *engine, xqc_h3_callbacks_t *h3_cbs) .stream_cbs = h3_stream_callbacks, }; - /* register ALPN and transport layer callbacks */ - if (xqc_engine_register_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &ap_cbs) != XQC_OK - || xqc_engine_register_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &ap_cbs) != XQC_OK) - { - xqc_h3_ctx_destroy(engine); - return -XQC_EFATAL; + h3_ctx = xqc_h3_ctx_create(h3_cbs); + if (h3_ctx == NULL) { + return -XQC_EMALLOC; + } + + /* register H3 */ + if (xqc_engine_register_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3), &ap_cbs, h3_ctx) != XQC_OK) { + xqc_free(h3_ctx); + ret = -XQC_EFATAL; + goto error; + } + + h3_ctx = xqc_h3_ctx_create(h3_cbs); + if (h3_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + + /* register H3-29 */ + if (xqc_engine_register_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29), &ap_cbs, h3_ctx) != XQC_OK) { + xqc_free(h3_ctx); + ret = -XQC_EFATAL; + goto error; } if (engine->config->enable_h3_ext) { ap_cbs.dgram_cbs = h3_ext_datagram_callbacks; + h3_ctx = xqc_h3_ctx_create(h3_cbs); + if (h3_ctx == NULL) { + ret = -XQC_EMALLOC; + goto error; + } + /* register h3-ext ALPN */ - if (xqc_engine_register_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &ap_cbs) != XQC_OK) - { - xqc_h3_ctx_destroy(engine); - return -XQC_EFATAL; + if (xqc_engine_register_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT), &ap_cbs, h3_ctx) != XQC_OK) { + xqc_free(h3_ctx); + ret = -XQC_EFATAL; + goto error; } } - return XQC_OK; + return ret; + +error: + xqc_h3_ctx_destroy(engine); + return ret; } xqc_int_t xqc_h3_ctx_destroy(xqc_engine_t *engine) { - xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29)); - xqc_engine_unregister_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3)); - xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT)); + xqc_h3_ctx_t *h3_ctx; + h3_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29)); if (h3_ctx) { xqc_free(h3_ctx); - h3_ctx = NULL; } + h3_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3)); + if (h3_ctx) { + xqc_free(h3_ctx); + } + + h3_ctx = xqc_engine_get_alpn_ctx(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT)); + if (h3_ctx) { + xqc_free(h3_ctx); + } + + + xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_29, strlen(XQC_ALPN_H3_29)); + xqc_engine_unregister_alpn(engine, XQC_ALPN_H3, strlen(XQC_ALPN_H3)); + xqc_engine_unregister_alpn(engine, XQC_ALPN_H3_EXT, strlen(XQC_ALPN_H3_EXT)); + return XQC_OK; } xqc_int_t -xqc_h3_ctx_get_app_callbacks(xqc_h3_callbacks_t **h3_cbs) +xqc_h3_ctx_get_app_callbacks(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_callbacks_t **h3_cbs) { - if (NULL == h3_ctx) { + xqc_list_head_t *pos, *next; + xqc_alpn_registration_t *alpn_reg; + xqc_h3_ctx_t *h3_ctx = NULL; + + h3_ctx = xqc_engine_get_alpn_ctx(engine, alpn, alpn_len); + + if (h3_ctx == NULL) { return -XQC_EFATAL; } *h3_cbs = &h3_ctx->h3_cbs; + return XQC_OK; } + +xqc_int_t +xqc_h3_ctx_get_default_conn_settings(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_conn_settings_t **settings) +{ + xqc_list_head_t *pos, *next; + xqc_alpn_registration_t *alpn_reg; + xqc_h3_ctx_t *h3_ctx = NULL; + + h3_ctx = xqc_engine_get_alpn_ctx(engine, alpn, alpn_len); + + if (h3_ctx == NULL) { + return -XQC_EFATAL; + } + + *settings = &h3_ctx->h3c_def_local_settings; + + return XQC_OK; +} \ No newline at end of file diff --git a/src/http3/xqc_h3_ctx.h b/src/http3/xqc_h3_ctx.h index ed9dfdae1..c78dbd62f 100644 --- a/src/http3/xqc_h3_ctx.h +++ b/src/http3/xqc_h3_ctx.h @@ -8,7 +8,17 @@ #include -xqc_int_t xqc_h3_ctx_get_app_callbacks(xqc_h3_callbacks_t **h3_cbs); +/* 应用层注册回调,放到engine */ +typedef struct xqc_h3_ctx_s { + xqc_h3_callbacks_t h3_cbs; + xqc_h3_conn_settings_t h3c_def_local_settings; +} xqc_h3_ctx_t; + +xqc_int_t xqc_h3_ctx_get_app_callbacks(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_callbacks_t **h3_cbs); + +xqc_int_t xqc_h3_ctx_get_default_conn_settings(xqc_engine_t *engine, char *alpn, + size_t alpn_len, xqc_h3_conn_settings_t **settings); #endif diff --git a/src/http3/xqc_h3_ext_bytestream.c b/src/http3/xqc_h3_ext_bytestream.c index 65776105d..3582f06b3 100644 --- a/src/http3/xqc_h3_ext_bytestream.c +++ b/src/http3/xqc_h3_ext_bytestream.c @@ -156,16 +156,9 @@ xqc_h3_ext_bytestream_data_buf_merge(xqc_h3_ext_bytestream_data_buf_t *buf) } xqc_int_t -xqc_h3_ext_bytestream_init_callbacks(xqc_h3_ext_bytestream_t *bs) +xqc_h3_ext_bytestream_init_callbacks(xqc_h3_conn_t *h3c, xqc_h3_ext_bytestream_t *bs) { - xqc_h3_callbacks_t *h3_cbs = NULL; - xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(&h3_cbs); - if (XQC_OK != ret || h3_cbs == NULL) { - xqc_log(bs->h3_stream->log, XQC_LOG_ERROR, "|can't get app callbacks, not registered ?|"); - return ret; - } - - bs->bs_callbacks = &h3_cbs->h3_ext_bs_cbs; + bs->bs_callbacks = &h3c->h3_ext_bs_callbacks; return XQC_OK; } @@ -180,7 +173,7 @@ xqc_h3_ext_bytestream_create_inner(xqc_h3_conn_t *h3_conn, return NULL; } - if (xqc_h3_ext_bytestream_init_callbacks(bs) != XQC_OK) { + if (xqc_h3_ext_bytestream_init_callbacks(h3_conn, bs) != XQC_OK) { xqc_free(bs); return NULL; } @@ -266,7 +259,7 @@ xqc_h3_ext_bytestream_create(xqc_engine_t *engine, xqc_log(engine->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3_stream->stream_id, h3_conn->conn, xqc_conn_state_2_str(h3_conn->conn->conn_state), - xqc_conn_flag_2_str(h3_conn->conn->conn_flag)); + xqc_conn_flag_2_str(h3_conn->conn, h3_conn->conn->conn_flag)); return h3_ext_bs; } @@ -350,13 +343,13 @@ xqc_h3_ext_bytestream_close(xqc_h3_ext_bytestream_t *h3_ext_bs) if (ret) { xqc_log(conn->log, XQC_LOG_ERROR, "|fail|ret:%d|stream_id:%ui|conn:%p|conn_state:%s|" "flag:%s|", ret, h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return ret; } xqc_log(conn->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return XQC_OK; } diff --git a/src/http3/xqc_h3_request.c b/src/http3/xqc_h3_request.c index 04e2ca847..a7e6dd541 100644 --- a/src/http3/xqc_h3_request.c +++ b/src/http3/xqc_h3_request.c @@ -41,7 +41,7 @@ xqc_h3_request_create(xqc_engine_t *engine, xqc_log(engine->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3_stream->stream_id, h3_conn->conn, xqc_conn_state_2_str(h3_conn->conn->conn_state), - xqc_conn_flag_2_str(h3_conn->conn->conn_flag)); + xqc_conn_flag_2_str(h3_conn->conn, h3_conn->conn->conn_flag)); return h3_request; } @@ -114,13 +114,13 @@ xqc_h3_request_close(xqc_h3_request_t *h3_request) if (ret) { xqc_log(conn->log, XQC_LOG_ERROR, "|fail|ret:%d|stream_id:%ui|conn:%p|conn_state:%s|" "flag:%s|", ret, h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return ret; } xqc_log(conn->log, XQC_LOG_DEBUG, "|success|stream_id:%ui|conn:%p|conn_state:%s|flag:%s|", h3s->stream_id, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); return XQC_OK; } @@ -134,17 +134,9 @@ xqc_h3_request_header_initial(xqc_h3_request_t *h3_request) xqc_int_t -xqc_h3_request_init_callbacks(xqc_h3_request_t *h3r) +xqc_h3_request_init_callbacks(xqc_h3_conn_t *h3c, xqc_h3_request_t *h3r) { - xqc_h3_callbacks_t *h3_cbs = NULL; - xqc_int_t ret = xqc_h3_ctx_get_app_callbacks(&h3_cbs); - if (XQC_OK != ret || h3_cbs == NULL) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|can't get app callbacks, not initialized ?"); - return ret; - } - - h3r->request_if = &h3_cbs->h3r_cbs; - + h3r->request_if = &h3c->h3_request_callbacks; return XQC_OK; } @@ -169,7 +161,7 @@ xqc_h3_request_create_inner(xqc_h3_conn_t *h3_conn, xqc_h3_stream_t *h3_stream, xqc_init_list_head(&h3_request->body_buf); h3_request->body_buf_count = 0; - xqc_h3_request_init_callbacks(h3_request); + xqc_h3_request_init_callbacks(h3_conn, h3_request); if (h3_request->request_if->h3_request_create_notify) { h3_request->request_if->h3_request_create_notify(h3_request, h3_request->user_data); @@ -719,12 +711,14 @@ xqc_h3_request_on_recv_header(xqc_h3_request_t *h3r) h3r->current_header++; /* header notify callback */ - ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); - if (ret < 0) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" - "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, - h3r->h3_stream->h3c->conn); - return ret; + if (h3r->request_if->h3_request_read_notify) { + ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); + if (ret < 0) { + xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" + "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, + h3r->h3_stream->h3c->conn); + return ret; + } } return XQC_OK; @@ -737,13 +731,14 @@ xqc_h3_request_on_recv_body(xqc_h3_request_t *h3r) if (!xqc_list_empty(&h3r->body_buf)) { h3r->read_flag |= XQC_REQ_NOTIFY_READ_BODY; - - xqc_int_t ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); - if (ret < 0) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" - "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, - h3r->h3_stream->h3c->conn); - return ret; + if (h3r->request_if->h3_request_read_notify) { + xqc_int_t ret = h3r->request_if->h3_request_read_notify(h3r, h3r->read_flag, h3r->user_data); + if (ret < 0) { + xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" + "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, + h3r->h3_stream->h3c->conn); + return ret; + } } } @@ -773,14 +768,16 @@ xqc_h3_request_on_recv_empty_fin(xqc_h3_request_t *h3r) return XQC_OK; } - /* if all header and content were received by application, notify empty fin */ - ret = h3r->request_if->h3_request_read_notify(h3r, XQC_REQ_NOTIFY_READ_EMPTY_FIN, - h3r->user_data); - if (ret < 0) { - xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" - "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, - h3r->h3_stream->h3c->conn); - return ret; + if (h3r->request_if->h3_request_read_notify) { + /* if all header and content were received by application, notify empty fin */ + ret = h3r->request_if->h3_request_read_notify(h3r, XQC_REQ_NOTIFY_READ_EMPTY_FIN, + h3r->user_data); + if (ret < 0) { + xqc_log(h3r->h3_stream->log, XQC_LOG_ERROR, "|h3_request_read_notify error|%d|" + "stream_id:%ui|conn:%p|", ret, h3r->h3_stream->stream_id, + h3r->h3_stream->h3c->conn); + return ret; + } } xqc_log(h3r->h3_stream->h3c->log, XQC_LOG_DEBUG, "|stream_id:%ui|recv_fin|conn:%p|", @@ -1031,11 +1028,6 @@ xqc_h3_request_set_priority(xqc_h3_request_t *h3r, xqc_h3_priority_t *prio) } xqc_h3_stream_set_priority(h3r->h3_stream, prio); - xqc_log(h3r->h3_stream->log, XQC_LOG_INFO, - "|urgency:%ui|incremental:%ui|schedule:%ui|reinject:%ui|" - "stream_id:%ui|conn:%p|", - prio->urgency, prio->incremental, prio->schedule, prio->reinject, - h3r->h3_stream->stream_id, h3r->h3_stream->h3c->conn); - + xqc_log_event(h3r->h3_stream->log, HTTP_PRIORITY_UPDATED, prio, h3r->h3_stream); return XQC_OK; } \ No newline at end of file diff --git a/src/http3/xqc_h3_stream.c b/src/http3/xqc_h3_stream.c index 8371e4e5a..8abd92ff6 100644 --- a/src/http3/xqc_h3_stream.c +++ b/src/http3/xqc_h3_stream.c @@ -388,7 +388,7 @@ xqc_h3_stream_send_headers(xqc_h3_stream_t *h3s, xqc_http_headers_t *headers, ui h3s->h3r->header_sent += headers->total_len; xqc_log(h3c->log, XQC_LOG_DEBUG, "|write:%z|stream_id:%ui|fin:%ud|conn:%p|flag:%s|", write, - h3s->stream_id, (unsigned int)fin, h3c->conn, xqc_conn_flag_2_str(h3c->conn->conn_flag)); + h3s->stream_id, (unsigned int)fin, h3c->conn, xqc_conn_flag_2_str(h3c->conn, h3c->conn->conn_flag)); h3s->flags &= ~XQC_HTTP3_STREAM_NEED_WRITE_NOTIFY; @@ -682,13 +682,15 @@ xqc_h3_stream_write_notify(xqc_stream_t *stream, void *user_data) if (h3s->type == XQC_H3_STREAM_TYPE_REQUEST && (h3s->flags & XQC_HTTP3_STREAM_NEED_WRITE_NOTIFY)) { - ret = h3s->h3r->request_if->h3_request_write_notify(h3s->h3r, h3s->h3r->user_data); - if (ret < 0) { - xqc_log(stream->stream_conn->log, XQC_LOG_ERROR, - "|h3_request_write_notify error|%d|", ret); - return ret; + if (h3s->h3r->request_if->h3_request_write_notify) { + ret = h3s->h3r->request_if->h3_request_write_notify(h3s->h3r, h3s->h3r->user_data); + if (ret < 0) { + xqc_log(stream->stream_conn->log, XQC_LOG_ERROR, + "|h3_request_write_notify error|%d|", ret); + return ret; + } + xqc_log(h3s->log, XQC_LOG_DEBUG, "|h3_request_write_notify|success|"); } - xqc_log(h3s->log, XQC_LOG_DEBUG, "|h3_request_write_notify|success|"); } //TODO: implement the notification of bytestream writable event diff --git a/src/tls/xqc_tls.c b/src/tls/xqc_tls.c index 3b68679c7..2c69e22ab 100644 --- a/src/tls/xqc_tls.c +++ b/src/tls/xqc_tls.c @@ -857,8 +857,8 @@ xqc_ssl_alpn_select_cb(SSL *ssl, const unsigned char **out, unsigned char *outle if (XQC_OK != ret) { return SSL_TLSEXT_ERR_ALERT_FATAL; } - - xqc_log(tls->log, XQC_LOG_DEBUG, "|select alpn|%*s|", alpn_len, alpn); + xqc_log_event(tls->log, TRA_ALPN_INFORMATION, alpn_list, alpn_list_len, in, + inlen, alpn, alpn_len); return SSL_TLSEXT_ERR_OK; } diff --git a/src/transport/fec_schemes/xqc_galois_calculation.c b/src/transport/fec_schemes/xqc_galois_calculation.c new file mode 100644 index 000000000..ced2cec10 --- /dev/null +++ b/src/transport/fec_schemes/xqc_galois_calculation.c @@ -0,0 +1,248 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include "src/transport/xqc_conn.h" +#include + + +unsigned char +xqc_galois_multiply(unsigned char a, unsigned char b) +{ + if (a == 0 || b == 0) { + return 0; + } + + unsigned char log_a = xqc_rs_log_table[a]; + unsigned char log_b = xqc_rs_log_table[b]; + + return xqc_rs_exp_table[log_a + log_b]; +} + +unsigned char +xqc_galois_exp(unsigned char a, unsigned char n) +{ + unsigned char log_a, log_r; + if (n == 0) { + return 1; + } + + if (a == 0) { + return 0; + } + + log_a = xqc_rs_log_table[a]; + log_r = (log_a * n) % 255; + + return xqc_rs_exp_table[log_r]; +} + +xqc_int_t +xqc_galois_divide(unsigned char a, unsigned char b, unsigned char *res) +{ + if (a == 0) { + *res = 0; + return XQC_OK; + } + + if (b == 0) { + return -XQC_EPARAM; + } + + unsigned char log_a = xqc_rs_log_table[a]; + unsigned char log_b = xqc_rs_log_table[b]; + unsigned char log_r = 0; + + if (log_a < log_b) { + log_r += 255; + } + + log_r += log_a - log_b; + *res = xqc_rs_exp_table[log_r]; + + return XQC_OK; +} + +unsigned char +xqc_galois_inversion(unsigned char a) +{ + uint16_t i = 0; + if (a == 0) { + return 0; + } + for (i = 1; i < 256; i++) { + if (xqc_galois_multiply(a, i) == 1) { + return i; + } + } + return 0; +} + + +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, + 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++) { + *(submatrix + (row_i - row_min) * col_max_sub + col_i - col_min) = *(matrix + row_i * col_max_matrix + col_i); + } + } +} + +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++) { + Vandermonde[i][j] = (unsigned char)xqc_galois_exp(i, j); + } + } +} + + + +/* Generate a identity matrix with given size */ +xqc_int_t +xqc_identity_matrix(unsigned char size, unsigned char (*output)[XQC_MAX_MT_ROW]) +{ + for (unsigned char i = 0; i < size; i++) { + xqc_memset(output[i], 0, XQC_MAX_MT_ROW); + output[i][i] = 1; + } + return XQC_OK; +} + +/* concatenate 2 matrices horizontally */ +xqc_int_t +xqc_concatenate_matrix(unsigned char (*left)[XQC_MAX_MT_ROW], unsigned char (*right)[XQC_MAX_MT_ROW], + unsigned char left_rows, unsigned char right_rows, + unsigned char left_cols, unsigned char right_cols, + unsigned char (*output)[2*XQC_MAX_MT_ROW]) +{ + if (left_rows != right_rows) { + 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++) { + output[row_i][col_i] = left[row_i][col_i]; + } + for (unsigned char col_i = 0; col_i < right_cols; col_i++) { + output[row_i][left_cols + col_i] = right[row_i][col_i]; + } + } + return XQC_OK; +} + + +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; + unsigned char ratio = 0; + for (row_i = 0; row_i < rows; row_i++) { + max_row = row_i; + for (i = row_i + 1; i < rows; i++) { + if (output[i][row_i] > output[max_row][row_i]) { + max_row = i; + } + } + + for (col_i = row_i; col_i < cols; col_i++) { + tmp = output[max_row][col_i]; + output[max_row][col_i] = output[row_i][col_i]; + output[row_i][col_i] = tmp; + } + + if (output[row_i][row_i] == 0) { + return -XQC_EFEC_SCHEME_ERROR; + } + + inv = xqc_galois_inversion(output[row_i][row_i]); + for (col_i = row_i; col_i < cols; col_i++) { + output[row_i][col_i] = xqc_galois_multiply(output[row_i][col_i], inv); + } + + for (i = row_i + 1; i < rows; i++) { + tmp = output[i][row_i]; + for (col_i = row_i; col_i < cols; col_i++) { + output[i][col_i] ^= xqc_galois_multiply(tmp, output[row_i][col_i]); + } + } + } + + for (row_i = 0; row_i < rows; row_i++) { + for (row_above = 0; row_above < row_i; row_above++) { + if (output[row_above][row_i] != 0) { + ratio = output[row_above][row_i]; + for (col_i = 0; col_i < cols; col_i++) { + output[row_above][col_i] ^= xqc_galois_multiply(ratio, output[row_i][col_i]); + } + } + } + } + return XQC_OK; +} + +xqc_int_t +xqc_invert_matrix(unsigned char rows, unsigned char cols, unsigned char (*output)[XQC_MAX_MT_ROW]) +{ + xqc_int_t ret; + if (rows != cols) { + return -XQC_EPARAM; + } + unsigned char identity_matrix[XQC_MAX_MT_ROW][XQC_MAX_MT_ROW], tmp_matrix[XQC_MAX_MT_ROW][2 * XQC_MAX_MT_ROW]; + if (xqc_identity_matrix(rows, identity_matrix) != XQC_OK) { + return -XQC_EPARAM; + } + + if (xqc_concatenate_matrix(output, identity_matrix, rows, rows, cols, rows, tmp_matrix) != XQC_OK) { + return -XQC_EPARAM; + } + + ret = xqc_gaussian_elimination(rows, rows + cols, tmp_matrix); + if (ret != XQC_OK) { + return ret; + } + + xqc_submatrix(0, rows, cols, 2 * cols, 256, 512, &output[0][0], &tmp_matrix[0][0]); + + return XQC_OK; +} + +xqc_int_t +xqc_matrix_time(unsigned char left_row, unsigned char left_col, + unsigned char (*left)[XQC_MAX_MT_ROW], + unsigned char right_row, unsigned char right_col, + unsigned char (*right)[XQC_MAX_MT_ROW], + unsigned char output_row, unsigned char output_col, + unsigned char (*output)[XQC_MAX_MT_ROW]) +{ + unsigned char value = 0; + if (left_col != right_row + || left_row > output_row + || right_col > output_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++) { + value = 0; + for (unsigned char i = 0; i < left_col; i++) { + value ^= xqc_galois_multiply(left[row_i][i], right[i][col_i]); + } + output[row_i][col_i] = value; + } + } + return XQC_OK; +} + diff --git a/src/transport/fec_schemes/xqc_galois_calculation.h b/src/transport/fec_schemes/xqc_galois_calculation.h new file mode 100644 index 000000000..070eee4a8 --- /dev/null +++ b/src/transport/fec_schemes/xqc_galois_calculation.h @@ -0,0 +1,161 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_GALOIS_CACULATION_H_ +#define _XQC_GALOIS_CACULATION_H_ + + +#include +#include +#include +#include "src/transport/xqc_defs.h" + +/** + * The following table stands for log_a(x) and exp_a(x), + * where a is the polynomial(here we use 29, (2^8 +) 2^4 + 2^3 + 2^2 + 1) used to generate a Galois field of 256 elements. + * and x is in [0, 255]. + */ +static const unsigned char xqc_rs_log_table[256] = { + -1, 0, 1, 25, 2, 50, 26, 198, + 3, 223, 51, 238, 27, 104, 199, 75, + 4, 100, 224, 14, 52, 141, 239, 129, + 28, 193, 105, 248, 200, 8, 76, 113, + 5, 138, 101, 47, 225, 36, 15, 33, + 53, 147, 142, 218, 240, 18, 130, 69, + 29, 181, 194, 125, 106, 39, 249, 185, + 201, 154, 9, 120, 77, 228, 114, 166, + 6, 191, 139, 98, 102, 221, 48, 253, + 226, 152, 37, 179, 16, 145, 34, 136, + 54, 208, 148, 206, 143, 150, 219, 189, + 241, 210, 19, 92, 131, 56, 70, 64, + 30, 66, 182, 163, 195, 72, 126, 110, + 107, 58, 40, 84, 250, 133, 186, 61, + 202, 94, 155, 159, 10, 21, 121, 43, + 78, 212, 229, 172, 115, 243, 167, 87, + 7, 112, 192, 247, 140, 128, 99, 13, + 103, 74, 222, 237, 49, 197, 254, 24, + 227, 165, 153, 119, 38, 184, 180, 124, + 17, 68, 146, 217, 35, 32, 137, 46, + 55, 63, 209, 91, 149, 188, 207, 205, + 144, 135, 151, 178, 220, 252, 190, 97, + 242, 86, 211, 171, 20, 42, 93, 158, + 132, 60, 57, 83, 71, 109, 65, 162, + 31, 45, 67, 216, 183, 123, 164, 118, + 196, 23, 73, 236, 127, 12, 111, 246, + 108, 161, 59, 82, 41, 157, 85, 170, + 251, 96, 134, 177, 187, 204, 62, 90, + 203, 89, 95, 176, 156, 169, 160, 81, + 11, 245, 22, 235, 122, 117, 44, 215, + 79, 174, 213, 233, 230, 231, 173, 232, + 116, 214, 244, 234, 168, 80, 88, 175 +}; + +static const unsigned char xqc_rs_exp_table[510] = { + 1, 2, 4, 8, 16, 32, 64, -128, + 29, 58, 116, -24, -51, -121, 19, 38, + 76, -104, 45, 90, -76, 117, -22, -55, + -113, 3, 6, 12, 24, 48, 96, -64, + -99, 39, 78, -100, 37, 74, -108, 53, + 106, -44, -75, 119, -18, -63, -97, 35, + 70, -116, 5, 10, 20, 40, 80, -96, + 93, -70, 105, -46, -71, 111, -34, -95, + 95, -66, 97, -62, -103, 47, 94, -68, + 101, -54, -119, 15, 30, 60, 120, -16, + -3, -25, -45, -69, 107, -42, -79, 127, + -2, -31, -33, -93, 91, -74, 113, -30, + -39, -81, 67, -122, 17, 34, 68, -120, + 13, 26, 52, 104, -48, -67, 103, -50, + -127, 31, 62, 124, -8, -19, -57, -109, + 59, 118, -20, -59, -105, 51, 102, -52, + -123, 23, 46, 92, -72, 109, -38, -87, + 79, -98, 33, 66, -124, 21, 42, 84, + -88, 77, -102, 41, 82, -92, 85, -86, + 73, -110, 57, 114, -28, -43, -73, 115, + -26, -47, -65, 99, -58, -111, 63, 126, + -4, -27, -41, -77, 123, -10, -15, -1, + -29, -37, -85, 75, -106, 49, 98, -60, + -107, 55, 110, -36, -91, 87, -82, 65, + -126, 25, 50, 100, -56, -115, 7, 14, + 28, 56, 112, -32, -35, -89, 83, -90, + 81, -94, 89, -78, 121, -14, -7, -17, + -61, -101, 43, 86, -84, 69, -118, 9, + 18, 36, 72, -112, 61, 122, -12, -11, + -9, -13, -5, -21, -53, -117, 11, 22, + 44, 88, -80, 125, -6, -23, -49, -125, + 27, 54, 108, -40, -83, 71, -114, + // Repeat the table a second time, so multiply() + // does not have to check bounds. + 1, 2, 4, 8, 16, 32, 64, -128, + 29, 58, 116, -24, -51, -121, 19, 38, + 76, -104, 45, 90, -76, 117, -22, -55, + -113, 3, 6, 12, 24, 48, 96, -64, + -99, 39, 78, -100, 37, 74, -108, 53, + 106, -44, -75, 119, -18, -63, -97, 35, + 70, -116, 5, 10, 20, 40, 80, -96, + 93, -70, 105, -46, -71, 111, -34, -95, + 95, -66, 97, -62, -103, 47, 94, -68, + 101, -54, -119, 15, 30, 60, 120, -16, + -3, -25, -45, -69, 107, -42, -79, 127, + -2, -31, -33, -93, 91, -74, 113, -30, + -39, -81, 67, -122, 17, 34, 68, -120, + 13, 26, 52, 104, -48, -67, 103, -50, + -127, 31, 62, 124, -8, -19, -57, -109, + 59, 118, -20, -59, -105, 51, 102, -52, + -123, 23, 46, 92, -72, 109, -38, -87, + 79, -98, 33, 66, -124, 21, 42, 84, + -88, 77, -102, 41, 82, -92, 85, -86, + 73, -110, 57, 114, -28, -43, -73, 115, + -26, -47, -65, 99, -58, -111, 63, 126, + -4, -27, -41, -77, 123, -10, -15, -1, + -29, -37, -85, 75, -106, 49, 98, -60, + -107, 55, 110, -36, -91, 87, -82, 65, + -126, 25, 50, 100, -56, -115, 7, 14, + 28, 56, 112, -32, -35, -89, 83, -90, + 81, -94, 89, -78, 121, -14, -7, -17, + -61, -101, 43, 86, -84, 69, -118, 9, + 18, 36, 72, -112, 61, 122, -12, -11, + -9, -13, -5, -21, -53, -117, 11, 22, + 44, 88, -80, 125, -6, -23, -49, -125, + 27, 54, 108, -40, -83, 71, -114 +}; + +unsigned char xqc_galois_multiply(unsigned char a, unsigned char b); +unsigned char xqc_galois_exp(unsigned char a, unsigned char n); + +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, + unsigned char *submatrix, unsigned char *matrix); + +xqc_int_t xqc_matrix_time(unsigned char left_row, unsigned char left_col, + unsigned char (*left)[XQC_MAX_MT_ROW], + unsigned char right_row, unsigned char right_col, + unsigned char (*right)[XQC_MAX_MT_ROW], + unsigned char output_row, unsigned char output_col, + unsigned char (*output)[XQC_MAX_MT_ROW]); + + +xqc_int_t xqc_identity_matrix(unsigned char size, unsigned char (*output)[XQC_MAX_MT_ROW]); + +xqc_int_t xqc_concatenate_matrix(unsigned char (*left)[XQC_MAX_MT_ROW], unsigned char (*right)[XQC_MAX_MT_ROW], + unsigned char left_rows, unsigned char right_rows, + unsigned char left_cols, unsigned char right_cols, + unsigned char (*output)[2*XQC_MAX_MT_ROW]); + + +xqc_int_t xqc_gaussian_elimination(unsigned char rows, unsigned char cols, + unsigned char (*output)[2*XQC_MAX_MT_ROW]); + +xqc_int_t xqc_invert_matrix(unsigned char rows, unsigned char cols, unsigned char (*output)[XQC_MAX_MT_ROW]); + + +#endif \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_reed_solomon.c b/src/transport/fec_schemes/xqc_reed_solomon.c new file mode 100644 index 000000000..7eaff5994 --- /dev/null +++ b/src/transport/fec_schemes/xqc_reed_solomon.c @@ -0,0 +1,227 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited +*/ + + +#include "src/transport/fec_schemes/xqc_reed_solomon.h" +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include "src/transport/xqc_conn.h" + + +void +xqc_build_generator_matrix(unsigned char src_symbol_num, unsigned char total_symbol_num, + unsigned char (*GM)[XQC_MAX_MT_ROW]) +{ + unsigned char tmp_GM[XQC_MAX_MT_ROW][XQC_MAX_MT_ROW], invert_GM[XQC_MAX_MT_ROW][XQC_MAX_MT_ROW]; + + xqc_build_vandermonde_matrix(total_symbol_num, src_symbol_num, tmp_GM); + /* invert GM rows corresponds to src symbols */ + xqc_submatrix(0, src_symbol_num, 0, src_symbol_num, 256, 256, &invert_GM[0][0], &tmp_GM[0][0]); + + xqc_invert_matrix(src_symbol_num, src_symbol_num, invert_GM); + + xqc_matrix_time(total_symbol_num, src_symbol_num, tmp_GM, + src_symbol_num, src_symbol_num, invert_GM, + total_symbol_num, src_symbol_num, GM); +} + +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 +xqc_rs_code_one_symbol(unsigned char (*GM_rows)[XQC_MAX_MT_ROW], unsigned char *input, unsigned char **outputs, + xqc_int_t outputs_rows_num, xqc_int_t item_size, xqc_int_t input_idx) +{ + xqc_int_t output_i, j; + unsigned char *output_p, *gm_p; + output_i = 0; + + if (input_idx > XQC_MAX_MT_ROW) { + return -XQC_EFEC_SCHEME_ERROR; + } + + for (output_i = 0; output_i < outputs_rows_num; output_i++) { + /* 一个单位的repair key的长度为symbollen */ + if (outputs[output_i] == NULL) { + if (input_idx != 0) { + return -XQC_EFEC_SCHEME_ERROR; + } + return -XQC_EMALLOC; + } + + if (input_idx == 0) { + xqc_memset(outputs[output_i], 0, item_size); + } + output_p = outputs[output_i]; + gm_p = GM_rows[output_i]; + for (j = 0; j < item_size; j++) { + *(output_p + j) ^= xqc_galois_multiply(*(gm_p + input_idx), *(input + j)); + } + } + return XQC_OK; +} + +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) +{ + xqc_int_t input_i, output_i, ret; + unsigned char *input_p, *output_p, *gm_p; + input_i = output_i = 0; + + /** + * outputs[i][byte j] = GM_rows[i][0]*Inputs[0][bytej] + GM_rows[i][1]*Inputs[1][bytej] + ... + * The "+" is equal to XOR in galois fields + */ + for (input_i = 0; input_i < inputs_rows_num; input_i++) { + input_p = inputs[input_i]; + ret = xqc_rs_code_one_symbol(GM_rows, input_p, outputs, outputs_rows_num, item_size, input_i); + if (ret != XQC_OK) { + return ret; + } + } + + return XQC_OK; +} + +xqc_int_t +xqc_reed_solomon_encode(xqc_connection_t *conn, unsigned char *stream, unsigned char **outputs) +{ + 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; + /* 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); + 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_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]; + symbol_idx = 0; + + 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; + } + xqc_memcpy(GM[i], conn->fec_ctl->fec_recv_repair_key[block_idx][j].payload, conn->remote_settings.fec_max_symbols_num); + j++; + } + } + 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) +{ + /** + * 根据fec_recv_symbols_buff和fec_recv_repair_key复原丢失的srcsymbol: + * 1. 生成GM的逆矩阵 + * 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]; + + 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; + } + 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++; + } + } + 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; + } + + ret = xqc_rs_code_symbols(GM, recv_symbols_buff, recv_symbols_num, + recovered_symbols_buff, recv_symbols_num, + symbol_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 < recv_symbols_num; i++) { + if (recovered_symbols_buff[i] != NULL) { + xqc_free(recovered_symbols_buff[i]); + } + } + + return ret; +} + + +const xqc_fec_code_callback_t xqc_reed_solomon_code_cb = { + .xqc_fec_init = xqc_reed_solomon_init, + .xqc_fec_decode = xqc_reed_solomon_decode, + .xqc_fec_encode = xqc_reed_solomon_encode, + // .destroy = xqc_rs_destroy, +}; \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_reed_solomon.h b/src/transport/fec_schemes/xqc_reed_solomon.h new file mode 100644 index 000000000..865a25693 --- /dev/null +++ b/src/transport/fec_schemes/xqc_reed_solomon.h @@ -0,0 +1,31 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_REED_SOLOMON_H_ +#define _XQC_FEC_REED_SOLOMON_H_ + + +#include +#include +#include +#include "src/transport/xqc_defs.h" + +extern const xqc_fec_code_callback_t xqc_reed_solomon_code_cb; + +xqc_int_t xqc_rs_code_one_symbol(unsigned char (*GM_rows)[XQC_MAX_MT_ROW], unsigned char *input, unsigned char **outputs, + xqc_int_t outputs_rows_num, xqc_int_t item_size, xqc_int_t input_idx); +void xqc_build_generator_matrix(unsigned char src_symbol_num, unsigned char total_symbol_num, + unsigned char (*GM)[XQC_MAX_MT_ROW]); + +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); + +#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 new file mode 100644 index 000000000..7ceb457b8 --- /dev/null +++ b/src/transport/fec_schemes/xqc_xor.c @@ -0,0 +1,117 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited +*/ + + +#include "src/transport/fec_schemes/xqc_xor.h" +#include "src/transport/xqc_conn.h" + +void +xqc_xor_init(xqc_connection_t *conn) +{ + return; +} + +xqc_int_t +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) { + return -XQC_EMALLOC; + } + + output_p = *outputs; + for (i = 0; i < item_size; i++) { + *(output_p + i) ^= *(input + i); + } + + return XQC_OK; +} + +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 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; + } + } + + 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 (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; + } + + 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; + } + + return XQC_OK; +} + +xqc_int_t +xqc_xor_encode(xqc_connection_t *conn, unsigned char *stream, unsigned char **outputs) +{ + size_t stream_size; + xqc_int_t ret; + + stream_size = conn->conn_settings.fec_params.fec_max_symbol_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; + } + + return XQC_OK; +} + +const xqc_fec_code_callback_t xqc_xor_code_cb = { + .xqc_fec_init = xqc_xor_init, + .xqc_fec_decode = xqc_xor_decode, + .xqc_fec_encode = xqc_xor_encode, + // .destroy = xqc_rs_destroy, +}; \ No newline at end of file diff --git a/src/transport/fec_schemes/xqc_xor.h b/src/transport/fec_schemes/xqc_xor.h new file mode 100644 index 000000000..04da0f012 --- /dev/null +++ b/src/transport/fec_schemes/xqc_xor.h @@ -0,0 +1,28 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_XOR_H_ +#define _XQC_FEC_XOR_H_ + + +#include "src/transport/fec_schemes/xqc_xor.h" +#include "src/transport/fec_schemes/xqc_galois_calculation.h" +#include +#include +#include + +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); + +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); + +#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 420890088..1b4325c78 100644 --- a/src/transport/reinjection_control/xqc_reinj_deadline.c +++ b/src/transport/reinjection_control/xqc_reinj_deadline.c @@ -88,7 +88,7 @@ xqc_deadline_reinj_can_reinject_before_sched(xqc_deadline_reinj_ctl_t *rctl, "lower_bound:%ui|now:%ui|sent_time:%ui|frame:%s|", deadline, factor, min_srtt, flexible, hard, lower_bound, now, po->po_sent_time, - xqc_frame_type_2_str(po->po_frame_types)); + xqc_frame_type_2_str(conn->engine, po->po_frame_types)); if ((double)(now - po->po_sent_time) >= deadline) { return XQC_TRUE; diff --git a/src/transport/scheduler/xqc_scheduler_backup.c b/src/transport/scheduler/xqc_scheduler_backup.c index 3e4da39e6..32cc1db22 100644 --- a/src/transport/scheduler/xqc_scheduler_backup.c +++ b/src/transport/scheduler/xqc_scheduler_backup.c @@ -34,10 +34,10 @@ xqc_backup_scheduler_get_path(void *scheduler, xqc_connection_t *conn, xqc_list_head_t *pos, *next; xqc_path_ctx_t *path; xqc_send_ctl_t *send_ctl; - xqc_bool_t path_can_send; + xqc_bool_t path_can_send = XQC_FALSE; /* min RTT */ - uint64_t path_srtt; + uint64_t path_srtt = 0; xqc_bool_t reached_cwnd_check = XQC_FALSE; if (cc_blocked) { @@ -122,7 +122,7 @@ xqc_backup_scheduler_get_path(void *scheduler, xqc_connection_t *conn, xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|" "pn:%ui|size:%ud|reinj:%d|path_class:%d|", best_path[path_class]->path_id, - xqc_frame_type_2_str(packet_out->po_frame_types), + 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 best_path[path_class]; diff --git a/src/transport/scheduler/xqc_scheduler_interop.c b/src/transport/scheduler/xqc_scheduler_interop.c index 32380cb6f..3c22ed975 100644 --- a/src/transport/scheduler/xqc_scheduler_interop.c +++ b/src/transport/scheduler/xqc_scheduler_interop.c @@ -100,7 +100,7 @@ xqc_interop_scheduler_get_path(void *scheduler, if (best_path) { xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|app_status:%d|", - best_path->path_id, xqc_frame_type_2_str(packet_out->po_frame_types), + best_path->path_id, xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), best_path->app_path_status); } diff --git a/src/transport/scheduler/xqc_scheduler_minrtt.c b/src/transport/scheduler/xqc_scheduler_minrtt.c index f9e35f061..7907c1b72 100644 --- a/src/transport/scheduler/xqc_scheduler_minrtt.c +++ b/src/transport/scheduler/xqc_scheduler_minrtt.c @@ -32,9 +32,9 @@ xqc_minrtt_scheduler_get_path(void *scheduler, xqc_send_ctl_t *send_ctl; /* min RTT */ - uint64_t path_srtt; + uint64_t path_srtt = 0; xqc_bool_t reached_cwnd_check = XQC_FALSE; - xqc_bool_t path_can_send; + xqc_bool_t path_can_send = XQC_FALSE; if (cc_blocked) { *cc_blocked = XQC_FALSE; @@ -103,7 +103,7 @@ xqc_minrtt_scheduler_get_path(void *scheduler, xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|" "pn:%ui|size:%ud|reinj:%d|path_class:%d|", best_path[path_class]->path_id, - xqc_frame_type_2_str(packet_out->po_frame_types), + 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 best_path[path_class]; diff --git a/src/transport/scheduler/xqc_scheduler_rap.c b/src/transport/scheduler/xqc_scheduler_rap.c index 96a13373d..9aea931b0 100644 --- a/src/transport/scheduler/xqc_scheduler_rap.c +++ b/src/transport/scheduler/xqc_scheduler_rap.c @@ -99,7 +99,7 @@ xqc_rap_scheduler_get_path(void *scheduler, } else { xqc_log(conn->log, XQC_LOG_DEBUG, "|best path:%ui|frame_type:%s|", - best_path->path_id, xqc_frame_type_2_str(packet_out->po_frame_types)); + best_path->path_id, xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); } return best_path; diff --git a/src/transport/xqc_cid.c b/src/transport/xqc_cid.c index 8458fd117..3c3d062aa 100644 --- a/src/transport/xqc_cid.c +++ b/src/transport/xqc_cid.c @@ -82,32 +82,30 @@ xqc_cid_set(xqc_cid_t *cid, const unsigned char *data, uint8_t len) } } -static unsigned char g_scid_buf[XQC_MAX_CID_LEN * 2 + 1]; -static unsigned char g_dcid_buf[XQC_MAX_CID_LEN * 2 + 1]; static unsigned char g_sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2 + 1]; unsigned char * -xqc_dcid_str(const xqc_cid_t *dcid) +xqc_dcid_str(xqc_engine_t *engine, const xqc_cid_t *dcid) { - xqc_hex_dump(g_dcid_buf, dcid->cid_buf, dcid->cid_len); - g_dcid_buf[dcid->cid_len * 2] = '\0'; - return g_dcid_buf; + xqc_hex_dump(engine->dcid_buf, dcid->cid_buf, dcid->cid_len); + engine->dcid_buf[dcid->cid_len * 2] = '\0'; + return engine->dcid_buf; } unsigned char * -xqc_scid_str(const xqc_cid_t *scid) +xqc_scid_str(xqc_engine_t *engine, const xqc_cid_t *scid) { - xqc_hex_dump(g_scid_buf, scid->cid_buf, scid->cid_len); - g_scid_buf[scid->cid_len * 2] = '\0'; - return g_scid_buf; + xqc_hex_dump(engine->scid_buf, scid->cid_buf, scid->cid_len); + engine->scid_buf[scid->cid_len * 2] = '\0'; + return engine->scid_buf; } unsigned char * -xqc_sr_token_str(const char *sr_token) +xqc_sr_token_str(xqc_engine_t *engine, const char *sr_token) { - xqc_hex_dump(g_sr_token_buf, sr_token, XQC_STATELESS_RESET_TOKENLEN); - g_sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2] = '\0'; - return g_sr_token_buf; + xqc_hex_dump(engine->sr_token_buf, sr_token, XQC_STATELESS_RESET_TOKENLEN); + engine->sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2] = '\0'; + return engine->sr_token_buf; } unsigned char * diff --git a/src/transport/xqc_cid.h b/src/transport/xqc_cid.h index 411dfcdb2..56ed4cde5 100644 --- a/src/transport/xqc_cid.h +++ b/src/transport/xqc_cid.h @@ -77,7 +77,7 @@ xqc_int_t xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid); xqc_bool_t xqc_validate_retire_cid_frame(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid); -unsigned char *xqc_sr_token_str(const char *sr_token); +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 48c2609a8..184cff2c8 100644 --- a/src/transport/xqc_client.c +++ b/src/transport/xqc_client.c @@ -68,7 +68,6 @@ xqc_client_connect(xqc_engine_t *engine, const xqc_conn_settings_t *conn_setting return NULL; } - xqc_log(engine->log, XQC_LOG_DEBUG, "|xqc_connect|"); xqc_log_event(xc->log, CON_CONNECTION_STARTED, xc, XQC_LOG_REMOTE_EVENT); /* conn_create callback */ diff --git a/src/transport/xqc_conn.c b/src/transport/xqc_conn.c index 6b39a41ad..62ac6994e 100644 --- a/src/transport/xqc_conn.c +++ b/src/transport/xqc_conn.c @@ -27,12 +27,15 @@ #include "src/transport/xqc_wakeup_pq.h" #include "src/transport/xqc_multipath.h" #include "src/transport/xqc_reinjection.h" -#include "src/tls/xqc_tls.h" #include "src/transport/xqc_datagram.h" +#include "src/transport/xqc_packet.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_fec_scheme.h" +#include "src/tls/xqc_tls.h" #include -xqc_conn_settings_t default_conn_settings = { +xqc_conn_settings_t internal_default_conn_settings = { .pacing_on = 0, .ping_on = 0, .so_sndbuf = 0, @@ -70,6 +73,7 @@ xqc_conn_settings_t default_conn_settings = { .recv_rate_bytes_per_sec = 0, .enable_stream_rate_limit = 0, + .close_dgram_redundancy= XQC_RED_NOT_USE, .scheduler_params = { .bw_Bps_thr = 375000, @@ -83,6 +87,20 @@ xqc_conn_settings_t default_conn_settings = { #ifdef XQC_PROTECT_POOL_MEM .protect_pool_mem = 0, #endif + .enable_encode_fec = 0, + .enable_decode_fec = 0, + .fec_params = { + .fec_code_rate = XQC_FEC_CODE_RATE_DEFAULT, + .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_encoder_schemes_num = 0, + .fec_decoder_schemes_num = 0, + .fec_encoder_scheme = 0, + .fec_decoder_scheme = 0, + }, }; @@ -102,125 +120,149 @@ xqc_conn_dgram_probe_timeout(xqc_gp_timer_id_t gp_timer_id, void -xqc_server_set_conn_settings(const xqc_conn_settings_t *settings) -{ - default_conn_settings.cong_ctrl_callback = settings->cong_ctrl_callback; - default_conn_settings.cc_params = settings->cc_params; - default_conn_settings.scheduler_params = settings->scheduler_params; - default_conn_settings.pacing_on = settings->pacing_on; - default_conn_settings.ping_on = settings->ping_on; - default_conn_settings.so_sndbuf = settings->so_sndbuf; - default_conn_settings.sndq_packets_used_max = settings->sndq_packets_used_max; - default_conn_settings.linger = settings->linger; - default_conn_settings.spurious_loss_detect_on = settings->spurious_loss_detect_on; - default_conn_settings.datagram_force_retrans_on = settings->datagram_force_retrans_on; - default_conn_settings.enable_pmtud = settings->enable_pmtud; - default_conn_settings.marking_reinjection = settings->marking_reinjection; - default_conn_settings.mp_ack_on_any_path = settings->mp_ack_on_any_path; - default_conn_settings.mp_ping_on = settings->mp_ping_on; - default_conn_settings.recv_rate_bytes_per_sec = settings->recv_rate_bytes_per_sec; - default_conn_settings.enable_stream_rate_limit = settings->enable_stream_rate_limit; - default_conn_settings.init_recv_window = settings->init_recv_window; - default_conn_settings.initial_rtt = settings->initial_rtt; - default_conn_settings.initial_pto_duration = settings->initial_pto_duration; +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; + engine->default_conn_settings.sndq_packets_used_max = settings->sndq_packets_used_max; + engine->default_conn_settings.linger = settings->linger; + engine->default_conn_settings.spurious_loss_detect_on = settings->spurious_loss_detect_on; + engine->default_conn_settings.datagram_force_retrans_on = settings->datagram_force_retrans_on; + engine->default_conn_settings.enable_pmtud = settings->enable_pmtud; + engine->default_conn_settings.marking_reinjection = settings->marking_reinjection; + engine->default_conn_settings.mp_ack_on_any_path = settings->mp_ack_on_any_path; + engine->default_conn_settings.mp_ping_on = settings->mp_ping_on; + engine->default_conn_settings.recv_rate_bytes_per_sec = settings->recv_rate_bytes_per_sec; + engine->default_conn_settings.enable_stream_rate_limit = settings->enable_stream_rate_limit; + 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; #ifdef XQC_PROTECT_POOL_MEM - default_conn_settings.protect_pool_mem = settings->protect_pool_mem; + engine->default_conn_settings.protect_pool_mem = settings->protect_pool_mem; #endif - default_conn_settings.adaptive_ack_frequency = settings->adaptive_ack_frequency; + engine->default_conn_settings.adaptive_ack_frequency = settings->adaptive_ack_frequency; - if (default_conn_settings.init_recv_window) { - default_conn_settings.init_recv_window = xqc_max(default_conn_settings.init_recv_window, XQC_QUIC_MAX_MSS); + 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); } if (settings->pmtud_probing_interval) { - default_conn_settings.pmtud_probing_interval = settings->pmtud_probing_interval; + engine->default_conn_settings.pmtud_probing_interval = settings->pmtud_probing_interval; } if (settings->max_ack_delay) { - default_conn_settings.max_ack_delay = xqc_min(settings->max_ack_delay, XQC_DEFAULT_MAX_ACK_DELAY); + engine->default_conn_settings.max_ack_delay = xqc_min(settings->max_ack_delay, XQC_DEFAULT_MAX_ACK_DELAY); } if (settings->datagram_redundant_probe) { - default_conn_settings.datagram_redundant_probe = xqc_max(settings->datagram_redundant_probe, + engine->default_conn_settings.datagram_redundant_probe = xqc_max(settings->datagram_redundant_probe, XQC_MIN_DATAGRAM_REDUNDANT_PROBE_INTERVAL); } if (settings->datagram_redundancy <= XQC_MAX_DATAGRAM_REDUNDANCY) { - default_conn_settings.datagram_redundancy = settings->datagram_redundancy; + engine->default_conn_settings.datagram_redundancy = settings->datagram_redundancy; } if (settings->init_idle_time_out > 0) { - default_conn_settings.init_idle_time_out = settings->init_idle_time_out; + engine->default_conn_settings.init_idle_time_out = settings->init_idle_time_out; } if (settings->idle_time_out > 0) { - default_conn_settings.idle_time_out = settings->idle_time_out; + engine->default_conn_settings.idle_time_out = settings->idle_time_out; } if (settings->anti_amplification_limit > XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT) { - default_conn_settings.anti_amplification_limit = settings->anti_amplification_limit; + engine->default_conn_settings.anti_amplification_limit = settings->anti_amplification_limit; } if (xqc_check_proto_version_valid(settings->proto_version)) { - default_conn_settings.proto_version = settings->proto_version; + engine->default_conn_settings.proto_version = settings->proto_version; } - default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; - default_conn_settings.max_datagram_frame_size = settings->max_datagram_frame_size; + engine->default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; + engine->default_conn_settings.max_datagram_frame_size = settings->max_datagram_frame_size; - if (settings->max_pkt_out_size > default_conn_settings.max_pkt_out_size) { - default_conn_settings.max_pkt_out_size = settings->max_pkt_out_size; + if (settings->max_pkt_out_size > engine->default_conn_settings.max_pkt_out_size) { + engine->default_conn_settings.max_pkt_out_size = settings->max_pkt_out_size; } - if (default_conn_settings.max_pkt_out_size > XQC_MAX_PACKET_OUT_SIZE) { - default_conn_settings.max_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; + if (engine->default_conn_settings.max_pkt_out_size > XQC_MAX_PACKET_OUT_SIZE) { + engine->default_conn_settings.max_pkt_out_size = XQC_MAX_PACKET_OUT_SIZE; } - default_conn_settings.enable_multipath = settings->enable_multipath; - default_conn_settings.is_interop_mode = settings->is_interop_mode; + engine->default_conn_settings.enable_multipath = settings->enable_multipath; + engine->default_conn_settings.is_interop_mode = settings->is_interop_mode; if (xqc_conn_is_current_mp_version_supported(settings->multipath_version) == XQC_OK) { - default_conn_settings.multipath_version = settings->multipath_version; + engine->default_conn_settings.multipath_version = settings->multipath_version; } else { - default_conn_settings.multipath_version = XQC_MULTIPATH_04; + engine->default_conn_settings.multipath_version = XQC_MULTIPATH_04; + } + + engine->default_conn_settings.close_dgram_redundancy = settings->close_dgram_redundancy; + +#ifdef XQC_ENABLE_FEC + engine->default_conn_settings.enable_encode_fec = settings->enable_encode_fec; + if (engine->default_conn_settings.enable_encode_fec) { + xqc_set_fec_schemes(settings->fec_params.fec_encoder_schemes, settings->fec_params.fec_encoder_schemes_num, + 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; } - default_conn_settings.scheduler_callback = settings->scheduler_callback; - default_conn_settings.reinj_ctl_callback = settings->reinj_ctl_callback; - default_conn_settings.mp_enable_reinjection = settings->mp_enable_reinjection; + engine->default_conn_settings.enable_decode_fec = settings->enable_decode_fec; + if (engine->default_conn_settings.enable_decode_fec) { + xqc_set_fec_schemes(settings->fec_params.fec_decoder_schemes, settings->fec_params.fec_decoder_schemes_num, + engine->default_conn_settings.fec_params.fec_decoder_schemes, &engine->default_conn_settings.fec_params.fec_decoder_schemes_num); + /* 如果一个fec scheme都没有设置成功, enable_decode_fec被置0 */ + engine->default_conn_settings.enable_decode_fec = engine->default_conn_settings.fec_params.fec_decoder_schemes_num == 0 ? 0 : settings->enable_decode_fec; + if (settings->fec_params.fec_max_window_size) { + engine->default_conn_settings.fec_params.fec_max_window_size = xqc_min(settings->fec_params.fec_max_window_size, XQC_SYMBOL_CACHE_LEN); + } + } + +#endif + + engine->default_conn_settings.scheduler_callback = settings->scheduler_callback; + engine->default_conn_settings.reinj_ctl_callback = settings->reinj_ctl_callback; + engine->default_conn_settings.mp_enable_reinjection = settings->mp_enable_reinjection; if (settings->ack_frequency > 0) { - default_conn_settings.ack_frequency = settings->ack_frequency; + engine->default_conn_settings.ack_frequency = settings->ack_frequency; } if (settings->pto_backoff_factor > 0) { - default_conn_settings.pto_backoff_factor = settings->pto_backoff_factor; + engine->default_conn_settings.pto_backoff_factor = settings->pto_backoff_factor; } if (settings->loss_detection_pkt_thresh > 0) { - default_conn_settings.loss_detection_pkt_thresh = settings->loss_detection_pkt_thresh; + engine->default_conn_settings.loss_detection_pkt_thresh = settings->loss_detection_pkt_thresh; } if (settings->reinj_flexible_deadline_srtt_factor > 0) { - default_conn_settings.reinj_flexible_deadline_srtt_factor = settings->reinj_flexible_deadline_srtt_factor; + engine->default_conn_settings.reinj_flexible_deadline_srtt_factor = settings->reinj_flexible_deadline_srtt_factor; } if (settings->reinj_hard_deadline > 0) { - default_conn_settings.reinj_hard_deadline = settings->reinj_hard_deadline; + engine->default_conn_settings.reinj_hard_deadline = settings->reinj_hard_deadline; } if (settings->reinj_deadline_lower_bound > 0) { - default_conn_settings.reinj_deadline_lower_bound = settings->reinj_deadline_lower_bound; + engine->default_conn_settings.reinj_deadline_lower_bound = settings->reinj_deadline_lower_bound; } if (settings->standby_path_probe_timeout > 0) { /* no less than 500ms */ - default_conn_settings.standby_path_probe_timeout = xqc_max(settings->standby_path_probe_timeout, XQC_MIN_STANDBY_RPOBE_TIMEOUT); + engine->default_conn_settings.standby_path_probe_timeout = xqc_max(settings->standby_path_probe_timeout, XQC_MIN_STANDBY_RPOBE_TIMEOUT); } if (settings->keyupdate_pkt_threshold != UINT64_MAX) { - default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; + engine->default_conn_settings.keyupdate_pkt_threshold = settings->keyupdate_pkt_threshold; } } @@ -268,26 +310,26 @@ static const char * const xqc_conn_flag_to_str[XQC_CONN_FLAG_SHIFT_NUM] = { [XQC_CONN_FLAG_MP_READY_NOTIFY_SHIFT] = "MP_READY", }; -unsigned char g_conn_flag_buf[1024]; const char * -xqc_conn_flag_2_str(xqc_conn_flag_t conn_flag) +xqc_conn_flag_2_str(xqc_connection_t *conn, xqc_conn_flag_t conn_flag) { - g_conn_flag_buf[0] = '\0'; + xqc_engine_t *engine = conn->engine; + engine->conn_flag_str_buf[0] = '\0'; size_t pos = 0; int wsize; for (int i = 0; i < XQC_CONN_FLAG_SHIFT_NUM; i++) { if (conn_flag & 1ULL << i) { - wsize = snprintf(g_conn_flag_buf + pos, sizeof(g_conn_flag_buf) - pos, "%s ", + wsize = snprintf(engine->conn_flag_str_buf + pos, sizeof(engine->conn_flag_str_buf) - pos, "%s ", xqc_conn_flag_to_str[i]); - if (wsize < 0 || wsize >= sizeof(g_conn_flag_buf) - pos) { + if (wsize < 0 || wsize >= sizeof(engine->conn_flag_str_buf) - pos) { break; } pos += wsize; } } - return g_conn_flag_buf; + return engine->conn_flag_str_buf; } static const char * const xqc_conn_state_to_str[XQC_CONN_STATE_N] = { @@ -417,6 +459,29 @@ xqc_conn_init_trans_settings(xqc_connection_t *conn) } } } + + ls->close_dgram_redundancy = conn->conn_settings.close_dgram_redundancy; + +#ifdef XQC_ENABLE_FEC + /* 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_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]; + } + } + if (conn->conn_settings.enable_decode_fec) { + ls->enable_decode_fec = conn->conn_settings.enable_decode_fec; + ls->fec_decoder_schemes_num = conn->conn_settings.fec_params.fec_decoder_schemes_num; + for (xqc_int_t i = 0; i < conn->conn_settings.fec_params.fec_decoder_schemes_num; i++) { + ls->fec_decoder_schemes[i] = conn->conn_settings.fec_params.fec_decoder_schemes[i]; + } + } +#endif + } @@ -481,30 +546,30 @@ xqc_conn_init_timer_manager(xqc_connection_t *conn) } void -xqc_conn_set_default_sched_params(xqc_conn_settings_t *settings) +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 = default_conn_settings.scheduler_params.bw_Bps_thr; + 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 = default_conn_settings.scheduler_params.loss_percent_thr_high; + 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 = default_conn_settings.scheduler_params.loss_percent_thr_low; + 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 = default_conn_settings.scheduler_params.pto_cnt_thr; + 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 = default_conn_settings.scheduler_params.rtt_us_thr_high; + 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 = default_conn_settings.scheduler_params.rtt_us_thr_low; + settings->scheduler_params.rtt_us_thr_low = engine->default_conn_settings.scheduler_params.rtt_us_thr_low; } } @@ -535,7 +600,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(&xc->conn_settings); + xqc_conn_set_default_sched_params(engine, &xc->conn_settings); if (xc->conn_settings.initial_rtt == 0) { xc->conn_settings.initial_rtt = XQC_kInitialRtt_us; @@ -551,14 +616,15 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, XQC_MIN_DATAGRAM_REDUNDANT_PROBE_INTERVAL); } - if (xc->conn_settings.datagram_redundancy > XQC_MAX_DATAGRAM_REDUNDANCY) { - xc->conn_settings.datagram_redundancy = XQC_MAX_DATAGRAM_REDUNDANCY; - } - if (xc->conn_settings.mp_enable_reinjection & XQC_REINJ_UNACK_BEFORE_SCHED) { xc->conn_settings.mp_enable_reinjection |= XQC_REINJ_UNACK_AFTER_SEND; } + + if (xc->conn_settings.datagram_redundancy > XQC_MAX_DATAGRAM_REDUNDANCY) { + xc->conn_settings.datagram_redundancy = XQC_MAX_DATAGRAM_REDUNDANCY; + } + if (xc->conn_settings.datagram_redundancy) { if (xc->conn_settings.datagram_redundancy == 1) { /* reinject packets on any path */ @@ -568,7 +634,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, /* do not reinject packets on the same path */ xc->conn_settings.scheduler_callback = xqc_minrtt_scheduler_cb; } - + xc->conn_settings.reinj_ctl_callback = xqc_dgram_reinj_ctl_cb; xc->conn_settings.mp_enable_reinjection |= XQC_REINJ_UNACK_AFTER_SEND; } @@ -584,8 +650,8 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_settings.standby_path_probe_timeout = xqc_max(xc->conn_settings.standby_path_probe_timeout, XQC_MIN_STANDBY_RPOBE_TIMEOUT); } - if (xc->conn_settings.max_pkt_out_size < default_conn_settings.max_pkt_out_size) { - xc->conn_settings.max_pkt_out_size = default_conn_settings.max_pkt_out_size; + if (xc->conn_settings.max_pkt_out_size < engine->default_conn_settings.max_pkt_out_size) { + xc->conn_settings.max_pkt_out_size = engine->default_conn_settings.max_pkt_out_size; } if (xc->conn_settings.max_pkt_out_size > XQC_MAX_PACKET_OUT_SIZE) { @@ -593,19 +659,19 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, } if (xc->conn_settings.pmtud_probing_interval == 0) { - xc->conn_settings.pmtud_probing_interval = default_conn_settings.pmtud_probing_interval; + xc->conn_settings.pmtud_probing_interval = engine->default_conn_settings.pmtud_probing_interval; } if (xc->conn_settings.ack_frequency == 0) { - xc->conn_settings.ack_frequency = default_conn_settings.ack_frequency; + xc->conn_settings.ack_frequency = engine->default_conn_settings.ack_frequency; } if (xc->conn_settings.pto_backoff_factor == 0) { - xc->conn_settings.pto_backoff_factor = default_conn_settings.pto_backoff_factor; + xc->conn_settings.pto_backoff_factor = engine->default_conn_settings.pto_backoff_factor; } if (xc->conn_settings.loss_detection_pkt_thresh == 0) { - xc->conn_settings.loss_detection_pkt_thresh = default_conn_settings.loss_detection_pkt_thresh; + xc->conn_settings.loss_detection_pkt_thresh = engine->default_conn_settings.loss_detection_pkt_thresh; } xc->version = (type == XQC_CONN_TYPE_CLIENT) ? settings->proto_version : XQC_IDRAFT_INIT_VER; @@ -631,17 +697,55 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, } if (xc->conn_settings.reinj_flexible_deadline_srtt_factor == 0) { - xc->conn_settings.reinj_flexible_deadline_srtt_factor = default_conn_settings.reinj_flexible_deadline_srtt_factor; + xc->conn_settings.reinj_flexible_deadline_srtt_factor = engine->default_conn_settings.reinj_flexible_deadline_srtt_factor; } if (xc->conn_settings.reinj_hard_deadline == 0) { - xc->conn_settings.reinj_hard_deadline = default_conn_settings.reinj_hard_deadline; + xc->conn_settings.reinj_hard_deadline = engine->default_conn_settings.reinj_hard_deadline; } if (xqc_conn_is_current_mp_version_supported(xc->conn_settings.multipath_version) != XQC_OK) { xc->conn_settings.multipath_version = XQC_MULTIPATH_04; } +#ifdef XQC_ENABLE_FEC + if (xc->conn_settings.enable_encode_fec + || xc->conn_settings.enable_decode_fec) + { + xc->fec_ctl = xqc_fec_ctl_create(xc); + if (xc->fec_ctl == NULL) { + xc->conn_settings.enable_encode_fec = 0; + xc->conn_settings.enable_decode_fec = 0; + } + } + + if (xc->conn_settings.enable_encode_fec) { + if (xc->conn_settings.fec_params.fec_code_rate == 0) { + xc->conn_settings.fec_params.fec_code_rate = engine->default_conn_settings.fec_params.fec_code_rate; + } + if (xc->conn_settings.fec_params.fec_ele_bit_size == 0) { + xc->conn_settings.fec_params.fec_ele_bit_size = engine->default_conn_settings.fec_params.fec_ele_bit_size; + } + 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.enable_decode_fec) { + if (xc->conn_settings.fec_params.fec_max_window_size) { + xc->conn_settings.fec_params.fec_max_window_size = xqc_min(xc->conn_settings.fec_params.fec_max_window_size, XQC_SYMBOL_CACHE_LEN); + + } else { + xc->conn_settings.fec_params.fec_max_window_size = engine->default_conn_settings.fec_params.fec_max_window_size; + } + } + +#endif xqc_conn_init_trans_settings(xc); xqc_conn_init_flow_ctl(xc); xqc_conn_init_key_update_ctx(xc); @@ -673,8 +777,8 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xqc_cid_copy(&(xc->initial_scid), scid); xc->engine = engine; - xc->log = xqc_log_init(engine->log->log_level, engine->log->log_event, engine->log->log_timestamp, - engine->log->log_level_name, engine->log->log_callbacks, engine->log->user_data); + xc->log = xqc_log_init(engine->log->log_level, engine->log->log_event, engine->log->qlog_importance, engine->log->log_timestamp, + engine->log->log_level_name, engine, engine->log->log_callbacks, engine->log->user_data); xc->log->scid = xc->scid_set.original_scid_str; xc->transport_cbs = engine->transport_cbs; xc->user_data = user_data; @@ -682,6 +786,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->conn_type = type; xc->conn_flag = 0; xc->conn_state = (type == XQC_CONN_TYPE_SERVER) ? XQC_CONN_STATE_SERVER_INIT : XQC_CONN_STATE_CLIENT_INIT; + xqc_log_event(xc->log, CON_CONNECTION_STATE_UPDATED, xc); xc->zero_rtt_count = 0; xc->conn_create_time = xqc_monotonic_timestamp(); xc->handshake_complete_time = 0; @@ -792,6 +897,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xc->reinj_callback->xqc_reinj_ctl_init(xc->reinj_ctl, xc); } + /* * Init paths after the scheduler and the reinjection controller are initialized. */ @@ -807,7 +913,7 @@ xqc_conn_create(xqc_engine_t *engine, xqc_cid_t *dcid, xqc_cid_t *scid, xqc_init_list_head(&xc->ping_notification_list); xqc_log(xc->log, XQC_LOG_DEBUG, "|success|scid:%s|dcid:%s|conn:%p|", - xqc_scid_str(&xc->scid_set.user_scid), xqc_dcid_str(&xc->dcid_set.current_dcid), xc); + xqc_scid_str(engine, &xc->scid_set.user_scid), xqc_dcid_str(engine, &xc->dcid_set.current_dcid), xc); xqc_log_event(xc->log, TRA_PARAMETERS_SET, xc, XQC_LOG_LOCAL_EVENT); return xc; @@ -929,7 +1035,7 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, } xqc_log(conn->log, XQC_LOG_INFO, "|hash odcid conn|odcid:%s|conn:%p|", - xqc_dcid_str(&conn->original_dcid), conn); + xqc_dcid_str(engine, &conn->original_dcid), conn); } ret = xqc_memcpy_with_cap(conn->local_addr, sizeof(conn->local_addr), @@ -968,7 +1074,7 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, goto fail; } - xqc_log(engine->log, XQC_LOG_DEBUG, "|server accept new conn|"); + xqc_log_event(conn->log, CON_CONNECTION_STARTED, conn, XQC_LOG_REMOTE_EVENT); if (conn->transport_cbs.server_accept) { if (conn->transport_cbs.server_accept(engine, conn, &conn->scid_set.user_scid, user_data) < 0) { @@ -979,7 +1085,6 @@ xqc_conn_server_create(xqc_engine_t *engine, const struct sockaddr *local_addr, conn->conn_flag |= XQC_CONN_FLAG_UPPER_CONN_EXIST; } - xqc_log_event(conn->log, CON_CONNECTION_STARTED, conn, XQC_LOG_REMOTE_EVENT); return conn; fail: @@ -993,9 +1098,22 @@ xqc_conn_client_on_alpn(xqc_connection_t *conn, const unsigned char *alpn, size_ { xqc_int_t ret; + /* save alpn */ + conn->alpn = xqc_calloc(1, alpn_len + 1); + if (conn->alpn == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|malloc alpn buffer error|"); + return -XQC_EMALLOC; + } + + xqc_memcpy(conn->alpn, alpn, alpn_len); + conn->alpn_len = alpn_len; + /* set quic callbacks to quic connection */ ret = xqc_engine_get_alpn_callbacks(conn->engine, alpn, alpn_len, &conn->app_proto_cbs); if (ret != XQC_OK) { + xqc_free(conn->alpn); + conn->alpn = NULL; + conn->alpn_len = 0; xqc_log(conn->log, XQC_LOG_ERROR, "|can't get application layer callback|ret:%d", ret); return ret; } @@ -1009,9 +1127,22 @@ xqc_conn_server_on_alpn(xqc_connection_t *conn, const unsigned char *alpn, size_ { xqc_int_t ret; + /* save alpn */ + conn->alpn = xqc_calloc(1, alpn_len + 1); + if (conn->alpn == NULL) { + xqc_log(conn->log, XQC_LOG_ERROR, "|malloc alpn buffer error|"); + return -XQC_EMALLOC; + } + + xqc_memcpy(conn->alpn, alpn, alpn_len); + conn->alpn_len = alpn_len; + /* set quic callbacks to quic connection */ ret = xqc_engine_get_alpn_callbacks(conn->engine, alpn, alpn_len, &conn->app_proto_cbs); if (ret != XQC_OK) { + xqc_free(conn->alpn); + conn->alpn = NULL; + conn->alpn_len = 0; xqc_log(conn->log, XQC_LOG_ERROR, "|can't get application layer callback|ret:%d", ret); return ret; } @@ -1074,6 +1205,7 @@ xqc_conn_destroy(xqc_connection_t *xc) if (xc->conn_flag & XQC_CONN_FLAG_TICKING) { xqc_log(xc->log, XQC_LOG_ERROR, "|in XQC_CONN_FLAG_TICKING|%p|", xc); xc->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(xc->log, CON_CONNECTION_STATE_UPDATED, xc); return; } @@ -1095,7 +1227,8 @@ xqc_conn_destroy(xqc_connection_t *xc) "first_send_delay:%ui|conn_persist:%ui|keyupdate_cnt:%d|err:0x%xi|close_msg:%s|%s|" "hsk_recv:%ui|close_recv:%ui|close_send:%ui|last_recv:%ui|last_send:%ui|" "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|" + "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|", xc, xc->conn_flag & XQC_CONN_FLAG_HAS_0RTT ? 1:0, @@ -1112,7 +1245,8 @@ xqc_conn_destroy(xqc_connection_t *xc) xqc_calc_delay(xc->conn_last_send_time, xc->conn_create_time), xc->enable_multipath, xc->create_path_count, xc->validated_path_count, xc->active_path_count, conn_stats.conn_info, out_alpn_len, out_alpn, conn_stats.total_rebind_count, - conn_stats.total_rebind_valid, conn_stats.lost_count, conn_stats.tlp_count, + 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); xqc_log_event(xc->log, CON_CONNECTION_CLOSED, xc); @@ -1171,7 +1305,11 @@ xqc_conn_destroy(xqc_connection_t *xc) xqc_timer_destroy_gp_timer_list(&xc->conn_timer_manager); xqc_send_queue_destroy(xc->conn_send_queue); - +#ifdef XQC_ENABLE_FEC + if (xc->fec_ctl) { + xqc_fec_ctl_destroy(xc->fec_ctl); + } +#endif /* free streams hash */ if (xc->streams_hash) { xqc_id_hash_release(xc->streams_hash); @@ -1216,6 +1354,10 @@ xqc_conn_destroy(xqc_connection_t *xc) xqc_log_release(xc->log); + if (xc->alpn) { + xqc_free(xc->alpn); + } + /* free pool, must be the last thing to do */ if (xc->conn_pool) { xqc_destroy_pool(xc->conn_pool); @@ -1374,7 +1516,7 @@ xqc_conn_send_ping(xqc_engine_t *engine, const xqc_cid_t *cid, void *ping_user_d conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return -XQC_ECONN_NFOUND; } @@ -1472,6 +1614,7 @@ xqc_send_burst(xqc_connection_t *conn, xqc_path_ctx_t *path, struct iovec *iov, if (xqc_conn_should_close(conn, path)) { 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); } } } @@ -1486,6 +1629,7 @@ xqc_send_burst(xqc_connection_t *conn, xqc_path_ctx_t *path, struct iovec *iov, if (sent == 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); } } } @@ -1510,7 +1654,7 @@ xqc_check_acked_or_dropped_pkt(xqc_connection_t *conn, "|conn:%p|pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|", conn, packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); return XQC_FALSE; } @@ -1541,7 +1685,7 @@ xqc_conn_schedule_packets(xqc_connection_t *conn, xqc_list_head_t *head, continue; } xqc_log(conn->log, XQC_LOG_DEBUG, "|specify|path:%ui|state:%d|frame_type:%s|stream_id:%ui|stream_offset:%ui|", - path->path_id, path->path_state, xqc_frame_type_2_str(packet_out->po_frame_types), + path->path_id, path->path_state, xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), packet_out->po_stream_id, packet_out->po_stream_offset); /* 2. schedule packet multipath */ @@ -1624,7 +1768,7 @@ xqc_on_packets_send_burst(xqc_connection_t *conn, xqc_path_ctx_t *path, ssize_t "|<==|conn:%p|path:%ui|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|inflight:%ud|now:%ui|", conn, path->path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), send_ctl->ctl_bytes_in_flight, now); } else { @@ -1684,7 +1828,7 @@ xqc_convert_pkt_0rtt_2_1rtt(xqc_connection_t *conn, xqc_packet_out_t *packet_out xqc_log(conn->log, XQC_LOG_DEBUG, "|0RTT to 1RTT|conn:%p|type:%d|pkt_num:%ui|pns:%d|frame:%s|", conn, packet_out->po_pkt.pkt_type, packet_out->po_pkt.pkt_num, packet_out->po_pkt.pkt_pns, - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); } @@ -1894,6 +2038,39 @@ xqc_path_send_packets(xqc_connection_t *conn, xqc_path_ctx_t *path, } +#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) { @@ -1969,6 +2146,7 @@ xqc_conn_enc_packet(xqc_connection_t *conn, xqc_gen_padding_frame(conn, packet_out); } + /* generate packet number and update packet length, might do packet number encoding here */ xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path); packet_out->po_pkt.pkt_num = pn_ctl->ctl_packet_number[packet_out->po_pkt.pkt_pns]++; @@ -1984,6 +2162,7 @@ xqc_conn_enc_packet(xqc_connection_t *conn, if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|encrypt packet error|"); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); return -XQC_EENCRYPT; } @@ -2026,6 +2205,7 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi if (xqc_conn_should_close(conn, path)) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn:%p|socket exception, close connection|", conn); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } } return -XQC_ESOCKET; @@ -2044,12 +2224,13 @@ xqc_send(xqc_connection_t *conn, xqc_path_ctx_t *path, unsigned char *data, unsi if (sent == XQC_SOCKET_ERROR) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn:%p|socket exception, close connection|", conn); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } return -XQC_ESOCKET; } } - xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, sent); + xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, sent, path->path_id); return sent; } @@ -2062,10 +2243,9 @@ xqc_process_packet_without_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_ ssize_t sent = xqc_send(conn, path, packet_out->po_buf, packet_out->po_used_size); xqc_log(conn->log, XQC_LOG_INFO, "|<==|conn:%p|size:%ud|sent:%z|pkt_type:%s|", conn, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type)); - + xqc_log_event(conn->log, TRA_PACKET_SENT, conn, packet_out, NULL, 0, sent, 0); if (sent > 0) { xqc_conn_log_sent_packet(conn, packet_out, xqc_monotonic_timestamp()); - xqc_log_event(conn->log, TRA_PACKET_SENT, packet_out); } return sent; } @@ -2086,7 +2266,7 @@ xqc_send_packet_with_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_packet "|write_socket error|conn:%p|path:%ui|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|now:%ui|", conn, path->path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), now); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), now); return sent; } else { @@ -2094,8 +2274,8 @@ xqc_send_packet_with_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_packet "|<==|conn:%p|path:%ui|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|inflight:%ud|now:%ui|stream_id:%ui|stream_offset:%ui|", conn, path->path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now, packet_out->po_stream_id, packet_out->po_stream_offset); - xqc_log_event(conn->log, TRA_PACKET_SENT, packet_out); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now, packet_out->po_stream_id, packet_out->po_stream_offset); + xqc_log_event(conn->log, TRA_PACKET_SENT, conn, packet_out, path, now, sent, 1); } /* deliver packet to send control */ @@ -2142,6 +2322,7 @@ xqc_enc_packet_with_pn(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_packet_ if (xqc_packet_encrypt(conn, packet_out) < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|encrypt packet error|"); conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); return -XQC_EENCRYPT; } @@ -2406,7 +2587,7 @@ xqc_conn_send_probe_pkt(xqc_connection_t *c, xqc_path_ctx_t *path, packet_out->po_path_id, packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(c->engine, packet_out->po_frame_types), xqc_conn_state_2_str(c->conn_state)); /* reinjection */ @@ -2421,7 +2602,7 @@ xqc_conn_send_probe_pkt(xqc_connection_t *c, xqc_path_ctx_t *path, "pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|", packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(c->engine, packet_out->po_frame_types)); reinject = 1; } } @@ -2603,12 +2784,12 @@ xqc_conn_close(xqc_engine_t *engine, const xqc_cid_t *cid) conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return -XQC_ECONN_NFOUND; } xqc_log(conn->log, XQC_LOG_INFO, "|conn:%p|state:%s|flag:%s|", conn, - xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn, conn->conn_flag)); XQC_CONN_CLOSE_MSG(conn, "local close"); @@ -2708,6 +2889,7 @@ xqc_conn_immediate_close(xqc_connection_t *conn) && conn->conn_type == XQC_CONN_TYPE_SERVER) { conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); xqc_conn_log(conn, XQC_LOG_ERROR, "|server cannot send CONNECTION_CLOSE before initial pkt received|"); return XQC_OK; } @@ -2718,8 +2900,9 @@ xqc_conn_immediate_close(xqc_connection_t *conn) /* convert state to CLOSING */ xqc_log(conn->log, XQC_LOG_INFO, "|state to closing|state:%s|flags:%s", xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); conn->conn_state = XQC_CONN_STATE_CLOSING; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); } /* @@ -2877,6 +3060,13 @@ xqc_conn_continue_send_by_conn(xqc_connection_t *conn) } 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); + } +#endif xqc_conn_schedule_packets_to_paths(conn); if (xqc_engine_is_sendmmsg_on(conn->engine)) { @@ -2904,7 +3094,7 @@ xqc_conn_continue_send(xqc_engine_t *engine, const xqc_cid_t *cid) xqc_connection_t *conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return -XQC_ECONN_NFOUND; } xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|", conn); @@ -2976,7 +3166,11 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) /* conn info */ ret = snprintf(buff, buff_size, "%s,%u,%u,%u,%u,%u,%u," - "%u,%u,%u,%u,%u,%u,%u,%"PRIu64",%"PRIu64",%"PRIu64",i%u,", + "%u,%u,%u,%u,%u,%u,%u,%"PRIu64",%"PRIu64",%"PRIu64",i%u," +#ifdef XQC_ENABLE_FEC + "%u,%u,%u,%u,%u,%u,%u," +#endif + , mp_settings, conn->create_path_count, conn->validated_path_count, @@ -2994,7 +3188,18 @@ xqc_conn_info_print(xqc_connection_t *conn, xqc_conn_stats_t *conn_stats) conn->stream_stats.send_bytes, conn->stream_stats.reinjected_bytes, conn->stream_stats.recv_bytes, - init_cwnd); + init_cwnd +#ifdef XQC_ENABLE_FEC + , + conn->conn_settings.fec_params.fec_encoder_scheme ? 1 : 0, + conn->conn_settings.fec_params.fec_decoder_scheme ? 1 : 0, + conn->fec_ctl ? (conn->fec_ctl->fec_processed_blk_num > 0 ? 1 : 0) : 0, + 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 +#endif + ); curr_size += ret; @@ -3195,7 +3400,7 @@ xqc_conn_get_stats(xqc_engine_t *engine, const xqc_cid_t *cid) conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return conn_stats; } @@ -3214,7 +3419,7 @@ xqc_conn_get_qos_stats(xqc_engine_t *engine, const xqc_cid_t *cid) conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return qos_stats; } @@ -3263,14 +3468,14 @@ xqc_conn_get_lastest_rtt(xqc_engine_t *engine, const xqc_cid_t *cid) conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return 0; } path = conn->conn_initial_path; if (!path) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find initial path|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return 0; } @@ -3663,6 +3868,7 @@ xqc_conn_process_undecrypt_packet_in(xqc_connection_t *conn, xqc_encrypt_level_t xqc_int_t ret; xqc_list_for_each_safe(pos, next, &conn->undecrypt_packet_in[encrypt_level]) { packet_in = xqc_list_entry(pos, xqc_packet_in_t, pi_list); + xqc_log_event(conn->log, TRA_DATAGRAMS_RECEIVED, packet_in->buf_size, packet_in->pi_path_id); xqc_log(conn->log, XQC_LOG_DEBUG, "|delay|undecrypt_count:%ud|encrypt_level:%d|", conn->undecrypt_count[encrypt_level], encrypt_level); ret = xqc_conn_process_packet(conn, packet_in->buf, packet_in->buf_size, packet_in->pkt_recv_time); @@ -3779,54 +3985,54 @@ static char g_local_addr_str[INET6_ADDRSTRLEN]; static char g_peer_addr_str[INET6_ADDRSTRLEN]; char * -xqc_local_addr_str(const struct sockaddr *local_addr, socklen_t local_addrlen) +xqc_local_addr_str(xqc_engine_t *engine, const struct sockaddr *local_addr, socklen_t local_addrlen) { if (local_addrlen == 0 || local_addr == NULL) { - g_local_addr_str[0] = '\0'; - return g_local_addr_str; + engine->local_addr_str[0] = '\0'; + return engine->local_addr_str; } struct sockaddr_in *sa_local = (struct sockaddr_in *)local_addr; if (sa_local->sin_family == AF_INET) { - if (inet_ntop(sa_local->sin_family, &sa_local->sin_addr, g_local_addr_str, local_addrlen) == NULL) { - g_local_addr_str[0] = '\0'; + if (inet_ntop(sa_local->sin_family, &sa_local->sin_addr, engine->local_addr_str, local_addrlen) == NULL) { + engine->local_addr_str[0] = '\0'; } } else { if (inet_ntop(sa_local->sin_family, &((struct sockaddr_in6*)sa_local)->sin6_addr, - g_local_addr_str, local_addrlen) == NULL) + engine->local_addr_str, local_addrlen) == NULL) { - g_local_addr_str[0] = '\0'; + engine->local_addr_str[0] = '\0'; } } - return g_local_addr_str; + return engine->local_addr_str; } char * -xqc_peer_addr_str(const struct sockaddr *peer_addr, socklen_t peer_addrlen) +xqc_peer_addr_str(xqc_engine_t *engine, const struct sockaddr *peer_addr, socklen_t peer_addrlen) { if (peer_addrlen == 0 || peer_addr == NULL) { - g_peer_addr_str[0] = '\0'; - return g_peer_addr_str; + engine->peer_addr_str[0] = '\0'; + return engine->peer_addr_str; } struct sockaddr_in *sa_peer = (struct sockaddr_in *)peer_addr; if (sa_peer->sin_family == AF_INET) { - if (inet_ntop(sa_peer->sin_family, &sa_peer->sin_addr, g_peer_addr_str, peer_addrlen) == NULL) { - g_peer_addr_str[0] = '\0'; + if (inet_ntop(sa_peer->sin_family, &sa_peer->sin_addr, engine->peer_addr_str, peer_addrlen) == NULL) { + engine->peer_addr_str[0] = '\0'; } } else { if (inet_ntop(sa_peer->sin_family, &((struct sockaddr_in6*)sa_peer)->sin6_addr, - g_peer_addr_str, peer_addrlen) == NULL) + engine->peer_addr_str, peer_addrlen) == NULL) { - g_peer_addr_str[0] = '\0'; + engine->peer_addr_str[0] = '\0'; } } - return g_peer_addr_str; + return engine->peer_addr_str; } @@ -3844,10 +4050,10 @@ xqc_conn_addr_str(xqc_connection_t *conn) struct sockaddr_in *sa_peer = (struct sockaddr_in *)conn->peer_addr; conn->addr_str_len = snprintf(conn->addr_str, sizeof(conn->addr_str), "l-%s-%d-%s p-%s-%d-%s", - xqc_local_addr_str((struct sockaddr*)sa_local, conn->local_addrlen), - ntohs(sa_local->sin_port), xqc_scid_str(&conn->scid_set.user_scid), - xqc_peer_addr_str((struct sockaddr*)sa_peer, conn->peer_addrlen), - ntohs(sa_peer->sin_port), xqc_dcid_str(&conn->dcid_set.current_dcid)); + xqc_local_addr_str(conn->engine, (struct sockaddr*)sa_local, conn->local_addrlen), + ntohs(sa_local->sin_port), xqc_scid_str(conn->engine, &conn->scid_set.user_scid), + xqc_peer_addr_str(conn->engine, (struct sockaddr*)sa_peer, conn->peer_addrlen), + ntohs(sa_peer->sin_port), xqc_dcid_str(conn->engine, &conn->dcid_set.current_dcid)); } return conn->addr_str; @@ -3867,10 +4073,10 @@ xqc_path_addr_str(xqc_path_ctx_t *path) struct sockaddr_in *sa_peer = (struct sockaddr_in *)path->peer_addr; path->addr_str_len = snprintf(path->addr_str, sizeof(path->addr_str), "l-%s-%d-%s p-%s-%d-%s", - xqc_local_addr_str((struct sockaddr*)sa_local, path->local_addrlen), - ntohs(sa_local->sin_port), xqc_scid_str(&path->path_scid), - xqc_peer_addr_str((struct sockaddr*)sa_peer, path->peer_addrlen), - ntohs(sa_peer->sin_port), xqc_dcid_str(&path->path_dcid)); + xqc_local_addr_str(path->parent_conn->engine, (struct sockaddr*)sa_local, path->local_addrlen), + ntohs(sa_local->sin_port), xqc_scid_str(path->parent_conn->engine, &path->path_scid), + xqc_peer_addr_str(path->parent_conn->engine, (struct sockaddr*)sa_peer, path->peer_addrlen), + ntohs(sa_peer->sin_port), xqc_dcid_str(path->parent_conn->engine, &path->path_dcid)); } return path->addr_str; @@ -3964,7 +4170,7 @@ xqc_conn_confirm_cid(xqc_connection_t *c, xqc_packet_t *pkt) if (XQC_OK != xqc_cid_is_equal(&c->dcid_set.current_dcid, &pkt->pkt_scid)) { xqc_log(c->log, XQC_LOG_INFO, "|dcid change|ori:%s|new:%s|", - xqc_dcid_str(&c->dcid_set.current_dcid), xqc_scid_str(&pkt->pkt_scid)); + xqc_dcid_str(c->engine, &c->dcid_set.current_dcid), xqc_scid_str(c->engine, &pkt->pkt_scid)); // TODO: DCID changes xqc_cid_copy(&c->dcid_set.current_dcid, &pkt->pkt_scid); xqc_cid_copy(&c->conn_initial_path->path_dcid, &pkt->pkt_scid); @@ -4144,7 +4350,7 @@ xqc_conn_on_pkt_processed(xqc_connection_t *c, xqc_packet_in_t *pi, xqc_usec_t n /* record packet */ xqc_conn_record_single(c, pi); - if (pi->pi_frame_types & (~(XQC_FRAME_BIT_STREAM|XQC_FRAME_BIT_DATAGRAM|XQC_FRAME_BIT_PADDING))) { + if (pi->pi_frame_types & (~(XQC_FRAME_BIT_STREAM|XQC_FRAME_BIT_DATAGRAM|XQC_FRAME_BIT_PADDING|XQC_FRAME_BIT_SID|XQC_FRAME_BIT_REPAIR_SYMBOL))) { c->conn_flag |= XQC_CONN_FLAG_NEED_RUN; } @@ -4152,7 +4358,7 @@ xqc_conn_on_pkt_processed(xqc_connection_t *c, xqc_packet_in_t *pi, xqc_usec_t n xqc_log(c->log, XQC_LOG_INFO, "|====>|conn:%p|path:%ui|size:%uz|pkt_type:%s|pkt_num:%ui|frame:%s|recv_time:%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(pi->pi_frame_types), pi->pkt_recv_time); + xqc_frame_type_2_str(c->engine, pi->pi_frame_types), pi->pkt_recv_time); return ret; } @@ -4257,7 +4463,7 @@ xqc_conn_process_packet_recved_path(xqc_connection_t *conn, xqc_cid_t *scid, } if (path == NULL) { - xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|scid:%s|", xqc_scid_str(scid)); + xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|scid:%s|", xqc_scid_str(conn->engine, scid)); return; } @@ -4344,10 +4550,9 @@ xqc_conn_destroy_cids(xqc_connection_t *conn) } } - if (conn->engine->conns_hash_dcid && (conn->conn_flag & XQC_CONN_FLAG_DCID_OK)) { - xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) { - cid = xqc_list_entry(pos, xqc_cid_inner_t, list); - + 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)) @@ -4356,6 +4561,8 @@ xqc_conn_destroy_cids(xqc_connection_t *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, @@ -4436,11 +4643,13 @@ xqc_conn_ptmud_probing(xqc_connection_t *conn) /* stop probing if the range is less than 10B */ if ((conn->max_pkt_out_size - conn->pkt_out_size) < 10) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|stop pmtud probing|max:%z|curr:%z|", - conn->max_pkt_out_size, conn->pkt_out_size); + xqc_log_event(conn->log, CON_MTU_UPDATED, conn, 1); conn->conn_flag &= ~XQC_CONN_FLAG_PMTUD_PROBING; return; } + xqc_log_event(conn->log, CON_MTU_UPDATED, conn, 0); + conn->MTU_updated_count ++; + size_t probing_size = conn->probing_pkt_out_size; xqc_list_head_t *pos, *next; @@ -4526,7 +4735,7 @@ xqc_conn_check_dcid(xqc_connection_t *conn, xqc_cid_t *dcid) ret = xqc_cid_switch_to_next_state(&conn->scid_set.cid_set, scid, XQC_CID_USED); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_switch_to_next_state error|scid:%s|", - xqc_scid_str(&scid->cid)); + xqc_scid_str(conn->engine, &scid->cid)); return ret; } } @@ -4547,7 +4756,7 @@ xqc_conn_set_cid_retired_ts(xqc_connection_t *conn, xqc_cid_inner_t *inner_cid) xqc_log(conn->log, XQC_LOG_DEBUG, "|retired|cid:%s|seq:%ui|len:%d|", - xqc_scid_str(&inner_cid->cid), + xqc_scid_str(conn->engine, &inner_cid->cid), inner_cid->cid.cid_seq_num, inner_cid->cid.cid_len); @@ -4680,7 +4889,7 @@ xqc_conn_reassemble_packet(xqc_connection_t *conn, xqc_packet_out_t *ori_po) xqc_log(conn->log, XQC_LOG_DEBUG, "|pkt_num:%ui|ptype:%d|frames:%s|", new_po->po_pkt.pkt_num, new_po->po_pkt.pkt_type, - xqc_frame_type_2_str(new_po->po_frame_types)); + xqc_frame_type_2_str(conn->engine, new_po->po_frame_types)); return XQC_OK; } @@ -4743,7 +4952,7 @@ xqc_conn_on_recv_retry(xqc_connection_t *conn, xqc_cid_t *retry_scid) if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_tls_reset_initial error|retry_scid:%s|ret:%d|", - xqc_scid_str(retry_scid), ret); + xqc_scid_str(conn->engine, retry_scid), ret); return ret; } @@ -4826,6 +5035,37 @@ xqc_conn_set_remote_transport_params(xqc_connection_t *conn, settings->enable_multipath = params->enable_multipath; settings->multipath_version = params->multipath_version; settings->max_datagram_frame_size = params->max_datagram_frame_size; + settings->close_dgram_redundancy = params->close_dgram_redundancy; + +#ifdef XQC_ENABLE_FEC + /* + * set fec params to remote_settings + */ + + 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; + settings->fec_decoder_schemes_num = params->fec_decoder_schemes_num; + for (xqc_int_t i = 0; i < settings->fec_decoder_schemes_num; i++) { + settings->fec_decoder_schemes[i] = params->fec_decoder_schemes[i]; + } + } + // if current host enable fec decode, set encoder params of remote settings + 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]; + } + } + } else { + settings->enable_encode_fec = 0; + settings->enable_decode_fec = 0; + } +#endif return XQC_OK; } @@ -4864,6 +5104,28 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params params->multipath_version = settings->multipath_version; params->max_datagram_frame_size = settings->max_datagram_frame_size; + params->close_dgram_redundancy = settings->close_dgram_redundancy; + +#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++) { + params->fec_encoder_schemes[i] = settings->fec_encoder_schemes[i]; + } + } + if (conn->conn_settings.enable_decode_fec) { + params->enable_decode_fec = settings->enable_decode_fec; + params->fec_decoder_schemes_num = settings->fec_decoder_schemes_num; + for (xqc_int_t i = 0; i < settings->fec_decoder_schemes_num; i++) { + params->fec_decoder_schemes[i] = settings->fec_decoder_schemes[i]; + } + } + +#endif + /* set other transport parameters */ if (conn->conn_type == XQC_CONN_TYPE_SERVER && conn->original_dcid.cid_len > 0) @@ -4880,8 +5142,8 @@ xqc_conn_get_local_transport_params(xqc_connection_t *conn, xqc_transport_params params->stateless_reset_token_present = 1; xqc_log(conn->log, XQC_LOG_INFO, "|generate sr_token[%s] for cid[%s]", - xqc_sr_token_str(params->stateless_reset_token), - xqc_scid_str(&conn->original_dcid)); + xqc_sr_token_str(conn->engine, params->stateless_reset_token), + xqc_scid_str(conn->engine, &conn->original_dcid)); } else { params->original_dest_connection_id_present = 0; @@ -4943,11 +5205,11 @@ xqc_conn_check_transport_params(xqc_connection_t *conn, const xqc_transport_para void xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) { - xqc_int_t ret; - xqc_transport_params_t params; + xqc_int_t ret, final_decoder_fec_scheme = 0, re_encode_local_tp_flag = 0, final_scheme; + xqc_cid_t *cid; xqc_list_head_t *node; xqc_cid_inner_t *cid_node; - xqc_cid_t *cid; + xqc_transport_params_t params; xqc_connection_t *conn = (xqc_connection_t *)user_data; xqc_transport_params_type_t tp_type = (conn->conn_type == XQC_CONN_TYPE_CLIENT @@ -5010,8 +5272,8 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) XQC_STATELESS_RESET_TOKENLEN); xqc_log(conn->log, XQC_LOG_INFO, "|store sr_token with cid: %s" - "|token:%s", xqc_dcid_str(&cid_node->cid), - xqc_sr_token_str(params.stateless_reset_token)); + "|token:%s", xqc_dcid_str(conn->engine, &cid_node->cid), + xqc_sr_token_str(conn->engine, params.stateless_reset_token)); if (xqc_insert_conns_hash(conn->engine->conns_hash_sr_token, conn, @@ -5032,9 +5294,59 @@ xqc_conn_tls_transport_params_cb(const uint8_t *tp, size_t len, void *user_data) && params.multipath_version != conn->local_settings.multipath_version && xqc_conn_is_current_mp_version_supported(params.multipath_version) == XQC_OK) { + conn->local_settings.multipath_version = params.multipath_version; + re_encode_local_tp_flag = 1; + } + + + /** Negotiate on whether send datagram redundancy on 1RTT packet; + * on XQC_RED_NOT_USE(default): + * No need to negotiate, and whether to send redundancy is + * completely decided by server's config; + * on XQC_RED_SET_CLOSE: + * The client's signal to close datagram redundancy, thus stop + * sending dgram redundancy. + * + */ + if (conn->conn_type == XQC_CONN_TYPE_SERVER + && params.close_dgram_redundancy != XQC_RED_NOT_USE) + { + if (params.close_dgram_redundancy == XQC_RED_SET_CLOSE) { + conn->local_settings.close_dgram_redundancy = XQC_RED_SET_CLOSE; + conn->conn_settings.datagram_redundancy = 0; + } + re_encode_local_tp_flag = 1; + } + + if (conn->local_settings.close_dgram_redundancy == XQC_RED_SET_CLOSE) { + conn->conn_settings.mp_enable_reinjection = 0; + xqc_log(conn->log, XQC_LOG_DEBUG, "|stop sending datagram redundancy."); + } + + +#ifdef XQC_ENABLE_FEC + if (conn->conn_settings.enable_encode_fec + || conn->conn_settings.enable_decode_fec) + { + 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); + } + } + } +#endif + /* TODOfec:整合参数选择逻辑与更新 */ + if (re_encode_local_tp_flag) { uint8_t tp_buf[XQC_MAX_TRANSPORT_PARAM_BUF_LEN] = {0}; size_t tp_len = 0; - conn->local_settings.multipath_version = params.multipath_version; + ret = xqc_conn_encode_local_tp(conn, tp_buf, XQC_MAX_TRANSPORT_PARAM_BUF_LEN, &tp_len); if (ret != XQC_OK) { @@ -5606,7 +5918,7 @@ xqc_conn_send_path_challenge(xqc_connection_t *conn, xqc_path_ctx_t *path) "|write_socket error|conn:%p|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|now:%ui|", conn, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), now); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), now); ret = -XQC_ESOCKET; goto end; @@ -5615,9 +5927,7 @@ xqc_conn_send_path_challenge(xqc_connection_t *conn, xqc_path_ctx_t *path) "|<==|conn:%p|pkt_num:%ui|size:%ud|sent:%z|pkt_type:%s|frame:%s|inflight:%ud|now:%ui|", conn, packet_out->po_pkt.pkt_num, packet_out->po_used_size, sent, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now); - xqc_log_event(conn->log, TRA_DATAGRAMS_SENT, ret); - xqc_log_event(conn->log, TRA_PACKET_SENT, packet_out); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), path->path_send_ctl->ctl_bytes_in_flight, now); } pn_ctl = xqc_get_pn_ctl(conn, path); @@ -5748,7 +6058,7 @@ xqc_conn_should_clear_0rtt_ticket(xqc_int_t conn_err) xqc_conn_settings_t xqc_conn_get_conn_settings_template(xqc_conn_settings_type_t settings_type) { - xqc_conn_settings_t conn_settings = default_conn_settings; + xqc_conn_settings_t conn_settings = internal_default_conn_settings; if (settings_type == XQC_CONN_SETTINGS_LOW_DELAY) { conn_settings.ack_frequency = 1; @@ -5849,6 +6159,7 @@ xqc_conn_reset(xqc_connection_t *conn) /* set error code and close message, notify to application */ conn->conn_state = XQC_CONN_STATE_DRAINING; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); conn->conn_err = XQC_ESTATELESS_RESET; XQC_CONN_CLOSE_MSG(conn, "stateless reset"); xqc_conn_closing(conn); @@ -5880,7 +6191,7 @@ xqc_conn_handle_stateless_reset(xqc_connection_t *conn, XQC_STATELESS_RESET_TOKENLEN); if (0 == res) { xqc_log(conn->log, XQC_LOG_INFO, "|====>|receive stateless reset" - "|cid:%s", xqc_dcid_str(&cid->cid)); + "|cid:%s", xqc_dcid_str(conn->engine, &cid->cid)); xqc_log_event(conn->log, TRA_STATELESS_RESET, conn); /* stateless reset received, close connection */ @@ -5941,7 +6252,7 @@ xqc_conn_handle_deprecated_stateless_reset(xqc_connection_t *conn, } xqc_log(conn->log, XQC_LOG_INFO, "|====>|receive stateless reset" - "|deprecated|cid:%s", xqc_dcid_str(scid)); + "|deprecated|cid:%s", xqc_dcid_str(conn->engine, scid)); /* reset state of connection */ xqc_conn_reset(conn); diff --git a/src/transport/xqc_conn.h b/src/transport/xqc_conn.h index 1dc48bd42..160ad432f 100644 --- a/src/transport/xqc_conn.h +++ b/src/transport/xqc_conn.h @@ -19,6 +19,8 @@ #include "src/transport/xqc_transport_params.h" #include "src/transport/xqc_timer.h" #include "src/transport/xqc_multipath.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_fec_scheme.h" #include "src/tls/xqc_tls.h" #include "src/common/xqc_list.h" @@ -64,7 +66,7 @@ static const uint32_t MAX_RSP_CONN_CLOSE_CNT = 3; } \ } while(0) \ -extern xqc_conn_settings_t default_conn_settings; +extern xqc_conn_settings_t internal_default_conn_settings; extern const xqc_tls_callbacks_t xqc_conn_tls_cbs; /* !!WARNING: to add state, please update conn_state_2_str */ @@ -207,8 +209,17 @@ typedef struct { uint16_t max_datagram_frame_size; uint32_t conn_options[XQC_CO_MAX_NUM]; uint8_t conn_option_num; + 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; } xqc_trans_settings_t; - + typedef struct { /* flow control limit */ @@ -320,6 +331,8 @@ struct xqc_connection_s { void *user_data; /* user_data for application layer */ /* callback function and user_data to application-layer-protocol layer */ + char *alpn; + size_t alpn_len; xqc_app_proto_callbacks_t app_proto_cbs; void *proto_data; @@ -360,6 +373,11 @@ struct xqc_connection_s { uint32_t create_path_count; uint32_t validated_path_count; uint32_t active_path_count; + + /* for qlog */ + uint32_t MTU_updated_count; + uint32_t packet_dropped_count; + const xqc_scheduler_callback_t *scheduler_callback; @@ -428,6 +446,10 @@ struct xqc_connection_s { uint32_t cli_bidi_streams; uint32_t svr_bidi_streams; + /* for fec */ + xqc_fec_ctl_t *fec_ctl; + + /* receved pkts stats */ struct { xqc_pkt_type_t pkt_types[3]; @@ -453,7 +475,9 @@ struct xqc_connection_s { } snd_pkt_stats; }; -const char *xqc_conn_flag_2_str(xqc_conn_flag_t conn_flag); +extern const xqc_h3_conn_settings_t default_local_h3_conn_settings; + +const char *xqc_conn_flag_2_str(xqc_connection_t *conn, xqc_conn_flag_t conn_flag); const char *xqc_conn_state_2_str(xqc_conn_state_t state); void xqc_conn_init_flow_ctl(xqc_connection_t *conn); @@ -509,8 +533,8 @@ void xqc_conn_buff_1rtt_packets(xqc_connection_t *conn); void xqc_conn_write_buffed_1rtt_packets(xqc_connection_t *conn); xqc_usec_t xqc_conn_next_wakeup_time(xqc_connection_t *conn); -char *xqc_local_addr_str(const struct sockaddr *local_addr, socklen_t local_addrlen); -char *xqc_peer_addr_str(const struct sockaddr *peer_addr, socklen_t peer_addrlen); +char *xqc_local_addr_str(xqc_engine_t *engine, const struct sockaddr *local_addr, socklen_t local_addrlen); +char *xqc_peer_addr_str(xqc_engine_t *engine, const struct sockaddr *peer_addr, socklen_t peer_addrlen); char *xqc_conn_addr_str(xqc_connection_t *conn); char *xqc_path_addr_str(xqc_path_ctx_t *path); @@ -659,5 +683,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 #endif /* _XQC_CONN_H_INCLUDED_ */ diff --git a/src/transport/xqc_datagram.c b/src/transport/xqc_datagram.c index e39ec96d1..13a763995 100644 --- a/src/transport/xqc_datagram.c +++ b/src/transport/xqc_datagram.c @@ -70,6 +70,11 @@ xqc_datagram_record_mss(xqc_connection_t *conn) } headroom = XQC_ACK_SPACE + XQC_TLS_AEAD_OVERHEAD_MAX_LEN + quic_header_size + XQC_DATAGRAM_HEADER_BYTES; + + if (conn->conn_settings.fec_params.fec_encoder_scheme) { + headroom += XQC_FEC_SPACE; + } + if (conn->remote_settings.max_udp_payload_size >= headroom) { udp_payload_limit = conn->remote_settings.max_udp_payload_size - headroom; @@ -78,6 +83,9 @@ xqc_datagram_record_mss(xqc_connection_t *conn) } headroom = quic_header_size + XQC_DATAGRAM_HEADER_BYTES; + if (conn->conn_settings.fec_params.fec_encoder_scheme) { + headroom += XQC_FEC_SPACE; + } if (conn->pkt_out_size >= headroom) { mtu_limit = conn->pkt_out_size - headroom; diff --git a/src/transport/xqc_defs.h b/src/transport/xqc_defs.h index 8d7d6d47b..cce6c3f3f 100644 --- a/src/transport/xqc_defs.h +++ b/src/transport/xqc_defs.h @@ -68,4 +68,6 @@ extern const unsigned char xqc_proto_version_field[][XQC_PROTO_VERSION_LEN]; /* limit of anti-amplification */ #define XQC_DEFAULT_ANTI_AMPLIFICATION_LIMIT 5 +#define XQC_MAX_MT_ROW 256 + #endif \ No newline at end of file diff --git a/src/transport/xqc_engine.c b/src/transport/xqc_engine.c index f5a27a153..4cde76bba 100644 --- a/src/transport/xqc_engine.c +++ b/src/transport/xqc_engine.c @@ -34,6 +34,7 @@ extern const xqc_qpack_ins_cb_t xqc_h3_qpack_ins_cb; xqc_config_t default_client_config = { .cfg_log_level = XQC_LOG_WARN, .cfg_log_event = 1, + .cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA, .cfg_log_timestamp = 1, .cfg_log_level_name = 1, .conn_pool_size = 4096, @@ -49,12 +50,14 @@ xqc_config_t default_client_config = { .reset_token_keylen = 0, .sendmmsg_on = 0, .enable_h3_ext = 0, + .log_disable = 0, }; xqc_config_t default_server_config = { .cfg_log_level = XQC_LOG_WARN, .cfg_log_event = 1, + .cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA, .cfg_log_timestamp = 1, .cfg_log_level_name = 1, .conn_pool_size = 4096, @@ -70,6 +73,7 @@ xqc_config_t default_server_config = { .reset_token_keylen = 0, .sendmmsg_on = 0, .enable_h3_ext = 0, + .log_disable = 0, }; @@ -128,10 +132,12 @@ xqc_set_config(xqc_config_t *dst, const xqc_config_t *src) dst->cid_negotiate = src->cid_negotiate; dst->cfg_log_level = src->cfg_log_level; dst->cfg_log_event = src->cfg_log_event; + dst->cfg_qlog_importance = src->cfg_qlog_importance; dst->cfg_log_timestamp = src->cfg_log_timestamp; 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; } @@ -271,6 +277,7 @@ xqc_engine_wakeup_pq_create(xqc_config_t *config) xqc_connection_t * xqc_engine_conns_hash_find(xqc_engine_t *engine, const xqc_cid_t *cid, char type) { + xqc_connection_t *xqc_conn; if (cid == NULL || cid->cid_len == 0) { return NULL; } @@ -286,7 +293,12 @@ xqc_engine_conns_hash_find(xqc_engine_t *engine, const xqc_cid_t *cid, char type } else { /* search by peer's cid */ - return xqc_str_hash_find(engine->conns_hash_dcid, hash, str); + xqc_conn = xqc_str_hash_find(engine->conns_hash_dcid, hash, str); + if (xqc_conn == NULL) { + xqc_log(engine->log, XQC_LOG_ERROR, "|xquic find dcid error|dcid:%s|", + xqc_dcid_str(engine, cid)); + } + return xqc_conn; } } @@ -432,11 +444,12 @@ 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->config->cfg_log_level_name, engine, &engine->eng_callback.log_callbacks, engine->user_data); @@ -500,6 +513,8 @@ xqc_engine_create(xqc_engine_type_t engine_type, goto fail; } + engine->default_conn_settings = internal_default_conn_settings; + return engine; fail: @@ -693,7 +708,7 @@ void xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) { xqc_log(conn->log, XQC_LOG_DEBUG, "|conn:%p|state:%s|flag:%s|now:%ui|", - conn, xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn->conn_flag), now); + conn, xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn, conn->conn_flag), now); int ret; xqc_bool_t wait_scid, wait_dcid; @@ -705,6 +720,7 @@ xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) if (XQC_UNLIKELY(conn->conn_flag & XQC_CONN_FLAG_TIME_OUT)) { conn->conn_state = XQC_CONN_STATE_CLOSED; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); return; } XQC_CHECK_IMMEDIATE_CLOSE(); @@ -767,9 +783,8 @@ xqc_engine_process_conn(xqc_connection_t *conn, xqc_usec_t now) XQC_CONN_ERR(conn, TRA_INTERNAL_ERROR); } } - - XQC_CHECK_IMMEDIATE_CLOSE(); + XQC_CHECK_IMMEDIATE_CLOSE(); ret = xqc_conn_try_add_new_conn_id(conn, 0); if (ret) { @@ -876,8 +891,6 @@ xqc_engine_main_logic(xqc_engine_t *engine) } conn = el->conn; - /* xqc_log(conn->log, XQC_LOG_DEBUG, "|wakeup|conn:%p|state:%s|flag:%s|now:%ui|wakeup:%ui|", - conn, xqc_conn_state_2_str(conn->conn_state), xqc_conn_flag_2_str(conn->conn_flag), now, el->wakeup_time); */ if (el->wakeup_time <= now) { xqc_wakeup_pq_pop(engine->conns_wait_wakeup_pq); conn->conn_flag &= ~XQC_CONN_FLAG_WAIT_WAKEUP; @@ -924,7 +937,14 @@ xqc_engine_main_logic(xqc_engine_t *engine) } else { 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)) { @@ -1048,7 +1068,7 @@ xqc_engine_handle_stateless_reset(xqc_engine_t *engine, if (NULL == conn) { /* can't find connection with sr_token */ xqc_log(engine->log, XQC_LOG_DEBUG, "|can't find conn with sr|sr:%s", - xqc_sr_token_str(sr_token)); + xqc_sr_token_str(engine, sr_token)); return -XQC_ERROR; } @@ -1143,7 +1163,7 @@ xqc_engine_packet_process(xqc_engine_t *engine, ret = xqc_packet_parse_cid(&scid, &dcid, engine->config->cid_len, (unsigned char *)packet_in_buf, packet_in_size); if (XQC_UNLIKELY(ret != XQC_OK)) { - xqc_log(engine->log, XQC_LOG_INFO, "|fail to parse cid|ret:%d|", ret); + xqc_log_event(engine->log, TRA_PACKET_DROPPED, "fail to parse cid", ret, "unknown", 0); return -XQC_EILLPKT; } @@ -1161,7 +1181,8 @@ xqc_engine_packet_process(xqc_engine_t *engine, { conn = xqc_conn_server_create(engine, local_addr, local_addrlen, peer_addr, peer_addrlen, &dcid, &scid, - &default_conn_settings, user_data); + &engine->default_conn_settings, user_data); + xqc_log_event(engine->log, CON_SERVER_LISTENING, peer_addr, peer_addrlen); if (conn == NULL) { xqc_log(engine->log, XQC_LOG_ERROR, "|fail to create connection|"); return -XQC_ECREATE_CONN; @@ -1196,9 +1217,9 @@ xqc_engine_packet_process(xqc_engine_t *engine, xqc_log(engine->log, lvl, "|fail to find connection, send reset|" "size:%uz|scid:%s|recv_time:%ui|peer_addr:%s|local_addr:%s", - packet_in_size, xqc_scid_str(&scid), recv_time, - xqc_peer_addr_str(peer_addr, peer_addrlen), - xqc_local_addr_str(local_addr, local_addrlen)); + packet_in_size, xqc_scid_str(engine, &scid), recv_time, + xqc_peer_addr_str(engine, peer_addr, peer_addrlen), + xqc_local_addr_str(engine, local_addr, local_addrlen)); ret = xqc_engine_send_reset(engine, &scid, peer_addr, peer_addrlen, local_addr, local_addrlen, packet_in_size, @@ -1211,7 +1232,6 @@ xqc_engine_packet_process(xqc_engine_t *engine, } process: - xqc_log_event(conn->log, TRA_DATAGRAMS_RECEIVED, packet_in_size); xqc_log(engine->log, XQC_LOG_INFO, "|==>|conn:%p|size:%uz|state:%s|recv_time:%ui|", conn, packet_in_size, xqc_conn_state_2_str(conn->conn_state), recv_time); @@ -1345,7 +1365,7 @@ xqc_engine_config_get_cid_len(xqc_engine_t *engine) xqc_int_t xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, - xqc_app_proto_callbacks_t *ap_cbs) + xqc_app_proto_callbacks_t *ap_cbs, void *alp_ctx) { /* register alpn in tls context */ xqc_int_t ret = xqc_tls_ctx_register_alpn(engine->tls_ctx, alpn, alpn_len); @@ -1353,7 +1373,7 @@ xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, return ret; } - xqc_alpn_registration_t *registration = xqc_malloc(sizeof(xqc_alpn_registration_t)); + xqc_alpn_registration_t *registration = xqc_calloc(1, sizeof(xqc_alpn_registration_t)); if (NULL == registration) { xqc_log(engine->log, XQC_LOG_ERROR, "|create alpn registration error!"); return -XQC_EMALLOC; @@ -1371,6 +1391,7 @@ xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, registration->alpn[alpn_len] = '\0'; registration->alpn_len = alpn_len; registration->ap_cbs = *ap_cbs; + registration->alp_ctx = alp_ctx; xqc_list_add_tail(®istration->head, &engine->alpn_reg_list); @@ -1381,7 +1402,7 @@ xqc_engine_add_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, xqc_int_t xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len, - xqc_app_proto_callbacks_t *ap_cbs) + xqc_app_proto_callbacks_t *ap_cbs, void *alp_ctx) { xqc_list_head_t *pos, *next; xqc_alpn_registration_t *alpn_reg; @@ -1398,12 +1419,31 @@ xqc_engine_register_alpn(xqc_engine_t *engine, const char *alpn, size_t alpn_len { /* if found registration, update */ alpn_reg->ap_cbs = *ap_cbs; + alpn_reg->alp_ctx = alp_ctx; return XQC_OK; } } /* not registered, add into alpn_reg_list */ - return xqc_engine_add_alpn(engine, alpn, alpn_len, ap_cbs); + return xqc_engine_add_alpn(engine, alpn, alpn_len, ap_cbs, alp_ctx); +} + +void* +xqc_engine_get_alpn_ctx(xqc_engine_t *engine, const char *alpn, size_t alpn_len) +{ + xqc_list_head_t *pos, *next; + xqc_alpn_registration_t *alpn_reg; + + xqc_list_for_each_safe(pos, next, &engine->alpn_reg_list) { + alpn_reg = xqc_list_entry(pos, xqc_alpn_registration_t, head); + if (alpn_reg && alpn_len == alpn_reg->alpn_len + && xqc_memcmp(alpn, alpn_reg->alpn, alpn_len) == 0) + { + return alpn_reg->alp_ctx; + } + } + + return NULL; } @@ -1486,3 +1526,22 @@ xqc_engine_is_sendmmsg_on(xqc_engine_t *engine) return engine->config->sendmmsg_on && (engine->transport_cbs.write_mmsg || engine->transport_cbs.write_mmsg_ex); } + + +void* +xqc_engine_get_priv_ctx(xqc_engine_t *engine) +{ + return engine->priv_ctx; +} + + +xqc_int_t +xqc_engine_set_priv_ctx(xqc_engine_t *engine, void *priv_ctx) +{ + if (engine->priv_ctx) { + return -XQC_ESTATE; + } + + engine->priv_ctx = priv_ctx; + return XQC_OK; +} diff --git a/src/transport/xqc_engine.h b/src/transport/xqc_engine.h index 6f1a6b974..e413f99c9 100644 --- a/src/transport/xqc_engine.h +++ b/src/transport/xqc_engine.h @@ -33,6 +33,8 @@ typedef struct xqc_alpn_registration_s { /* Application-Layer-Protocol callback functions */ xqc_app_proto_callbacks_t ap_cbs; + void *alp_ctx; + } xqc_alpn_registration_t; @@ -56,6 +58,7 @@ typedef struct xqc_engine_s { xqc_tls_ctx_t *tls_ctx; /* common */ + xqc_bool_t log_disable; xqc_log_t *log; xqc_random_generator_t *rand_generator; @@ -68,6 +71,18 @@ typedef struct xqc_engine_s { /* list of xqc_alpn_registration_t */ xqc_list_head_t alpn_reg_list; + xqc_conn_settings_t default_conn_settings; + + char scid_buf[XQC_MAX_CID_LEN * 2 + 1]; + char dcid_buf[XQC_MAX_CID_LEN * 2 + 1]; + char sr_token_buf[XQC_STATELESS_RESET_TOKENLEN * 2 + 1]; + char conn_flag_str_buf[1024]; + char frame_type_buf[128]; + char local_addr_str[INET6_ADDRSTRLEN]; + char peer_addr_str[INET6_ADDRSTRLEN]; + + void *priv_ctx; + } xqc_engine_t; diff --git a/src/transport/xqc_fec.c b/src/transport/xqc_fec.c new file mode 100644 index 000000000..4cfed8687 --- /dev/null +++ b/src/transport/xqc_fec.c @@ -0,0 +1,663 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_fec_scheme.h" +#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) +{ + switch (scheme) { + case XQC_REED_SOLOMON_CODE: + case XQC_XOR_CODE: + return XQC_OK; + + default: + return -XQC_EFEC_NOT_SUPPORT_FEC; + } +} + +xqc_int_t +xqc_set_valid_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme) +{ + switch (scheme) { + case XQC_REED_SOLOMON_CODE: + *callback = xqc_reed_solomon_code_cb; + return XQC_OK; + case XQC_XOR_CODE: + *callback = xqc_xor_code_cb; + return XQC_OK; + } + + return -XQC_EFEC_SCHEME_ERROR; +} + + +unsigned char * +xqc_get_fec_scheme_str(xqc_fec_schemes_e scheme) +{ + switch (scheme) { + case XQC_REED_SOLOMON_CODE: + return "Reed-Solomon"; + case XQC_XOR_CODE: + return "XOR"; + case XQC_PACKET_MASK: + return "Packet-Mask"; + default: + return "Unknown"; + } +} + +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) +{ + uint32_t p, schemes_flag; + xqc_int_t i; + + if (*local_fec_schemes_buff_len == 0 || remote_fec_schemes_buff_len == 0) { + return -XQC_EFEC_NOT_SUPPORT_FEC; + } + + p = schemes_flag = 0; + *final_scheme = 0; + + for (i = 0; i < remote_fec_schemes_buff_len; i++) { + if (remote_fec_schemes_buff[i] > XQC_FEC_MAX_SCHEME_VAL) { + continue; + } + p = 1 << remote_fec_schemes_buff[i]; + schemes_flag |= p; + } + + /* 初始化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]; + 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; +} + +xqc_int_t +xqc_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out) +{ + switch (in) { + case XQC_REED_SOLOMON_CODE: + *out = XQC_REED_SOLOMON_CODE; + return XQC_OK; + case XQC_XOR_CODE: + *out = XQC_XOR_CODE; + return XQC_OK; + case XQC_PACKET_MASK: + *out = XQC_PACKET_MASK; + return XQC_OK; + default: + break; + } + + return -XQC_EFEC_SCHEME_ERROR; +} + +xqc_int_t +xqc_set_fec_schemes(const xqc_fec_schemes_e *schemes, xqc_int_t schemes_len, + xqc_fec_schemes_e *fec_schemes_buff, xqc_int_t *fec_schemes_buff_len) +{ + xqc_int_t i = 0, j = 0; + + for (i = 0; i < XQC_FEC_MAX_SCHEME_NUM; i++) + { + fec_schemes_buff[i] = 0; + } + + *fec_schemes_buff_len = 0; + for (i = 0, j = 0; i < schemes_len && j < XQC_FEC_MAX_SCHEME_NUM; i++) { + switch (schemes[i]) { + case XQC_XOR_CODE: + fec_schemes_buff[j] = XQC_XOR_CODE; + j++; + break; + case XQC_REED_SOLOMON_CODE: + fec_schemes_buff[j] = XQC_REED_SOLOMON_CODE; + j++; + break; + case XQC_PACKET_MASK: + fec_schemes_buff[j] = XQC_PACKET_MASK; + j++; + break; + default: + /* TODOfec: 失败报错, 缺少报错途径 */ + break; + } + + if (j != *fec_schemes_buff_len) { + *fec_schemes_buff_len = j; + } + } + 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) { + 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) +{ + if (src_symbol_num <= 0 || src_symbol_num > XQC_FEC_MAX_SYMBOL_NUM_PBLOCK) { + return -XQC_EFEC_SYMBOL_ERROR; + } + if (total_symbol_num <= src_symbol_num) { + return -XQC_EFEC_SYMBOL_ERROR; + } + if (max_window_size <= 0 || max_window_size > XQC_SYMBOL_CACHE_LEN) { + return -XQC_EFEC_SYMBOL_ERROR; + } + + return XQC_OK; +} + +/* 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_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; + } + + 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; + } + + 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; + } + + /* 为当前packet 生成SID Frame */ + ret = xqc_write_sid_frame_to_one_packet(conn, packet_out); + 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); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|quic_fec|xqc_process_fec_protected_packet|xqc_fec_encoder error|"); + 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); + 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; + } + } + + return XQC_OK; +} + + +xqc_int_t +xqc_gen_src_payload_id(xqc_fec_ctl_t *fec_ctl, uint64_t *payload_id) +{ + 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) { + return -XQC_EFEC_SYMBOL_ERROR; + } + *payload_id = fec_ctl->fec_send_src_symbols_num; + return XQC_OK; +} + +xqc_fec_ctl_t * +xqc_fec_ctl_create(xqc_connection_t *conn) +{ + xqc_int_t i, j; + xqc_fec_ctl_t *fec_ctl = NULL; + + fec_ctl = xqc_malloc(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; + + fec_ctl->fec_send_src_symbols_num = 0; + fec_ctl->fec_send_repair_symbols_num = 0; + + + 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); + } + + 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 (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); + } + } + + return fec_ctl; +} + +void +xqc_fec_ctl_destroy(xqc_fec_ctl_t *fec_ctl) +{ + xqc_int_t i, j; + 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; + } + } + + 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 (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; + } + } + } + + xqc_free(fec_ctl); +} + + +xqc_int_t +xqc_fec_ctl_save_symbol(unsigned char **symbol_buff_addr, const unsigned char *data, + xqc_int_t data_len) +{ + if (*symbol_buff_addr == NULL) { + return -XQC_EMALLOC; + } + xqc_memset(*symbol_buff_addr, 0, data_len); + xqc_memcpy(*symbol_buff_addr, data, data_len); + return XQC_OK; +} + +xqc_int_t +xqc_fec_ctl_init_send_params(xqc_fec_ctl_t *fec_ctl) +{ + xqc_int_t i, symbol_size, key_size; + + symbol_size = key_size = 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].is_valid) { + xqc_init_object_value(&fec_ctl->fec_send_repair_key[i]); + } + + if (fec_ctl->fec_send_repair_symbols_buff[i].is_valid) { + xqc_init_object_value(&fec_ctl->fec_send_repair_symbols_buff[i]); + } + } + + return XQC_OK; +} + +void +xqc_set_object_value(xqc_fec_object_t *object, xqc_int_t is_valid, + unsigned char *payload, size_t size) +{ + object->is_valid = is_valid; + object->payload = payload; + object->payload_size = size; +} + +void +xqc_init_object_value(xqc_fec_object_t *object) +{ + object->is_valid = 0; + xqc_memset(object->payload, 0, object->payload_size); + object->payload_size = 0; +} + +xqc_int_t +xqc_fec_ctl_init_recv_params(xqc_fec_ctl_t *fec_ctl, xqc_int_t block_idx) +{ + xqc_int_t j, symbol_size, key_size; + + 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]); + } + } + + 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]); + } + } + + return XQC_OK; +} + +xqc_int_t +xqc_negotiate_fec_schemes(xqc_connection_t *conn, xqc_transport_params_t params) +{ + xqc_int_t ret; + + ret = -XQC_EFEC_NOT_SUPPORT_FEC; + /* + * 如果对端发来了多种FEC schemes选择,接收端需要选择其中的一种FEC schemes并重新encode local_settings + * AS Server: + * 如果FEC协商成功 且 收到的FEC schemes列表长度大于1,需要进行选择; + * 随后需要进行重新设置并encode选择完成后的schemes list,其长度必须为1; + * AS Client: + * 需要设置服务端选择的FEC Scheme至conn_settings + */ + 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; + 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) + { + /* 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; + + } else { + conn->local_settings.enable_encode_fec = 0; + conn->local_settings.fec_encoder_schemes_num = 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.|"); + } + + /* 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) + { + 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; + + } else { + conn->local_settings.enable_decode_fec = 0; + conn->local_settings.fec_decoder_schemes_num = 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.|"); + } + return ret; + } + + /* 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); + } + + } 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 (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)); + + } 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); + } + + } 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."); + } + return ret; +} + +void +xqc_fec_record_flush_blk(xqc_connection_t *conn, xqc_int_t block_id) +{ + xqc_int_t skip_block, window_size, block_cache_idx; + + 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; + } + 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; + } + } +} + +xqc_int_t +xqc_process_valid_symbol(xqc_connection_t *conn, xqc_int_t block_id, xqc_int_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; + + 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; + + } else if (conn->fec_ctl->fec_recv_symbols_num[block_cache_idx] == 0) { + return XQC_OK; + } + + 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) + { + /* here the symbol value should not exits,otherwise it means there're some repeated sid in this block. */ + return -XQC_EFEC_SYMBOL_ERROR; + } + + ret = xqc_fec_ctl_save_symbol(&conn->fec_ctl->fec_recv_symbols_buff[block_cache_idx][symbol_idx].payload, + 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; + } + + tmp_payload_p = conn->fec_ctl->fec_recv_symbols_buff[block_cache_idx][symbol_idx].payload; + + xqc_set_object_value(&conn->fec_ctl->fec_recv_symbols_buff[block_cache_idx][symbol_idx], 1, tmp_payload_p, symbol_size); + + conn->fec_ctl->fec_recv_symbols_flag[block_cache_idx] ^= (1 << symbol_idx); + conn->fec_ctl->fec_recv_symbols_num[block_cache_idx]++; + + return XQC_OK; +} \ No newline at end of file diff --git a/src/transport/xqc_fec.h b/src/transport/xqc_fec.h new file mode 100644 index 000000000..df4c3c538 --- /dev/null +++ b/src/transport/xqc_fec.h @@ -0,0 +1,115 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_H_INCLUDED_ +#define _XQC_FEC_H_INCLUDED_ + + +#include +#include +#include +#include "src/transport/xqc_packet_out.h" +#include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_transport_params.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 + +typedef struct xqc_fec_object_s { + size_t payload_size; + xqc_int_t is_valid; + unsigned char *payload; +} xqc_fec_object_t; + +typedef struct xqc_fec_ctl_s { + xqc_connection_t *conn; + + xqc_int_t fec_flow_id; + uint32_t fec_recover_pkt_cnt; + 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]; +} xqc_fec_ctl_t; + +xqc_int_t xqc_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out); +/* + * @desc + * copy fec schemes from schemes to fec_schemes_buff, filtered by xqc_fec_schemes_e + */ +xqc_int_t xqc_set_fec_schemes(const xqc_fec_schemes_e *schemes, xqc_int_t schemes_len, + xqc_fec_schemes_e *fec_schemes_buff, xqc_int_t *fec_schemes_buff_len); + + +/* + * @desc + * 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_int_t xqc_is_packet_fec_protected(xqc_connection_t *conn, xqc_packet_out_t *packet_out); + + + +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_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_recv_params(xqc_fec_ctl_t *fec_ctl, xqc_int_t block_idx); + +xqc_int_t xqc_set_valid_scheme_cb(xqc_fec_code_callback_t *callback, xqc_int_t scheme); + +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); + +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, + unsigned char *symbol, xqc_int_t symbol_size); + +void xqc_fec_record_flush_blk(xqc_connection_t *conn, xqc_int_t block_id); +#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 new file mode 100644 index 000000000..bdc4b5da8 --- /dev/null +++ b/src/transport/xqc_fec_scheme.c @@ -0,0 +1,174 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#include "src/transport/xqc_fec_scheme.h" +#include "src/transport/xqc_conn.h" + + +xqc_int_t +xqc_fec_encoder(xqc_connection_t *conn, unsigned char *stream) +{ + 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 (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; + } + + 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; + } + + for (i = 0; i < repair_symbol_num; i++) { + repair_symbols_payload_buff[i] = conn->fec_ctl->fec_send_repair_symbols_buff[i].payload; + } + + ret = conn->conn_settings.fec_encode_callback.xqc_fec_encode(conn, stream, repair_symbols_payload_buff); + + 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); + } + + 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_int_t i, ret, res, symbol_idx, symbol_size; + + symbol_size = conn->remote_settings.fec_max_symbol_size; + res = XQC_OK; + + 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; + + 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; + + } 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++; + } + } + return res; +} + +xqc_int_t +xqc_fec_decoder(xqc_connection_t *conn, xqc_int_t block_idx) +{ + 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]; + + 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); + } + + 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; + } + 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++; + } + } + /* proceeds if there's no loss src symbol */ + if (loss_src_num == 0) { + ret = XQC_OK; + goto 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; + } + 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"); + ret = -XQC_EFEC_SCHEME_ERROR; + goto 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]); + } + +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; + } + 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]); + } + } + 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 new file mode 100644 index 000000000..8f7c077d5 --- /dev/null +++ b/src/transport/xqc_fec_scheme.h @@ -0,0 +1,29 @@ + +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + + +#ifndef _XQC_FEC_SCHEME_H_INCLUDED_ +#define _XQC_FEC_SCHEME_H_INCLUDED_ + + +#include +#include +#include "src/transport/fec_schemes/xqc_reed_solomon.h" + + +typedef enum { + XQC_FEC_ENCODE_TYPE_NORMAL, + XQC_FEC_ENCODE_TYPE_UNI, +} xqc_fec_encode_type_t; + + +xqc_int_t xqc_fec_encoder(xqc_connection_t *conn, unsigned char *stream); + +xqc_int_t xqc_fec_decoder(xqc_connection_t *conn, xqc_int_t block_idx); + +xqc_int_t xqc_process_recovered_packet(xqc_connection_t *conn, unsigned char **recovered_symbols_buff, + xqc_int_t loss_symbol_idx_len); + +#endif /* _XQC_FEC_SCHEME_H_INCLUDED_ */ diff --git a/src/transport/xqc_frame.c b/src/transport/xqc_frame.c index f6c12785e..4aff7fb2b 100644 --- a/src/transport/xqc_frame.c +++ b/src/transport/xqc_frame.c @@ -49,25 +49,23 @@ static const char * const frame_type_2_str[XQC_FRAME_NUM] = { [XQC_FRAME_Extension] = "Extension", }; -static char g_frame_type_buf[128]; - const char * -xqc_frame_type_2_str(xqc_frame_type_bit_t type_bit) +xqc_frame_type_2_str(xqc_engine_t *engine, xqc_frame_type_bit_t type_bit) { - g_frame_type_buf[0] = '\0'; + engine->frame_type_buf[0] = '\0'; size_t pos = 0; int wsize; for (int i = 0; i < XQC_FRAME_NUM; i++) { if (type_bit & 1 << i) { - wsize = snprintf(g_frame_type_buf + pos, sizeof(g_frame_type_buf) - pos, "%s ", + wsize = snprintf(engine->frame_type_buf + pos, sizeof(engine->frame_type_buf) - pos, "%s ", frame_type_2_str[i]); - if (wsize < 0 || wsize >= sizeof(g_frame_type_buf) - pos) { + if (wsize < 0 || wsize >= sizeof(engine->frame_type_buf) - pos) { break; } pos += wsize; } } - return g_frame_type_buf; + return engine->frame_type_buf; } unsigned int @@ -351,6 +349,32 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) ret = -XQC_EMP_INVALID_MP_VERTION; } break; + +#ifdef XQC_ENABLE_FEC + case 0xfec5: + if (conn->conn_settings.enable_decode_fec + && conn->conn_settings.fec_params.fec_decoder_scheme != 0) + { + ret = xqc_process_sid_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|fec negotiation failed but still received fec packet."); + ret = -XQC_EFEC_NOT_SUPPORT_FEC; + } + break; + + case 0xfec6: + if (conn->conn_settings.enable_decode_fec + && conn->conn_settings.fec_params.fec_decoder_scheme != 0) + { + ret = xqc_process_repair_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|fec negotiation failed but still received fec packet."); + ret = -XQC_EFEC_NOT_SUPPORT_FEC; + } + break; +#endif default: xqc_log(conn->log, XQC_LOG_ERROR, "|unknown frame type|"); return -XQC_EIGNORE_PKT; @@ -432,6 +456,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)) @@ -455,10 +480,11 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) conn->stream_stats.recv_bytes += stream_frame->data_length; - xqc_stream_path_metrics_on_recv(conn, stream, packet_in); - - if (packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) { - stream->paths_info[packet_in->pi_path_id].path_recv_bytes += stream_frame->data_length; + 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) { + stream->paths_info[packet_in->pi_path_id].path_recv_bytes += stream_frame->data_length; + } } if (stream->stream_state_recv >= XQC_RECV_STREAM_ST_RESET_RECVD) { @@ -568,7 +594,9 @@ xqc_process_stream_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_stream_ready_to_read(stream); } - if (packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) { + if (!(packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) + && packet_in->pi_path_id < XQC_MAX_PATHS_COUNT) + { stream->paths_info[packet_in->pi_path_id].path_recv_effective_bytes += stream_frame->data_length; } @@ -698,11 +726,13 @@ xqc_process_ack_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_ack_frame error|"); return ret; } + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } for (int i = 0; i < ack_info.n_ranges; i++) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|high:%ui|low:%ui|pkt_pns:%d|", - ack_info.ranges[i].high, ack_info.ranges[i].low, packet_in->pi_pkt.pkt_pns); - xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, ack_info.ranges[i].low); + xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, + ack_info.ranges[i].low, packet_in->pi_path_id); } /* 对端还不支持MP,或还未握手确认时,使用 initial path */ @@ -756,7 +786,7 @@ 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(&new_conn_cid), xqc_sr_token_str(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) { /* @@ -874,6 +904,10 @@ xqc_process_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet "|xqc_parse_retire_conn_id_frame error|"); return ret; } + + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } if (seq_num > conn->scid_set.largest_scid_seq_num) { /* @@ -971,6 +1005,7 @@ xqc_process_conn_close_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } } conn->conn_state = XQC_CONN_STATE_DRAINING; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); xqc_conn_closing(conn); return XQC_OK; @@ -1425,6 +1460,10 @@ xqc_process_path_challenge_frame(xqc_connection_t *conn, xqc_packet_in_t *packet return ret; } + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + //TODO: MPQUIC fix migration xqc_path_ctx_t *path = NULL; if (conn->enable_multipath) { @@ -1449,7 +1488,7 @@ xqc_process_path_challenge_frame(xqc_connection_t *conn, xqc_packet_in_t *packet } else { xqc_log(conn->log, XQC_LOG_ERROR, "|no path to challenge|dcid:%s|path_id:%ui|", - xqc_dcid_str(&packet_in->pi_pkt.pkt_dcid), + xqc_dcid_str(conn->engine, &packet_in->pi_pkt.pkt_dcid), packet_in->pi_path_id); return XQC_OK; } @@ -1458,7 +1497,7 @@ xqc_process_path_challenge_frame(xqc_connection_t *conn, xqc_packet_in_t *packet xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|state:%d|RECV path_challenge_data:%s|cid:%s|", path->path_id, path->path_state, - path_challenge_data, xqc_dcid_str(&packet_in->pi_pkt.pkt_dcid)); + path_challenge_data, xqc_dcid_str(conn->engine, &packet_in->pi_pkt.pkt_dcid)); ret = xqc_write_path_response_frame_to_packet(conn, path, path_challenge_data); if (ret != XQC_OK) { @@ -1482,6 +1521,10 @@ xqc_process_path_response_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_ return ret; } + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + //TODO: MPQUIC fix migration xqc_path_ctx_t *path = NULL; if (conn->enable_multipath) { @@ -1489,7 +1532,7 @@ xqc_process_path_response_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_ if (path == NULL) { xqc_log(conn->log, XQC_LOG_ERROR, "|ingnore path response|pkt_dcid:%s|path_id:%ui|", - xqc_scid_str(&packet_in->pi_pkt.pkt_dcid), + xqc_scid_str(conn->engine, &packet_in->pi_pkt.pkt_dcid), packet_in->pi_path_id); return XQC_OK; } @@ -1565,6 +1608,10 @@ xqc_process_ack_mp_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) return ret; } + if ((packet_in->pi_flag & XQC_PIF_FEC_RECOVERED) != 0) { + return XQC_OK; + } + xqc_path_ctx_t *path_to_be_acked = xqc_conn_find_path_by_dcid_seq(conn, dcid_seq_num); if (path_to_be_acked == NULL) { xqc_log(conn->log, XQC_LOG_INFO, "|ignore unknown path|dcid_seq:%ui|", dcid_seq_num); @@ -1579,9 +1626,8 @@ xqc_process_ack_mp_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) } for (int i = 0; i < ack_info.n_ranges; i++) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|high:%ui|low:%ui|pkt_pns:%d|", path_to_be_acked->path_id, - ack_info.ranges[i].high, ack_info.ranges[i].low, packet_in->pi_pkt.pkt_pns); - xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, ack_info.ranges[i].low); + xqc_log_event(conn->log, TRA_PACKETS_ACKED, packet_in, ack_info.ranges[i].high, + ack_info.ranges[i].low, path_to_be_acked->path_id); } xqc_pn_ctl_t *pn_ctl = xqc_get_pn_ctl(conn, path_to_be_acked); @@ -1760,3 +1806,37 @@ xqc_process_path_available_frame(xqc_connection_t *conn, xqc_packet_in_t *packet return XQC_OK; } + +#ifdef XQC_ENABLE_FEC +xqc_int_t +xqc_process_sid_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in) +{ + xqc_int_t ret; + + ret = xqc_parse_sid_frame(conn, packet_in); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_sid_frame err|ret:%d|", ret); + } + if (ret == -XQC_EVINTREAD) { + return ret; + } + /* if there's error, just ignore fec module */ + return XQC_OK; +} + +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); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_parse_repair_frame err|ret:%d|", ret); + } + if (ret == -XQC_EVINTREAD) { + return ret; + } + /* if there's error, just ignore fec module */ + 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 f39482836..ff7d18857 100644 --- a/src/transport/xqc_frame.h +++ b/src/transport/xqc_frame.h @@ -36,6 +36,8 @@ typedef enum { XQC_FRAME_DATAGRAM, XQC_FRAME_Extension, XQC_FRAME_NUM, + XQC_FRAME_SID, + XQC_FRAME_REPAIR_SYMBOL, } xqc_frame_type_t; typedef enum { @@ -67,6 +69,8 @@ typedef enum { 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_type_bit_t; @@ -79,7 +83,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)) +#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)) /* * https://tools.ietf.org/html/draft-ietf-quic-recovery-24#section-3 @@ -97,10 +101,10 @@ typedef enum { * PING and PADDING frames contain no information, so lost PING or * PADDING frames do not require repair */ -#define XQC_NEED_REPAIR(types) ((types) & ~(XQC_FRAME_BIT_ACK| XQC_FRAME_BIT_PADDING | XQC_FRAME_BIT_PING | XQC_FRAME_BIT_CONNECTION_CLOSE | XQC_FRAME_BIT_DATAGRAM)) +#define XQC_NEED_REPAIR(types) ((types) & ~(XQC_FRAME_BIT_ACK| XQC_FRAME_BIT_PADDING | XQC_FRAME_BIT_PING | XQC_FRAME_BIT_CONNECTION_CLOSE | XQC_FRAME_BIT_DATAGRAM | XQC_FRAME_BIT_SID | XQC_FRAME_BIT_REPAIR_SYMBOL)) -const char *xqc_frame_type_2_str(xqc_frame_type_bit_t type_bit); +const char *xqc_frame_type_2_str(xqc_engine_t *engine, xqc_frame_type_bit_t type_bit); unsigned int xqc_stream_frame_header_size(xqc_stream_id_t stream_id, uint64_t offset, size_t length); @@ -162,4 +166,8 @@ xqc_int_t xqc_process_path_available_frame(xqc_connection_t *conn, xqc_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); + #endif /* _XQC_FRAME_H_INCLUDED_ */ diff --git a/src/transport/xqc_frame_parser.c b/src/transport/xqc_frame_parser.c index f999ca502..a615337ef 100644 --- a/src/transport/xqc_frame_parser.c +++ b/src/transport/xqc_frame_parser.c @@ -8,16 +8,19 @@ #include "src/common/utils/vint/xqc_variable_len_int.h" #include "src/common/xqc_log.h" #include "src/common/xqc_log_event_callback.h" +#include "src/common/xqc_str.h" #include "src/transport/xqc_conn.h" #include "src/transport/xqc_stream.h" #include "src/transport/xqc_packet_out.h" #include "src/transport/xqc_packet_parser.h" #include "src/transport/xqc_reinjection.h" +#include "src/transport/xqc_fec_scheme.h" /** * generate datagram frame */ -xqc_int_t xqc_gen_datagram_frame(xqc_packet_out_t *packet_out, +xqc_int_t +xqc_gen_datagram_frame(xqc_packet_out_t *packet_out, const unsigned char *payload, size_t size) { if (packet_out == NULL) { @@ -25,7 +28,7 @@ xqc_int_t xqc_gen_datagram_frame(xqc_packet_out_t *packet_out, } unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_len = xqc_get_po_remained_size(packet_out); unsigned char *p = dst_buf + 1; if ((size + 1 + XQC_DATAGRAM_LENGTH_FIELD_BYTES) > dst_buf_len) { @@ -125,7 +128,7 @@ xqc_gen_stream_frame(xqc_packet_out_t *packet_out, */ unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_len = xqc_get_po_remained_size(packet_out); *written_size = 0; /* variable length integer's most significant 2 bits */ @@ -365,7 +368,7 @@ xqc_gen_crypto_frame(xqc_packet_out_t *packet_out, uint64_t offset, const unsigned char *payload, uint64_t payload_size, size_t *written_size) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size; + size_t dst_buf_len = xqc_get_po_remained_size(packet_out); unsigned char offset_bits, length_bits; unsigned offset_vlen, length_vlen; @@ -450,7 +453,7 @@ void xqc_gen_padding_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) { size_t total_len = XQC_PACKET_INITIAL_MIN_LENGTH; - + if (conn->conn_settings.enable_pmtud) { if ((packet_out->po_frame_types & (XQC_FRAME_BIT_PATH_CHALLENGE | XQC_FRAME_BIT_PATH_RESPONSE)) || (packet_out->po_flag & XQC_POF_PMTUD_PROBING)) @@ -467,6 +470,27 @@ xqc_gen_padding_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) } } +xqc_int_t +xqc_gen_padding_frame_with_len(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + size_t padding_len, size_t limit) +{ + unsigned char *p; + + /* fec模式padding长度 */ + if (packet_out->po_used_size + padding_len > limit) { + xqc_log(conn->log, XQC_LOG_WARN, "|packet_out too large|"); + return -XQC_EFEC_SYMBOL_ERROR; + } + + if (packet_out->po_used_size < limit) { + packet_out->po_padding = packet_out->po_buf + packet_out->po_used_size; + memset(packet_out->po_padding, 0, padding_len); + packet_out->po_used_size += padding_len; + packet_out->po_frame_types |= XQC_FRAME_BIT_PADDING; + } + return XQC_OK; +} + xqc_int_t xqc_parse_padding_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn) { @@ -491,7 +515,7 @@ xqc_gen_ping_frame(xqc_packet_out_t *packet_out) unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; unsigned need = 1; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } *dst_buf++ = 0x01; @@ -510,7 +534,336 @@ xqc_parse_ping_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn) return XQC_OK; } +#ifdef XQC_ENABLE_FEC +ssize_t +xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + size_t dst_buf_len = XQC_FEC_SPACE; + 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; + } + + /* gen src_payload_id and save src symbol */ + ret = xqc_gen_src_payload_id(conn->fec_ctl, &src_payload_id); + if (ret != XQC_OK) { + xqc_log(conn->log, XQC_LOG_ERROR, "|generate source payload id error."); + return -XQC_EFEC_SYMBOL_ERROR; + } + frame_type_bits = xqc_vint_get_2bit(frame_type); + flow_id_bits = xqc_vint_get_2bit(flow_id); + src_payload_id_bits = xqc_vint_get_2bit(src_payload_id); + + need = xqc_vint_len(frame_type_bits) /* type: 0xfec5 */ + + 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; + } + + 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, flow_id, flow_id_bits, xqc_vint_len(flow_id_bits)); + dst_buf += xqc_vint_len(flow_id_bits); + + 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) +{ + 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; + 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; + + vlen = xqc_vint_read(p, end, &frame_type); + if (vlen < 0 || frame_type != 0xfec5) { + return -XQC_EVINTREAD; + } + p += vlen; + sid_frame_len += vlen; + + 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); + 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; + } + } + +end_parse: + packet_in->pos = (unsigned char *)p; + packet_in->pi_frame_types |= XQC_FRAME_BIT_SID; + return ret; +} + +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) +{ + if (packet_out == NULL + || repair_idx < 0 + || repair_idx >= XQC_REPAIR_LEN + || repair_key_size < 0) + { + xqc_log(conn->log, XQC_LOG_WARN, "fec parameter error"); + 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) + { + xqc_log(conn->log, XQC_LOG_WARN, "No available repair key or repair symbol"); + return -XQC_EFEC_SYMBOL_ERROR; + } + + 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 char *dst_buf, *repair_symbol_p, *repair_key_p; + + const unsigned char *begin, *end; + + 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; + + 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; + } + + 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) + + repair_key_size + + 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); + + xqc_vint_write(dst_buf, flow_id, flow_id_bits, xqc_vint_len(flow_id_bits)); + dst_buf += xqc_vint_len(flow_id_bits); + + xqc_vint_write(dst_buf, fss_esi, fss_esi_bits, xqc_vint_len(fss_esi_bits)); + dst_buf += xqc_vint_len(fss_esi_bits); + + 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_memcpy(dst_buf, repair_key_p, repair_key_size); + dst_buf += repair_key_size; + + 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) +{ + 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; + 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; + } + 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; + + vlen = xqc_vint_read(p, end, &repair_payload_id); + if (vlen < 0) { + return -XQC_EVINTREAD; + } + p += vlen; + repair_payload_len += vlen; + + 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; + } + + 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; + } + conn->fec_ctl->fec_recv_repair_num++; + + 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; + } + + 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) { + 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|"); + 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; + packet_in->pi_frame_types |= XQC_FRAME_BIT_REPAIR_SYMBOL; + + return ret; +} +#endif /* * 0 1 2 3 @@ -547,7 +900,7 @@ xqc_gen_ack_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_usec int *has_gap, xqc_packet_number_t *largest_ack) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size + XQC_ACK_SPACE; + size_t dst_buf_len = xqc_get_po_remained_size_with_ack_spc(packet_out); xqc_packet_number_t lagest_recv, prev_low; xqc_usec_t ack_delay; @@ -786,7 +1139,7 @@ xqc_gen_conn_close_frame(xqc_packet_out_t *packet_out, + xqc_vint_len(frame_type_bits) + xqc_vint_len(reason_len_bits) + reason_len; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -891,7 +1244,7 @@ xqc_gen_reset_stream_frame(xqc_packet_out_t *packet_out, xqc_stream_id_t stream_ + xqc_vint_len(err_code_bits) + xqc_vint_len(final_size_bits) ; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -972,7 +1325,7 @@ xqc_gen_stop_sending_frame(xqc_packet_out_t *packet_out, xqc_stream_id_t stream_ + xqc_vint_len(stream_id_bits) + xqc_vint_len(err_code_bits) ; - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1381,11 +1734,10 @@ xqc_gen_new_token_frame(xqc_packet_out_t *packet_out, const unsigned char *token xqc_vint_write(dst_buf, token_len, token_len_bits, xqc_vint_len(token_len_bits)); dst_buf += xqc_vint_len(token_len_bits); - if (packet_out->po_used_size - + 1 + if (1 + xqc_vint_len(token_len_bits) + token_len - > packet_out->po_buf_size) + > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1443,7 +1795,7 @@ xqc_gen_handshake_done_frame(xqc_packet_out_t *packet_out) const unsigned char *begin = dst_buf; unsigned need = 1; /* only need 1 byte */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } *dst_buf++ = 0x1e; @@ -1665,7 +2017,7 @@ xqc_gen_path_challenge_frame(xqc_packet_out_t *packet_out, unsigned char *data) need = xqc_vint_len(frame_type_bits) + XQC_PATH_CHALLENGE_DATA_LEN; /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1725,7 +2077,7 @@ xqc_gen_path_response_frame(xqc_packet_out_t *packet_out, unsigned char *data) need = xqc_vint_len(frame_type_bits) + XQC_PATH_CHALLENGE_DATA_LEN; /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -1787,6 +2139,7 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, 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; @@ -1799,7 +2152,7 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t dcid_seq, } unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; - size_t dst_buf_len = packet_out->po_buf_size - packet_out->po_used_size + XQC_ACK_SPACE; + size_t dst_buf_len = xqc_get_po_remained_size_with_ack_spc(packet_out); xqc_packet_number_t lagest_recv, prev_low; xqc_usec_t ack_delay; @@ -2047,9 +2400,11 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; - unsigned need = 0; + unsigned need, po_remained_size; uint64_t frame_type; + need = po_remained_size = 0; + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_04) { frame_type = 0xbaba05; @@ -2075,8 +2430,10 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + xqc_vint_len(reason_len_bits) + reason_len; + po_remained_size = xqc_get_po_remained_size(packet_out); + /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > po_remained_size) { return -XQC_ENOBUF; } @@ -2203,7 +2560,7 @@ xqc_gen_path_status_frame(xqc_connection_t *conn, + xqc_vint_len(path_status_bits); /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -2309,7 +2666,7 @@ xqc_gen_path_standby_frame(xqc_connection_t *conn, + xqc_vint_len(path_status_seq_num_bits); /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } @@ -2407,7 +2764,7 @@ xqc_gen_path_available_frame(xqc_connection_t *conn, + xqc_vint_len(path_status_seq_num_bits); /* check packout_out have enough buffer length */ - if (need > packet_out->po_buf_size - packet_out->po_used_size) { + if (need > xqc_get_po_remained_size(packet_out)) { return -XQC_ENOBUF; } diff --git a/src/transport/xqc_frame_parser.h b/src/transport/xqc_frame_parser.h index 19aa56430..ca79e9574 100644 --- a/src/transport/xqc_frame_parser.h +++ b/src/transport/xqc_frame_parser.h @@ -43,6 +43,9 @@ xqc_int_t xqc_parse_crypto_frame(xqc_packet_in_t *packet_in, xqc_connection_t *c void xqc_gen_padding_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out); +xqc_int_t xqc_gen_padding_frame_with_len(xqc_connection_t *conn, xqc_packet_out_t *packet_out, + size_t padding_len, size_t limit); + xqc_int_t xqc_parse_padding_frame(xqc_packet_in_t *packet_in, xqc_connection_t *conn); ssize_t xqc_gen_ping_frame(xqc_packet_out_t *packet_out); @@ -158,4 +161,12 @@ 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); +ssize_t xqc_gen_sid_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out); + +xqc_int_t 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_int_t xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in); + #endif /*_XQC_FRAME_PARSER_H_INCLUDED_*/ diff --git a/src/transport/xqc_multipath.c b/src/transport/xqc_multipath.c index f45719bb3..0d1136cd7 100644 --- a/src/transport/xqc_multipath.c +++ b/src/transport/xqc_multipath.c @@ -120,7 +120,7 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) /* already have scid */ xqc_cid_inner_t *inner_cid = xqc_cid_in_cid_set(&conn->scid_set.cid_set, scid); if (inner_cid == NULL) { - xqc_log(conn->log, XQC_LOG_DEBUG, "|invalid scid:%s|", xqc_scid_str(scid)); + xqc_log(conn->log, XQC_LOG_DEBUG, "|invalid scid:%s|", xqc_scid_str(conn->engine, scid)); goto err; } @@ -149,7 +149,7 @@ xqc_path_create(xqc_connection_t *conn, xqc_cid_t *scid, xqc_cid_t *dcid) conn->create_path_count++; xqc_log(conn->engine->log, XQC_LOG_DEBUG, "|path:%ui|dcid:%s|scid:%s|create_path_count:%ud|", - path->path_id, xqc_dcid_str(&path->path_dcid), xqc_scid_str(&path->path_scid), conn->create_path_count); + path->path_id, xqc_dcid_str(conn->engine, &path->path_dcid), xqc_scid_str(conn->engine, &path->path_scid), conn->create_path_count); return path; @@ -211,7 +211,7 @@ 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(&path->path_dcid), xqc_scid_str(&path->path_scid), path->path_state); + path->path_id, xqc_dcid_str(conn->engine, &path->path_dcid), xqc_scid_str(path->parent_conn->engine, &path->path_scid), path->path_state); return XQC_OK; } @@ -660,7 +660,7 @@ xqc_conn_create_path_inner(xqc_connection_t *conn, xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_path_init error|%d|", ret); return NULL; } - + xqc_log_event(conn->log, CON_PATH_ASSIGNED, path, conn); return path; } @@ -778,7 +778,7 @@ xqc_stream_path_metrics_print(xqc_connection_t *conn, xqc_stream_t *stream, char if (!conn->enable_multipath) { snprintf(buff, buff_size, "mp is not supported in connection scid:%s", - xqc_scid_str(&conn->scid_set.user_scid)); + xqc_scid_str(conn->engine, &conn->scid_set.user_scid)); return; } @@ -1058,8 +1058,8 @@ xqc_conn_server_init_path_addr(xqc_connection_t *conn, uint64_t path_id, 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|", path_id, xqc_conn_addr_str(conn), - xqc_peer_addr_str((struct sockaddr*)peer_addr, conn->peer_addrlen), - xqc_local_addr_str((struct sockaddr*)active_path->peer_addr, active_path->peer_addrlen)); + 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)); return XQC_OK; } } diff --git a/src/transport/xqc_multipath.h b/src/transport/xqc_multipath.h index 1e1d8688e..78ce62ee4 100644 --- a/src/transport/xqc_multipath.h +++ b/src/transport/xqc_multipath.h @@ -188,8 +188,7 @@ typedef struct { uint32_t red_dgram_recv_cnt; uint32_t standby_probe_count; - uint32_t app_path_status_changed_count; - + uint32_t app_path_status_changed_count; } xqc_path_info_t; xqc_bool_t xqc_is_same_addr(const struct sockaddr *sa1, const struct sockaddr *sa2); diff --git a/src/transport/xqc_packet.c b/src/transport/xqc_packet.c index 308cb4c55..9dbb001bd 100644 --- a/src/transport/xqc_packet.c +++ b/src/transport/xqc_packet.c @@ -192,8 +192,9 @@ xqc_packet_decrypt_single(xqc_connection_t *c, xqc_packet_in_t *packet_in) ret = -XQC_EIGNORE_PKT; } else { - xqc_log(c->log, XQC_LOG_WARN, "|decrypt data error, return|%d|pkt_type:%s|pkt_num:%ui|", - ret, xqc_pkt_type_2_str(packet_in->pi_pkt.pkt_type), packet_in->pi_pkt.pkt_num); + xqc_log_event(c->log, TRA_PACKET_DROPPED, "decrypt data error", ret, + xqc_pkt_type_2_str(packet_in->pi_pkt.pkt_type), packet_in->pi_pkt.pkt_num); + c->packet_dropped_count ++; ret = -XQC_EDECRYPT; /* don't close connection, just drop the packet */ } diff --git a/src/transport/xqc_packet.h b/src/transport/xqc_packet.h index 3427e6af7..70036a326 100644 --- a/src/transport/xqc_packet.h +++ b/src/transport/xqc_packet.h @@ -10,8 +10,10 @@ #include "src/tls/xqc_tls_defs.h" #define XQC_ACK_SPACE 16 +#define XQC_FEC_SPACE 12 +#define XQC_HEADER_SPACE 28 #define XQC_QUIC_MIN_MSS 1200 -/* 1500 - 40 (IPv6) - 8 (UDP) - 16 (ACK) - 16 (AEAD)*/ +/* 1500 - 40 (IPv6) - 8 (UDP) - 16 (ACK) - 16 (AEAD) */ #define XQC_QUIC_MAX_MSS 1420 #define XQC_MSS (XQC_QUIC_MAX_MSS + XQC_ACK_SPACE) diff --git a/src/transport/xqc_packet_in.h b/src/transport/xqc_packet_in.h index f5a341766..d14509af0 100644 --- a/src/transport/xqc_packet_in.h +++ b/src/transport/xqc_packet_in.h @@ -14,6 +14,7 @@ typedef enum { XQC_PIF_REINJECTED_REPLICA = 1 << 0, + XQC_PIF_FEC_RECOVERED = 1 << 1, } xqc_packet_in_flag_t; struct xqc_packet_in_s { diff --git a/src/transport/xqc_packet_out.c b/src/transport/xqc_packet_out.c index d82c36341..8e39cb681 100644 --- a/src/transport/xqc_packet_out.c +++ b/src/transport/xqc_packet_out.c @@ -112,6 +112,10 @@ xqc_packet_out_can_attach_ack(xqc_packet_out_t *po, return XQC_FALSE; } + if (po->po_frame_types & XQC_FRAME_BIT_REPAIR_SYMBOL) { + return XQC_FALSE; + } + return XQC_TRUE; } @@ -187,12 +191,11 @@ xqc_packet_out_get(xqc_send_queue_t *send_queue) { xqc_packet_out_t *packet_out; unsigned int buf_size; - size_t buf_cap; + size_t buf_cap, reserved_size; xqc_list_head_t *pos, *next; xqc_list_for_each_safe(pos, next, &send_queue->sndq_free_packets) { packet_out = xqc_list_entry(pos, xqc_packet_out_t, po_list); - xqc_send_queue_remove_free(pos, send_queue); unsigned char *tmp = packet_out->po_buf; @@ -202,7 +205,7 @@ xqc_packet_out_get(xqc_send_queue_t *send_queue) packet_out->po_buf = tmp; packet_out->po_buf_size = buf_size; packet_out->po_buf_cap = buf_cap; - return packet_out; + goto return_po; } packet_out = xqc_packet_out_create(send_queue->sndq_conn->pkt_out_size); @@ -210,6 +213,12 @@ xqc_packet_out_get(xqc_send_queue_t *send_queue) return NULL; } +return_po: + reserved_size = 0; + if (send_queue->sndq_conn->conn_settings.fec_params.fec_encoder_scheme) { + reserved_size += XQC_FEC_SPACE; + } + packet_out->po_reserved_size = reserved_size; return packet_out; } @@ -431,6 +440,71 @@ xqc_write_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out return ret; } +#ifdef XQC_ENABLE_FEC +xqc_int_t +xqc_write_sid_frame_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out) +{ + ssize_t ret; + + ret = xqc_gen_sid_frame(conn, packet_out); + + if (ret < 0) { + xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_sid_frame error|"); + return -XQC_EWRITE_PKT; + } + packet_out->po_used_size += ret; + + return XQC_OK; +} + +xqc_int_t +xqc_write_repair_packets(xqc_connection_t *conn, xqc_int_t fss_esi, xqc_list_head_t *prev) +{ + xqc_int_t ret, repair_packet_num, max_symbol_num, max_src_symbol_num, curr_repair_idx, repair_symbol_size, repair_key_size; + 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; + + repair_packet_num = conn->fec_ctl->fec_send_repair_symbols_num; + + 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); + 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); + + return XQC_OK; +} +#endif xqc_int_t xqc_write_ack_or_mp_ack_to_one_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_pkt_num_space_t pns, xqc_path_ctx_t *path, xqc_bool_t is_mp_ack) { @@ -1253,7 +1327,7 @@ xqc_write_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire_pr packet_out->po_used_size += ret; xqc_log(conn->log, XQC_LOG_DEBUG, "|gen_new_scid|cid:%s|sr_token:%s|seq_num:%ui", - xqc_scid_str(&new_conn_cid), xqc_sr_token_str(new_conn_cid.sr_token), + 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); @@ -1283,8 +1357,7 @@ xqc_write_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_nu xqc_datagram_record_mss(conn); } xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|", - xqc_dcid_str(&conn->dcid_set.current_dcid), - conn->dcid_set.current_dcid.cid_seq_num); + 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) { @@ -1358,7 +1431,7 @@ xqc_write_path_challenge_frame_to_packet(xqc_connection_t *conn, xqc_log(conn->log, XQC_LOG_DEBUG, "|initial_path_status|status:%d|frames:%s|", path->app_path_status, - xqc_frame_type_2_str(packet_out->po_frame_types)); + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types)); packet_out->po_used_size += ret; } } @@ -1564,3 +1637,22 @@ xqc_write_path_standby_or_available_frame_to_packet(xqc_connection_t *conn, xqc_ 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; + if (res >= 0) { + return res; + } + return po->po_buf_size - po->po_used_size; +} + +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; +} + diff --git a/src/transport/xqc_packet_out.h b/src/transport/xqc_packet_out.h index 4e43d1d91..83b5f37b2 100644 --- a/src/transport/xqc_packet_out.h +++ b/src/transport/xqc_packet_out.h @@ -113,6 +113,8 @@ typedef struct xqc_packet_out_s { /* PMTUD Probing */ size_t po_max_pkt_out_size; + size_t po_reserved_size; + /* ping notification */ xqc_ping_record_t *po_pr; @@ -211,7 +213,20 @@ xqc_int_t xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_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); + int xqc_write_pmtud_ping_to_packet(xqc_path_ctx_t *path, size_t probing_size, xqc_pkt_type_t pkt_type); +/** + * @brief Get remained space size in packet out buff. + * + * @param conn + * @param po + * @return size_t + */ +size_t xqc_get_po_remained_size(xqc_packet_out_t *po); +size_t xqc_get_po_remained_size_with_ack_spc(xqc_packet_out_t *po); #endif /* _XQC_PACKET_OUT_H_INCLUDED_ */ diff --git a/src/transport/xqc_packet_parser.c b/src/transport/xqc_packet_parser.c index 7893cda2a..35ea7e979 100644 --- a/src/transport/xqc_packet_parser.c +++ b/src/transport/xqc_packet_parser.c @@ -271,7 +271,7 @@ xqc_packet_parse_short_header(xqc_connection_t *c, xqc_packet_in_t *packet_in) if (xqc_conn_check_dcid(c, &(packet->pkt_dcid)) != XQC_OK) { /* log & ignore, the pkt might be corrupted or stateless reset */ xqc_log(c->log, XQC_LOG_WARN, "|parse short header|invalid destination cid, pkt dcid: %s, conn scid: %s|", - xqc_dcid_str(&packet->pkt_dcid), xqc_scid_str(&c->scid_set.user_scid)); + xqc_dcid_str(c->engine, &packet->pkt_dcid), xqc_scid_str(c->engine, &c->scid_set.user_scid)); return -XQC_EILLPKT; } @@ -292,7 +292,7 @@ xqc_packet_parse_short_header(xqc_connection_t *c, xqc_packet_in_t *packet_in) } 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(&(packet->pkt_dcid)), spin_bit); + packet_in->pi_path_id, xqc_scid_str(c->engine, &(packet->pkt_dcid)), spin_bit); /* packet number */ packet_in->pi_pkt.length = packet_in->last - pos; @@ -1047,8 +1047,8 @@ xqc_packet_parse_retry(xqc_connection_t *c, xqc_packet_in_t *packet_in) */ if (xqc_cid_is_equal(&c->original_dcid, &packet_in->pi_pkt.pkt_scid) == XQC_OK) { xqc_log(c->log, XQC_LOG_DEBUG, "|discard|packet SCID error|odcid:%s|scid:%s|", - xqc_dcid_str(&c->original_dcid), - xqc_scid_str(&packet_in->pi_pkt.pkt_scid)); + xqc_dcid_str(c->engine, &c->original_dcid), + xqc_scid_str(c->engine, &packet_in->pi_pkt.pkt_scid)); return -XQC_EILLPKT; } @@ -1142,7 +1142,7 @@ xqc_packet_parse_version_negotiation(xqc_connection_t *c, xqc_packet_in_t *packe /* check original DCID */ if (xqc_cid_is_equal(&c->original_dcid, &packet_in->pi_pkt.pkt_scid) != XQC_OK) { xqc_log(c->log, XQC_LOG_ERROR, "|version negotiation pkt SCID error|original_dcid:%s|scid:%s|", - xqc_dcid_str(&c->original_dcid), xqc_scid_str(&packet_in->pi_pkt.pkt_scid)); + xqc_dcid_str(c->engine, &c->original_dcid), xqc_scid_str(c->engine, &packet_in->pi_pkt.pkt_scid)); return -XQC_EILLPKT; } diff --git a/src/transport/xqc_recv_record.c b/src/transport/xqc_recv_record.c index 85e0a11cb..525fde8b3 100644 --- a/src/transport/xqc_recv_record.c +++ b/src/transport/xqc_recv_record.c @@ -294,7 +294,7 @@ xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t "pns:%d|flag:%s|ack_freq:%ud|", path->path_id, out_of_order, send_ctl->ctl_ack_eliciting_pkt[pns], - pns, xqc_conn_flag_2_str(conn->conn_flag), + pns, xqc_conn_flag_2_str(conn, conn->conn_flag), ack_frequency); } else if (send_ctl->ctl_ack_eliciting_pkt[pns] > 0 @@ -306,7 +306,7 @@ xqc_maybe_should_ack(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_pn_ctl_t xqc_log(conn->log, XQC_LOG_DEBUG, "|path:%ui|set ack timer|ack_eliciting_pkt:%ud|pns:%d|flag:%s|now:%ui|max_ack_delay:%ui|", path->path_id, - send_ctl->ctl_ack_eliciting_pkt[pns], pns, xqc_conn_flag_2_str(conn->conn_flag), + send_ctl->ctl_ack_eliciting_pkt[pns], pns, xqc_conn_flag_2_str(conn, conn->conn_flag), now, conn->local_settings.max_ack_delay * 1000); } } diff --git a/src/transport/xqc_reinjection.c b/src/transport/xqc_reinjection.c index 72dfdca9c..00c8b9144 100644 --- a/src/transport/xqc_reinjection.c +++ b/src/transport/xqc_reinjection.c @@ -107,7 +107,7 @@ xqc_conn_try_reinject_packet(xqc_connection_t *conn, xqc_packet_out_t *packet_ou "path:%ui|stream_id:%ui|stream_offset:%ui|" "pkt_type:%s|origin_pkt_path:%ui|origin_pkt_num:%ui|", po_copy->po_path_id, po_copy->po_stream_id, po_copy->po_stream_offset, - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), packet_out->po_path_id, packet_out->po_pkt.pkt_num); return XQC_OK; @@ -135,7 +135,7 @@ xqc_conn_reinject_unack_packets(xqc_connection_t *conn, xqc_reinjection_mode_t m "pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|mode:%d|", packet_out->po_pkt.pkt_num, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), mode); } } diff --git a/src/transport/xqc_send_ctl.c b/src/transport/xqc_send_ctl.c index ff79907e4..c0d114d91 100644 --- a/src/transport/xqc_send_ctl.c +++ b/src/transport/xqc_send_ctl.c @@ -184,7 +184,7 @@ xqc_send_ctl_create(xqc_path_ctx_t *path) send_ctl->sampler.send_ctl = send_ctl; - xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl); + xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl, XQC_kGranularity, conn->conn_settings.cc_params); return send_ctl; } @@ -285,7 +285,7 @@ xqc_send_ctl_reset(xqc_send_ctl_t *send_ctl) xqc_send_queue_move_to_tail(pos, &send_queue->sndq_send_packets); } - xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl); + xqc_log_event(conn->log, REC_PARAMETERS_SET, send_ctl, XQC_kGranularity, conn->conn_settings.cc_params); } xqc_pn_ctl_t * @@ -591,7 +591,7 @@ xqc_send_ctl_on_pns_discard(xqc_send_ctl_t *send_ctl, xqc_pkt_num_space_t pns) static void -xqc_send_ctl_update_cwnd_limited(xqc_send_ctl_t *send_ctl) +xqc_send_ctl_update_cwnd_limited(xqc_send_ctl_t *send_ctl, xqc_usec_t now) { if (send_ctl->ctl_bytes_in_flight > send_ctl->ctl_max_bytes_in_flight) { send_ctl->ctl_max_bytes_in_flight = send_ctl->ctl_bytes_in_flight; @@ -605,6 +605,9 @@ xqc_send_ctl_update_cwnd_limited(xqc_send_ctl_t *send_ctl) uint32_t actual_mss = xqc_conn_get_mss(send_ctl->ctl_conn); if ((send_ctl->ctl_bytes_in_flight + actual_mss) > cwnd_bytes) { send_ctl->ctl_is_cwnd_limited = 1; + /* record the time of cwnd limited */ + send_ctl->ctl_recent_cwnd_limitation_time[send_ctl->ctl_cwndlim_update_idx] = now; + send_ctl->ctl_cwndlim_update_idx = (send_ctl->ctl_cwndlim_update_idx + 1) % 3; } } @@ -625,7 +628,7 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ "|retrans:%d|", send_ctl->ctl_conn, send_ctl->ctl_path->path_id, packet_out->po_pkt.pkt_num, orig_pktnum, packet_out->po_used_size, packet_out->po_enc_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types), xqc_conn_state_2_str(send_ctl->ctl_conn->conn_state), packet_out->po_flag & XQC_POF_IN_FLIGHT ? 1: 0, packet_out->po_flag & (XQC_POF_LOST | XQC_POF_TLP)); @@ -642,7 +645,7 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ send_ctl->ctl_conn, send_ctl->ctl_path->path_id, packet_out->po_pkt.pkt_num, orig_pktnum, packet_out->po_used_size, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types), xqc_conn_state_2_str(send_ctl->ctl_conn->conn_state), packet_out->po_flag & XQC_POF_IN_FLIGHT ? 1: 0); } @@ -741,7 +744,7 @@ xqc_send_ctl_on_packet_sent(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc_ xqc_stream_path_metrics_on_send(send_ctl->ctl_conn, packet_out); send_ctl->ctl_last_inflight_pkt_sent_time = now; - xqc_send_ctl_update_cwnd_limited(send_ctl); + xqc_send_ctl_update_cwnd_limited(send_ctl, now); } if (packet_out->po_frame_types & XQC_FRAME_BIT_CONNECTION_CLOSE) { @@ -866,7 +869,7 @@ xqc_send_ctl_on_ack_received(xqc_send_ctl_t *send_ctl, xqc_pn_ctl_t *pn_ctl, xqc (xqc_packet_number_t)packet_out->po_origin ? packet_out->po_origin->po_pkt.pkt_num : 0, packet_out->po_used_size, pns, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), + xqc_frame_type_2_str(conn->engine, packet_out->po_frame_types), xqc_conn_state_2_str(conn->conn_state), frame_largest_ack, send_ctl->ctl_largest_acked[pns]); @@ -1246,7 +1249,7 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, "pkt_num:%ui|size:%ud|pkt_type:%s|frame:%s|", po->po_pkt.pkt_num, po->po_used_size, xqc_pkt_type_2_str(po->po_pkt.pkt_type), - xqc_frame_type_2_str(po->po_frame_types)); + xqc_frame_type_2_str(conn->engine, po->po_frame_types)); has_reinjection = 1; } } @@ -1285,8 +1288,8 @@ xqc_send_ctl_detect_lost(xqc_send_ctl_t *send_ctl, xqc_send_queue_t *send_queue, xqc_log(conn->log, XQC_LOG_DEBUG, "|mark lost|pns:%d|pkt_num:%ui|" "lost_pn:%ui|po_sent_time:%ui|lost_send_time:%ui|loss_delay:%ui|frame:%s|repair:%d|", pns, po->po_pkt.pkt_num, lost_pn, po->po_sent_time, lost_send_time, loss_delay, - xqc_frame_type_2_str(po->po_frame_types), XQC_NEED_REPAIR(po->po_frame_types)); - xqc_log_event(conn->log, REC_PACKET_LOST, po); + xqc_frame_type_2_str(conn->engine, po->po_frame_types), XQC_NEED_REPAIR(po->po_frame_types)); + xqc_log_event(conn->log, REC_PACKET_LOST, po, lost_pn, lost_send_time, loss_delay); } else { xqc_log(conn->log, XQC_LOG_DEBUG, "|it's a copy of origin pkt|acked:%d|origin_acked:%d|origin_ref_cnt:%d|", diff --git a/src/transport/xqc_send_ctl.h b/src/transport/xqc_send_ctl.h index 4af123fca..e874781c2 100644 --- a/src/transport/xqc_send_ctl.h +++ b/src/transport/xqc_send_ctl.h @@ -112,6 +112,10 @@ typedef struct xqc_send_ctl_s { unsigned ctl_spurious_loss_count; unsigned ctl_lost_dgram_cnt; + /* record time for last three cwnd limitation and rtt mutation*/ + xqc_msec_t ctl_recent_cwnd_limitation_time[3]; + uint8_t ctl_cwndlim_update_idx; + unsigned ctl_recv_count; /* for QUIC datagrams */ diff --git a/src/transport/xqc_send_queue.c b/src/transport/xqc_send_queue.c index be169f2fc..f23407188 100644 --- a/src/transport/xqc_send_queue.c +++ b/src/transport/xqc_send_queue.c @@ -203,7 +203,7 @@ xqc_send_queue_insert_send(xqc_packet_out_t *po, xqc_list_head_t *head, xqc_send { xqc_list_add_tail(&po->po_list, head); send_queue->sndq_packets_used++; - } +} void xqc_send_queue_remove_send(xqc_list_head_t *pos) @@ -508,7 +508,7 @@ xqc_send_queue_drop_packets_from_list_with_type(xqc_send_ctl_t *send_ctl, xqc_se xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|drop pkt from %s list|inflight:%ud|cwnd:%ui|" "pkt_num:%ui|ptype:%d|frames:%s|len:%ud|", list_name, send_ctl->ctl_bytes_in_flight, send_ctl->ctl_cong_callback->xqc_cong_ctl_get_cwnd(send_ctl->ctl_cong), packet_out->po_pkt.pkt_num, - packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(packet_out->po_frame_types), + packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types), packet_out->po_used_size); } } @@ -537,7 +537,7 @@ xqc_send_queue_drop_packets_with_type(xqc_send_ctl_t *send_ctl, xqc_send_queue_t xqc_log(send_ctl->ctl_conn->log, XQC_LOG_DEBUG, "|drop pkt from unacked|inflight:%ud|cwnd:%ui|" "pkt_num:%ui|ptype:%d|frames:%s|", send_ctl->ctl_bytes_in_flight, send_ctl->ctl_cong_callback->xqc_cong_ctl_get_cwnd(send_ctl->ctl_cong), packet_out->po_pkt.pkt_num, - packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(packet_out->po_frame_types)); + packet_out->po_pkt.pkt_type, xqc_frame_type_2_str(send_ctl->ctl_conn->engine, packet_out->po_frame_types)); } xqc_send_queue_drop_packets_from_list_with_type(send_ctl, send_queue, type, &send_queue->sndq_send_packets_high_pri, "high_pri", XQC_FALSE); @@ -592,7 +592,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); + 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); 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 84827f891..bcb3c3bd7 100644 --- a/src/transport/xqc_stream.c +++ b/src/transport/xqc_stream.c @@ -513,7 +513,7 @@ xqc_stream_create(xqc_engine_t *engine, const xqc_cid_t *cid, xqc_stream_setting conn = xqc_engine_conns_hash_find(engine, cid, 's'); if (!conn) { xqc_log(engine->log, XQC_LOG_ERROR, "|can not find connection|cid:%s", - xqc_scid_str(cid)); + xqc_scid_str(engine, cid)); return NULL; } @@ -566,7 +566,7 @@ xqc_create_stream_with_conn(xqc_connection_t *conn, xqc_stream_id_t stream_id, if (conn->conn_state >= XQC_CONN_STATE_CLOSING) { xqc_log(conn->log, XQC_LOG_ERROR, "|conn closing, cannot create stream|type:%d|state:%d|flag:%s|", - conn->conn_type, conn->conn_state, xqc_conn_flag_2_str(conn->conn_flag)); + conn->conn_type, conn->conn_state, xqc_conn_flag_2_str(conn, conn->conn_flag)); return NULL; } @@ -1026,8 +1026,8 @@ xqc_crypto_stream_on_read(xqc_stream_t *stream, void *user_data) encrypt_level); return -XQC_ELEVEL; } - conn->conn_state = next_state; + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); int ret = xqc_conn_check_handshake_complete(conn); if (ret < 0) { return ret; @@ -1089,7 +1089,7 @@ xqc_crypto_stream_send(xqc_stream_t *stream, "|crypto send data|pkt_num:%ui|size:%ud|sent:%d|pkt_type:%s|frame:%s|now:%ui|", packet_out->po_pkt.pkt_num, packet_out->po_used_size, n_written, xqc_pkt_type_2_str(packet_out->po_pkt.pkt_type), - xqc_frame_type_2_str(packet_out->po_frame_types), now); + xqc_frame_type_2_str(stream->stream_conn->engine, packet_out->po_frame_types), now); xqc_send_queue_move_to_high_pri(&packet_out->po_list, stream->stream_conn->conn_send_queue); } @@ -1197,7 +1197,8 @@ xqc_crypto_stream_on_write(xqc_stream_t *stream, void *user_data) xqc_stream_shutdown_write(stream); conn->conn_state = next_state; - + xqc_log_event(conn->log, CON_CONNECTION_STATE_UPDATED, conn); + ret = xqc_conn_check_handshake_complete(conn); if (ret < 0) { return ret; @@ -1340,11 +1341,8 @@ xqc_stream_recv(xqc_stream_t *stream, unsigned char *recv_buf, size_t recv_buf_s stream->stream_conn->conn_flow_ctl.fc_data_read += read; - xqc_log(stream->stream_conn->log, XQC_LOG_DEBUG, - "|stream_id:%ui|read:%z|recv_buf_size:%uz|fin:%d|stream_length:%ui|next_read_offset:%ui|conn:%p|", - stream->stream_id, read, recv_buf_size, *fin, stream->stream_data_in.stream_length, - stream->stream_data_in.next_read_offset, stream->stream_conn); - + xqc_log_event(stream->stream_conn->log, TRA_STREAM_DATA_MOVED, stream, 1, read, + recv_buf_size, *fin, 0, 0, 0, 0); xqc_stream_shutdown_read(stream); int ret = xqc_stream_do_recv_flow_ctl(stream); @@ -1475,7 +1473,9 @@ xqc_stream_send(xqc_stream_t *stream, unsigned char *send_data, size_t send_data "send_data_size:%uz|offset:%uz|fin:%d|stream_flag:%d|conn:%p|conn_state:%s|flag:%s|", ret, stream->stream_id, stream->stream_send_offset, xqc_pkt_type_2_str(pkt_type), buff_1rtt, send_data_size, offset, fin, stream->stream_flag, conn, xqc_conn_state_2_str(conn->conn_state), - xqc_conn_flag_2_str(conn->conn_flag)); + xqc_conn_flag_2_str(conn, conn->conn_flag)); + 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)) { diff --git a/src/transport/xqc_timer.c b/src/transport/xqc_timer.c index af551fa47..6843fb3a5 100644 --- a/src/transport/xqc_timer.c +++ b/src/transport/xqc_timer.c @@ -264,7 +264,7 @@ xqc_timer_retire_cid_timeout(xqc_timer_type_t type, xqc_usec_t now, void *user_d xqc_log(conn->log, XQC_LOG_DEBUG, "|retired->removed|cid:%s|seq:%ui|len:%d|", - xqc_scid_str(&inner_cid->cid), + xqc_scid_str(conn->engine, &inner_cid->cid), inner_cid->cid.cid_seq_num, inner_cid->cid.cid_len); diff --git a/src/transport/xqc_transport_params.c b/src/transport/xqc_transport_params.c index 0b244bae0..07abe1b3a 100644 --- a/src/transport/xqc_transport_params.c +++ b/src/transport/xqc_transport_params.c @@ -7,6 +7,7 @@ #include "src/common/xqc_str.h" #include "src/transport/xqc_defs.h" #include "src/transport/xqc_cid.h" +#include "src/transport/xqc_fec.h" #include #include #include @@ -34,7 +35,7 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, xqc_transport_params_type_t exttype) { size_t len = 0; - size_t preferred_addrlen = 0; + size_t preferred_addrlen = 0, preferred_fec_paramslen = 0; if (params->original_dest_connection_id_present) { len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_ORIGINAL_DEST_CONNECTION_ID) + @@ -169,11 +170,65 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, } 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); + xqc_put_varint_len(xqc_put_varint_len(params->enable_multipath)) + + xqc_put_varint_len(params->enable_multipath); } } + 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); + } + +#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); + } + + /* + * if enable_encode_fec, add fec related params' length: + * max_symbol_size; max_src_symbol_len; max_encoder_schemes; + */ + if (params->enable_encode_fec + && params->fec_encoder_schemes_num > 0 + && params->fec_encoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_encoder_schemes_num); + + for (xqc_int_t i = 0; i < params->fec_encoder_schemes_num; i++) { + 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); + + 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); + } + /* + * if enable_decode_fec, add fec related params' length: + * max_decoder_schemes; + */ + if (params->enable_decode_fec + && params->fec_decoder_schemes_num > 0 + && params->fec_decoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen = 0; + preferred_fec_paramslen += xqc_put_varint_len(params->fec_decoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_decoder_schemes_num; i++) { + 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; + } +#endif + if (params->max_datagram_frame_size) { len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE) + xqc_put_varint_len(xqc_put_varint_len(params->max_datagram_frame_size)) + @@ -220,7 +275,7 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, { uint8_t *p = out; size_t len = 0; - size_t preferred_addrlen = 0; + size_t preferred_addrlen = 0, preferred_fec_paramslen = 0; int i; /* calculate encoding length */ @@ -362,6 +417,12 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, } } + if (params->close_dgram_redundancy == XQC_RED_SET_CLOSE) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY, + params->close_dgram_redundancy); + } + + if (params->conn_option_num) { p = xqc_put_varint(p, XQC_TRANSPORT_PARAM_GOOGLE_CO); p = xqc_put_varint(p, sizeof(uint32_t) * params->conn_option_num); @@ -370,6 +431,55 @@ 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); + } + + if (params->enable_encode_fec + && params->fec_encoder_schemes_num > 0 + && params->fec_encoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen = 0; + p = xqc_put_varint(p, XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES); + preferred_fec_paramslen = xqc_put_varint_len(params->fec_encoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_encoder_schemes_num; i++) { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_encoder_schemes[i]); + } + p = xqc_put_varint(p, preferred_fec_paramslen); + + p = xqc_put_varint(p, params->fec_encoder_schemes_num); + 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); + } + + if (params->enable_decode_fec + && params->fec_decoder_schemes_num > 0 + && params->fec_decoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) + { + preferred_fec_paramslen = 0; + if (params->fec_decoder_schemes_num > 0 && params->fec_encoder_schemes_num <= XQC_FEC_MAX_SCHEME_NUM) { + p = xqc_put_varint(p, XQC_TRANSPORT_PARAM_FEC_DECODER_SCHEMES); + preferred_fec_paramslen = xqc_put_varint_len(params->fec_decoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_decoder_schemes_num; i++) { + preferred_fec_paramslen += xqc_put_varint_len(params->fec_decoder_schemes[i]); + } + p = xqc_put_varint(p, preferred_fec_paramslen); + + p = xqc_put_varint(p, params->fec_decoder_schemes_num); + for (xqc_int_t i = 0; i < params->fec_decoder_schemes_num; i++) { + p = xqc_put_varint(p, params->fec_decoder_schemes[i]); + } + } + } +#endif + if ((size_t)(p - out) != len) { return -XQC_TLS_MALFORMED_TRANSPORT_PARAM; } @@ -630,6 +740,130 @@ xqc_decode_enable_multipath(xqc_transport_params_t *params, xqc_transport_params return XQC_OK; } +static xqc_int_t +xqc_decode_close_dgram_redundancy(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) +{ + uint64_t ret = 0; + ssize_t nread = xqc_vint_read(p, end, &ret); + + switch (ret) { + case XQC_RED_SET_CLOSE: + params->close_dgram_redundancy = XQC_RED_SET_CLOSE; + break; + + default: + params->close_dgram_redundancy = XQC_RED_NOT_USE; + break; + } + return XQC_OK; +} + +#ifdef XQC_ENABLE_FEC +static xqc_int_t +xqc_decode_fec_version(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) +{ + switch (param_type) { + case XQC_TRANSPORT_PARAM_FEC_VERSION: + params->fec_version = XQC_FEC_01; + break; + + default: + params->fec_version = XQC_ERR_FEC_VERSION; + break; + } + + 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, + const uint8_t *p, const uint8_t *end, uint64_t param_type, uint64_t param_len) +{ + XQC_DECODE_VINT_VALUE(¶ms->fec_max_symbols_num, p, end); +} + +static xqc_int_t +xqc_decode_encoder_schemes(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) +{ + int vlen; + uint64_t schemes_len, curr_scheme; + xqc_int_t i, tmp_len; + + tmp_len = 0; + schemes_len = curr_scheme = 0; + vlen = xqc_vint_read(p, end, &schemes_len); + + if (schemes_len < 0) { + return -XQC_TLS_MALFORMED_TRANSPORT_PARAM; + } + + params->fec_encoder_schemes_num = schemes_len; + p += vlen; + + for (i = 0; i < schemes_len && tmp_len < XQC_FEC_MAX_SCHEME_NUM; i++) { + vlen = xqc_vint_read(p, end, &curr_scheme); + if (xqc_set_fec_scheme(curr_scheme, ¶ms->fec_encoder_schemes[tmp_len]) == XQC_OK) { + tmp_len++; + } + p += vlen; + } + + for (i; i < schemes_len; i++) { + p += xqc_vint_read(p, end, &curr_scheme); + } + + params->enable_encode_fec = 1; + params->fec_encoder_schemes_num = tmp_len; + return XQC_OK; +} + +static xqc_int_t +xqc_decode_decoder_schemes(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) +{ + int vlen; + uint64_t schemes_len, curr_scheme; + xqc_int_t i, tmp_len; + + tmp_len = 0; + schemes_len = curr_scheme = 0; + vlen = xqc_vint_read(p, end, &schemes_len); + + if (schemes_len < 0) { + return -XQC_TLS_MALFORMED_TRANSPORT_PARAM; + } + + params->fec_decoder_schemes_num = schemes_len; + p += vlen; + + for (i = 0; i < schemes_len && tmp_len < XQC_FEC_MAX_SCHEME_NUM; i++) { + vlen = xqc_vint_read(p, end, &curr_scheme); + if (xqc_set_fec_scheme(curr_scheme, ¶ms->fec_decoder_schemes[tmp_len]) == XQC_OK) { + tmp_len++; + } + p += vlen; + } + + for (i; i < schemes_len; i++) { + p += xqc_vint_read(p, end, &curr_scheme); + } + + params->enable_decode_fec = 1; + params->fec_decoder_schemes_num = tmp_len; + + return XQC_OK; +} +#endif static xqc_int_t xqc_decode_max_datagram_frame_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) @@ -661,9 +895,17 @@ xqc_trans_param_decode_func xqc_trans_param_decode_func_list[] = { xqc_decode_active_cid_limit, xqc_decode_initial_scid, xqc_decode_retry_scid, - xqc_decode_no_crypto, xqc_decode_enable_multipath, xqc_decode_max_datagram_frame_size, + xqc_decode_close_dgram_redundancy, +#ifdef XQC_ENABLE_FEC + 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, }; @@ -691,17 +933,39 @@ xqc_trans_param_get_index(uint64_t param_type) case XQC_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID: case XQC_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID: return param_type; - - case XQC_TRANSPORT_PARAM_NO_CRYPTO: - return XQC_TRANSPORT_PARAM_PROTOCOL_MAX; case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_04: case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_05: case XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_06: - return XQC_TRANSPORT_PARAM_PROTOCOL_MAX + 1; + return XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_PARSER; case XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE: - return XQC_TRANSPORT_PARAM_PROTOCOL_MAX + 2; + return XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE_PARSER; + + case XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY: + return param_type; + +#ifdef XQC_ENABLE_FEC + case XQC_TRANSPORT_PARAM_FEC_VERSION: + return XQC_TRANSPORT_PARAM_FEC_VERSION_PARSER; + + case XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES: + return XQC_TRANSPORT_PARAM_FEC_ENCODER_SCHEMES_PARSER; + + 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; default: break; @@ -796,6 +1060,17 @@ xqc_decode_transport_params(xqc_transport_params_t *params, params->enable_multipath = 0; params->multipath_version = XQC_ERR_MULTIPATH_VERSION; + /* 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; + + params->close_dgram_redundancy = XQC_RED_NOT_USE; + while (p < end) { ret = xqc_decode_one_transport_param(params, exttype, &p, end); if (ret < 0) { diff --git a/src/transport/xqc_transport_params.h b/src/transport/xqc_transport_params.h index 901dcc60b..637962eb5 100644 --- a/src/transport/xqc_transport_params.h +++ b/src/transport/xqc_transport_params.h @@ -60,9 +60,23 @@ typedef enum { XQC_TRANSPORT_PARAM_INITIAL_SOURCE_CONNECTION_ID = 0x000f, XQC_TRANSPORT_PARAM_RETRY_SOURCE_CONNECTION_ID = 0x0010, + XQC_TRANSPORT_PARAM_ENABLE_MULTIPATH_PARSER = 0x0011, + XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE_PARSER = 0x0012, + + /* whether enable datagram reduncy */ + XQC_TRANSPORT_PARAM_CLOSE_DGRAM_REDUNDANCY = 0x0013, +#ifdef XQC_ENABLE_FEC + /* fec attributes' parser */ + 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, +#endif /* upper limit of params defined in [Transport] */ XQC_TRANSPORT_PARAM_PROTOCOL_MAX, + /* max datagram frame size */ XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE = 0x0020, @@ -76,7 +90,14 @@ typedef enum { /* 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_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 */ XQC_TRANSPORT_PARAM_UNKNOWN, } xqc_transport_param_id_t; @@ -154,6 +175,17 @@ typedef struct { 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; } xqc_transport_params_t; diff --git a/tests/CMakeLists.txt b/tests/CMakeLists.txt index a1588b53a..09c4f93c0 100644 --- a/tests/CMakeLists.txt +++ b/tests/CMakeLists.txt @@ -125,6 +125,15 @@ if(HAVE_CUNIT) ${UNIT_TEST_DIR}/xqc_h3_ext_test.c ) + if(XQC_ENABLE_FEC) + set( + test_SOURCES + ${test_SOURCES} + ${UNIT_TEST_DIR}/xqc_galois_test.c + ${UNIT_TEST_DIR}/xqc_fec_scheme_test.c + ${UNIT_TEST_DIR}/xqc_fec_test.c + ) + endif() add_executable(run_tests ${test_SOURCES} diff --git a/tests/test_client.c b/tests/test_client.c index 9650d9083..7d64dd164 100644 --- a/tests/test_client.c +++ b/tests/test_client.c @@ -257,6 +257,7 @@ 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; +int g_enable_fec = 0; int g_enable_reinjection = 0; int g_verify_cert = 0; int g_verify_cert_allow_self_sign = 0; @@ -275,7 +276,6 @@ char g_header_value[MAX_HEADER_VALUE_LEN]; char g_multi_interface[XQC_DEMO_MAX_PATH_COUNT][64]; xqc_user_path_t g_client_path[XQC_DEMO_MAX_PATH_COUNT]; int g_multi_interface_cnt = 0; -int mp_has_closed = 0; int mp_has_recved = 0; char g_priority[64] = {'\0'}; @@ -428,7 +428,7 @@ xqc_client_datagram_send(user_conn_t *user_conn) if (ret == -XQC_EAGAIN) { printf("[dgram]|retry_datagram_send_later|\n"); return; - } else if (ret == -XQC_EDGRAM_TOO_LARGE ) { + } else if (ret == -XQC_EDGRAM_TOO_LARGE) { printf("[dgram]|trying_to_send_an_oversized_datagram|recorded_mss:%zu|send_size:%zu|current_mss:%zu|\n", user_conn->dgram_mss, dgram_size, xqc_datagram_get_mss(user_conn->quic_conn)); xqc_conn_close(ctx.engine, &user_conn->cid); return; @@ -475,6 +475,7 @@ xqc_client_datagram_send(user_conn_t *user_conn) printf("[dgram]|partially_sent_pkts_in_a_batch|cnt:%zu|\n", succ_sent); xqc_conn_close(ctx.engine, &user_conn->cid); return; + } else if (ret < 0 && ret != -XQC_EAGAIN) { printf("[dgram]|send_datagram_multiple_error|err_code:%d|\n", ret); xqc_conn_close(ctx.engine, &user_conn->cid); @@ -1771,8 +1772,8 @@ xqc_client_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retir memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -1789,7 +1790,7 @@ xqc_client_conn_handshake_finished(xqc_connection_t *conn, void *user_data, void } printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, &user_conn->cid)); - printf("====>SCID:%s\n", xqc_scid_str(&user_conn->cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, &user_conn->cid)); } hsk_completed = 1; @@ -1817,32 +1818,6 @@ xqc_client_h3_conn_create_notify(xqc_h3_conn_t *conn, const xqc_cid_t *cid, void DEBUG; user_conn_t *user_conn = (user_conn_t *) user_data; - if (g_test_case == 18) { /* test h3 settings */ - xqc_h3_conn_settings_t settings = { - .max_field_section_size = 512, - .qpack_enc_max_table_capacity = 4096, - .qpack_dec_max_table_capacity = 4096, - .qpack_blocked_streams = 32, - }; - xqc_h3_conn_set_settings(conn, &settings); - } - - if (g_test_case == 32) { - xqc_h3_conn_settings_t settings = { - .max_field_section_size = 10000000, - .qpack_enc_max_table_capacity = 4096, - .qpack_dec_max_table_capacity = 4096, - .qpack_blocked_streams = 32, - }; - xqc_h3_conn_set_settings(conn, &settings); - } - - if (g_test_case == 19) { /* test header size constraints */ - xqc_h3_conn_settings_t settings = { - .max_field_section_size = 100, - }; - xqc_h3_conn_set_settings(conn, &settings); - } user_conn->dgram_mss = xqc_h3_ext_datagram_get_mss(conn); user_conn->h3_conn = conn; @@ -1920,7 +1895,7 @@ xqc_client_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data) } printf("====>DCID:%s\n", xqc_dcid_str_by_scid(p_ctx->engine, &user_conn->cid)); - printf("====>SCID:%s\n", xqc_scid_str(&user_conn->cid)); + printf("====>SCID:%s\n", xqc_scid_str(p_ctx->engine, &user_conn->cid)); hsk_completed = 1; @@ -1963,8 +1938,8 @@ xqc_client_h3_conn_update_cid_notify(xqc_h3_conn_t *conn, const xqc_cid_t *retir memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -2915,25 +2890,6 @@ xqc_client_request_read_notify(xqc_h3_request_t *h3_request, xqc_request_notify_ fin = 1; } - /* close initial path */ - if (g_test_case == 100 && !mp_has_closed && mp_has_recved >= (g_send_body_size/2)) { - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 0); - mp_has_closed = 1; - } - - /* close new path */ - if (g_test_case == 101 && !mp_has_closed && mp_has_recved >= (g_send_body_size/2)) { - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 1); - mp_has_closed = 1; - } - - /* close all path */ - if (g_test_case == 102 && !mp_has_closed && mp_has_recved >= (g_send_body_size/2)) { - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 1); - xqc_conn_close_path(ctx.engine, &user_stream->user_conn->cid, 0); - mp_has_closed = 1; - } - // mpshell: 批量测试,无需打印 // printf("xqc_h3_request_recv_body read:%zd, offset:%zu, fin:%d\n", read_sum, user_stream->recv_body_len, fin); } @@ -3033,19 +2989,7 @@ xqc_client_request_close_notify(xqc_h3_request_t *h3_request, void *user_data) free(user_stream); return 0; } - - /* close initial path */ - if (g_test_case == 105 && !mp_has_closed) { - xqc_conn_close_path(p_ctx->engine, &user_stream->user_conn->cid, 0); - mp_has_closed = 1; - } - - /* close new path */ - if (g_test_case == 106 && !mp_has_closed) { - xqc_conn_close_path(p_ctx->engine, &user_stream->user_conn->cid, 1); - mp_has_closed = 1; - } - + printf("***** xqc_client_request_send\n"); xqc_client_request_send(user_stream->h3_request, user_stream); xqc_engine_main_logic(p_ctx->engine); @@ -3594,6 +3538,22 @@ xqc_client_epoch_callback(int fd, short what, void *arg) } } + /* close initial path */ + if (g_test_case == 100 && g_cur_epoch > 3) { + xqc_conn_close_path(ctx.engine, &user_conn->cid, 0); + } + + /* close new path */ + if (g_test_case == 101 && g_cur_epoch > 3) { + xqc_conn_close_path(ctx.engine, &user_conn->cid, 1); + } + + /* close all path */ + if (g_test_case == 102 && g_cur_epoch > 3) { + xqc_conn_close_path(ctx.engine, &user_conn->cid, 1); + xqc_conn_close_path(ctx.engine, &user_conn->cid, 0); + } + if (g_cur_epoch < g_epoch) { struct timeval tv; tv.tv_sec = g_epoch_timeout / 1000000; @@ -3651,6 +3611,29 @@ xqc_client_write_log(xqc_log_level_t lvl, const void *buf, size_t count, void *e } } +void +xqc_client_write_qlog(qlog_event_importance_t imp, const void *buf, size_t count, void *engine_user_data) +{ + unsigned char log_buf[XQC_MAX_LOG_LEN + 1]; + + client_ctx_t *ctx = (client_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + printf("xqc_client_write_qlog fd err\n"); + return; + } + + int log_len = snprintf(log_buf, XQC_MAX_LOG_LEN + 1, "%s\n", (char *)buf); + if (log_len < 0) { + printf("xqc_client_write_qlog err\n"); + return; + } + + int write_len = write(ctx->log_fd, log_buf, log_len); + if (write_len < 0) { + printf("write qlog failed, errno: %d\n", errno); + } +} + /** * key log functions @@ -3689,7 +3672,7 @@ xqc_keylog_cb(const xqc_cid_t *scid, const char *line, void *user_data) return; } - printf("scid:%s\n", xqc_scid_str(scid)); + printf("scid:%s\n", xqc_scid_str(ctx->engine, scid)); int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { @@ -3853,7 +3836,7 @@ static void xqc_client_concurrent_callback(int fd, short what, void *arg){ } }; - xqc_engine_register_alpn(ctx->engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs); + xqc_engine_register_alpn(ctx->engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs, NULL); if (g_conn_count < g_max_conn_num) { @@ -3959,6 +3942,26 @@ xqc_qch_ddos_cid_generate(const xqc_cid_t *ori_cid, uint8_t *cid_buf, size_t cid } } +xqc_int_t +xqc_client_set_fec_scheme(uint64_t in, xqc_fec_schemes_e *out) +{ + switch (in) { + case XQC_REED_SOLOMON_CODE: + *out = XQC_REED_SOLOMON_CODE; + return XQC_OK; + case XQC_XOR_CODE: + *out = XQC_XOR_CODE; + return XQC_OK; + case XQC_PACKET_MASK: + *out = XQC_PACKET_MASK; + return XQC_OK; + default: + break; + } + + return -XQC_EFEC_SCHEME_ERROR; +} + client_ctx_t * client_create_ctx(xqc_engine_ssl_config_t *engine_ssl_config, xqc_transport_callbacks_t *tcbs, xqc_config_t *config) @@ -3974,6 +3977,7 @@ client_ctx_t * client_create_ctx(xqc_engine_ssl_config_t *engine_ssl_config, .log_callbacks = { .xqc_log_write_err = xqc_client_write_log, .xqc_log_write_stat = xqc_client_write_log, + .xqc_qlog_event_write = xqc_client_write_qlog, }, .keylog_cb = xqc_keylog_cb, .cid_generate_cb = xqc_qch_ddos_cid_generate, /* 设置cid 生产的回调函数 */ @@ -4100,6 +4104,12 @@ int main(int argc, char *argv[]) { int use_1rtt = 0; uint64_t rate_limit = 0; char conn_options[XQC_CO_STR_MAX_LEN] = {0}; + int g_close_red_redundancy = 0; + xqc_fec_schemes_e fec_encoder_scheme = 11; + xqc_fec_schemes_e fec_decoder_scheme = 11; + uint8_t c_qlog_disable = 0; + char c_qlog_importance = 'r'; + strcpy(g_log_path, "./clog"); @@ -4116,11 +4126,16 @@ int main(int argc, char *argv[]) { {"mp_ping", required_argument, &long_opt_index, 6}, {"rate_limit", required_argument, &long_opt_index, 7}, {"conn_options", required_argument, &long_opt_index, 8}, + {"fec_encoder", required_argument, &long_opt_index, 9}, + {"fec_decoder", required_argument, &long_opt_index, 10}, + {"close_dg_red", required_argument, &long_opt_index, 11}, + {"qlog_disable", no_argument, &long_opt_index, 12}, + {"qlog_importance", required_argument, &long_opt_index, 13}, {0, 0, 0, 0} }; int ch = 0; - while ((ch = getopt_long(argc, argv, "a:p:P:n:c:Ct:T:1s:w:r:l:Ed:u:H:h:Gx:6NMR:i:V:v:q:o:fe:F:D:b:B:J:Q:U:AyzS:", long_opts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "a:p:P:n:c:Ct:T:1s:w:r:l:Ed:u:H:h:Gx:6NMR:i:V:v:q:o:fe:F:D:b:B:J:Q:U:AyzS:g", long_opts, NULL)) != -1) { switch (ch) { case 'U': printf("option send_datagram 0 (off), 1 (on), 2(on + batch): %s\n", optarg); @@ -4337,6 +4352,10 @@ int main(int argc, char *argv[]) { printf("option stream per second:%s\n", optarg); g_req_per_time = atoi(optarg); break; + case 'g': + printf("option enable fec mode :on\n"); + g_enable_fec = 1; + break; /* long options */ case 0: @@ -4403,6 +4422,31 @@ int main(int argc, char *argv[]) { printf("option conn_options: %s\n", conn_options); break; + case 9: + fec_encoder_scheme = atoi(optarg); + printf("option fec_encoder_scheme: %d\n", fec_encoder_scheme); + break; + + case 10: + fec_decoder_scheme = atoi(optarg); + printf("option fec_decoder_schemes: %d\n", fec_decoder_scheme); + break; + + case 11: + g_close_red_redundancy = atoi(optarg) ? 1 : 0; + printf("option close dgram redundancy: %d\n", g_close_red_redundancy); + break; + + case 12: + c_qlog_disable = 1; + printf("option disable qlog\n"); + break; + + case 13: + c_qlog_importance = optarg[0]; + printf("option qlog importance :%s\n", optarg); + break; + default: break; } @@ -4421,10 +4465,6 @@ int main(int argc, char *argv[]) { memset(g_header_value, 'v', sizeof(g_header_value)); memset(&ctx, 0, sizeof(ctx)); - if (g_test_case == 44) { - xqc_log_enable(XQC_FALSE); - } - xqc_client_open_keylog_file(&ctx); xqc_client_open_log_file(&ctx); @@ -4445,6 +4485,7 @@ int main(int argc, char *argv[]) { .log_callbacks = { .xqc_log_write_err = xqc_client_write_log, .xqc_log_write_stat = xqc_client_write_log, + .xqc_qlog_event_write = xqc_client_write_qlog, }, .keylog_cb = xqc_keylog_cb, }; @@ -4526,10 +4567,13 @@ int main(int argc, char *argv[]) { .keyupdate_pkt_threshold = 0, .max_datagram_frame_size = g_max_dgram_size, .enable_multipath = g_enable_multipath, + .enable_encode_fec = g_enable_fec, + .enable_decode_fec = g_enable_fec, .multipath_version = g_multipath_version, .marking_reinjection = 1, .mp_ping_on = g_mp_ping_on, .recv_rate_bytes_per_sec = rate_limit, + .close_dgram_redundancy = XQC_RED_NOT_USE }; strncpy(conn_settings.conn_option_str, conn_options, XQC_CO_STR_MAX_LEN); @@ -4598,6 +4642,18 @@ int main(int argc, char *argv[]) { case 'd': config.cfg_log_level = XQC_LOG_DEBUG; break; default: config.cfg_log_level = XQC_LOG_DEBUG; } + + if (c_qlog_disable) { + config.cfg_log_event = 0; + } + switch(c_qlog_importance) { + case 's': config.cfg_qlog_importance = EVENT_IMPORTANCE_SELECTED; break; + case 'c': config.cfg_qlog_importance = EVENT_IMPORTANCE_CORE; break; + case 'b': config.cfg_qlog_importance = EVENT_IMPORTANCE_BASE; break; + case 'e': config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; break; + case 'r': config.cfg_qlog_importance = EVENT_IMPORTANCE_REMOVED; break; + default: config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; + } /* test different cid_len */ if (g_test_case == 13) { @@ -4673,6 +4729,11 @@ int main(int argc, char *argv[]) { ctx.ev_engine = event_new(eb, -1, 0, xqc_client_engine_callback, &ctx); + if (g_test_case == 44) { + // turn off the log switch + config.log_disable = 1; + } + ctx.engine = xqc_engine_create(XQC_ENGINE_CLIENT, &config, &engine_ssl_config, &callback, &tcbs, &ctx); if (ctx.engine == NULL) { @@ -4680,6 +4741,12 @@ 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, @@ -4715,6 +4782,63 @@ int main(int argc, char *argv[]) { return ret; } + if (g_test_case == 18) { /* test h3 settings */ + xqc_h3_conn_settings_t settings = { + .max_field_section_size = 512, + .qpack_enc_max_table_capacity = 4096, + .qpack_dec_max_table_capacity = 4096, + .qpack_blocked_streams = 32, + }; + xqc_h3_engine_set_local_settings(ctx.engine, &settings); + } + + if (g_test_case == 32) { + xqc_h3_conn_settings_t settings = { + .max_field_section_size = 10000000, + .qpack_enc_max_table_capacity = 4096, + .qpack_dec_max_table_capacity = 4096, + .qpack_blocked_streams = 32, + }; + xqc_h3_engine_set_local_settings(ctx.engine, &settings); + } + + if (g_test_case == 19) { /* test header size constraints */ + xqc_h3_conn_settings_t settings = { + .max_field_section_size = 100, + }; + xqc_h3_engine_set_local_settings(ctx.engine, &settings); + } + + if (g_test_case == 152) { + conn_settings.proto_version = XQC_IDRAFT_VER_29; + g_test_case = 150; + } + + if (g_test_case == 153) { + conn_settings.proto_version = XQC_IDRAFT_VER_29; + g_test_case = 151; + } + + /* modify h3 default settings */ + if (g_test_case == 150) { + xqc_h3_engine_set_dec_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_enc_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + + if (g_test_case == 151) { + xqc_h3_engine_set_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + /* register transport callbacks */ xqc_app_proto_callbacks_t ap_cbs = { .conn_cbs = { @@ -4737,9 +4861,9 @@ int main(int argc, char *argv[]) { } }; - xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs); + xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs, NULL); /* test alpn negotiation failure */ - xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT_TEST, 14, &ap_cbs); + xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT_TEST, 14, &ap_cbs, NULL); user_conn_t *user_conn = xqc_client_user_conn_create(server_addr, server_port, transport); if (user_conn == NULL) { @@ -4795,10 +4919,37 @@ int main(int argc, char *argv[]) { conn_settings.datagram_redundant_probe = 30000; } + if (g_enable_fec) { + 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; + + } else { + conn_settings.enable_encode_fec = 0; + } + + if (xqc_client_set_fec_scheme(fec_decoder_scheme, &fec_params.fec_decoder_schemes[0]) == XQC_OK) { + fec_params.fec_decoder_schemes_num = 1; + + } else { + conn_settings.enable_decode_fec = 0; + } + + if (g_test_case == 80) { + fec_params.fec_code_rate = 1; + } + + conn_settings.fec_params = fec_params; + } + if (g_mp_backup_mode) { conn_settings.scheduler_callback = xqc_backup_scheduler_cb; } + if (g_close_red_redundancy) { + conn_settings.close_dgram_redundancy = XQC_RED_SET_CLOSE; + } + if (g_test_case == 501) { conn_settings.scheduler_callback = xqc_backup_scheduler_cb; conn_settings.mp_enable_reinjection = 0; diff --git a/tests/test_server.c b/tests/test_server.c index 93a670638..88ed65c75 100644 --- a/tests/test_server.c +++ b/tests/test_server.c @@ -156,6 +156,7 @@ int g_enable_reinjection = 0; int g_spec_local_addr = 0; int g_mpshell = 0; int g_endless_sending = 0; +int g_enable_fec = 0; double g_copa_ai = 1.0; double g_copa_delta = 0.05; int g_enable_h3_ext = 1; @@ -720,8 +721,8 @@ xqc_server_conn_update_cid_notify(xqc_connection_t *conn, const xqc_cid_t *retir memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -1007,8 +1008,8 @@ xqc_server_h3_conn_update_cid_notify(xqc_h3_conn_t *h3_conn, const xqc_cid_t *re memcpy(&user_conn->cid, new_cid, sizeof(*new_cid)); - printf("====>RETIRE SCID:%s\n", xqc_scid_str(retire_cid)); - printf("====>SCID:%s\n", xqc_scid_str(new_cid)); + printf("====>RETIRE SCID:%s\n", xqc_scid_str(ctx.engine, retire_cid)); + printf("====>SCID:%s\n", xqc_scid_str(ctx.engine, new_cid)); printf("====>DCID:%s\n", xqc_dcid_str_by_scid(ctx.engine, new_cid)); } @@ -1515,7 +1516,7 @@ xqc_server_write_socket(const unsigned char *buf, size_t size, do { set_sys_errno(0); res = sendto(fd, send_buf, send_buf_size, 0, peer_addr, peer_addrlen); - printf("xqc_server_send write %zd, %s\n", res, strerror(get_sys_errno())); + // printf("xqc_server_send write %zd, %s\n", res, strerror(get_sys_errno())); if (res < 0) { printf("xqc_server_write_socket err %zd %s\n", res, strerror(get_sys_errno())); if (get_sys_errno() == EAGAIN) { @@ -1935,6 +1936,29 @@ xqc_server_write_log(xqc_log_level_t lvl, const void *buf, size_t count, void *e } } +void +xqc_server_write_qlog(qlog_event_importance_t imp, const void *buf, size_t count, void *engine_user_data) +{ + unsigned char log_buf[XQC_MAX_LOG_LEN + 1]; + + xqc_server_ctx_t *ctx = (xqc_server_ctx_t*)engine_user_data; + if (ctx->log_fd <= 0) { + printf("xqc_server_write_qlog fd err\n"); + return; + } + + int log_len = snprintf(log_buf, XQC_MAX_LOG_LEN + 1, "%s\n", (char *)buf); + if (log_len < 0) { + printf("xqc_server_write_qlog err\n"); + return; + } + + int write_len = write(ctx->log_fd, log_buf, log_len); + if (write_len < 0) { + printf("xqc_server_write_log write failed, errno: %d\n", get_sys_errno()); + } +} + /** * key log functions @@ -1973,7 +1997,7 @@ xqc_keylog_cb(const xqc_cid_t *scid, const char *line, void *user_data) return; } - printf("scid:%s\n", xqc_scid_str(scid)); + printf("scid:%s\n", xqc_scid_str(ctx->engine, scid)); int write_len = write(ctx->keylog_fd, line, strlen(line)); if (write_len < 0) { printf("write keys failed, errno: %d\n", get_sys_errno()); @@ -2099,6 +2123,8 @@ int main(int argc, char *argv[]) { char c_cong_ctl = 'b'; char c_log_level = 'd'; int c_cong_plus = 0; + uint8_t c_qlog_disable = 0; + char c_qlog_importance = 'r'; int pacing_on = 0; strncpy(g_log_path, "./slog", sizeof(g_log_path)); @@ -2112,11 +2138,13 @@ int main(int argc, char *argv[]) { {"copa_ai_unit", required_argument, &long_opt_index, 2}, {"dgram_qos", required_argument, &long_opt_index, 3}, {"pmtud", required_argument, &long_opt_index, 4}, + {"qlog_disable", no_argument, &long_opt_index, 5}, + {"qlog_importance", required_argument, &long_opt_index, 6}, {0, 0, 0, 0} }; int ch = 0; - while ((ch = getopt_long(argc, argv, "a:p:ec:Cs:w:r:l:u:x:6bS:MR:o:EK:mLQ:U:yH", long_opts, NULL)) != -1) { + while ((ch = getopt_long(argc, argv, "a:p:efc:Cs:w:r:l:u:x:6bS:MR:o:EK:mLQ:U:yH", long_opts, NULL)) != -1) { switch (ch) { case 'H': printf("option disable h3_ext\n"); @@ -2144,6 +2172,10 @@ int main(int argc, char *argv[]) { printf("option echo :%s\n", "on"); g_echo = 1; break; + case 'f': + printf("option fec: on\n"); + g_enable_fec = 1; + break; case 'c': /* Congestion Control Algorithm. r:reno b:bbr c:cubic B:bbr2 bbr+ bbr2+ */ c_cong_ctl = optarg[0]; if (strncmp("bbr2", optarg, 4) == 0) { @@ -2290,6 +2322,16 @@ int main(int argc, char *argv[]) { printf("option g_pmtud_on: %d\n", g_pmtud_on); break; + case 5: + c_qlog_disable = 1; + printf("option disable qlog\n"); + break; + + case 6: + c_qlog_importance = optarg[0]; + printf("option qlog importance :%s\n", optarg); + break; + default: break; } @@ -2337,6 +2379,7 @@ int main(int argc, char *argv[]) { .log_callbacks = { .xqc_log_write_err = xqc_server_write_log, .xqc_log_write_stat = xqc_server_write_log, + .xqc_qlog_event_write = xqc_server_write_qlog, }, .keylog_cb = xqc_keylog_cb, @@ -2414,10 +2457,13 @@ int main(int argc, char *argv[]) { }, .enable_multipath = g_enable_multipath, // .multipath_version = g_multipath_version, + .enable_encode_fec = g_enable_fec, + .enable_decode_fec = g_enable_fec, .spurious_loss_detect_on = 0, .max_datagram_frame_size = g_max_dgram_size, // .datagram_force_retrans_on = 1, .marking_reinjection = 1, + .close_dgram_redundancy = XQC_RED_NOT_USE, }; if (g_pmtud_on) { @@ -2452,6 +2498,19 @@ int main(int argc, char *argv[]) { conn_settings.scheduler_callback = xqc_backup_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++) { + 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_max_window_size = 8; + conn_settings.fec_params = fec_params; + } + if (g_test_case == 12) { conn_settings.linger.linger_on = 1; } @@ -2482,8 +2541,6 @@ int main(int argc, char *argv[]) { conn_settings.datagram_redundant_probe = 30000; } - xqc_server_set_conn_settings(&conn_settings); - xqc_config_t config; if (xqc_engine_get_default_config(&config, XQC_ENGINE_SERVER) < 0) { return -1; @@ -2500,6 +2557,18 @@ int main(int argc, char *argv[]) { default: config.cfg_log_level = XQC_LOG_DEBUG; } + if (c_qlog_disable) { + config.cfg_log_event = 0; + } + switch(c_qlog_importance) { + case 's': config.cfg_qlog_importance = EVENT_IMPORTANCE_SELECTED; break; + case 'c': config.cfg_qlog_importance = EVENT_IMPORTANCE_CORE; break; + case 'b': config.cfg_qlog_importance = EVENT_IMPORTANCE_BASE; break; + case 'e': config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; break; + case 'r': config.cfg_qlog_importance = EVENT_IMPORTANCE_REMOVED; break; + default: config.cfg_qlog_importance = EVENT_IMPORTANCE_EXTRA; + } + eb = event_base_new(); ctx.ev_engine = event_new(eb, -1, 0, xqc_server_engine_callback, &ctx); @@ -2534,6 +2603,8 @@ int main(int argc, char *argv[]) { return -1; } + xqc_server_set_conn_settings(ctx.engine, &conn_settings); + /* register http3 callbacks */ xqc_h3_callbacks_t h3_cbs = { .h3c_cbs = { @@ -2597,7 +2668,27 @@ int main(int argc, char *argv[]) { return ret; } - xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs); + /* modify h3 default settings */ + if (g_test_case == 150 || g_test_case == 152) { + xqc_h3_engine_set_dec_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_enc_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + + if (g_test_case == 151 || g_test_case == 153) { + xqc_h3_engine_set_max_dtable_capacity(ctx.engine, 4096); + xqc_h3_engine_set_max_field_section_size(ctx.engine, 512); + xqc_h3_engine_set_qpack_blocked_streams(ctx.engine, 32); +#ifdef XQC_COMPAT_DUPLICATE + xqc_h3_engine_set_qpack_compat_duplicate(ctx.engine, 1); +#endif + } + + xqc_engine_register_alpn(ctx.engine, XQC_ALPN_TRANSPORT, 9, &ap_cbs, NULL); if (g_test_case == 10) { xqc_h3_engine_set_max_field_section_size(ctx.engine, 10000000); diff --git a/tests/unittest/main.c b/tests/unittest/main.c index 3607870c4..6b4a028e1 100644 --- a/tests/unittest/main.c +++ b/tests/unittest/main.c @@ -38,7 +38,9 @@ #include "xqc_retry_test.h" #include "xqc_datagram_test.h" #include "xqc_h3_ext_test.h" - +#include "xqc_galois_test.h" +#include "xqc_fec_scheme_test.h" +#include "xqc_fec_test.h" static int xqc_init_suite(void) { return 0; } static int xqc_clean_suite(void) { return 0; } @@ -99,6 +101,11 @@ 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 + || !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) +#endif /* ADD TESTS HERE */) { CU_cleanup_registry(); diff --git a/tests/unittest/xqc_common_test.c b/tests/unittest/xqc_common_test.c index a96673c44..4cba6b555 100644 --- a/tests/unittest/xqc_common_test.c +++ b/tests/unittest/xqc_common_test.c @@ -269,7 +269,7 @@ test_create_engine() /* transport ALPN */ xqc_app_proto_callbacks_t transport_cbs = {{NULL}, {NULL}}; - xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs); + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); return engine; } @@ -313,7 +313,7 @@ test_create_engine_server() /* transport ALPN */ xqc_app_proto_callbacks_t transport_cbs = {{NULL}, {NULL}}; - xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs); + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); return engine; } diff --git a/tests/unittest/xqc_common_test.h b/tests/unittest/xqc_common_test.h index 395dc3f8c..3cda7ece1 100644 --- a/tests/unittest/xqc_common_test.h +++ b/tests/unittest/xqc_common_test.h @@ -17,5 +17,4 @@ xqc_connection_t *test_engine_connect(); xqc_engine_t *test_create_engine(); xqc_engine_t *test_create_engine_server(); - #endif diff --git a/tests/unittest/xqc_fec_scheme_test.c b/tests/unittest/xqc_fec_scheme_test.c new file mode 100644 index 000000000..5a2cc8596 --- /dev/null +++ b/tests/unittest/xqc_fec_scheme_test.c @@ -0,0 +1,149 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include + +#include "xqc_fec_scheme_test.h" +#include "src/transport/xqc_conn.h" +#include "src/transport/xqc_engine.h" +#include "src/transport/xqc_frame.h" +#include "src/transport/xqc_frame_parser.h" +#include "src/transport/xqc_packet_out.h" +#include "src/transport/xqc_packet_in.h" +#include "src/transport/xqc_fec_scheme.h" +#include "src/transport/fec_schemes/xqc_xor.h" +#include "xqc_common_test.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}; + + +const xqc_cid_t * +test_cid_connect_fec(xqc_engine_t *engine) +{ + xqc_conn_settings_t conn_settings; + memset(&conn_settings, 0, sizeof(xqc_conn_settings_t)); + conn_settings.proto_version = XQC_VERSION_V1; + conn_settings.enable_encode_fec = 1; + conn_settings.enable_decode_fec = 1; + + xqc_conn_ssl_config_t conn_ssl_config; + memset(&conn_ssl_config, 0, sizeof(conn_ssl_config)); + const xqc_cid_t *cid = xqc_connect(engine, &conn_settings, NULL, 0, "", 0, &conn_ssl_config, + NULL, 0, "transport", NULL); + return cid; +} +static xqc_connection_t * +test_fec_connect(xqc_engine_t *engine) +{ + const xqc_cid_t *cid = test_cid_connect_fec(engine); + if (cid == NULL) { + return NULL; + } + return xqc_engine_conns_hash_find(engine, cid, 's'); +} + +xqc_connection_t * +test_engine_connect_fec() +{ + xqc_engine_t *engine = test_create_engine(); + if (engine == NULL) { + return NULL; + } + xqc_connection_t *conn = test_fec_connect(engine); + return conn; +} + +void +xqc_test_fec_frame_err() +{ + xqc_connection_t *conn = test_engine_connect_fec(); + CU_ASSERT(conn != NULL); + xqc_packet_in_t packet_in; + 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); + + 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); + + 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); + 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->conn_settings.fec_encode_callback.xqc_fec_encode = NULL; + ret = xqc_fec_encoder(conn, XQC_TEST_STREAM); + CU_ASSERT(ret == -XQC_EFEC_SCHEME_ERROR); + + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_invalid_decoder_params() +{ + xqc_int_t ret; + xqc_connection_t *conn = test_engine_connect_fec(); + 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); + + // 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); + 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); + + xqc_engine_destroy(conn->engine); +} + +void xqc_test_fec_scheme() +{ + xqc_test_fec_frame_err(); + xqc_test_invalid_encoder_params(); + xqc_test_invalid_decoder_params(); +} diff --git a/tests/unittest/xqc_fec_scheme_test.h b/tests/unittest/xqc_fec_scheme_test.h new file mode 100644 index 000000000..2afa73eff --- /dev/null +++ b/tests/unittest/xqc_fec_scheme_test.h @@ -0,0 +1,19 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef _XQC_FEC_SCHEME_TEST_H_INCLUDED_ +#define _XQC_FEC_SCHEME_TEST_H_INCLUDED_ +#include "src/common/xqc_queue.h" +#include "src/common/xqc_hash.h" +#include "xquic/xquic.h" +#include "src/common/xqc_log.h" +#include "src/transport/xqc_engine.h" + +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(); + +#endif /* _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ */ diff --git a/tests/unittest/xqc_fec_test.c b/tests/unittest/xqc_fec_test.c new file mode 100644 index 000000000..0d4e38dd5 --- /dev/null +++ b/tests/unittest/xqc_fec_test.c @@ -0,0 +1,128 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include +#include "xqc_fec_test.h" +#include "xqc_fec_scheme_test.h" +#include "include/xquic/xquic.h" +#include "src/transport/xqc_fec.h" +#include "src/transport/xqc_conn.h" +#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}; + +void +xqc_test_fec_scheme_setter() +{ + xqc_int_t ret, encoder_scheme_len; + xqc_fec_schemes_e encoder_schemes[XQC_FEC_MAX_SCHEME_NUM]; + + ret = xqc_set_fec_schemes(fec_schemes, 4, encoder_schemes, &encoder_scheme_len); + CU_ASSERT(ret == XQC_OK && encoder_scheme_len == 3); +} + +void +xqc_test_fec_negotiation() +{ + xqc_int_t ret; + xqc_connection_t *conn = test_engine_connect_fec(); + 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); + 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); + CU_ASSERT(ret == -XQC_EFEC_NOT_SUPPORT_FEC); + xqc_engine_destroy(conn->engine); +} + +void +xqc_test_write_repair_packet() +{ + xqc_int_t ret; + 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); + 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); + + xqc_engine_destroy(conn->engine); +} + +void +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; + padding_len = 500; + limit = 1200; + 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); + + 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); + 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); + CU_ASSERT(ret == -XQC_EFEC_SYMBOL_ERROR); + + 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(); +} \ No newline at end of file diff --git a/tests/unittest/xqc_fec_test.h b/tests/unittest/xqc_fec_test.h new file mode 100644 index 000000000..1a1775312 --- /dev/null +++ b/tests/unittest/xqc_fec_test.h @@ -0,0 +1,10 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef _XQC_FEC_TEST_H_INCLUDED_ +#define _XQC_FEC_TEST_H_INCLUDED_ + +void xqc_test_fec(); + +#endif /* _XQC_WAKEUP_PQ_TEST_H_INCLUDED_ */ diff --git a/tests/unittest/xqc_galois_test.c b/tests/unittest/xqc_galois_test.c new file mode 100644 index 000000000..64c01f2df --- /dev/null +++ b/tests/unittest/xqc_galois_test.c @@ -0,0 +1,32 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#include +#include +#include "src/transport/fec_schemes/xqc_galois_calculation.h" + + +void +xqc_test_galois_divide() +{ + xqc_int_t ret; + unsigned char res; + ret = xqc_galois_divide(0, 1, &res); + CU_ASSERT(res == 0 && ret == 0); + + ret = xqc_galois_divide(1, 0, &res); + CU_ASSERT(ret == -XQC_EPARAM); + + ret = xqc_galois_divide(5, 3, &res); + CU_ASSERT(ret == 0 && res == 3); + + ret = xqc_galois_divide(3, 5, &res); + CU_ASSERT(ret == 0 && res == 244); +} + +void +xqc_test_galois_calculation() +{ + xqc_test_galois_divide(); +} \ No newline at end of file diff --git a/tests/unittest/xqc_galois_test.h b/tests/unittest/xqc_galois_test.h new file mode 100644 index 000000000..d347f0f36 --- /dev/null +++ b/tests/unittest/xqc_galois_test.h @@ -0,0 +1,10 @@ +/** + * @copyright Copyright (c) 2022, Alibaba Group Holding Limited + */ + +#ifndef XQUIC_XQC_GALOIS_TEST_H +#define XQUIC_XQC_GALOIS_TEST_H + +void xqc_test_galois_calculation(); + +#endif //XQUIC_XQC_H3_EXT_TEST_H diff --git a/tests/unittest/xqc_h3_test.c b/tests/unittest/xqc_h3_test.c index 74f48f8ee..09c4f5304 100644 --- a/tests/unittest/xqc_h3_test.c +++ b/tests/unittest/xqc_h3_test.c @@ -430,6 +430,14 @@ xqc_test_stream() xqc_connection_t *conn = test_engine_connect(); CU_ASSERT(conn != NULL); + /* set alpn to H3 */ + if (conn->alpn) { + xqc_free(conn->alpn); + } + conn->alpn_len = strlen(XQC_ALPN_H3); + conn->alpn = xqc_calloc(1, conn->alpn_len + 1); + xqc_memcpy(conn->alpn, XQC_ALPN_H3, conn->alpn_len); + xqc_stream_t *stream = xqc_create_stream_with_conn(conn, XQC_UNDEFINE_STREAM_ID, XQC_CLI_UNI, NULL, NULL); CU_ASSERT(stream != NULL); @@ -448,4 +456,8 @@ xqc_test_stream() xqc_h3_stream_destroy(h3s); xqc_h3_conn_destroy(h3c); xqc_destroy_stream(stream); + + if (conn->alpn) { + xqc_free(conn->alpn); + } } diff --git a/tests/unittest/xqc_packet_test.c b/tests/unittest/xqc_packet_test.c index e7bb6bd62..5d4cdb505 100644 --- a/tests/unittest/xqc_packet_test.c +++ b/tests/unittest/xqc_packet_test.c @@ -167,7 +167,7 @@ test_create_engine_buf_server(test_ctx *tctx) &callback, &tcbs, tctx); /* transport ALPN */ - xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs); + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); return engine; } @@ -202,7 +202,7 @@ test_create_engine_buf_client(test_ctx *tctx) &callback, &tcbs, tctx); /* transport ALPN */ - xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs); + xqc_engine_register_alpn(engine, "transport", 9, &transport_cbs, NULL); return engine; } diff --git a/xqc_build.sh b/xqc_build.sh index fb58d8e8a..a9f1e85b0 100755 --- a/xqc_build.sh +++ b/xqc_build.sh @@ -61,11 +61,16 @@ if [ x"$platform" == xios ] ; then -DCMAKE_TOOLCHAIN_FILE=${IOS_CMAKE_TOOLCHAIN} -DENABLE_BITCODE=OFF -DXQC_NO_SHARED=ON + -DXQC_ENABLE_TH3=ON + -DXQC_COMPAT_GENERATE_SR_PKT=ON -DXQC_ENABLE_RENO=OFF -DXQC_ENABLE_BBR2=ON -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" @@ -93,7 +98,11 @@ elif [ x"$platform" == xandroid ] ; then -DXQC_ENABLE_MP_INTEROP=OFF -DXQC_DISABLE_LOG=OFF -DXQC_ONLY_ERROR_LOG=ON - -DXQC_COMPAT_GENERATE_SR_PKT=ON" + -DXQC_ENABLE_TH3=ON + -DXQC_COMPAT_GENERATE_SR_PKT=ON + -DXQC_ENABLE_FEC=OFF + -DXQC_ENABLE_XOR=OFF + -DXQC_ENABLE_RSC=OFF" elif [ x"$platform" == xharmony ] ; then if [ x"$HMOS_CMAKE_TOOLCHAIN" == x ] ; then echo "HMOS_CMAKE_TOOLCHAIN MUST be defined" diff --git a/xqc_configure.h.in b/xqc_configure.h.in index 6479bfaac..94d6ac24d 100644 --- a/xqc_configure.h.in +++ b/xqc_configure.h.in @@ -8,4 +8,8 @@ #cmakedefine XQC_ENABLE_UNLIMITED #cmakedefine XQC_ENABLE_MP_INTEROP #cmakedefine XQC_NO_PID_PACKET_PROCESS -#cmakedefine XQC_PROTECT_POOL_MEM \ No newline at end of file +#cmakedefine XQC_PROTECT_POOL_MEM +#cmakedefine XQC_COMPAT_DUPLICATE +#cmakedefine XQC_ENABLE_FEC +#cmakedefine XQC_ENABLE_XOR +#cmakedefine XQC_ENABLE_RSC \ No newline at end of file