Release 2.3.0

- [FEATURE] BBR congestion control is on by default
- [BUGFIX] BBR app-limited logic
- [BUGFIX] Fix uninitialized warnings in IETF
- [BUGFIX] Update ls-qpack to v0.9.14
- [CLEANUP] Code cleanup
This commit is contained in:
Dmitri Tikhonov 2019-09-12 14:39:50 -04:00
parent 5392f7a3b0
commit cca2541523
19 changed files with 116 additions and 58 deletions

View file

@ -1,3 +1,11 @@
2019-09-12
- 2.3.0
- [FEATURE] BBR congestion control is on by default
- [BUGFIX] BBR app-limited logic
- [BUGFIX] Fix uninitialized warnings in IETF
- [BUGFIX] Update ls-qpack to v0.9.14
- [CLEANUP] Code cleanup
2019-09-11 2019-09-11
- 2.2.0 - 2.2.0
- [FEATURE] Server code is included in the library - [FEATURE] Server code is included in the library

View file

@ -24,7 +24,7 @@ extern "C" {
#endif #endif
#define LSQUIC_MAJOR_VERSION 2 #define LSQUIC_MAJOR_VERSION 2
#define LSQUIC_MINOR_VERSION 2 #define LSQUIC_MINOR_VERSION 3
#define LSQUIC_PATCH_VERSION 0 #define LSQUIC_PATCH_VERSION 0
/** /**
@ -371,7 +371,7 @@ typedef struct ssl_ctx_st * (*lsquic_lookup_cert_f)(
#define LSQUIC_DF_ALLOW_MIGRATION 1 #define LSQUIC_DF_ALLOW_MIGRATION 1
/* 1: Cubic; 2: BBR */ /* 1: Cubic; 2: BBR */
#define LSQUIC_DF_CC_ALGO 1 #define LSQUIC_DF_CC_ALGO 2
struct lsquic_engine_settings { struct lsquic_engine_settings {
/** /**

View file

@ -282,15 +282,21 @@ is_pipe_sufficiently_full (struct lsquic_bbr *bbr, uint64_t bytes_in_flight)
} }
/* See BbrSender::OnApplicationLimited */
static void static void
lsquic_bbr_was_quiet (void *cong_ctl, lsquic_time_t now, lsquic_bbr_was_quiet (void *cong_ctl, lsquic_time_t now, uint64_t in_flight)
uint64_t bytes_in_flight)
{ {
struct lsquic_bbr *const bbr = cong_ctl; struct lsquic_bbr *const bbr = cong_ctl;
LSQ_DEBUG("was quiet"); /* Do nothing */
}
/* See BbrSender::OnApplicationLimited */
static void
bbr_app_limited (struct lsquic_bbr *bbr, uint64_t bytes_in_flight)
{
uint64_t cwnd; uint64_t cwnd;
cwnd = lsquic_bbr_get_cwnd(cong_ctl); cwnd = lsquic_bbr_get_cwnd(bbr);
if (bytes_in_flight >= cwnd) if (bytes_in_flight >= cwnd)
return; return;
if ((bbr->bbr_flags & BBR_FLAG_FLEXIBLE_APP_LIMITED) if ((bbr->bbr_flags & BBR_FLAG_FLEXIBLE_APP_LIMITED)
@ -328,7 +334,7 @@ lsquic_bbr_ack (void *cong_ctl, struct lsquic_packet_out *packet_out,
static void static void
lsquic_bbr_sent (void *cong_ctl, struct lsquic_packet_out *packet_out, lsquic_bbr_sent (void *cong_ctl, struct lsquic_packet_out *packet_out,
uint64_t in_flight) uint64_t in_flight, int app_limited)
{ {
struct lsquic_bbr *const bbr = cong_ctl; struct lsquic_bbr *const bbr = cong_ctl;
@ -340,6 +346,9 @@ lsquic_bbr_sent (void *cong_ctl, struct lsquic_packet_out *packet_out,
* increasing. * increasing.
*/ */
bbr->bbr_last_sent_packno = packet_out->po_packno; bbr->bbr_last_sent_packno = packet_out->po_packno;
if (app_limited)
bbr_app_limited(bbr, in_flight);
} }

View file

@ -42,7 +42,7 @@ struct cong_ctl_if
/* Optional method */ /* Optional method */
void void
(*cci_sent) (void *cong_ctl, struct lsquic_packet_out *, (*cci_sent) (void *cong_ctl, struct lsquic_packet_out *,
uint64_t in_flight); uint64_t in_flight, int app_limited);
/* Optional method */ /* Optional method */
void void

View file

@ -242,8 +242,6 @@ struct conn_iface
(*ci_get_log_cid) (const struct lsquic_conn *); (*ci_get_log_cid) (const struct lsquic_conn *);
}; };
struct cert_susp_head;
#define LSCONN_CCE_BITS 3 #define LSCONN_CCE_BITS 3
#define LSCONN_MAX_CCES (1 << LSCONN_CCE_BITS) #define LSCONN_MAX_CCES (1 << LSCONN_CCE_BITS)
@ -292,7 +290,6 @@ struct lsquic_conn
const struct conn_iface *cn_if; const struct conn_iface *cn_if;
const struct parse_funcs *cn_pf; const struct parse_funcs *cn_pf;
struct attq_elem *cn_attq_elem; struct attq_elem *cn_attq_elem;
struct cert_susp_head *cn_cert_susp_head;
lsquic_time_t cn_last_sent; lsquic_time_t cn_last_sent;
lsquic_time_t cn_last_ticked; lsquic_time_t cn_last_ticked;
struct conn_cid_elem *cn_cces; /* At least one is available */ struct conn_cid_elem *cn_cces; /* At least one is available */

View file

@ -64,6 +64,13 @@ struct data_in_iface
/* Return number of bytes readable starting at offset `read_offset' */ /* Return number of bytes readable starting at offset `read_offset' */
uint64_t uint64_t
(*di_readable_bytes) (struct data_in *, uint64_t read_offset); (*di_readable_bytes) (struct data_in *, uint64_t read_offset);
/* If set, this means that when di_insert_frame() returns INS_FRAME_OK,
* the data_in handler has taken ownership of the frame. Otherwise, it
* is up to the caller to free it.
*/
const int
di_own_on_ok;
}; };

View file

@ -96,6 +96,7 @@ static const struct data_in_iface di_if_error = {
.di_get_frame = error_di_get_frame, .di_get_frame = error_di_get_frame,
.di_insert_frame = error_di_insert_frame, .di_insert_frame = error_di_insert_frame,
.di_mem_used = error_di_mem_used, .di_mem_used = error_di_mem_used,
.di_own_on_ok = 0, /* Never returns INS_FRAME_OK, but anyway */
.di_readable_bytes .di_readable_bytes
= error_di_readable_bytes, = error_di_readable_bytes,
.di_switch_impl = error_di_switch_impl, .di_switch_impl = error_di_switch_impl,

View file

@ -440,6 +440,7 @@ hash_di_insert_frame (struct data_in *data_in,
ins = data_in_hash_insert_data_frame(data_in, data_frame, read_offset); ins = data_in_hash_insert_data_frame(data_in, data_frame, read_offset);
assert(ins != INS_FRAME_OVERLAP); assert(ins != INS_FRAME_OVERLAP);
lsquic_packet_in_put(hdi->hdi_conn_pub->mm, new_frame->packet_in); lsquic_packet_in_put(hdi->hdi_conn_pub->mm, new_frame->packet_in);
if (ins != INS_FRAME_OK)
lsquic_malo_put(new_frame); lsquic_malo_put(new_frame);
return ins; return ins;
} }
@ -678,6 +679,7 @@ static const struct data_in_iface di_if_hash = {
.di_get_frame = hash_di_get_frame, .di_get_frame = hash_di_get_frame,
.di_insert_frame = hash_di_insert_frame, .di_insert_frame = hash_di_insert_frame,
.di_mem_used = hash_di_mem_used, .di_mem_used = hash_di_mem_used,
.di_own_on_ok = 0,
.di_readable_bytes .di_readable_bytes
= hash_di_readable_bytes, = hash_di_readable_bytes,
.di_switch_impl = hash_di_switch_impl, .di_switch_impl = hash_di_switch_impl,

View file

@ -551,6 +551,7 @@ static const struct data_in_iface di_if_nocopy = {
.di_get_frame = nocopy_di_get_frame, .di_get_frame = nocopy_di_get_frame,
.di_insert_frame = nocopy_di_insert_frame, .di_insert_frame = nocopy_di_insert_frame,
.di_mem_used = nocopy_di_mem_used, .di_mem_used = nocopy_di_mem_used,
.di_own_on_ok = 1,
.di_readable_bytes .di_readable_bytes
= nocopy_di_readable_bytes, = nocopy_di_readable_bytes,
.di_switch_impl = nocopy_di_switch_impl, .di_switch_impl = nocopy_di_switch_impl,

View file

@ -1625,7 +1625,7 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
size_t out_sz, dst_sz; size_t out_sz, dst_sz;
int header_sz; int header_sz;
int ipv6; int ipv6;
unsigned packno_off, packno_len, sample_off, cliser; unsigned packno_off, packno_len, cliser;
enum packnum_space pns; enum packnum_space pns;
char errbuf[ERR_ERROR_STRING_BUF_LEN]; char errbuf[ERR_ERROR_STRING_BUF_LEN];
@ -1739,8 +1739,10 @@ iquic_esf_encrypt_packet (enc_session_t *enc_session_p,
assert(out_sz == dst_sz - header_sz); assert(out_sz == dst_sz - header_sz);
lconn->cn_pf->pf_packno_info(lconn, packet_out, &packno_off, &packno_len); lconn->cn_pf->pf_packno_info(lconn, packet_out, &packno_off, &packno_len);
sample_off = packno_off + 4; #ifndef NDEBUG
const unsigned sample_off = packno_off + 4;
assert(sample_off + IQUIC_TAG_LEN <= dst_sz); assert(sample_off + IQUIC_TAG_LEN <= dst_sz);
#endif
apply_hp(enc_sess, hp, cliser, dst, packno_off, packno_len); apply_hp(enc_sess, hp, cliser, dst, packno_off, packno_len);
packet_out->po_enc_data = dst; packet_out->po_enc_data = dst;
@ -1876,6 +1878,7 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
} }
else else
{ {
key_phase = 0;
assert(enc_sess->esi_hsk_pairs); assert(enc_sess->esi_hsk_pairs);
pair = &enc_sess->esi_hsk_pairs[ enc_level ]; pair = &enc_sess->esi_hsk_pairs[ enc_level ];
crypto_ctx = &pair->ykp_ctx[ cliser ]; crypto_ctx = &pair->ykp_ctx[ cliser ];
@ -1976,6 +1979,9 @@ iquic_esf_decrypt_packet (enc_session_t *enc_session_p,
pns = lsquic_enclev2pns[enc_level]; pns = lsquic_enclev2pns[enc_level];
if (packet_in->pi_packno > enc_sess->esi_max_packno[pns]) if (packet_in->pi_packno > enc_sess->esi_max_packno[pns])
enc_sess->esi_max_packno[pns] = packet_in->pi_packno; enc_sess->esi_max_packno[pns] = packet_in->pi_packno;
/* XXX Compiler complains that `pair' may be uninitialized here, but this
* variable is set in `if (crypto_ctx == &crypto_ctx_buf)' above.
*/
if (is_valid_packno(pair->ykp_thresh) if (is_valid_packno(pair->ykp_thresh)
&& packet_in->pi_packno > pair->ykp_thresh) && packet_in->pi_packno > pair->ykp_thresh)
pair->ykp_thresh = packet_in->pi_packno; pair->ykp_thresh = packet_in->pi_packno;

View file

@ -165,12 +165,6 @@ force_close_conn (lsquic_engine_t *engine, lsquic_conn_t *conn);
|LSCONN_ATTQ) |LSCONN_ATTQ)
struct cert_susp_head
{
TAILQ_HEAD(, lsquic_conn) csh_conns;
struct lsquic_hash_elem csh_hash_el;
char csh_sni[0];
};
struct cid_update_batch struct cid_update_batch
@ -237,7 +231,6 @@ struct lsquic_engine
lsquic_time_t deadline; lsquic_time_t deadline;
lsquic_time_t resume_sending_at; lsquic_time_t resume_sending_at;
unsigned mini_conns_count; unsigned mini_conns_count;
struct lsquic_hash *suspended_sni_heads;
struct lsquic_purga *purga; struct lsquic_purga *purga;
#if LSQUIC_CONN_STATS #if LSQUIC_CONN_STATS
struct { struct {
@ -581,7 +574,6 @@ lsquic_engine_new (unsigned flags,
engine->attq = attq_create(); engine->attq = attq_create();
eng_hist_init(&engine->history); eng_hist_init(&engine->history);
engine->batch_size = INITIAL_OUT_BATCH_SIZE; engine->batch_size = INITIAL_OUT_BATCH_SIZE;
engine->suspended_sni_heads = lsquic_hash_create();
if (engine->pub.enp_settings.es_honor_prst) if (engine->pub.enp_settings.es_honor_prst)
{ {
engine->pub.enp_srst_hash = lsquic_hash_create(); engine->pub.enp_srst_hash = lsquic_hash_create();
@ -659,20 +651,6 @@ shrink_batch_size (struct lsquic_engine *engine)
} }
static void
delete_susp_head (struct lsquic_engine *engine, struct cert_susp_head *head)
{
struct lsquic_hash_elem *el;
el = lsquic_hash_find(engine->suspended_sni_heads, head->csh_sni,
strlen(head->csh_sni));
assert(el);
assert(head == lsquic_hashelem_getdata(el));
lsquic_hash_erase(engine->suspended_sni_heads, el);
free(head);
}
struct cce_cid_iter struct cce_cid_iter
{ {
const struct lsquic_conn *conn; const struct lsquic_conn *conn;
@ -744,14 +722,6 @@ destroy_conn (struct lsquic_engine *engine, struct lsquic_conn *conn,
lsquic_time_t drain_time; lsquic_time_t drain_time;
struct purga_el *puel; struct purga_el *puel;
if (conn->cn_cert_susp_head)
{
TAILQ_REMOVE(&conn->cn_cert_susp_head->csh_conns, conn,
cn_next_susp_cert);
if (TAILQ_EMPTY(&conn->cn_cert_susp_head->csh_conns))
delete_susp_head(engine, conn->cn_cert_susp_head);
conn->cn_cert_susp_head = NULL;
}
engine->mini_conns_count -= !!(conn->cn_flags & LSCONN_MINI); engine->mini_conns_count -= !!(conn->cn_flags & LSCONN_MINI);
if (engine->purga if (engine->purga
/* Blacklist all CIDs except for promoted mini connections */ /* Blacklist all CIDs except for promoted mini connections */
@ -1411,7 +1381,6 @@ lsquic_engine_destroy (lsquic_engine_t *engine)
if (engine->flags & ENG_LOSE_PACKETS) if (engine->flags & ENG_LOSE_PACKETS)
regfree(&engine->lose_packets_re); regfree(&engine->lose_packets_re);
#endif #endif
lsquic_hash_destroy(engine->suspended_sni_heads);
if (engine->pub.enp_tokgen) if (engine->pub.enp_tokgen)
lsquic_tg_destroy(engine->pub.enp_tokgen); lsquic_tg_destroy(engine->pub.enp_tokgen);
#if LSQUIC_CONN_STATS #if LSQUIC_CONN_STATS

View file

@ -3470,6 +3470,8 @@ full_conn_ci_tick (lsquic_conn_t *lconn, lsquic_time_t now)
if (!TAILQ_EMPTY(&conn->fc_pub.write_streams)) if (!TAILQ_EMPTY(&conn->fc_pub.write_streams))
process_streams_write_events(conn, 0); process_streams_write_events(conn, 0);
lsquic_send_ctl_maybe_app_limited(&conn->fc_send_ctl, &conn->fc_path);
end_write: end_write:
skip_write: skip_write:

View file

@ -6027,6 +6027,8 @@ ietf_full_conn_ci_tick (struct lsquic_conn *lconn, lsquic_time_t now)
if (!TAILQ_EMPTY(&conn->ifc_pub.write_streams)) if (!TAILQ_EMPTY(&conn->ifc_pub.write_streams))
process_streams_write_events(conn, 0, &highest_non_crit); process_streams_write_events(conn, 0, &highest_non_crit);
lsquic_send_ctl_maybe_app_limited(&conn->ifc_send_ctl, CUR_NPATH(conn));
end_write: end_write:
if ((conn->ifc_flags & IFC_CLOSING) && conn_ok_to_close(conn)) if ((conn->ifc_flags & IFC_CLOSING) && conn_ok_to_close(conn))
{ {

View file

@ -1940,14 +1940,19 @@ mini_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
{ {
struct mini_conn *mc = (struct mini_conn *) lconn; struct mini_conn *mc = (struct mini_conn *) lconn;
struct lsquic_packet_out *packet_out; struct lsquic_packet_out *packet_out;
size_t len;
if (NP_IS_IPv6(&mc->mc_path) != (AF_INET6 == peer_sa->sa_family)) if (NP_IS_IPv6(&mc->mc_path) != (AF_INET6 == peer_sa->sa_family))
TAILQ_FOREACH(packet_out, &mc->mc_packets_out, po_next) TAILQ_FOREACH(packet_out, &mc->mc_packets_out, po_next)
if ((packet_out->po_flags & (PO_SENT|PO_ENCRYPTED)) == PO_ENCRYPTED) if ((packet_out->po_flags & (PO_SENT|PO_ENCRYPTED)) == PO_ENCRYPTED)
return_enc_data(mc, packet_out); return_enc_data(mc, packet_out);
memcpy(mc->mc_path.np_peer_addr, peer_sa, sizeof(mc->mc_path.np_peer_addr)); len = local_sa->sa_family == AF_INET ? sizeof(struct sockaddr_in)
memcpy(mc->mc_path.np_local_addr, local_sa, sizeof(mc->mc_path.np_local_addr)); : sizeof(struct sockaddr_in6);
memcpy(mc->mc_path.np_peer_addr, peer_sa, len);
memcpy(mc->mc_path.np_local_addr, local_sa, len);
mc->mc_path.np_peer_ctx = peer_ctx; mc->mc_path.np_peer_ctx = peer_ctx;
return 0; return 0;
} }

View file

@ -1426,16 +1426,18 @@ ietf_mini_conn_ci_record_addrs (struct lsquic_conn *lconn, void *peer_ctx,
{ {
struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn; struct ietf_mini_conn *conn = (struct ietf_mini_conn *) lconn;
struct lsquic_packet_out *packet_out; struct lsquic_packet_out *packet_out;
size_t len;
if (NP_IS_IPv6(&conn->imc_path) != (AF_INET6 == peer_sa->sa_family)) if (NP_IS_IPv6(&conn->imc_path) != (AF_INET6 == peer_sa->sa_family))
TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next) TAILQ_FOREACH(packet_out, &conn->imc_packets_out, po_next)
if ((packet_out->po_flags & (PO_SENT|PO_ENCRYPTED)) == PO_ENCRYPTED) if ((packet_out->po_flags & (PO_SENT|PO_ENCRYPTED)) == PO_ENCRYPTED)
imico_return_enc_data(conn, packet_out); imico_return_enc_data(conn, packet_out);
memcpy(conn->imc_path.np_peer_addr, peer_sa, len = local_sa->sa_family == AF_INET ? sizeof(struct sockaddr_in)
sizeof(conn->imc_path.np_peer_addr)); : sizeof(struct sockaddr_in6);
memcpy(conn->imc_path.np_local_addr, local_sa,
sizeof(conn->imc_path.np_local_addr)); memcpy(conn->imc_path.np_peer_addr, peer_sa, len);
memcpy(conn->imc_path.np_local_addr, local_sa, len);
conn->imc_path.np_peer_ctx = peer_ctx; conn->imc_path.np_peer_ctx = peer_ctx;
return 0; return 0;
} }

View file

@ -591,7 +591,8 @@ lsquic_send_ctl_sent_packet (lsquic_send_ctl_t *ctl,
++ctl->sc_stats.n_total_sent; ++ctl->sc_stats.n_total_sent;
#endif #endif
if (ctl->sc_ci->cci_sent) if (ctl->sc_ci->cci_sent)
ctl->sc_ci->cci_sent(CGP(ctl), packet_out, ctl->sc_n_in_flight_all); ctl->sc_ci->cci_sent(CGP(ctl), packet_out, ctl->sc_n_in_flight_all,
ctl->sc_flags & SC_APP_LIMITED);
lsquic_send_ctl_sanity_check(ctl); lsquic_send_ctl_sanity_check(ctl);
return 0; return 0;
} }
@ -1291,6 +1292,38 @@ lsquic_send_ctl_can_send (lsquic_send_ctl_t *ctl)
} }
/* Like lsquic_send_ctl_can_send(), but no mods */
static int
send_ctl_could_send (const struct lsquic_send_ctl *ctl)
{
uint64_t cwnd;
unsigned n_out;
if ((ctl->sc_flags & SC_PACE) && pacer_delayed(&ctl->sc_pacer))
return 0;
cwnd = ctl->sc_ci->cci_get_cwnd(CGP(ctl));
n_out = send_ctl_all_bytes_out(ctl);
return n_out < cwnd;
}
void
lsquic_send_ctl_maybe_app_limited (struct lsquic_send_ctl *ctl,
const struct network_path *path)
{
const struct lsquic_packet_out *packet_out;
packet_out = lsquic_send_ctl_last_scheduled(ctl, PNS_APP, path, 0);
if ((packet_out && lsquic_packet_out_avail(packet_out) > 10)
|| send_ctl_could_send(ctl))
{
LSQ_DEBUG("app-limited");
ctl->sc_flags |= SC_APP_LIMITED;
}
}
static void static void
send_ctl_expire (struct lsquic_send_ctl *ctl, enum packnum_space pns, send_ctl_expire (struct lsquic_send_ctl *ctl, enum packnum_space pns,
enum expire_filter filter) enum expire_filter filter)

View file

@ -42,6 +42,7 @@ enum send_ctl_flags {
SC_LOST_ACK_HSK = SC_LOST_ACK_INIT << PNS_HSK, SC_LOST_ACK_HSK = SC_LOST_ACK_INIT << PNS_HSK,
SC_LOST_ACK_APP = SC_LOST_ACK_INIT << PNS_APP, SC_LOST_ACK_APP = SC_LOST_ACK_INIT << PNS_APP,
SC_1RTT_ACKED = 1 << 11, SC_1RTT_ACKED = 1 << 11,
SC_APP_LIMITED = 1 << 12,
}; };
typedef struct lsquic_send_ctl { typedef struct lsquic_send_ctl {
@ -255,6 +256,7 @@ lsquic_send_ctl_drop_scheduled (lsquic_send_ctl_t *);
(ctl)->sc_flags |= SC_SCHED_TICK; \ (ctl)->sc_flags |= SC_SCHED_TICK; \
pacer_tick_in(&(ctl)->sc_pacer, now); \ pacer_tick_in(&(ctl)->sc_pacer, now); \
} \ } \
(ctl)->sc_flags &= ~SC_APP_LIMITED; \
} while (0) } while (0)
#define lsquic_send_ctl_tick_out(ctl) do { \ #define lsquic_send_ctl_tick_out(ctl) do { \
@ -353,4 +355,8 @@ lsquic_send_ctl_return_enc_data (struct lsquic_send_ctl *);
#define lsquic_send_ctl_1rtt_acked(ctl) ((ctl)->sc_flags & SC_1RTT_ACKED) #define lsquic_send_ctl_1rtt_acked(ctl) ((ctl)->sc_flags & SC_1RTT_ACKED)
void
lsquic_send_ctl_maybe_app_limited (struct lsquic_send_ctl *,
const struct network_path *);
#endif #endif

View file

@ -846,7 +846,7 @@ int
lsquic_stream_frame_in (lsquic_stream_t *stream, stream_frame_t *frame) lsquic_stream_frame_in (lsquic_stream_t *stream, stream_frame_t *frame)
{ {
uint64_t max_off; uint64_t max_off;
int got_next_offset; int got_next_offset, rv, free_frame;
enum ins_frame ins_frame; enum ins_frame ins_frame;
assert(frame->packet_in); assert(frame->packet_in);
@ -871,9 +871,11 @@ lsquic_stream_frame_in (lsquic_stream_t *stream, stream_frame_t *frame)
/* Update maximum offset in the flow controller and check for flow /* Update maximum offset in the flow controller and check for flow
* control violation: * control violation:
*/ */
rv = -1;
free_frame = !stream->data_in->di_if->di_own_on_ok;
max_off = frame->data_frame.df_offset + frame->data_frame.df_size; max_off = frame->data_frame.df_offset + frame->data_frame.df_size;
if (0 != lsquic_stream_update_sfcw(stream, max_off)) if (0 != lsquic_stream_update_sfcw(stream, max_off))
return -1; goto end_ok;
if (frame->data_frame.df_fin) if (frame->data_frame.df_fin)
{ {
SM_HISTORY_APPEND(stream, SHE_FIN_IN); SM_HISTORY_APPEND(stream, SHE_FIN_IN);
@ -889,13 +891,17 @@ lsquic_stream_frame_in (lsquic_stream_t *stream, stream_frame_t *frame)
if (!stream->data_in) if (!stream->data_in)
{ {
stream->data_in = data_in_error_new(); stream->data_in = data_in_error_new();
return -1; goto end_ok;
} }
} }
if (got_next_offset) if (got_next_offset)
/* Checking the offset saves di_get_frame() call */ /* Checking the offset saves di_get_frame() call */
maybe_conn_to_tickable_if_readable(stream); maybe_conn_to_tickable_if_readable(stream);
return 0; rv = 0;
end_ok:
if (free_frame)
lsquic_malo_put(frame);
return rv;
} }
else if (INS_FRAME_DUP == ins_frame) else if (INS_FRAME_DUP == ins_frame)
{ {

View file

@ -412,8 +412,8 @@ test_not_congestion_controlled (void)
{ {
sample = sampler_test_ack_packet(&stest, packets[i]); sample = sampler_test_ack_packet(&stest, packets[i]);
assert(sample); assert(sample);
lsquic_malo_put(sample);
assert(expected_bw == BW_VALUE(&sample->bandwidth)); assert(expected_bw == BW_VALUE(&sample->bandwidth));
lsquic_malo_put(sample);
} }
stest.time += time_between_packets; stest.time += time_between_packets;
} }
@ -436,6 +436,7 @@ test_compressed_ack (void)
const lsquic_time_t time_between_packets = ms(1), const lsquic_time_t time_between_packets = ms(1),
ridiculously_small_time_delta = us(20); ridiculously_small_time_delta = us(20);
uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize); uint64_t expected_bw = FromKBytesPerSecond(kRegularPacketSize);
uint64_t bw;
unsigned i; unsigned i;
struct bw_sample *sample; struct bw_sample *sample;
struct lsquic_packet_out *packets[41]; struct lsquic_packet_out *packets[41];
@ -453,10 +454,11 @@ test_compressed_ack (void)
sample = sampler_test_ack_packet(&stest, packets[i]); sample = sampler_test_ack_packet(&stest, packets[i]);
assert(sample); assert(sample);
stest.time += ridiculously_small_time_delta; stest.time += ridiculously_small_time_delta;
bw = BW_VALUE(&sample->bandwidth);
lsquic_malo_put(sample); lsquic_malo_put(sample);
} }
assert(BW_VALUE(&sample->bandwidth) == expected_bw); assert(bw == expected_bw);
assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0); assert(lsquic_bw_sampler_entry_count(&stest.sampler) == 0);
assert(stest.bytes_in_flight == 0); assert(stest.bytes_in_flight == 0);