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.
diff --git a/src/quic_conn.c b/src/quic_conn.c
index 8c7676a..d97e82e 100644
--- a/src/quic_conn.c
+++ b/src/quic_conn.c
@@ -4183,6 +4183,34 @@
 	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 @@
 		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 @@
 		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 @@
 	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.