diff --git a/CHANGELOG b/CHANGELOG index 2af86fb..1cf6374 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,3 +1,10 @@ +2023-12-19 + - 4.0.2 + - More strict RFC compliance. + - Minimize packet generated when send STREAM_BLOCKED frame + - Fix memory management bugs. + - Fix memory leak in unit tests. + 2023-05-14 - 4.0.1 - Fix send_ctl bug. diff --git a/CMakeLists.txt b/CMakeLists.txt index 81848f0..e9ca3d8 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -272,7 +272,8 @@ ENDIF() SET(LIBS lsquic ${BORINGSSL_LIB_ssl} ${BORINGSSL_LIB_crypto} ${ZLIB_LIB} ${LIBS}) IF (LSQUIC_BIN) - FIND_PATH(EVENT_INCLUDE_DIR NAMES event2/event.h) + FIND_PATH(EVENT_INCLUDE_DIR NAMES event2/event.h + PATHS ${PROJECT_SOURCE_DIR}/../third-party/include) IF (EVENT_INCLUDE_DIR) INCLUDE_DIRECTORIES(${EVENT_INCLUDE_DIR}) ELSE() @@ -285,7 +286,8 @@ IF (LSQUIC_BIN) IF (CMAKE_SYSTEM_NAME STREQUAL Windows) FIND_LIBRARY(EVENT_LIB event) ELSE() - FIND_LIBRARY(EVENT_LIB libevent${LIB_SUFFIX}) + FIND_LIBRARY(EVENT_LIB libevent${LIB_SUFFIX} + PATHS ${PROJECT_SOURCE_DIR}/../third-party/lib) IF(NOT EVENT_LIB) FIND_LIBRARY(EVENT_LIB libevent.so) ENDIF() diff --git a/bin/http_client.c b/bin/http_client.c index 39b95cf..c784a63 100644 --- a/bin/http_client.c +++ b/bin/http_client.c @@ -348,7 +348,10 @@ http_client_on_conn_closed (lsquic_conn_t *conn) if (conn_h->client_ctx->hcc_flags & HCC_ABORT_ON_INCOMPLETE) { if (!(conn_h->client_ctx->hcc_flags & HCC_SEEN_FIN)) - abort(); + { + LSQ_INFO("abort incomplete connection"); + exit(1); + } } --conn_h->client_ctx->hcc_n_open_conns; diff --git a/docs/conf.py b/docs/conf.py index f68d528..92bf1bf 100644 --- a/docs/conf.py +++ b/docs/conf.py @@ -26,7 +26,7 @@ author = u'LiteSpeed Technologies' # The short X.Y version version = u'4.0' # The full version, including alpha/beta/rc tags -release = u'4.0.1' +release = u'4.0.2' # -- General configuration --------------------------------------------------- diff --git a/include/lsquic.h b/include/lsquic.h index 257c311..6dcd979 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 1 +#define LSQUIC_PATCH_VERSION 2 /** * Engine flags: diff --git a/src/liblsquic/ls-qpack b/src/liblsquic/ls-qpack index 19863c2..5217927 160000 --- a/src/liblsquic/ls-qpack +++ b/src/liblsquic/ls-qpack @@ -1 +1 @@ -Subproject commit 19863c2ed8bf28d648213460093d1991def4e643 +Subproject commit 521792711f2839f05565fd3dd617708cfb5b80ee diff --git a/src/liblsquic/lsquic_di_hash.c b/src/liblsquic/lsquic_di_hash.c index 2278edc..ca861b7 100644 --- a/src/liblsquic/lsquic_di_hash.c +++ b/src/liblsquic/lsquic_di_hash.c @@ -438,7 +438,8 @@ hash_di_insert_frame (struct data_in *data_in, ins = lsquic_data_in_hash_insert_data_frame(data_in, data_frame, read_offset); assert(ins != INS_FRAME_OVERLAP); - /* NOTE: other cases are handled by caller */ + /* NOTE: Only release packet and frame for INS_FRAME_OK, + * other cases are handled by caller */ if (ins == INS_FRAME_OK) { lsquic_packet_in_put(hdi->hdi_conn_pub->mm, new_frame->packet_in); diff --git a/src/liblsquic/lsquic_engine.c b/src/liblsquic/lsquic_engine.c index bcc29b9..cfdc0c0 100644 --- a/src/liblsquic/lsquic_engine.c +++ b/src/liblsquic/lsquic_engine.c @@ -3232,6 +3232,7 @@ lsquic_engine_packet_in (lsquic_engine_t *engine, * by PI_OWN_DATA flag. */ packet_in->pi_data = (unsigned char *) packet_in_data; + packet_in->pi_pkt_size = packet_in_size; if (0 != parse_packet_in_begin(packet_in, packet_end - packet_in_data, engine->flags & ENG_SERVER, engine->pub.enp_settings.es_scid_len, &ppstate)) diff --git a/src/liblsquic/lsquic_full_conn_ietf.c b/src/liblsquic/lsquic_full_conn_ietf.c index f9c76ff..cd9466b 100644 --- a/src/liblsquic/lsquic_full_conn_ietf.c +++ b/src/liblsquic/lsquic_full_conn_ietf.c @@ -2491,46 +2491,6 @@ generate_max_stream_data_frame (struct ietf_full_conn *conn, } -/* Return true if generated, false otherwise */ -static int -generate_stream_blocked_frame (struct ietf_full_conn *conn, - struct lsquic_stream *stream) -{ - struct lsquic_packet_out *packet_out; - unsigned need; - uint64_t off; - int sz; - - off = lsquic_stream_combined_send_off(stream); - need = conn->ifc_conn.cn_pf->pf_stream_blocked_frame_size(stream->id, off); - packet_out = get_writeable_packet(conn, need); - if (!packet_out) - return 0; - sz = conn->ifc_conn.cn_pf->pf_gen_stream_blocked_frame( - packet_out->po_data + packet_out->po_data_sz, - lsquic_packet_out_avail(packet_out), stream->id, off); - if (sz < 0) - { - ABORT_ERROR("Generating STREAM_BLOCKED frame failed"); - return 0; - } - LSQ_DEBUG("generated %d-byte STREAM_BLOCKED " - "frame; stream_id: %"PRIu64"; offset: %"PRIu64, sz, stream->id, off); - EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "generated %d-byte STREAM_BLOCKED " - "frame; stream_id: %"PRIu64"; offset: %"PRIu64, sz, stream->id, off); - if (0 != lsquic_packet_out_add_frame(packet_out, conn->ifc_pub.mm, 0, - QUIC_FRAME_STREAM_BLOCKED, packet_out->po_data_sz, sz)) - { - ABORT_ERROR("adding frame to packet failed: %d", errno); - return 0; - } - lsquic_send_ctl_incr_pack_sz(&conn->ifc_send_ctl, packet_out, sz); - packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM_BLOCKED; - lsquic_stream_blocked_frame_sent(stream); - return 1; -} - - static int generate_stop_sending_frame_by_id (struct ietf_full_conn *conn, lsquic_stream_id_t stream_id, enum http_error_code error_code) @@ -2918,7 +2878,7 @@ process_stream_ready_to_send (struct ietf_full_conn *conn, 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 &= generate_stream_blocked_frame(conn, stream); + 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_mini_conn_ietf.c b/src/liblsquic/lsquic_mini_conn_ietf.c index 427e83f..5881c79 100644 --- a/src/liblsquic/lsquic_mini_conn_ietf.c +++ b/src/liblsquic/lsquic_mini_conn_ietf.c @@ -734,7 +734,7 @@ ietf_mini_conn_ci_hsk_done (struct lsquic_conn *lconn, { case LSQ_HSK_OK: case LSQ_HSK_RESUMED_OK: - conn->imc_flags |= IMC_HSK_OK; + conn->imc_flags |= IMC_HSK_OK | IMC_IGNORE_INIT; conn->imc_conn.cn_flags |= LSCONN_HANDSHAKE_DONE; LSQ_DEBUG("handshake OK"); break; @@ -1436,6 +1436,14 @@ imico_parse_regular_packet (struct ietf_mini_conn *conn, p = packet_in->pi_data + packet_in->pi_header_sz; pend = packet_in->pi_data + packet_in->pi_data_sz; + if (p >= pend) + { + ietf_mini_conn_ci_abort_error(&conn->imc_conn, 0, + TEC_PROTOCOL_VIOLATION, + "packet %"PRIu64" has no frames", + packet_in->pi_packno); + return -1; + } while (p < pend) { len = imico_process_packet_frame(conn, packet_in, p, pend - p); @@ -1677,10 +1685,20 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn, imico_maybe_validate_by_dcid(conn, &packet_in->pi_dcid); pns = lsquic_hety2pns[ packet_in->pi_header_type ]; - if (pns == PNS_INIT && (conn->imc_flags & IMC_IGNORE_INIT)) + if (pns == PNS_INIT) { - LSQ_DEBUG("ignore init packet"); /* Don't bother decrypting */ - return; + if (conn->imc_flags & IMC_IGNORE_INIT) + { + LSQ_DEBUG("ignore init packet"); /* Don't bother decrypting */ + return; + } + if (packet_in->pi_pkt_size + && packet_in->pi_pkt_size < IQUIC_MIN_INIT_PACKET_SZ) + { + LSQ_DEBUG("ignore init packet smaller than minimum size required"); + /* Don't bother decrypting */ + return; + } } dec_packin = lconn->cn_esf_c->esf_decrypt_packet(lconn->cn_enc_session, @@ -1718,7 +1736,15 @@ ietf_mini_conn_ci_packet_in (struct lsquic_conn *lconn, return; } else if (pns == PNS_HSK) + { + if (!LSQUIC_CIDS_EQ(CN_SCID(&conn->imc_conn), &packet_in->pi_dcid)) + { + ietf_mini_conn_ci_abort_error(lconn, 0, TEC_PROTOCOL_VIOLATION, + "protocol violation detected bad dcid for HSK pns"); + return; + } imico_peer_addr_validated(conn, "handshake PNS"); + } if (((conn->imc_flags >> IMCBIT_PNS_BIT_SHIFT) & 3) < pns) { diff --git a/src/liblsquic/lsquic_mm.c b/src/liblsquic/lsquic_mm.c index 6d82a5c..38dbf7e 100644 --- a/src/liblsquic/lsquic_mm.c +++ b/src/liblsquic/lsquic_mm.c @@ -364,6 +364,7 @@ maybe_shrink_packet_out_bufs (struct lsquic_mm *mm, unsigned idx) #endif +#if LSQUIC_USE_POOLS /* If average maximum falls under 1/4 of all objects allocated, release * half of the objects allocated. */ @@ -398,6 +399,7 @@ maybe_shrink_packet_in_bufs (struct lsquic_mm *mm, unsigned idx) } #endif } +#endif void diff --git a/src/liblsquic/lsquic_packet_common.h b/src/liblsquic/lsquic_packet_common.h index 3fc21af..9d89171 100644 --- a/src/liblsquic/lsquic_packet_common.h +++ b/src/liblsquic/lsquic_packet_common.h @@ -148,28 +148,16 @@ lsquic_frame_types_to_str (char *buf, size_t bufsz, enum quic_ft_bit); enum packno_bits { PACKNO_BITS_0 = 0, - PACKNO_BITS_1 = 1, - PACKNO_BITS_2 = 2, - PACKNO_BITS_3 = 3, -}; - - -/* GQUIC maps 0, 1, 2, 3 -> 1, 2, 4, 6 */ -enum -{ GQUIC_PACKNO_LEN_1 = PACKNO_BITS_0, - GQUIC_PACKNO_LEN_2 = PACKNO_BITS_1, - GQUIC_PACKNO_LEN_4 = PACKNO_BITS_2, - GQUIC_PACKNO_LEN_6 = PACKNO_BITS_3, -}; - - -/* IQUIC maps 0, 1, 2, 3 -> 1, 2, 3, 4 (as of ID-17) */ -enum -{ IQUIC_PACKNO_LEN_1 = PACKNO_BITS_0, + PACKNO_BITS_1 = 1, + GQUIC_PACKNO_LEN_2 = PACKNO_BITS_1, IQUIC_PACKNO_LEN_2 = PACKNO_BITS_1, + PACKNO_BITS_2 = 2, + GQUIC_PACKNO_LEN_4 = PACKNO_BITS_2, IQUIC_PACKNO_LEN_3 = PACKNO_BITS_2, + PACKNO_BITS_3 = 3, + GQUIC_PACKNO_LEN_6 = PACKNO_BITS_3, IQUIC_PACKNO_LEN_4 = PACKNO_BITS_3, }; diff --git a/src/liblsquic/lsquic_packet_in.h b/src/liblsquic/lsquic_packet_in.h index 5cd81b3..9cff163 100644 --- a/src/liblsquic/lsquic_packet_in.h +++ b/src/liblsquic/lsquic_packet_in.h @@ -93,6 +93,7 @@ typedef struct lsquic_packet_in } pi_flags; /* pi_token and pi_token_size are set in Initial and Retry packets */ unsigned short pi_token_size; /* Size of the token */ + unsigned short pi_pkt_size; /* Size of the whole packet */ unsigned char pi_token; /* Offset to token */ /* pi_odcid and pi_odcid_len are only set in Retry packets for I-D < 25 */ unsigned char pi_odcid; /* Offset to Original DCID */ diff --git a/src/liblsquic/lsquic_send_ctl.c b/src/liblsquic/lsquic_send_ctl.c index 84fa7c5..63fc55f 100644 --- a/src/liblsquic/lsquic_send_ctl.c +++ b/src/liblsquic/lsquic_send_ctl.c @@ -2132,7 +2132,7 @@ lsquic_send_ctl_next_packet_to_send (struct lsquic_send_ctl *ctl, else packet_out->po_lflags &= ~POL_LIMITED; - if (UNLIKELY(!(ctl->sc_conn_pub->lconn->cn_flags & LSCONN_HANDSHAKE_DONE)) + if (UNLIKELY(packet_out->po_header_type == HETY_INITIAL) && (!(ctl->sc_conn_pub->lconn->cn_flags & LSCONN_SERVER) || (packet_out->po_frame_types & IQUIC_FRAME_ACKABLE_MASK)) @@ -2966,6 +2966,42 @@ lsquic_send_ctl_get_packet_for_stream (lsquic_send_ctl_t *ctl, } +/* Return true if generated, false otherwise */ +int +lsquic_sendctl_gen_stream_blocked_frame (struct lsquic_send_ctl *ctl, + struct lsquic_stream *stream) +{ + struct lsquic_packet_out *packet_out; + const struct parse_funcs *const pf = stream->conn_pub->lconn->cn_pf; + unsigned need; + uint64_t off; + int sz; + + 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; + 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); + if (sz < 0) + return 0; + LSQ_DEBUG("generated %d-byte STREAM_BLOCKED " + "frame; stream_id: %"PRIu64"; offset: %"PRIu64, sz, stream->id, off); + EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, "generated %d-byte STREAM_BLOCKED " + "frame; stream_id: %"PRIu64"; offset: %"PRIu64, sz, stream->id, off); + if (0 != lsquic_packet_out_add_frame(packet_out, &ctl->sc_enpub->enp_mm, 0, + QUIC_FRAME_STREAM_BLOCKED, packet_out->po_data_sz, sz)) + return 0; + lsquic_send_ctl_incr_pack_sz(ctl, packet_out, sz); + packet_out->po_frame_types |= 1 << QUIC_FRAME_STREAM_BLOCKED; + lsquic_stream_blocked_frame_sent(stream); + return 1; +} + + #ifdef NDEBUG static #elif __GNUC__ @@ -3775,9 +3811,9 @@ lsquic_send_ctl_resize (struct lsquic_send_ctl *ctl) size = lsquic_packet_out_total_sz(lconn, packet_out); if (size > packet_out->po_path->np_pack_size) { - send_ctl_resize_q(ctl, *q, packet_out->po_path); path_ids |= 1 << packet_out->po_path->np_path_id; q_idxs |= 1 << (q - queues); + send_ctl_resize_q(ctl, *q, packet_out->po_path); goto redo_q; } } diff --git a/src/liblsquic/lsquic_send_ctl.h b/src/liblsquic/lsquic_send_ctl.h index 0115637..22414d4 100644 --- a/src/liblsquic/lsquic_send_ctl.h +++ b/src/liblsquic/lsquic_send_ctl.h @@ -236,6 +236,10 @@ lsquic_send_ctl_get_packet_for_stream (lsquic_send_ctl_t *, unsigned need_at_least, const struct network_path *, const struct lsquic_stream *); +int +lsquic_sendctl_gen_stream_blocked_frame (struct lsquic_send_ctl *ctl, + struct lsquic_stream *stream); + struct lsquic_packet_out * lsquic_send_ctl_get_packet_for_crypto (struct lsquic_send_ctl *ctl, unsigned need_at_least, enum packnum_space, const struct network_path *); diff --git a/src/liblsquic/lsquic_stream.c b/src/liblsquic/lsquic_stream.c index 5baddb6..e7b5178 100644 --- a/src/liblsquic/lsquic_stream.c +++ b/src/liblsquic/lsquic_stream.c @@ -3695,10 +3695,15 @@ stream_write (lsquic_stream_t *stream, struct lsquic_reader *reader, } while (nwritten < len && stream->sm_n_buffered < stream->sm_n_allocated); - return nwritten; } else - return stream_write_to_packets(stream, reader, thresh, swo); + nwritten = stream_write_to_packets(stream, reader, thresh, swo); + if ((stream->sm_qflags & SMQF_SEND_BLOCKED) && + (stream->sm_bflags & SMBF_IETF)) + { + lsquic_sendctl_gen_stream_blocked_frame(stream->conn_pub->send_ctl, stream); + } + return nwritten; } diff --git a/src/lshpack b/src/lshpack index df068e6..32e96f1 160000 --- a/src/lshpack +++ b/src/lshpack @@ -1 +1 @@ -Subproject commit df068e6feec3268a32a1edbbec4a4636d200ee90 +Subproject commit 32e96f10593c7cb8553cd8c9c12721100ae9e924 diff --git a/tests/test_frame_reader.c b/tests/test_frame_reader.c index 0d71a94..f2180ac 100644 --- a/tests/test_frame_reader.c +++ b/tests/test_frame_reader.c @@ -1134,8 +1134,9 @@ test_one_frt (const struct frame_reader_test *frt) stream.conn_pub = &conn_pub; conn_pub.lconn = &lconn; - top: lsquic_mm_init(&mm); + + top: lshpack_dec_init(&hdec); memset(&input, 0, sizeof(input)); memcpy(input.in_buf, frt->frt_buf, frt->frt_bufsz); diff --git a/tests/test_h3_framing.c b/tests/test_h3_framing.c index a3fcda1..ef2deed 100644 --- a/tests/test_h3_framing.c +++ b/tests/test_h3_framing.c @@ -376,7 +376,7 @@ init_test_objs (struct test_objs *tobjs, unsigned initial_conn_window, tobjs->stream_if = &stream_if; tobjs->stream_if_ctx = &test_ctx; tobjs->ctor_flags = stream_ctor_flags; - if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS) + //if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS) { lsquic_qeh_init(&tobjs->qeh, &tobjs->lconn); s = lsquic_qeh_settings(&tobjs->qeh, 0, 0, 0, 0); @@ -395,7 +395,7 @@ deinit_test_objs (struct test_objs *tobjs) lsquic_send_ctl_cleanup(&tobjs->send_ctl); lsquic_malo_destroy(tobjs->conn_pub.packet_out_malo); lsquic_mm_cleanup(&tobjs->eng_pub.enp_mm); - if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS) + //if ((1 << tobjs->lconn.cn_version) & LSQUIC_IETF_VERSIONS) lsquic_qeh_cleanup(&tobjs->qeh); } diff --git a/tests/test_tokgen.c b/tests/test_tokgen.c index 0bc8e63..0d66499 100644 --- a/tests/test_tokgen.c +++ b/tests/test_tokgen.c @@ -35,6 +35,7 @@ main (int argc, char **argv) printf("\n"); lsquic_tg_destroy(tg); + lsquic_stock_shared_hash_destroy(enpub.enp_shi_ctx); return 0; }