diff --git a/demo/demo_client.c b/demo/demo_client.c index 2a28e23c2..cd74323cd 100644 --- a/demo/demo_client.c +++ b/demo/demo_client.c @@ -1936,7 +1936,7 @@ xqc_demo_cli_usage(int argc, char *argv[]) " -Q Send requests one by one (default disabled)\n" " -T Throttle recving rate (Bps)\n" " -R Reinjection (1,2,4) \n" - " -V Multipath Version\n" + " -V Multipath Version (19/3e for draft-19, or numeric value)\n" " -B Set initial path standby after recvd first application data, and set initial path available after X ms\n" " -I Idle interval between requests (ms)\n" " -n Throttling the {1,2,...}xn-th requests\n" @@ -2184,8 +2184,13 @@ xqc_demo_cli_parse_args(int argc, char *argv[], xqc_demo_cli_client_args_t *args break; case 'V': - printf("option multipath version: %s\n", optarg); - args->quic_cfg.mp_version = atoi(optarg); + if (strcmp(optarg, "19") == 0 || strcmp(optarg, "3e") == 0) { + args->quic_cfg.mp_version = XQC_MULTIPATH_3E; + printf("option multipath version: %s (draft-19, using 0x3e)\n", optarg); + } else { + args->quic_cfg.mp_version = atoi(optarg); + printf("option multipath version: %s (numeric value: 0x%02x)\n", optarg, args->quic_cfg.mp_version); + } break; case 'B': @@ -2524,6 +2529,18 @@ xqc_demo_cli_h3_conn_handshake_finished(xqc_h3_conn_t *h3_conn, void *user_data) xqc_conn_stats_t stats = xqc_conn_get_stats(user_conn->ctx->engine, &user_conn->cid); printf("0rtt_flag:%d\n", stats.early_data_flag); + // 打印协商完成的multipath版本信息 + if (stats.enable_multipath) { + xqc_multipath_version_t negotiated_version = xqc_conn_get_multipath_version(user_conn->ctx->engine, &user_conn->cid); + + printf("=== Multipath Negotiated ===\n"); + printf("Multipath enabled: %d\n", stats.enable_multipath); + printf("Negotiated multipath version: 0x%02x\n", (uint8_t)negotiated_version); + printf("============================\n"); + } else { + printf("Multipath not negotiated\n"); + } + } void diff --git a/include/xquic/xqc_errno.h b/include/xquic/xqc_errno.h index fb9d32293..65741abf0 100644 --- a/include/xquic/xqc_errno.h +++ b/include/xquic/xqc_errno.h @@ -36,6 +36,16 @@ typedef enum { TRA_MP_PROTOCOL_VIOLATION = 0x1001d76d3ded42f3 } xqc_mp_err_code_t; +/** + * @brief Multipath PATH_ABANDON error codes (RFC draft-19) + */ +typedef enum { + APPLICATION_ABANDON_PATH = 0x3e, + PATH_RESOURCE_LIMIT_REACHED = 0x3e75, + PATH_UNSTABLE_OR_POOR = 0x3e76, + NO_CID_AVAILABLE_FOR_PATH = 0x3e77 +} xqc_path_abandon_err_code_t; + #define TRA_CRYPTO_ERROR_BASE 0x100 diff --git a/include/xquic/xquic.h b/include/xquic/xquic.h index dd80dbff3..d40314d99 100644 --- a/include/xquic/xquic.h +++ b/include/xquic/xquic.h @@ -1306,7 +1306,8 @@ typedef struct xqc_linger_s { typedef enum { XQC_ERR_MULTIPATH_VERSION = 0x00, - XQC_MULTIPATH_10 = 0x0a, + XQC_MULTIPATH_10 = 0x0a, + XQC_MULTIPATH_3E = 0x3e, } xqc_multipath_version_t; typedef enum { @@ -2144,6 +2145,12 @@ void xqc_conn_continue_send_by_conn(xqc_connection_t *conn); XQC_EXPORT_PUBLIC_API xqc_conn_stats_t xqc_conn_get_stats(xqc_engine_t *engine, const xqc_cid_t *cid); +/** + * Get negotiated multipath version by cid + */ +XQC_EXPORT_PUBLIC_API +xqc_multipath_version_t xqc_conn_get_multipath_version(xqc_engine_t *engine, const xqc_cid_t *cid); + /** * User can get xqc_conn_qos_stats_t by cid diff --git a/src/transport/xqc_conn.c b/src/transport/xqc_conn.c index ed3e83565..f1f65e94c 100644 --- a/src/transport/xqc_conn.c +++ b/src/transport/xqc_conn.c @@ -3736,7 +3736,20 @@ xqc_conn_get_stats(xqc_engine_t *engine, const xqc_cid_t *cid) return conn_stats; } -xqc_conn_qos_stats_t +xqc_multipath_version_t +xqc_conn_get_multipath_version(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(engine, cid)); + return XQC_ERR_MULTIPATH_VERSION; + } + + return xqc_conn_multipath_version_negotiation(conn); +} + +xqc_conn_qos_stats_t xqc_conn_get_qos_stats(xqc_engine_t *engine, const xqc_cid_t *cid) { xqc_connection_t *conn; diff --git a/src/transport/xqc_frame.c b/src/transport/xqc_frame.c index f7d52f25b..cf322ea8a 100644 --- a/src/transport/xqc_frame.c +++ b/src/transport/xqc_frame.c @@ -195,7 +195,9 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) frame_type); /* respond connection close when recv any packet except conn_close and ack / ack_mp */ if (frame_type != 0x1c && frame_type != 0x1d - && frame_type != XQC_TRANS_FRAME_TYPE_MP_ACK0 + && frame_type != XQC_TRANS_FRAME_TYPE_PATH_ACK + && frame_type != XQC_TRANS_FRAME_TYPE_PATH_ACK_ECN + && frame_type != XQC_TRANS_FRAME_TYPE_MP_ACK0 && frame_type != XQC_TRANS_FRAME_TYPE_MP_ACK1) { xqc_conn_immediate_close(conn); @@ -292,13 +294,34 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) case XQC_TRANS_FRAME_TYPE_ACK_EXT: ret = xqc_process_ack_ext_frame(conn, packet_in); break; + case XQC_TRANS_FRAME_TYPE_PATH_ACK: + case XQC_TRANS_FRAME_TYPE_PATH_ACK_ECN: + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + ret = xqc_process_ack_mp_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); + ret = -XQC_EMP_INVALID_MP_VERTION; + } + break; case XQC_TRANS_FRAME_TYPE_MP_ACK0: case XQC_TRANS_FRAME_TYPE_MP_ACK1: if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { ret = xqc_process_ack_mp_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); + ret = -XQC_EMP_INVALID_MP_VERTION; + } + break; + case XQC_TRANS_FRAME_TYPE_PATH_ABANDON: + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + ret = xqc_process_path_abandon_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } @@ -308,12 +331,23 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) ret = xqc_process_path_abandon_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; + case XQC_TRANS_FRAME_TYPE_PATH_STATUS_STANDBY: + case XQC_TRANS_FRAME_TYPE_PATH_STATUS_AVAILABLE: + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + ret = xqc_process_path_status_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); + ret = -XQC_EMP_INVALID_MP_VERTION; + } + break; case XQC_TRANS_FRAME_TYPE_MP_STANDBY: case XQC_TRANS_FRAME_TYPE_MP_AVAILABLE: case XQC_TRANS_FRAME_TYPE_MP_FROZEN: @@ -321,18 +355,38 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) ret = xqc_process_path_status_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } break; + case XQC_TRANS_FRAME_TYPE_PATH_NEW_CONNECTION_ID: + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + ret = xqc_process_mp_new_conn_id_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); + ret = -XQC_EMP_INVALID_MP_VERTION; + } + break; case XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID: if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { ret = xqc_process_mp_new_conn_id_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); + ret = -XQC_EMP_INVALID_MP_VERTION; + } + break; + case XQC_TRANS_FRAME_TYPE_PATH_RETIRE_CONNECTION_ID: + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + ret = xqc_process_mp_retire_conn_id_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } @@ -342,7 +396,17 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) ret = xqc_process_mp_retire_conn_id_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + conn->conn_settings.multipath_version, frame_type); + ret = -XQC_EMP_INVALID_MP_VERTION; + } + break; + case XQC_TRANS_FRAME_TYPE_PATH_MAX_PATH_ID: + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + ret = xqc_process_max_path_id_frame(conn, packet_in); + + } else { + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } @@ -352,7 +416,7 @@ xqc_process_frames(xqc_connection_t *conn, xqc_packet_in_t *packet_in) ret = xqc_process_max_path_id_frame(conn, packet_in); } else { - xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", + xqc_log(conn->log, XQC_LOG_ERROR, "|mp_version error|v:%ud|f:%xL|", conn->conn_settings.multipath_version, frame_type); ret = -XQC_EMP_INVALID_MP_VERTION; } diff --git a/src/transport/xqc_frame_parser.c b/src/transport/xqc_frame_parser.c index 59358a198..5d7dd00ac 100644 --- a/src/transport/xqc_frame_parser.c +++ b/src/transport/xqc_frame_parser.c @@ -2243,7 +2243,10 @@ xqc_gen_ack_mp_frame(xqc_connection_t *conn, uint64_t path_id, { uint64_t frame_type; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + frame_type = XQC_TRANS_FRAME_TYPE_PATH_ACK; + + } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { frame_type = XQC_TRANS_FRAME_TYPE_MP_ACK0; } else { @@ -2501,7 +2504,10 @@ xqc_gen_path_abandon_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, need = po_remained_size = 0; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + frame_type = XQC_TRANS_FRAME_TYPE_PATH_ABANDON; + + } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { /* same frame type in 05 and 06 */ frame_type = XQC_TRANS_FRAME_TYPE_MP_ABANDON; @@ -2622,14 +2628,33 @@ xqc_gen_path_status_frame(xqc_connection_t *conn, uint64_t frame_type; uint64_t ft_flag; - if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { switch (status) { - case XQC_APP_PATH_STATUS_STANDBY: - frame_type = XQC_TRANS_FRAME_TYPE_MP_STANDBY; + case XQC_APP_PATH_STATUS_STANDBY: + frame_type = XQC_TRANS_FRAME_TYPE_PATH_STATUS_STANDBY; ft_flag = XQC_FRAME_BIT_PATH_STANDBY; break; - case XQC_APP_PATH_STATUS_AVAILABLE: - frame_type = XQC_TRANS_FRAME_TYPE_MP_AVAILABLE; + case XQC_APP_PATH_STATUS_AVAILABLE: + frame_type = XQC_TRANS_FRAME_TYPE_PATH_STATUS_AVAILABLE; + ft_flag = XQC_FRAME_BIT_PATH_AVAILABLE; + break; + case XQC_APP_PATH_STATUS_FROZEN: + /* Map FROZEN to STANDBY in RFC version */ + frame_type = XQC_TRANS_FRAME_TYPE_PATH_STATUS_STANDBY; + ft_flag = XQC_FRAME_BIT_PATH_FROZEN; + break; + default: + return -XQC_EMP_PATH_STATE_ERROR; + } + + } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + switch (status) { + case XQC_APP_PATH_STATUS_STANDBY: + frame_type = XQC_TRANS_FRAME_TYPE_MP_STANDBY; + ft_flag = XQC_FRAME_BIT_PATH_STANDBY; + break; + case XQC_APP_PATH_STATUS_AVAILABLE: + frame_type = XQC_TRANS_FRAME_TYPE_MP_AVAILABLE; ft_flag = XQC_FRAME_BIT_PATH_AVAILABLE; break; case XQC_APP_PATH_STATUS_FROZEN: @@ -2639,7 +2664,7 @@ xqc_gen_path_status_frame(xqc_connection_t *conn, default: return -XQC_EMP_PATH_STATE_ERROR; } - + } else { return -XQC_EMP_INVALID_MP_VERTION; } @@ -2742,14 +2767,24 @@ xqc_parse_path_status_frame(xqc_packet_in_t *packet_in, * Figure 39: MP_NEW_CONNECTION_ID Frame Format * */ ssize_t -xqc_gen_mp_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, +xqc_gen_mp_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, uint64_t retire_prior_to, const uint8_t *sr_token, uint64_t path_id) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; /* write frame type */ - uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID; + uint64_t frame_type; + + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + frame_type = XQC_TRANS_FRAME_TYPE_PATH_NEW_CONNECTION_ID; + + } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + frame_type = XQC_TRANS_FRAME_TYPE_MP_NEW_CONN_ID; + + } else { + return -XQC_EMP_INVALID_MP_VERTION; + } unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); @@ -2872,13 +2907,23 @@ xqc_parse_mp_new_conn_id_frame(xqc_packet_in_t *packet_in, * } * */ ssize_t -xqc_gen_mp_retire_conn_id_frame(xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id) +xqc_gen_mp_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; /* write frame type */ - uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID; + uint64_t frame_type; + + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + frame_type = XQC_TRANS_FRAME_TYPE_PATH_RETIRE_CONNECTION_ID; + + } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + frame_type = XQC_TRANS_FRAME_TYPE_MP_RETIRE_CONN_ID; + + } else { + return -XQC_EMP_INVALID_MP_VERTION; + } unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); @@ -2942,13 +2987,23 @@ xqc_parse_mp_retire_conn_id_frame(xqc_packet_in_t *packet_in, uint64_t *seq_num, * Figure: MAX_PATH_ID Frame Format * */ ssize_t -xqc_gen_max_path_id_frame(xqc_packet_out_t *packet_out, uint64_t max_path_id) +xqc_gen_max_path_id_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, uint64_t max_path_id) { unsigned char *dst_buf = packet_out->po_buf + packet_out->po_used_size; const unsigned char *begin = dst_buf; /* write frame type */ - uint64_t frame_type = XQC_TRANS_FRAME_TYPE_MAX_PATH_ID; + uint64_t frame_type; + + if (conn->conn_settings.multipath_version == XQC_MULTIPATH_3E) { + frame_type = XQC_TRANS_FRAME_TYPE_PATH_MAX_PATH_ID; + + } else if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) { + frame_type = XQC_TRANS_FRAME_TYPE_MAX_PATH_ID; + + } else { + return -XQC_EMP_INVALID_MP_VERTION; + } unsigned frame_type_bits = xqc_vint_get_2bit(frame_type); xqc_vint_write(dst_buf, frame_type, frame_type_bits, xqc_vint_len(frame_type_bits)); dst_buf += xqc_vint_len(frame_type_bits); diff --git a/src/transport/xqc_frame_parser.h b/src/transport/xqc_frame_parser.h index 17e14eafe..8ab9f2ad6 100644 --- a/src/transport/xqc_frame_parser.h +++ b/src/transport/xqc_frame_parser.h @@ -17,6 +17,7 @@ #define XQC_DATAGRAM_LENGTH_FIELD_BYTES 2 #define XQC_DATAGRAM_HEADER_BYTES (XQC_DATAGRAM_LENGTH_FIELD_BYTES + 1) +/* Legacy multipath frame types (v10) */ #define XQC_TRANS_FRAME_TYPE_MP_ACK0 0x15228c00 #define XQC_TRANS_FRAME_TYPE_MP_ACK1 0x15228c01 #define XQC_TRANS_FRAME_TYPE_MP_ABANDON 0x15228c05 @@ -27,6 +28,16 @@ #define XQC_TRANS_FRAME_TYPE_MAX_PATH_ID 0x15228c0c #define XQC_TRANS_FRAME_TYPE_MP_FROZEN 0x15228cff +/* RFC multipath frame types */ +#define XQC_TRANS_FRAME_TYPE_PATH_ACK 0x3e +#define XQC_TRANS_FRAME_TYPE_PATH_ACK_ECN 0x3f +#define XQC_TRANS_FRAME_TYPE_PATH_ABANDON 0x3e75 +#define XQC_TRANS_FRAME_TYPE_PATH_STATUS_STANDBY 0x3e76 +#define XQC_TRANS_FRAME_TYPE_PATH_STATUS_AVAILABLE 0x3e77 +#define XQC_TRANS_FRAME_TYPE_PATH_NEW_CONNECTION_ID 0x3e78 +#define XQC_TRANS_FRAME_TYPE_PATH_RETIRE_CONNECTION_ID 0x3e79 +#define XQC_TRANS_FRAME_TYPE_PATH_MAX_PATH_ID 0x3e7a + #define XQC_TRANS_FRAME_TYPE_ACK_EXT 0xB1 /** @@ -168,17 +179,17 @@ xqc_int_t xqc_gen_repair_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_ xqc_int_t xqc_parse_repair_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in, xqc_fec_rpr_syb_t *rpr_symbol); -ssize_t xqc_gen_mp_new_conn_id_frame(xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, +ssize_t xqc_gen_mp_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, xqc_cid_t *new_cid, uint64_t retire_prior_to, const uint8_t *sr_token, uint64_t path_id); xqc_int_t xqc_parse_mp_new_conn_id_frame(xqc_packet_in_t *packet_in, xqc_cid_t *new_cid, uint64_t *retire_prior_to, uint64_t *path_id, xqc_connection_t *conn); -ssize_t xqc_gen_mp_retire_conn_id_frame(xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id); +ssize_t xqc_gen_mp_retire_conn_id_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, uint64_t seq_num, uint64_t path_id); xqc_int_t xqc_parse_mp_retire_conn_id_frame(xqc_packet_in_t *packet_in, uint64_t *seq_num, uint64_t *path_id); -ssize_t xqc_gen_max_path_id_frame(xqc_packet_out_t *packet_out, uint64_t max_path_id); +ssize_t xqc_gen_max_path_id_frame(xqc_connection_t *conn, xqc_packet_out_t *packet_out, uint64_t max_path_id); xqc_int_t xqc_parse_max_path_id_frame(xqc_packet_in_t *packet_in, uint64_t *max_path_id); void xqc_try_process_fec_decode(xqc_connection_t *conn, xqc_int_t block_id); diff --git a/src/transport/xqc_multipath.c b/src/transport/xqc_multipath.c index fbe17e26e..1b02d87e4 100644 --- a/src/transport/xqc_multipath.c +++ b/src/transport/xqc_multipath.c @@ -308,7 +308,7 @@ xqc_path_immediate_close(xqc_path_ctx_t *path) xqc_connection_t *conn = path->parent_conn; xqc_int_t ret = XQC_OK; - ret = xqc_write_path_abandon_frame_to_packet(conn, path); + ret = xqc_write_path_abandon_frame_to_packet(conn, path, APPLICATION_ABANDON_PATH); if (ret != XQC_OK) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_path_abandon_frame_to_packet error|ret:%d|", ret); } @@ -417,6 +417,7 @@ xqc_conn_is_current_mp_version_supported(xqc_multipath_version_t mp_version) xqc_int_t ret; switch (mp_version) { case XQC_MULTIPATH_10: + case XQC_MULTIPATH_3E: ret = XQC_OK; break; default: diff --git a/src/transport/xqc_packet_out.c b/src/transport/xqc_packet_out.c index b564cc947..a9e9004cb 100644 --- a/src/transport/xqc_packet_out.c +++ b/src/transport/xqc_packet_out.c @@ -1616,7 +1616,7 @@ xqc_write_ack_mp_to_one_packet(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_int_t -xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path) +xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path, uint64_t error_code) { xqc_int_t ret = XQC_ERROR; @@ -1628,7 +1628,7 @@ xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *p uint64_t path_id = path->path_id; - ret = xqc_gen_path_abandon_frame(conn, packet_out, path_id, 0); + ret = xqc_gen_path_abandon_frame(conn, packet_out, path_id, error_code); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_path_abandon_frame error|%d|", ret); goto error; @@ -1757,7 +1757,7 @@ xqc_write_mp_new_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t retire return -XQC_EWRITE_PKT; } - ret = xqc_gen_mp_new_conn_id_frame(packet_out, &new_conn_cid, retire_prior_to, + ret = xqc_gen_mp_new_conn_id_frame(conn, packet_out, &new_conn_cid, retire_prior_to, sr_token, path_id); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_mp_new_conn_id_frame error|"); @@ -1832,7 +1832,7 @@ xqc_write_mp_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq return -XQC_EWRITE_PKT; } - ret = xqc_gen_mp_retire_conn_id_frame(packet_out, seq_num, path_id); + ret = xqc_gen_mp_retire_conn_id_frame(conn, packet_out, seq_num, path_id); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_mp_retire_conn_id_frame error|"); xqc_maybe_recycle_packet_out(packet_out, conn); @@ -1858,7 +1858,7 @@ xqc_write_max_path_id_to_packet(xqc_connection_t *conn, uint64_t max_path_id) return -XQC_EWRITE_PKT; } - ret = xqc_gen_max_path_id_frame(packet_out, max_path_id); + ret = xqc_gen_max_path_id_frame(conn, packet_out, max_path_id); if (ret < 0) { xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_gen_max_streams_frame error|"); goto error; diff --git a/src/transport/xqc_packet_out.h b/src/transport/xqc_packet_out.h index 160a484fa..0ce438066 100644 --- a/src/transport/xqc_packet_out.h +++ b/src/transport/xqc_packet_out.h @@ -213,7 +213,7 @@ xqc_int_t xqc_write_path_response_frame_to_packet(xqc_connection_t *conn, xqc_pa int xqc_write_ack_mp_to_one_packet(xqc_connection_t *conn, xqc_path_ctx_t *path, xqc_packet_out_t *packet_out, xqc_pkt_num_space_t pns); -xqc_int_t xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path); +xqc_int_t xqc_write_path_abandon_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path, uint64_t error_code); xqc_int_t xqc_write_path_status_frame_to_packet(xqc_connection_t *conn, xqc_path_ctx_t *path); diff --git a/src/transport/xqc_transport_params.c b/src/transport/xqc_transport_params.c index 20f955c39..09ff75ea9 100644 --- a/src/transport/xqc_transport_params.c +++ b/src/transport/xqc_transport_params.c @@ -166,7 +166,10 @@ xqc_transport_params_calc_length(const xqc_transport_params_t *params, len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10) + xqc_put_varint_len(xqc_put_varint_len(params->init_max_path_id)) + xqc_put_varint_len(params->init_max_path_id); - + } else if (params->multipath_version == XQC_MULTIPATH_3E) { + len += xqc_put_varint_len(XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V3E) + + xqc_put_varint_len(xqc_put_varint_len(params->init_max_path_id)) + + xqc_put_varint_len(params->init_max_path_id); } } @@ -418,7 +421,8 @@ xqc_encode_transport_params(const xqc_transport_params_t *params, if (params->enable_multipath) { if (params->multipath_version == XQC_MULTIPATH_10) { p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10, params->init_max_path_id); - + } else if (params->multipath_version == XQC_MULTIPATH_3E) { + p = xqc_put_varint_param(p, XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V3E, params->init_max_path_id); } } @@ -742,6 +746,11 @@ xqc_decode_enable_multipath(xqc_transport_params_t *params, xqc_transport_params params->multipath_version = XQC_MULTIPATH_10; XQC_DECODE_VINT_VALUE(¶ms->init_max_path_id, p, end); return XQC_OK; + } else if (param_type == XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V3E) { + params->enable_multipath = 1; + params->multipath_version = XQC_MULTIPATH_3E; + XQC_DECODE_VINT_VALUE(¶ms->init_max_path_id, p, end); + return XQC_OK; } return XQC_OK; } @@ -1004,6 +1013,7 @@ xqc_trans_param_get_index(uint64_t param_type) return (xqc_tp_decoder_index_t)param_type; case XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10: + case XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V3E: return XQC_TP_DECODER_ENABLE_MULTIPATH; case XQC_TRANSPORT_PARAM_MAX_DATAGRAM_FRAME_SIZE: diff --git a/src/transport/xqc_transport_params.h b/src/transport/xqc_transport_params.h index e572f6ad7..26b56126d 100644 --- a/src/transport/xqc_transport_params.h +++ b/src/transport/xqc_transport_params.h @@ -74,6 +74,7 @@ typedef enum { /* multipath quic attributes */ XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V10 = 0x0f739bbc1b666d09, + XQC_TRANSPORT_PARAM_INIT_MAX_PATH_ID_V3E = 0x3e, /* google connection options */ XQC_TRANSPORT_PARAM_GOOGLE_CO = 0x3128,