qc->state >= QUIC_HS_ST_COMPLETE) {
quic_build_post_handshake_frames(qc);
qel_register_send(&send_list, qc->ael, &qc->ael->pktns->tx.frms);
- qc_send(qc, 0, &send_list);
+ qc_send(qc, 0, &send_list, NULL);
}
TRACE_STATE("preparing data (from MUX)", QUIC_EV_CONN_TXPKT, qc);
qel_register_send(&send_list, qc->ael, frms);
- ret = qc_send(qc, 0, &send_list);
+ ret = qc_send(qc, 0, &send_list, NULL);
TRACE_LEAVE(QUIC_EV_CONN_TXPKT, qc);
return ret;
* (may be 0), or -1 if something wrong happened.
*/
static int qc_prep_pkts(struct quic_conn *qc, struct buffer *buf,
- struct list *qels)
+ struct list *qels, int *max_pkts)
{
int ret, cc, padding;
struct quic_tx_packet *first_pkt, *prv_pkt;
*/
BUG_ON_HOT(buf->head || buf->data);
+ BUG_ON(max_pkts && *max_pkts <= 0);
+
ret = -1;
cc = qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE;
padding = 0;
TRACE_PROTO("TX prep pkts", QUIC_EV_CONN_PHPKTS, qc, qel);
+ /* Start to decrement <max_pkts> after the first packet built. */
+ if (!dglen && pos != (unsigned char *)b_head(buf)) {
+ if (max_pkts && !--(*max_pkts)) {
+ BUG_ON(LIST_ISEMPTY(frms));
+ TRACE_PROTO("reached max allowed built datagrams", QUIC_EV_CONN_PHPKTS, qc, qel);
+ goto out;
+ }
+ }
+
if (!first_pkt)
pos += QUIC_DGRAM_HEADLEN;
* Returns 1 on success else 0. Note that <send_list> will always be reset
* after qc_send() exit.
*/
-int qc_send(struct quic_conn *qc, int old_data, struct list *send_list)
+int qc_send(struct quic_conn *qc, int old_data, struct list *send_list, int *max_pkts)
{
struct quic_enc_level *qel, *tmp_qel;
int ret = 0, status = 0;
BUG_ON_HOT(b_data(buf));
b_reset(buf);
- ret = qc_prep_pkts(qc, buf, send_list);
+ ret = qc_prep_pkts(qc, buf, send_list, max_pkts);
if (b_data(buf) && !qc_send_ppkts(buf, qc->xprt_ctx)) {
if (qc->flags & QUIC_FL_CONN_TO_KILL)
break;
}
+ if (max_pkts && !*max_pkts) {
+ TRACE_DEVEL("stopping for artificial pacing", QUIC_EV_CONN_TXPKT, qc);
+ break;
+ }
+
if ((qc->flags & QUIC_FL_CONN_DRAINING) &&
!(qc->flags & QUIC_FL_CONN_IMMEDIATE_CLOSE)) {
TRACE_DEVEL("draining connection", QUIC_EV_CONN_TXPKT, qc);
if (qc->hel)
qel_register_send(&send_list, qc->hel, &hfrms);
- sret = qc_send(qc, 1, &send_list);
+ sret = qc_send(qc, 1, &send_list, NULL);
qc_free_frm_list(qc, &ifrms);
qc_free_frm_list(qc, &hfrms);
if (!sret)
*/
ipktns->tx.pto_probe = 1;
qel_register_send(&send_list, qc->iel, &ifrms);
- sret = qc_send(qc, 0, &send_list);
+ sret = qc_send(qc, 0, &send_list, NULL);
qc_free_frm_list(qc, &ifrms);
qc_free_frm_list(qc, &hfrms);
if (!sret)
if (!LIST_ISEMPTY(&frms1)) {
hpktns->tx.pto_probe = 1;
qel_register_send(&send_list, qc->hel, &frms1);
- sret = qc_send(qc, 1, &send_list);
+ sret = qc_send(qc, 1, &send_list, NULL);
qc_free_frm_list(qc, &frms1);
if (!sret)
goto leave;
if (!LIST_ISEMPTY(&frms1)) {
apktns->tx.pto_probe = 1;
qel_register_send(&send_list, qc->ael, &frms1);
- sret = qc_send(qc, 1, &send_list);
+ sret = qc_send(qc, 1, &send_list, NULL);
qc_free_frm_list(qc, &frms1);
if (!sret) {
qc_free_frm_list(qc, &frms2);
if (!LIST_ISEMPTY(&frms2)) {
apktns->tx.pto_probe = 1;
qel_register_send(&send_list, qc->ael, &frms2);
- sret = qc_send(qc, 1, &send_list);
+ sret = qc_send(qc, 1, &send_list, NULL);
qc_free_frm_list(qc, &frms2);
if (!sret)
goto leave;