summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAmaury Denoyelle <adenoyelle@haproxy.com>2023-02-28 15:10:00 +0100
committerAmaury Denoyelle <adenoyelle@haproxy.com>2023-03-01 14:29:16 +0100
commit147862de6199542fa95f2203ec7617e61de9e181 (patch)
tree26df76c0ee595c19201cdaf4afceafcb326bde0d
parente0fe118dad6cf78c3e563aff9726b8e015d87340 (diff)
downloadhaproxy-147862de6199542fa95f2203ec7617e61de9e181.tar.gz
MINOR: quic: purge txbuf before preparing new packets
Sending is implemented in two parts on quic-conn module. First, QUIC packets are prepared in a buffer and then sendto() is called with this buffer as input. qc.tx.buf is used as the input buffer. It must always be empty before starting to prepare new packets in it. Currently, this is guarantee by the fact that either sendto() is completed, a fatal error is encountered which prevent future send, or a transient error is encountered and we rely on retransmission to send the remaining data. This will change when poller subscribe of socket FD on sendto() transient error will be implemented. In this case, qc.tx.buf will not be emptied to resume sending when the transient error is cleared. To allow the current sending process to work as expected, a new function qc_purge_txbuf() is implemented. It will try to send remaining data before preparing new packets for sending. If successful, txbuf will be emptied and sending can continue. If not, sending will be interrupted. This should be backported up to 2.7.
-rw-r--r--src/quic_conn.c37
1 files changed, 37 insertions, 0 deletions
diff --git a/src/quic_conn.c b/src/quic_conn.c
index 8c7676ac9..d97e82eee 100644
--- a/src/quic_conn.c
+++ b/src/quic_conn.c
@@ -4183,6 +4183,34 @@ static int qc_qel_may_rm_hp(struct quic_conn *qc, struct quic_enc_level *qel)
return ret;
}
+/* Flush txbuf for <qc> connection. This must be called prior to a packet
+ * preparation when txbuf contains older data. A send will be conducted for
+ * these data.
+ *
+ * Returns 1 on success : buffer is empty and can be use for packet
+ * preparation. On error 0 is returned.
+ */
+static int qc_purge_txbuf(struct quic_conn *qc, struct buffer *buf)
+{
+ TRACE_ENTER(QUIC_EV_CONN_TXPKT, qc);
+
+ /* This operation can only be conducted if txbuf is not empty. This
+ * case only happens for connection with their owned socket due to an
+ * older transient sendto() error.
+ */
+ BUG_ON(!qc_test_fd(qc));
+
+ if (b_data(buf) && !qc_send_ppkts(buf, qc->xprt_ctx)) {
+ if (qc->flags & QUIC_FL_CONN_TO_KILL)
+ qc_txb_release(qc);
+ TRACE_DEVEL("leaving in error", QUIC_EV_CONN_TXPKT, qc);
+ return 0;
+ }
+
+ TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
+ return 1;
+}
+
/* Try to send application frames from list <frms> on connection <qc>.
*
* Use qc_send_app_probing wrapper when probing with old data.
@@ -4208,6 +4236,9 @@ static int qc_send_app_pkts(struct quic_conn *qc, struct list *frms)
goto err;
}
+ if (b_data(buf) && !qc_purge_txbuf(qc, buf))
+ goto err;
+
/* Prepare and send packets until we could not further prepare packets. */
while (1) {
int ret;
@@ -4306,6 +4337,9 @@ int qc_send_hdshk_pkts(struct quic_conn *qc, int old_data,
goto leave;
}
+ if (b_data(buf) && !qc_purge_txbuf(qc, buf))
+ goto out;
+
/* Currently buf cannot be non-empty at this stage. Even if a previous
* sendto() has failed it is emptied to simulate packet emission and
* rely on QUIC lost detection to try to emit it.
@@ -4613,6 +4647,9 @@ struct task *quic_conn_io_cb(struct task *t, void *context, unsigned int state)
if (!buf)
goto out;
+ if (b_data(buf) && !qc_purge_txbuf(qc, buf))
+ goto skip_send;
+
/* Currently buf cannot be non-empty at this stage. Even if a previous
* sendto() has failed it is emptied to simulate packet emission and
* rely on QUIC lost detection to try to emit it.