Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 20 additions & 3 deletions demo/demo_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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':
Expand Down Expand Up @@ -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
Expand Down
10 changes: 10 additions & 0 deletions include/xquic/xqc_errno.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down
9 changes: 8 additions & 1 deletion include/xquic/xquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
15 changes: 14 additions & 1 deletion src/transport/xqc_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
78 changes: 71 additions & 7 deletions src/transport/xqc_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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;
}
Expand All @@ -308,31 +331,62 @@ 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:
if (conn->conn_settings.multipath_version >= XQC_MULTIPATH_10) {
ret = xqc_process_path_status_frame(conn, packet_in);

} else {
xqc_log(conn->log, XQC_LOG_ERROR, "|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;
}
Expand All @@ -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;
}
Expand All @@ -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;
}
Expand Down
83 changes: 69 additions & 14 deletions src/transport/xqc_frame_parser.c
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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;

Expand Down Expand Up @@ -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:
Expand All @@ -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;
}
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -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);
Expand Down
Loading
Loading