diff --git a/CHANGELOG b/CHANGELOG index 1a03d1c5..4cb931b0 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,7 @@ +2024-02-07 + - 4.0.5 + - Fix CPU spinning due to STREAM_BLOCKED frame. + 2024-01-08 - 4.0.4 - Fix DCID validation. diff --git a/docs/conf.py b/docs/conf.py index 0542e982..3d24c27c 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ # The short X.Y version version = u'4.0' # The full version, including alpha/beta/rc tags -release = u'4.0.4' +release = u'4.0.5' # -- General configuration --------------------------------------------------- diff --git a/include/lsquic.h b/include/lsquic.h index 75d1e4af..9e360438 100644 --- a/include/lsquic.h +++ b/include/lsquic.h @@ -27,7 +27,7 @@ extern "C" { #define LSQUIC_MAJOR_VERSION 4 #define LSQUIC_MINOR_VERSION 0 -#define LSQUIC_PATCH_VERSION 4 +#define LSQUIC_PATCH_VERSION 5 /** * Engine flags: @@ -318,7 +318,7 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)( #define LSQUIC_DF_STTL 86400 #define LSQUIC_DF_MAX_INCHOATE (1 * 1000 * 1000) -#define LSQUIC_DF_SUPPORT_SREJ_SERVER 0 +#define LSQUIC_DF_SUPPORT_SREJ_SERVER 1 #define LSQUIC_DF_SUPPORT_SREJ_CLIENT 0 /** Do not use NSTP by default */ diff --git a/src/liblsquic/lsquic_full_conn.c b/src/liblsquic/lsquic_full_conn.c index ec9b102d..eca099d1 100644 --- a/src/liblsquic/lsquic_full_conn.c +++ b/src/liblsquic/lsquic_full_conn.c @@ -904,12 +904,12 @@ lsquic_gquic_full_conn_server_new (struct lsquic_engine_public *enpub, for (n = 0; received; ++n) { - if (received & (1U << n)) + if (received & (1ULL << n)) /* Setting `now' to zero is OK here, as we should have had at * least one other packet above. */ lsquic_rechist_received(&conn->fc_rechist, n + 1, 0); - received &= ~(1U << n); + received &= ~(1ULL << n); } /* Mini connection sends out packets 1, 2, 3... and so on. It deletes diff --git a/src/liblsquic/lsquic_full_conn_ietf.c b/src/liblsquic/lsquic_full_conn_ietf.c index 718a6885..fd8501a4 100644 --- a/src/liblsquic/lsquic_full_conn_ietf.c +++ b/src/liblsquic/lsquic_full_conn_ietf.c @@ -453,6 +453,7 @@ struct ietf_full_conn unsigned ifc_n_slack_akbl[N_PNS]; unsigned ifc_n_slack_all; /* App PNS only */ unsigned ifc_max_retx_since_last_ack; + unsigned short ifc_max_udp_payload; /* Cached TP */ lsquic_time_t ifc_max_ack_delay; uint64_t ifc_ecn_counts_in[N_PNS][4]; lsquic_stream_id_t ifc_max_req_id; @@ -491,7 +492,8 @@ struct ietf_full_conn unsigned ifc_max_pack_tol_sent; #endif unsigned ifc_max_ack_freq_seqno; /* Incoming */ - unsigned short ifc_max_udp_payload; /* Cached TP */ + unsigned short ifc_min_dg_sz, + ifc_max_dg_sz; lsquic_time_t ifc_last_live_update; struct conn_path ifc_paths[N_PATHS]; union { @@ -520,8 +522,6 @@ struct ietf_full_conn lsquic_time_t ifc_ping_period; struct lsquic_hash *ifc_bpus; uint64_t ifc_last_max_data_off_sent; - unsigned short ifc_min_dg_sz, - ifc_max_dg_sz; struct packet_tolerance_stats ifc_pts; #if LSQUIC_CONN_STATS @@ -768,7 +768,8 @@ blocked_ka_alarm_expired (enum alarm_id al_id, void *ctx, el = lsquic_hash_next(conn->ifc_pub.all_streams)) { stream = lsquic_hashelem_getdata(el); - if (lsquic_stream_is_blocked(stream)) + if (lsquic_stream_is_blocked(stream) + && !lsquic_stream_is_write_reset(stream)) { has_send_flag = (stream->sm_qflags & SMQF_SENDING_FLAGS); stream->sm_qflags |= SMQF_SEND_BLOCKED; @@ -782,6 +783,7 @@ blocked_ka_alarm_expired (enum alarm_id al_id, void *ctx, TAILQ_INSERT_TAIL(&conn->ifc_pub.sending_streams, stream, next_send_stream); } + return; } } } @@ -2882,10 +2884,26 @@ process_stream_ready_to_send (struct ietf_full_conn *conn, struct lsquic_stream *stream) { int r = 1; + + LSQ_DEBUG("process_stream_ready_to_send: stream: %"PRIu64", " + "sm_qflags: %d. stream_flags: %d, sm_bflags: %d, ", stream->id, + stream->sm_qflags, stream->stream_flags, stream->sm_bflags); + if (stream->sm_qflags & SMQF_SEND_MAX_STREAM_DATA) r &= generate_max_stream_data_frame(conn, stream); if (stream->sm_qflags & SMQF_SEND_BLOCKED) - r &= lsquic_sendctl_gen_stream_blocked_frame(&conn->ifc_send_ctl, stream); + { + if (lsquic_stream_is_write_reset(stream)) + { + stream->sm_qflags &= ~SMQF_SEND_BLOCKED; + if (!(stream->sm_qflags & SMQF_SENDING_FLAGS)) + TAILQ_REMOVE(&stream->conn_pub->sending_streams, stream, + next_send_stream); + } + else + r &= lsquic_sendctl_gen_stream_blocked_frame(&conn->ifc_send_ctl, + stream); + } if (stream->sm_qflags & SMQF_SEND_RST) r &= generate_rst_stream_frame(conn, stream); if (stream->sm_qflags & SMQF_SEND_STOP_SENDING) diff --git a/src/liblsquic/lsquic_send_ctl.c b/src/liblsquic/lsquic_send_ctl.c index 63fc55fc..d9ebb774 100644 --- a/src/liblsquic/lsquic_send_ctl.c +++ b/src/liblsquic/lsquic_send_ctl.c @@ -2976,13 +2976,23 @@ lsquic_sendctl_gen_stream_blocked_frame (struct lsquic_send_ctl *ctl, unsigned need; uint64_t off; int sz; + int is_err; off = lsquic_stream_combined_send_off(stream); need = pf->pf_stream_blocked_frame_size(stream->id, off); packet_out = lsquic_send_ctl_get_packet_for_stream(ctl, need, stream->conn_pub->path, stream); if (!packet_out) - return 0; + { + LSQ_DEBUG("failed to get packet_out with lsquic_send_ctl_get_packet_for_stream"); + packet_out = lsquic_send_ctl_get_writeable_packet(ctl, + PNS_APP, need, stream->conn_pub->path, 0, &is_err); + if (!packet_out) + { + LSQ_DEBUG("cannot get writeable packet for STREAM_BLOCKED frame"); + return 0; + } + } sz = pf->pf_gen_stream_blocked_frame( packet_out->po_data + packet_out->po_data_sz, lsquic_packet_out_avail(packet_out), stream->id, off); diff --git a/src/liblsquic/lsquic_stream.c b/src/liblsquic/lsquic_stream.c index a7b56f85..c0f26aa4 100644 --- a/src/liblsquic/lsquic_stream.c +++ b/src/liblsquic/lsquic_stream.c @@ -1334,6 +1334,15 @@ lsquic_stream_stop_sending_in (struct lsquic_stream *stream, && !(stream->sm_qflags & SMQF_SEND_RST)) stream_reset(stream, 0, 0); + if (stream->sm_qflags & (SMQF_SEND_WUF | SMQF_SEND_BLOCKED \ + | SMQF_SEND_STOP_SENDING)) + { + stream->sm_qflags &= ~(SMQF_SEND_WUF | SMQF_SEND_BLOCKED \ + | SMQF_SEND_STOP_SENDING); + if (!(stream->sm_qflags & SMQF_SENDING_FLAGS)) + TAILQ_REMOVE(&stream->conn_pub->sending_streams, stream, next_send_stream); + } + maybe_finish_stream(stream); maybe_schedule_call_on_close(stream); }