Skip to content

Commit 07b1838

Browse files
authored
[!] fix handle Retire Prior To error when NEW_CONNECTION_ID arrives and retire all the previous CIDs (#427)
* [!] fix interop multiplexing testcase error when hq stream send content and fin separately. * [!] fix handle Retire Prior To error when NEW_CONNECTION_ID arrives and retire all the previous CIDs * [!] fix anti-amplification interop testcase error * [!] fix annotation error * [!] fix sending pkt with retired cid error after receiving NCI with Retire Prior To
1 parent 6b5f20d commit 07b1838

File tree

8 files changed

+182
-46
lines changed

8 files changed

+182
-46
lines changed

demo/demo_server.c

+1
Original file line numberDiff line numberDiff line change
@@ -1506,6 +1506,7 @@ xqc_demo_svr_init_conn_settings(xqc_demo_svr_args_t *args)
15061506
.is_interop_mode = args->quic_cfg.is_interop_mode,
15071507
.max_pkt_out_size = args->quic_cfg.max_pkt_sz,
15081508
.adaptive_ack_frequency = 1,
1509+
.anti_amplification_limit = 3,
15091510
};
15101511

15111512
xqc_server_set_conn_settings(&conn_settings);

include/xquic/xquic.h

+1-1
Original file line numberDiff line numberDiff line change
@@ -1145,7 +1145,7 @@ typedef struct xqc_conn_settings_s {
11451145
xqc_msec_t init_idle_time_out; /* initial idle timeout interval, effective before handshake completion */
11461146
xqc_msec_t idle_time_out; /* idle timeout interval, effective after handshake completion */
11471147
int32_t spurious_loss_detect_on;
1148-
uint32_t anti_amplification_limit; /* limit of anti-amplification, default 3 */
1148+
uint32_t anti_amplification_limit; /* limit of anti-amplification, default 5 */
11491149
uint64_t keyupdate_pkt_threshold; /* packet limit of a single 1-rtt key, 0 for unlimited */
11501150
size_t max_pkt_out_size;
11511151

src/transport/xqc_cid.c

+43
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,49 @@ xqc_destroy_cid_set(xqc_cid_set_t *cid_set)
167167
xqc_init_cid_set(cid_set);
168168
}
169169

170+
uint64_t
171+
xqc_cid_set_cnt(xqc_cid_set_t *cid_set)
172+
{
173+
return cid_set->unused_cnt + cid_set->used_cnt;
174+
}
175+
176+
xqc_bool_t
177+
xqc_cid_set_validate_new_cid_limit(xqc_cid_set_t *cid_set,
178+
uint64_t max_retire_prior_to, uint64_t *active_cid_limit)
179+
{
180+
xqc_list_head_t *pos, *next;
181+
xqc_cid_inner_t *cid = NULL;
182+
uint64_t retire_cnt = 0;
183+
184+
if (xqc_cid_set_cnt(cid_set) + 1 <= *active_cid_limit) {
185+
return XQC_TRUE;
186+
}
187+
188+
/* the new cid might exceed the active_cid_limit, but will not retire any
189+
cid, shall not be inserted */
190+
if (max_retire_prior_to == 0) {
191+
return XQC_FALSE;
192+
}
193+
194+
/* validate if cid cnt is legal after to be retired */
195+
xqc_list_for_each_safe(pos, next, &cid_set->list_head) {
196+
cid = xqc_list_entry(pos, xqc_cid_inner_t, list);
197+
if (cid->cid.cid_seq_num < max_retire_prior_to) {
198+
retire_cnt++;
199+
}
200+
}
201+
202+
if (xqc_cid_set_cnt(cid_set) + 1 - retire_cnt > *active_cid_limit) {
203+
return XQC_FALSE;
204+
}
205+
206+
/* allow the new connection id */
207+
*active_cid_limit = xqc_cid_set_cnt(cid_set) + 1;
208+
209+
return XQC_TRUE;
210+
}
211+
212+
170213
xqc_int_t
171214
xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit)
172215
{

src/transport/xqc_cid.h

+4
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,10 @@ void xqc_init_scid_set(xqc_scid_set_t *scid_set);
6161
void xqc_init_dcid_set(xqc_dcid_set_t *dcid_set);
6262
void xqc_destroy_cid_set(xqc_cid_set_t *cid_set);
6363

64+
uint64_t xqc_cid_set_cnt(xqc_cid_set_t *cid_set);
65+
xqc_bool_t xqc_cid_set_validate_new_cid_limit(xqc_cid_set_t *cid_set,
66+
uint64_t max_retire_prior_to, uint64_t *active_cid_limit);
67+
6468
xqc_int_t xqc_cid_set_insert_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid, xqc_cid_state_t state, uint64_t limit);
6569
xqc_int_t xqc_cid_set_delete_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid);
6670

src/transport/xqc_conn.c

+72
Original file line numberDiff line numberDiff line change
@@ -3944,6 +3944,13 @@ xqc_conn_confirm_cid(xqc_connection_t *c, xqc_packet_t *pkt)
39443944
if (!(c->conn_flag & XQC_CONN_FLAG_DCID_OK)) {
39453945

39463946
if (xqc_cid_in_cid_set(&c->dcid_set.cid_set, &pkt->pkt_scid) == NULL) {
3947+
/* delete original cid which is not chosen by peer */
3948+
ret = xqc_cid_set_delete_cid(&c->dcid_set.cid_set, &c->original_dcid);
3949+
if (ret != XQC_OK) {
3950+
xqc_log(c->log, XQC_LOG_WARN, "|delete original dcid error");
3951+
}
3952+
3953+
/* insert peer's first dcid */
39473954
ret = xqc_cid_set_insert_cid(&c->dcid_set.cid_set, &pkt->pkt_scid, XQC_CID_USED,
39483955
c->local_settings.active_connection_id_limit);
39493956
if (ret != XQC_OK) {
@@ -5943,3 +5950,68 @@ xqc_conn_handle_deprecated_stateless_reset(xqc_connection_t *conn,
59435950
}
59445951

59455952
#endif
5953+
5954+
5955+
/* Retire DCID on initial path. this is called when NEW_CONNECTION_ID frame with
5956+
Retire Prior To field is received. */
5957+
xqc_int_t
5958+
xqc_conn_retire_dcid_prior_to(xqc_connection_t *conn, uint64_t retire_prior_to)
5959+
{
5960+
xqc_int_t ret;
5961+
uint64_t seq_num;
5962+
xqc_cid_inner_t *inner_cid;
5963+
xqc_list_head_t *pos, *next;
5964+
5965+
xqc_log(conn->log, XQC_LOG_DEBUG, "|retire cid prior to:%ui|current "
5966+
"largest_retire_prior_to:%ui|", retire_prior_to,
5967+
conn->dcid_set.largest_retire_prior_to);
5968+
5969+
xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) {
5970+
5971+
inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list);
5972+
seq_num = inner_cid->cid.cid_seq_num;
5973+
5974+
if ((inner_cid->state == XQC_CID_UNUSED
5975+
|| inner_cid->state == XQC_CID_USED)
5976+
&& (seq_num >= conn->dcid_set.largest_retire_prior_to
5977+
&& seq_num < retire_prior_to))
5978+
{
5979+
ret = xqc_write_retire_conn_id_frame_to_packet(conn, seq_num);
5980+
if (ret != XQC_OK) {
5981+
xqc_log(conn->log, XQC_LOG_ERROR,
5982+
"|xqc_write_retire_conn_id_frame_to_packet error|");
5983+
return ret;
5984+
}
5985+
5986+
/* change state */
5987+
ret = xqc_cid_switch_to_next_state(&conn->dcid_set.cid_set,
5988+
inner_cid, XQC_CID_RETIRED);
5989+
if (ret != XQC_OK) {
5990+
xqc_log(conn->log, XQC_LOG_ERROR, "|switch cid state to "
5991+
"RETIRED error|seq_num:%ui|cur_state:%d|", seq_num,
5992+
inner_cid->state);
5993+
}
5994+
5995+
/* immediately delete cid */
5996+
xqc_list_del(pos);
5997+
xqc_free(inner_cid);
5998+
5999+
xqc_log(conn->log, XQC_LOG_INFO, "|cid[%ui] retired", seq_num);
6000+
}
6001+
}
6002+
6003+
conn->dcid_set.largest_retire_prior_to = retire_prior_to;
6004+
6005+
/* path dcid retired */
6006+
if (conn->conn_initial_path->path_dcid.cid_seq_num < retire_prior_to) {
6007+
xqc_log(conn->log, XQC_LOG_DEBUG, "");
6008+
xqc_cid_copy(&conn->conn_initial_path->path_dcid,
6009+
&conn->dcid_set.current_dcid);
6010+
}
6011+
6012+
xqc_log(conn->log, XQC_LOG_DEBUG, "|retire_prior_to|%ui|increase to %ui"
6013+
"|cnt:%ui", conn->dcid_set.largest_retire_prior_to,
6014+
retire_prior_to, xqc_cid_set_cnt(&conn->dcid_set.cid_set));
6015+
6016+
return XQC_OK;
6017+
}

src/transport/xqc_conn.h

+2
Original file line numberDiff line numberDiff line change
@@ -658,4 +658,6 @@ xqc_int_t xqc_conn_send_ping_internal(xqc_connection_t *conn, void *ping_user_da
658658

659659
void xqc_conn_encode_mp_settings(xqc_connection_t *conn, char *buf, size_t buf_sz);
660660

661+
xqc_int_t xqc_conn_retire_dcid_prior_to(xqc_connection_t *conn, uint64_t retire_prior_to);
662+
661663
#endif /* _XQC_CONN_H_INCLUDED_ */

src/transport/xqc_frame.c

+45-34
Original file line numberDiff line numberDiff line change
@@ -738,12 +738,15 @@ xqc_process_ping_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in)
738738
xqc_int_t
739739
xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in)
740740
{
741-
xqc_int_t ret = XQC_ERROR;
742-
xqc_cid_t new_conn_cid;
743-
uint64_t retire_prior_to;
741+
xqc_int_t ret = XQC_ERROR;
742+
xqc_cid_t new_conn_cid;
743+
uint64_t retire_prior_to;
744+
uint64_t largest_retire_prior_to;
745+
uint64_t cid_limit;
746+
744747

745-
xqc_cid_inner_t *inner_cid;
746-
xqc_list_head_t *pos, *next;
748+
/* the initial cid limit */
749+
cid_limit = conn->local_settings.active_connection_id_limit;
747750

748751
ret = xqc_parse_new_conn_id_frame(packet_in, &new_conn_cid, &retire_prior_to, conn);
749752
if (ret != XQC_OK) {
@@ -769,6 +772,7 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in
769772

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

775+
/* the current cid was retired and is needed no more */
772776
if (new_conn_cid.cid_seq_num < conn->dcid_set.largest_retire_prior_to) {
773777
/*
774778
* An endpoint that receives a NEW_CONNECTION_ID frame with a sequence number smaller
@@ -788,37 +792,26 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in
788792
return XQC_OK;
789793
}
790794

791-
if (retire_prior_to > conn->dcid_set.largest_retire_prior_to) {
792-
/*
793-
* Upon receipt of an increased Retire Prior To field, the peer MUST stop using the
794-
* corresponding connection IDs and retire them with RETIRE_CONNECTION_ID frames before
795-
* adding the newly provided connection ID to the set of active connection IDs.
796-
*/
797-
798-
xqc_list_for_each_safe(pos, next, &conn->dcid_set.cid_set.list_head) {
799-
inner_cid = xqc_list_entry(pos, xqc_cid_inner_t, list);
800-
uint64_t seq_num = inner_cid->cid.cid_seq_num;
801-
if ((inner_cid->state == XQC_CID_UNUSED || inner_cid->state == XQC_CID_USED)
802-
&& (seq_num >= conn->dcid_set.largest_retire_prior_to && seq_num < retire_prior_to))
803-
{
804-
ret = xqc_write_retire_conn_id_frame_to_packet(conn, seq_num);
805-
if (ret != XQC_OK) {
806-
xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_write_retire_conn_id_frame_to_packet error|");
807-
return ret;
808-
}
809-
}
810-
}
811-
812-
conn->dcid_set.largest_retire_prior_to = retire_prior_to;
813-
xqc_log(conn->log, XQC_LOG_DEBUG, "|retire_prior_to|%ui|increase to|%ui|",
814-
conn->dcid_set.largest_retire_prior_to, retire_prior_to);
815-
}
816-
817795
/* store dcid & add unused_dcid_count */
818796
if (xqc_cid_in_cid_set(&conn->dcid_set.cid_set, &new_conn_cid) != NULL) {
819797
return XQC_OK;
820798
}
821799

800+
/* check if insertion of the new conneciton id will violate the cid limit */
801+
largest_retire_prior_to = xqc_max(retire_prior_to,
802+
conn->dcid_set.largest_retire_prior_to);
803+
if (!xqc_cid_set_validate_new_cid_limit(&conn->dcid_set.cid_set,
804+
largest_retire_prior_to, &cid_limit))
805+
{
806+
xqc_log(conn->log, XQC_LOG_ERROR, "|retire_prior_to:%ui greater than seq_num:%ui|",
807+
retire_prior_to, new_conn_cid.cid_seq_num);
808+
XQC_CONN_ERR(conn, TRA_PROTOCOL_VIOLATION);
809+
return -XQC_EPROTO;
810+
}
811+
812+
xqc_log(conn->log, XQC_LOG_DEBUG, "|nci allow to be inserted|seq:%ui|dcid_cnt:%ui|cid_limit:%ui",
813+
new_conn_cid.cid_seq_num, xqc_cid_set_cnt(&conn->dcid_set.cid_set), cid_limit);
814+
822815
/* insert into dcid-connection hash, for processing the deprecated stateless
823816
reset packet */
824817
ret = xqc_insert_conns_hash(conn->engine->conns_hash_dcid, conn,
@@ -840,13 +833,31 @@ xqc_process_new_conn_id_frame(xqc_connection_t *conn, xqc_packet_in_t *packet_in
840833
return ret;
841834
}
842835

843-
ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &new_conn_cid, XQC_CID_UNUSED, conn->local_settings.active_connection_id_limit);
836+
/* An endpoint MAY send connection IDs that temporarily exceed a peer's
837+
* limit if the NEW_CONNECTION_ID frame also requires the retirement of any
838+
* excess, by including a sufficiently large value in the Retire Prior To
839+
* field. Hence it is not reasonable to consider it as an error */
840+
ret = xqc_cid_set_insert_cid(&conn->dcid_set.cid_set, &new_conn_cid,
841+
XQC_CID_UNUSED, cid_limit);
844842
if (ret != XQC_OK) {
845-
xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error|limit:%ui|unused:%ui|used:%ui|",
846-
conn->local_settings.active_connection_id_limit, conn->dcid_set.cid_set.unused_cnt, conn->dcid_set.cid_set.used_cnt);
843+
xqc_log(conn->log, XQC_LOG_ERROR, "|xqc_cid_set_insert_cid error"
844+
"|local_limit:%ui|largest_limit:%ui|retire_prior_to:%ui|"
845+
"unused:%ui|used:%ui|",
846+
conn->local_settings.active_connection_id_limit,
847+
cid_limit, retire_prior_to, conn->dcid_set.cid_set.unused_cnt,
848+
conn->dcid_set.cid_set.used_cnt);
847849
return ret;
848850
}
849851

852+
/*
853+
* Upon receipt of an increased Retire Prior To field, the peer MUST stop
854+
* using the corresponding connection IDs and retire them with
855+
* RETIRE_CONNECTION_ID frames before adding the newly provided connection
856+
* ID to the set of active connection IDs.
857+
*/
858+
if (retire_prior_to > conn->dcid_set.largest_retire_prior_to) {
859+
xqc_conn_retire_dcid_prior_to(conn, retire_prior_to);
860+
}
850861

851862
return XQC_OK;
852863
}

src/transport/xqc_packet_out.c

+14-11
Original file line numberDiff line numberDiff line change
@@ -1270,18 +1270,21 @@ xqc_write_retire_conn_id_frame_to_packet(xqc_connection_t *conn, uint64_t seq_nu
12701270
{
12711271
xqc_int_t ret = XQC_ERROR;
12721272

1273-
/* select new current_dcid to replace the cid to be retired */
1274-
if (seq_num == conn->dcid_set.current_dcid.cid_seq_num) {
1275-
// TODO: DCID changes
1276-
ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &conn->dcid_set.current_dcid);
1277-
if (ret != XQC_OK) {
1278-
xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available dcid|");
1279-
return ret;
1273+
/* select new current_dcid to replace the cid to be retired */
1274+
if (seq_num == conn->dcid_set.current_dcid.cid_seq_num) {
1275+
// TODO: DCID changes
1276+
ret = xqc_get_unused_cid(&conn->dcid_set.cid_set, &conn->dcid_set.current_dcid);
1277+
if (ret != XQC_OK) {
1278+
xqc_log(conn->log, XQC_LOG_ERROR, "|conn don't have available dcid"
1279+
"|seq_num:%ui|cur_cid_seq_num:%ui", seq_num,
1280+
conn->dcid_set.current_dcid.cid_seq_num);
1281+
return ret;
12801282
}
1281-
xqc_datagram_record_mss(conn);
1282-
}
1283-
xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|",
1284-
xqc_dcid_str(&conn->dcid_set.current_dcid), conn->dcid_set.current_dcid.cid_seq_num);
1283+
xqc_datagram_record_mss(conn);
1284+
}
1285+
xqc_log(conn->log, XQC_LOG_DEBUG, "|get_new_dcid:%s|seq_num:%ui|",
1286+
xqc_dcid_str(&conn->dcid_set.current_dcid),
1287+
conn->dcid_set.current_dcid.cid_seq_num);
12851288

12861289
xqc_packet_out_t *packet_out = xqc_write_new_packet(conn, XQC_PTYPE_SHORT_HEADER);
12871290
if (packet_out == NULL) {

0 commit comments

Comments
 (0)