LIST_APPEND(&frms, &frm->list);
if (qcc_send_frames(qcs->qcc, &frms)) {
if (!LIST_ISEMPTY(&frms))
- qc_frm_free(&frm);
+ qc_frm_free(qcs->qcc->conn->handle.qc, &frm);
TRACE_DEVEL("cannot send RESET_STREAM", QMUX_EV_QCS_SEND, qcs->qcc->conn, qcs);
return 1;
}
LIST_APPEND(&frms, &frm->list);
if (qcc_send_frames(qcs->qcc, &frms)) {
if (!LIST_ISEMPTY(&frms))
- qc_frm_free(&frm);
+ qc_frm_free(qcc->conn->handle.qc, &frm);
TRACE_DEVEL("cannot send STOP_SENDING", QMUX_EV_QCS_SEND, qcs->qcc->conn, qcs);
return 1;
}
struct quic_frame *frm, *frm2;
list_for_each_entry_safe(frm, frm2, &frms, list)
- qc_frm_free(&frm);
+ qc_frm_free(qcc->conn->handle.qc, &frm);
}
/* Re-insert on-error QCS at the end of the send-list. */
while (!LIST_ISEMPTY(&qcc->lfctl.frms)) {
struct quic_frame *frm = LIST_ELEM(qcc->lfctl.frms.n, struct quic_frame *, list);
- qc_frm_free(&frm);
+ qc_frm_free(qcc->conn->handle.qc, &frm);
}
if (qcc->app_ops && qcc->app_ops->release)
TRACE_DEVEL("freeing unsent frame",
QUIC_EV_CONN_PRSAFRM, qc, f);
LIST_DEL_INIT(&f->ref);
- qc_frm_free(&f);
+ qc_frm_free(qc, &f);
}
}
LIST_DEL_INIT(&frm->list);
quic_tx_packet_refdec(frm->pkt);
TRACE_DEVEL("freeing frame from packet",
QUIC_EV_CONN_PRSAFRM, qc, frm, &pn);
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc);
}
TRACE_DEVEL("released stream", QUIC_EV_CONN_PRSAFRM, qc, frm);
TRACE_DEVEL("freeing frame from packet", QUIC_EV_CONN_PRSAFRM,
qc, frm, &pn);
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
continue;
}
if (strm_frm->offset.key + strm_frm->len <= stream_desc->ack_offset) {
TRACE_DEVEL("ignored frame in already acked range",
QUIC_EV_CONN_PRSAFRM, qc, frm);
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
continue;
}
else if (strm_frm->offset.key < stream_desc->ack_offset) {
qc, frm, &pn);
if (frm->origin)
LIST_DEL_INIT(&frm->ref);
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
continue;
}
TRACE_DEVEL("already acked frame", QUIC_EV_CONN_PRSAFRM, qc, frm);
TRACE_DEVEL("freeing frame from packet", QUIC_EV_CONN_PRSAFRM,
qc, frm, &pn);
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
}
else {
if (++frm->loss_count >= global.tune.quic_max_frame_loss) {
goto leave;
list_for_each_entry_safe(frm, frmbak, &pkt->frms, list)
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
pool_free(pool_head_quic_tx_packet, pkt);
leave:
TRACE_ENTER(QUIC_EV_CONN_PHPKTS, qc);
list_for_each_entry_safe(frm, frmbak, &pktns->tx.frms, list)
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
TRACE_LEAVE(QUIC_EV_CONN_PHPKTS, qc);
}
rs = qc_frm_alloc(QUIC_FT_RESET_STREAM);
if (!rs) {
TRACE_ERROR("failed to allocate quic_frame", QUIC_EV_CONN_PRSHPKT, qc);
- qc_frm_free(&ss);
+ qc_frm_free(qc, &ss);
goto out;
}
/* Free all frames in <l> list. In addition also remove all these frames
* from the original ones if they are the results of duplications.
*/
-static inline void qc_free_frm_list(struct list *l)
+static inline void qc_free_frm_list(struct quic_conn *qc, struct list *l)
{
struct quic_frame *frm, *frmbak;
list_for_each_entry_safe(frm, frmbak, l, list) {
LIST_DEL_INIT(&frm->ref);
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
}
}
/* Free <pkt> TX packet and all the packets coalesced to it. */
-static inline void qc_free_tx_coalesced_pkts(struct quic_tx_packet *p)
+static inline void qc_free_tx_coalesced_pkts(struct quic_conn *qc,
+ struct quic_tx_packet *p)
{
struct quic_tx_packet *pkt, *nxt_pkt;
for (pkt = p; pkt; pkt = nxt_pkt) {
- qc_free_frm_list(&pkt->frms);
+ qc_free_frm_list(qc, &pkt->frms);
nxt_pkt = pkt->next;
pool_free(pool_head_quic_tx_packet, pkt);
}
}
/* Purge <buf> TX buffer from its prepare packets. */
-static void qc_purge_tx_buf(struct buffer *buf)
+static void qc_purge_tx_buf(struct quic_conn *qc, struct buffer *buf)
{
while (b_contig_data(buf, 0)) {
uint16_t dglen;
dglen = read_u16(b_head(buf));
pkt = read_ptr(b_head(buf) + sizeof dglen);
- qc_free_tx_coalesced_pkts(pkt);
+ qc_free_tx_coalesced_pkts(qc, pkt);
b_del(buf, dglen + headlen);
}
if (ret < 0) {
TRACE_ERROR("sendto fatal error", QUIC_EV_CONN_SPPKTS, qc, first_pkt);
qc_kill_conn(qc);
- qc_free_tx_coalesced_pkts(first_pkt);
+ qc_free_tx_coalesced_pkts(qc, first_pkt);
b_del(buf, dglen + headlen);
- qc_purge_tx_buf(buf);
+ qc_purge_tx_buf(qc, buf);
goto leave;
}
else if (!ret) {
conn_id = new_quic_cid(&qc->cids, qc, NULL, NULL);
if (!conn_id) {
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
TRACE_ERROR("CID allocation error", QUIC_EV_CONN_IO_CB, qc);
goto err;
}
err:
/* free the frames */
list_for_each_entry_safe(frm, frmbak, &frm_list, list)
- qc_frm_free(&frm);
+ qc_frm_free(qc, &frm);
/* The first CID sequence number value used to allocated CIDs by this function is 1,
* 0 being the sequence number of the CID for this connection.
if (!LIST_ISEMPTY(&frms1)) {
apktns->tx.pto_probe = 1;
if (!qc_send_app_probing(qc, &frms1)) {
- qc_free_frm_list(&frms2);
+ qc_free_frm_list(qc, &frms2);
goto leave;
}
node = eb64_lookup(&qc->streams_by_id, strm_frm->id);
if (!node) {
TRACE_DEVEL("released stream", QUIC_EV_CONN_PRSAFRM, qc, cf);
- qc_frm_free(&cf);
+ qc_frm_free(qc, &cf);
continue;
}
if (strm_frm->offset.key + strm_frm->len <= stream_desc->ack_offset) {
TRACE_DEVEL("ignored frame frame in already acked range",
QUIC_EV_CONN_PRSAFRM, qc, cf);
- qc_frm_free(&cf);
+ qc_frm_free(qc, &cf);
continue;
}
else if (strm_frm->offset.key < stream_desc->ack_offset) {
{
struct quic_frame *f, *tmp;
- TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc);
+ TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc, frm);
list_for_each_entry_safe(f, tmp, &frm->reflist, ref) {
f->origin = NULL;
TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc);
}
+
+/* Free a <frm> quic_frame. Remove it from parent element if still attached. */
+void qc_frm_free(struct quic_conn *qc, struct quic_frame **frm)
+{
+
+ TRACE_ENTER(QUIC_EV_CONN_PRSAFRM, qc, *frm);
+ /* Caller must ensure that no other frame points to <frm>. Use
+ * qc_frm_unref() to handle this properly.
+ */
+ BUG_ON(!LIST_ISEMPTY(&((*frm)->reflist)));
+ BUG_ON(LIST_INLIST(&((*frm)->ref)));
+
+ /* TODO simplify frame deallocation. In some code paths, we must
+ * manually call this LIST_DEL_INIT before using
+ * quic_tx_packet_refdec() and freeing the frame.
+ */
+ LIST_DEL_INIT(&((*frm)->list));
+
+ pool_free(pool_head_quic_frame, *frm);
+ *frm = NULL;
+ TRACE_LEAVE(QUIC_EV_CONN_PRSAFRM, qc);
+}