Skip to content

Commit

Permalink
[+] support standard stateless reset (#313)
Browse files Browse the repository at this point in the history
  • Loading branch information
Kulsk authored Jul 12, 2023
1 parent cac2e72 commit 04994e2
Show file tree
Hide file tree
Showing 36 changed files with 894 additions and 214 deletions.
5 changes: 5 additions & 0 deletions cmake/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ if (XQC_ENABLE_EVENT_LOG)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_ENABLE_EVENT_LOG ")
endif()

if(XQC_COMPAT_GENERATE_SR_PKT)
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DXQC_COMPAT_GENERATE_SR_PKT")
endif()


if(ANDROID)
set(DYMAMIC_LINK_OPTION
${DYMAMIC_LINK_OPTION}
Expand Down
3 changes: 2 additions & 1 deletion demo/demo_client.c
Original file line number Diff line number Diff line change
Expand Up @@ -974,7 +974,8 @@ xqc_demo_cli_socket_read_handler(xqc_demo_cli_user_conn_t *user_conn)
if (xqc_engine_packet_process(user_conn->ctx->engine, packet_buf, recv_size,
(struct sockaddr *)(&user_conn->local_addr),
user_conn->local_addrlen, (struct sockaddr *)(&addr),
addr_len, (xqc_msec_t)recv_time, user_conn) != XQC_OK)
addr_len, (xqc_msec_t)recv_time,
user_conn) != XQC_OK)
{
return;
}
Expand Down
13 changes: 9 additions & 4 deletions include/xquic/xqc_http3.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,8 @@ typedef int (*xqc_h3_request_notify_pt)(xqc_h3_request_t *h3_request, void *h3s_
typedef int (*xqc_h3_request_read_notify_pt)(xqc_h3_request_t *h3_request,
xqc_request_notify_flag_t flag, void *h3s_user_data);

typedef void (*xqc_h3_request_closing_notify_pt)(xqc_h3_request_t *h3_request,
xqc_int_t err, void *h3s_user_data);

/**
* @brief encode flags of http headers
Expand Down Expand Up @@ -304,16 +306,19 @@ typedef struct xqc_h3_conn_callbacks_s {
typedef struct xqc_h3_request_callbacks_s {
/* request creation notify. it will be triggered after a request was created, and is required
for server, optional for client */
xqc_h3_request_notify_pt h3_request_create_notify;
xqc_h3_request_notify_pt h3_request_create_notify;

/* request close notify. which will be triggered after a request was closed */
xqc_h3_request_notify_pt h3_request_close_notify;
xqc_h3_request_notify_pt h3_request_close_notify;

/* request read notify callback. which will be triggered after received http headers or body */
xqc_h3_request_read_notify_pt h3_request_read_notify;
xqc_h3_request_read_notify_pt h3_request_read_notify;

/* request write notify callback. when triggered, users can continue to send headers or body */
xqc_h3_request_notify_pt h3_request_write_notify;
xqc_h3_request_notify_pt h3_request_write_notify;

/* request closing notify callback, will be triggered when request is closing */
xqc_h3_request_closing_notify_pt h3_request_closing_notify;

} xqc_h3_request_callbacks_t;

Expand Down
28 changes: 24 additions & 4 deletions include/xquic/xquic.h
Original file line number Diff line number Diff line change
Expand Up @@ -479,6 +479,19 @@ typedef ssize_t (*xqc_send_mmsg_ex_pt)(uint64_t path_id,
typedef xqc_int_t (*xqc_stream_notify_pt)(xqc_stream_t *stream,
void *strm_user_data);

/**
* @brief stream closing callback function, this will be triggered when some
* error on a stream happens.
*
* @param stream QUIC stream handler
* @param err_code error code
* @param strm_user_data stream level user_data, which was the parameter of xqc_stream_create set by
* client, or the parameter of xqc_stream_set_user_data set by server
* @return 0 for success, -1 for failure
*/
typedef void (*xqc_stream_closing_notify_pt)(xqc_stream_t *stream,
xqc_int_t err_code, void *strm_user_data);

/**
* @brief the callback API to notify application that there is a datagram to be read
*
Expand Down Expand Up @@ -708,23 +721,23 @@ typedef struct xqc_stream_callbacks_s {
* this will be triggered when QUIC stream data is ready for read. application layer could read
* data when xqc_stream_recv interface.
*/
xqc_stream_notify_pt stream_read_notify;
xqc_stream_notify_pt stream_read_notify;

/**
* stream write callback function. REQUIRED for both client and server
*
* when sending data with xqc_stream_send, xquic might be blocked or send part of the data. if
* this callback function is triggered, applications can continue to send the rest data.
*/
xqc_stream_notify_pt stream_write_notify;
xqc_stream_notify_pt stream_write_notify;

/**
* stream create callback function. REQUIRED for server, OPTIONAL for client.
*
* this will be triggered when QUIC stream is created. applications can create its own stream
* context in this callback function.
*/
xqc_stream_notify_pt stream_create_notify;
xqc_stream_notify_pt stream_create_notify;

/**
* stream close callback function. REQUIRED for both server and client.
Expand All @@ -733,7 +746,14 @@ typedef struct xqc_stream_callbacks_s {
* sending or receiving RESET_STREAM frame after 3 times of PTO, or when connection is closed.
* Applications can free the context which was created in stream_create_notify here.
*/
xqc_stream_notify_pt stream_close_notify;
xqc_stream_notify_pt stream_close_notify;

/**
* @brief stream reset callback function. OPTIONAL for both server and client
*
* this function will be triggered when a RESET_STREAM frame is received.
*/
xqc_stream_closing_notify_pt stream_closing_notify;

} xqc_stream_callbacks_t;

Expand Down
4 changes: 4 additions & 0 deletions include/xquic/xquic_typedef.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,10 +74,14 @@ typedef uint8_t xqc_bool_t;
/* restrictions of key length in lb cid encryption */
#define XQC_LB_CID_KEY_LEN 16

/* length of stateless reset token */
#define XQC_STATELESS_RESET_TOKENLEN 16

typedef struct xqc_cid_s {
uint8_t cid_len;
uint8_t cid_buf[XQC_MAX_CID_LEN];
uint64_t cid_seq_num;
uint8_t sr_token[XQC_STATELESS_RESET_TOKENLEN];
} xqc_cid_t;

typedef enum xqc_log_level_s {
Expand Down
37 changes: 34 additions & 3 deletions scripts/case_test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -1367,8 +1367,8 @@ killall test_server
sleep 1
clear_log
echo -e "stateless reset...\c"
./test_client -l d -x 41 -1 > stdlog
result=`grep "receive reset, enter draining" clog`
./test_client -l d -x 41 -1 -t 5 > stdlog
result=`grep "|====>|receive stateless reset" clog`
cloing_notify=`grep "conn closing: 641" stdlog`
if [ -n "$result" ] && [ -n "$cloing_notify" ]; then
echo ">>>>>>>> pass:1"
Expand All @@ -1379,6 +1379,21 @@ else
fi


clear_log
echo -e "stateless reset during hsk...\c"
./test_client -l d -t 5 -x 45 -1 -s 100 -G > stdlog
result=`grep "|====>|receive stateless reset" clog`
cloing_notify=`grep "conn closing: 641" stdlog`
svr_hsk=`grep "handshake_time:0" slog`
if [ -n "$result" ] && [ -n "$cloing_notify" ] && [ -n "$svr_hsk" ]; then
echo ">>>>>>>> pass:1"
case_print_result "stateless_reset_during_hsk" "pass"
else
echo ">>>>>>>> pass:0"
case_print_result "stateless_reset_during_hsk" "fail"
exit
fi

killall test_server
./test_server -l d -e -M > /dev/null &
sleep 1
Expand Down Expand Up @@ -1611,7 +1626,7 @@ if [ -f xqc_token ]; then
rm -f xqc_token
fi
if [ -f stdlog ]; then
. rm -f stdlog
rm -f stdlog
fi
./test_server -l d -Q 9000 > /dev/null &
sleep 1
Expand Down Expand Up @@ -3596,4 +3611,20 @@ fi
rm -rf tp_localhost test_session xqc_token
killall test_server

clear_log
echo -e "request_closing_notify...\c"
./test_server -l d -x 14 > /dev/null &
sleep 1
./test_client -l d >> stdlog
res=`grep "request closing notify triggered" stdlog`
if [ -n "$res" ]; then
echo ">>>>>>>> pass:1"
case_print_result "request_closing_notify" "pass"
else
echo ">>>>>>>> pass:0"
case_print_result "request_closing_notify" "fail"
fi

killall test_server

cd -
1 change: 1 addition & 0 deletions scripts/xquic.lds
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ XQUIC_VERS_1.0 {
xqc_h3_conn_get_errno;
xqc_h3_conn_get_ssl;
xqc_h3_conn_set_user_data;
xqc_h3_conn_get_user_data;
xqc_h3_conn_get_peer_addr;
xqc_h3_conn_get_local_addr;
xqc_h3_conn_is_ready_to_send_early_data;
Expand Down
2 changes: 2 additions & 0 deletions src/common/xqc_log.c
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ xqc_log_type_2_level(xqc_log_type_t type)
case TRA_DATAGRAMS_SENT:
case TRA_DATAGRAMS_RECEIVED:
case TRA_STREAM_STATE_UPDATED:
case TRA_STATELESS_RESET:
case REC_METRICS_UPDATED:
case REC_PARAMETERS_SET:
case REC_CONGESTION_STATE_UPDATED:
Expand Down Expand Up @@ -139,6 +140,7 @@ xqc_log_type_str(xqc_log_type_t type)
[TRA_STREAM_STATE_UPDATED] = "stream_state_updated",
[TRA_FRAMES_PROCESSED] = "frames_processed",
[TRA_DATA_MOVED] = "data_moved",
[TRA_STATELESS_RESET] = "stateless_reset",
[REC_PARAMETERS_SET] = "rec_parameters_set",
[REC_METRICS_UPDATED] = "rec_metrics_updated",
[REC_CONGESTION_STATE_UPDATED] = "congestion_state_updated",
Expand Down
1 change: 1 addition & 0 deletions src/common/xqc_log.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ typedef enum {
TRA_STREAM_STATE_UPDATED,
TRA_FRAMES_PROCESSED,
TRA_DATA_MOVED,
TRA_STATELESS_RESET,

/* recovery event */
REC_PARAMETERS_SET,
Expand Down
16 changes: 12 additions & 4 deletions src/common/xqc_log_event_callback.c
Original file line number Diff line number Diff line change
Expand Up @@ -398,6 +398,14 @@ xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...)
va_end(args);
}


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",
log->scid);
}

void
xqc_log_REC_PARAMETERS_SET_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl)
{
Expand Down Expand Up @@ -504,7 +512,7 @@ xqc_log_HTTP_STREAM_TYPE_SET_callback(xqc_log_t *log, const char *func, xqc_h3_s
{
xqc_log_implement(log, HTTP_STREAM_TYPE_SET, func,
"|%s|stream_id:%ui|stream_type:%d|",
local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", h3_stream->stream->stream_id, h3_stream->type);
local == XQC_LOG_LOCAL_EVENT ? "local" : "remote", h3_stream->stream_id, h3_stream->type);
}

void
Expand All @@ -514,7 +522,7 @@ xqc_log_HTTP_FRAME_CREATED_callback(xqc_log_t *log, const char *func, ...)
va_list args;
va_start(args, func);
xqc_h3_stream_t *h3_stream = va_arg(args, xqc_h3_stream_t*);
xqc_stream_id_t stream_id = h3_stream->stream->stream_id;
xqc_stream_id_t stream_id = h3_stream->stream_id;
xqc_h3_frm_type_t type = va_arg(args, xqc_h3_frm_type_t);
switch (type) {
case XQC_H3_FRM_DATA: {
Expand Down Expand Up @@ -574,7 +582,7 @@ void
xqc_log_HTTP_FRAME_PARSED_callback(xqc_log_t *log, const char *func, xqc_h3_stream_t *h3_stream)
{
xqc_h3_frame_t *frame = &h3_stream->pctx.frame_pctx.frame;
xqc_stream_id_t stream_id = h3_stream->stream->stream_id;
xqc_stream_id_t stream_id = h3_stream->stream_id;
switch (frame->type) {
case XQC_H3_FRM_DATA:
case XQC_H3_FRM_HEADERS:
Expand Down Expand Up @@ -621,7 +629,7 @@ 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,
"|stream_id:%ui|%s|", h3_stream->stream->stream_id,
"|stream_id:%ui|%s|", h3_stream->stream_id,
h3_stream->flags & XQC_HTTP3_STREAM_FLAG_QPACK_DECODE_BLOCKED ? "blocked" : "unblocked");
}

Expand Down
2 changes: 2 additions & 0 deletions src/common/xqc_log_event_callback.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,8 @@ void xqc_log_TRA_STREAM_STATE_UPDATED_callback(xqc_log_t *log, const char *func,

void xqc_log_TRA_FRAMES_PROCESSED_callback(xqc_log_t *log, const char *func, ...);

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_METRICS_UPDATED_callback(xqc_log_t *log, const char *func, xqc_send_ctl_t *send_ctl);
Expand Down
9 changes: 9 additions & 0 deletions src/http3/xqc_h3_request.c
Original file line number Diff line number Diff line change
Expand Up @@ -762,6 +762,15 @@ xqc_h3_request_end(xqc_h3_request_t *h3r)
XQC_H3_REQUEST_RECORD_TIME(h3r->h3r_end_time);
}

void
xqc_h3_request_closing(xqc_h3_request_t *h3r, xqc_int_t err)
{
if (h3r->request_if->h3_request_closing_notify) {
h3r->request_if->h3_request_closing_notify(h3r, err, h3r->user_data);
}
}


#define XQC_PRIORITY_URGENCY "u="
#define XQC_PRIORITY_URGENCY_LEN 2

Expand Down
1 change: 1 addition & 0 deletions src/http3/xqc_h3_request.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,5 +92,6 @@ void xqc_h3_request_on_body_send(xqc_h3_request_t *h3r);
void xqc_h3_request_stream_fin(xqc_h3_request_t *h3r);
void xqc_h3_request_begin(xqc_h3_request_t *h3r);
void xqc_h3_request_end(xqc_h3_request_t *h3r);
void xqc_h3_request_closing(xqc_h3_request_t *h3r, xqc_int_t err);

#endif /* _XQC_H3_REQUEST_H_INCLUDED_ */
26 changes: 23 additions & 3 deletions src/http3/xqc_h3_stream.c
Original file line number Diff line number Diff line change
Expand Up @@ -1883,13 +1883,33 @@ xqc_h3_stream_close_notify(xqc_stream_t *stream, void *user_data)
}


void
xqc_h3_stream_closing_notify(xqc_stream_t *stream,
xqc_int_t err_code, void *strm_user_data)
{
xqc_h3_stream_t *h3s;

h3s = (xqc_h3_stream_t *)strm_user_data;
if (NULL == h3s) {
return;
}

/* only http3 request shall be notified */
if (h3s->type == XQC_H3_STREAM_TYPE_REQUEST
&& h3s->h3r)
{
xqc_h3_request_closing(h3s->h3r, err_code);
}
}

/**
* transport callback
*/
const xqc_stream_callbacks_t h3_stream_callbacks = {
.stream_write_notify = xqc_h3_stream_write_notify,
.stream_read_notify = xqc_h3_stream_read_notify,
.stream_close_notify = xqc_h3_stream_close_notify,
.stream_write_notify = xqc_h3_stream_write_notify,
.stream_read_notify = xqc_h3_stream_read_notify,
.stream_close_notify = xqc_h3_stream_close_notify,
.stream_closing_notify = xqc_h3_stream_closing_notify,
};


Expand Down
12 changes: 11 additions & 1 deletion src/transport/xqc_cid.c
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,7 @@ xqc_cid_copy(xqc_cid_t *dst, xqc_cid_t *src)
dst->cid_len = src->cid_len;
xqc_memcpy(dst->cid_buf, src->cid_buf, dst->cid_len);
dst->cid_seq_num = src->cid_seq_num;
xqc_memcpy(dst->sr_token, src->sr_token, XQC_STATELESS_RESET_TOKENLEN);
}

void
Expand All @@ -83,6 +84,7 @@ 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)
Expand All @@ -100,6 +102,14 @@ xqc_scid_str(const xqc_cid_t *scid)
return g_scid_buf;
}

unsigned char *
xqc_sr_token_str(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;
}

unsigned char *
xqc_dcid_str_by_scid(xqc_engine_t *engine, const xqc_cid_t *scid)
{
Expand Down Expand Up @@ -160,7 +170,7 @@ xqc_destroy_cid_set(xqc_cid_set_t *cid_set)
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)
{
if (cid_set->unused_cnt + cid_set->used_cnt >= limit) {
if (cid_set->unused_cnt + cid_set->used_cnt > limit) {
return -XQC_EACTIVE_CID_LIMIT;
}

Expand Down
3 changes: 3 additions & 0 deletions src/transport/xqc_cid.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,5 +71,8 @@ xqc_cid_inner_t *xqc_cid_in_cid_set(const xqc_cid_set_t *cid_set, xqc_cid_t *cid
xqc_int_t xqc_cid_switch_to_next_state(xqc_cid_set_t *cid_set, xqc_cid_inner_t *cid, xqc_cid_state_t state);
xqc_int_t xqc_get_unused_cid(xqc_cid_set_t *cid_set, xqc_cid_t *cid);


unsigned char *xqc_sr_token_str(const char *sr_token);

#endif /* _XQC_CID_H_INCLUDED_ */

Loading

0 comments on commit 04994e2

Please sign in to comment.