Packages
hackney
2.0.0
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/lsquic/src/liblsquic/lsquic_pacer.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
#include <assert.h>
#include <inttypes.h>
#include <stdint.h>
#include <string.h>
#ifdef WIN32
#include <vc_compat.h>
#endif
#include "lsquic_types.h"
#include "lsquic_int_types.h"
#include "lsquic_pacer.h"
#include "lsquic_packet_common.h"
#include "lsquic_packet_gquic.h"
#include "lsquic_packet_out.h"
#include "lsquic_util.h"
#define LSQUIC_LOGGER_MODULE LSQLM_PACER
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(pacer->pa_conn)
#include "lsquic_logger.h"
#ifndef MAX
# define MAX(a, b) ((a) > (b) ? (a) : (b))
#endif
void
lsquic_pacer_init (struct pacer *pacer, const struct lsquic_conn *conn,
unsigned clock_granularity)
{
memset(pacer, 0, sizeof(*pacer));
pacer->pa_burst_tokens = 10;
pacer->pa_conn = conn;
pacer->pa_clock_granularity = clock_granularity;
}
void
lsquic_pacer_cleanup (struct pacer *pacer)
{
#ifndef NDEBUG
LSQ_DEBUG("scheduled calls: %u", pacer->pa_stats.n_scheduled);
#endif
}
void
lsquic_pacer_packet_scheduled (struct pacer *pacer, unsigned n_in_flight,
int in_recovery, tx_time_f tx_time, void *tx_ctx)
{
lsquic_time_t delay, sched_time;
int app_limited, making_up;
#ifndef NDEBUG
++pacer->pa_stats.n_scheduled;
#endif
++pacer->pa_n_scheduled;
if (n_in_flight == 0 && !in_recovery)
{
pacer->pa_burst_tokens = 10;
LSQ_DEBUG("%s: replenish tokens: %u", __func__, pacer->pa_burst_tokens);
}
if (pacer->pa_burst_tokens > 0)
{
--pacer->pa_burst_tokens;
pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED;
pacer->pa_next_sched = 0;
pacer->pa_last_delayed = 0;
LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens);
return;
}
sched_time = pacer->pa_now;
delay = tx_time(tx_ctx);
if (pacer->pa_flags & PA_LAST_SCHED_DELAYED)
{
pacer->pa_next_sched += delay;
app_limited = pacer->pa_last_delayed != 0
&& pacer->pa_last_delayed + delay <= sched_time;
making_up = pacer->pa_next_sched <= sched_time;
LSQ_DEBUG("making up: %d; app limited; %d", making_up, app_limited);
if (making_up && !app_limited)
pacer->pa_last_delayed = sched_time;
else
{
pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED;
pacer->pa_last_delayed = 0;
}
}
else
pacer->pa_next_sched = MAX(pacer->pa_next_sched + delay,
sched_time + delay);
LSQ_DEBUG("next_sched is set to %"PRIu64" usec from now",
pacer->pa_next_sched - pacer->pa_now);
}
void
lsquic_pacer_loss_event (struct pacer *pacer)
{
pacer->pa_burst_tokens = 0;
LSQ_DEBUG("%s: tokens: %u", __func__, pacer->pa_burst_tokens);
}
int
lsquic_pacer_can_schedule (struct pacer *pacer, unsigned n_in_flight)
{
int can;
if (pacer->pa_burst_tokens > 0 || n_in_flight == 0)
can = 1;
else if (pacer->pa_next_sched > pacer->pa_now + pacer->pa_clock_granularity)
{
pacer->pa_flags |= PA_LAST_SCHED_DELAYED;
can = 0;
}
else
can = 1;
LSQ_DEBUG("%s: %d", __func__, can);
return can;
}
int
lsquic_pacer_can_schedule_probe (const struct pacer *pacer,
unsigned n_in_flight, lsquic_time_t tx_time)
{
return pacer->pa_burst_tokens > 1 /* Double packet size, want two tokens */
|| n_in_flight == 0
|| pacer->pa_next_sched > pacer->pa_now + tx_time / 2;
}
void
lsquic_pacer_tick_in (struct pacer *pacer, lsquic_time_t now)
{
assert(now >= pacer->pa_now);
pacer->pa_now = now;
if (pacer->pa_flags & PA_LAST_SCHED_DELAYED)
pacer->pa_flags |= PA_DELAYED_ON_TICK_IN;
pacer->pa_n_scheduled = 0;
}
void
lsquic_pacer_tick_out (struct pacer *pacer)
{
if ((pacer->pa_flags & PA_DELAYED_ON_TICK_IN)
&& pacer->pa_n_scheduled == 0
&& pacer->pa_now > pacer->pa_next_sched)
{
LSQ_DEBUG("tick passed without scheduled packets: reset delayed flag");
pacer->pa_flags &= ~PA_LAST_SCHED_DELAYED;
}
pacer->pa_flags &= ~PA_DELAYED_ON_TICK_IN;
}