Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[!] fix handle Retire Prior To error when NEW_CONNECTION_ID arrives and retire all the previous CIDs #427

Merged
merged 9 commits into from
May 30, 2024
84 changes: 52 additions & 32 deletions src/transport/xqc_frame.c
Original file line number Diff line number Diff line change
Expand Up @@ -738,13 +738,17 @@ xqc_process_ping_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in)
xqc_int_t
xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in)
{
xqc_int_t ret = XQC_ERROR;
xqc_cid_t new_conn_cid;
uint64_t retire_prior_to;
xqc_int_t ret = XQC_ERROR;
xqc_cid_t new_conn_cid;
uint64_t retire_prior_to;
uint64_t cid_limit;

xqc_cid_inner_t *inner_cid;
xqc_list_head_t *pos, *next;

/* the initial cid limit */
cid_limit = conn->local_settings.active_connection_id_limit;

ret = xqc_parse_new_conn_id_frame(packet_in, &new_conn_cid, &retire_prior_to, conn);
if (ret != XQC_OK) {
xqc_log(conn->log, XQC_LOG_ERROR,
Expand All @@ -769,6 +773,7 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in

/* TODO: write_retire_conn_id_frame 可能涉及到 替换 path.dcid (当前无 retire_prior_to 因此不涉及) */

/* the current cid was retired and is needed no more */
if (new_conn_cid.cid_seq_num < conn->dcid_set.largest_retire_prior_to) {
/*
* An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller
Expand All @@ -788,32 +793,6 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in
return XQC_OK;
}

if (retire_prior_to > conn->dcid_set.largest_retire_prior_to) {
/*
* Upon receipt of an increased Retire Prior To field, the peer MUST stop using the
* corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames before
* adding the newly provided connection ID to the set of active connection IDs.
*/

xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) {
inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list);
uint64_t seq_num = inner_cid->cid.cid_seq_num;
if ((inner_cid->state == XQC_CID_UNUSED || inner_cid->state == XQC_CID_USED)
&& (seq_num >= conn->dcid_set.largest_retire_prior_to && seq_num < retire_prior_to))
{
ret = xqc_write_retire_conn_id_frame_to_packet(conn, seq_num);
if (ret != XQC_OK) {
xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_retire_conn_id_frame_to_packet error|");
return ret;
}
}
}

conn->dcid_set.largest_retire_prior_to = retire_prior_to;
xqc_log(conn->log, XQC_LOG_DEBUG, "|retire_prior_to|%ui|increase to|%ui|",
conn->dcid_set.largest_retire_prior_to, retire_prior_to);
}

/* store dcid & add unused_dcid_count */
if (xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &new_conn_cid) != NULL) {
return XQC_OK;
Expand All @@ -840,13 +819,54 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in
return ret;
}

ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &new_conn_cid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit);
/* An endpoint MAY send connection IDs that temporarily exceed a peer's
* limit if the NEW_CONNECTION_ID frame also requires the retirement of any
* excess, by including a sufficiently large value in the Retire Prior To
* field. Hence it is not reasonable to consider it as an error */
cid_limit += retire_prior_to;
Kulsk marked this conversation as resolved.
Show resolved Hide resolved
ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &new_conn_cid,
XQC_CID_UNUSED, cid_limit);
if (ret != XQC_OK) {
xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error|limit:%ui|unused:%ui|used:%ui|",
conn->local_settings.active_connection_id_limit, conn->dcid_set.cid_set.unused_cnt, conn->dcid_set.cid_set.used_cnt);
xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error"
"|local_limit:%ui|retire_prior_to:%ui|unused:%ui|used:%ui|",
conn->local_settings.active_connection_id_limit,
retire_prior_to, conn->dcid_set.cid_set.unused_cnt,
conn->dcid_set.cid_set.used_cnt);
return ret;
}

/* process retire_prior_to */
if (retire_prior_to > conn->dcid_set.largest_retire_prior_to) {
/*
* Upon receipt of an increased Retire Prior To field, the peer MUST stop using the
* corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames before
* adding the newly provided connection ID to the set of active connection IDs.
*/

xqc_log(conn->log, XQC_LOG_DEBUG, "|retire cid prior to:%ui|current "
"largest_retire_prior_to:%ui|", retire_prior_to,
conn->dcid_set.largest_retire_prior_to);

xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) {
inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list);
uint64_t seq_num = inner_cid->cid.cid_seq_num;
if ((inner_cid->state == XQC_CID_UNUSED || inner_cid->state == XQC_CID_USED)
&& (seq_num >= conn->dcid_set.largest_retire_prior_to && seq_num < retire_prior_to))
{
ret = xqc_write_retire_conn_id_frame_to_packet(conn, seq_num);
if (ret != XQC_OK) {
xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_retire_conn_id_frame_to_packet error|");
return ret;
}
}
}

conn->dcid_set.largest_retire_prior_to = retire_prior_to;
xqc_log(conn->log, XQC_LOG_DEBUG, "|retire_prior_to|%ui|increase to|%ui|",
conn->dcid_set.largest_retire_prior_to, retire_prior_to);
}



return XQC_OK;
}
Expand Down
25 changes: 14 additions & 11 deletions src/transport/xqc_packet_out.c
Original file line number Diff line number Diff line change
Expand Up @@ -1270,18 +1270,21 @@ xqc_write_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_nu
{
xqc_int_t ret = XQC_ERROR;

/* select new current_dcid to replace the cid to be retired */
if (seq_num == conn->dcid_set.current_dcid.cid_seq_num) {
// TODO: DCID changes
ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &conn->dcid_set.current_dcid);
if (ret != XQC_OK) {
xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available dcid|");
return ret;
/* select new current_dcid to replace the cid to be retired */
if (seq_num == conn->dcid_set.current_dcid.cid_seq_num) {
// TODO: DCID changes
ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &conn->dcid_set.current_dcid);
if (ret != XQC_OK) {
xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available dcid"
"|seq_num:%ui|cur_cid_seq_num:%ui", seq_num,
conn->dcid_set.current_dcid.cid_seq_num);
return ret;
}
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_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_packet_out_t *packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER);
if (packet_out == NULL) {
Expand Down
Loading