Packages
hackney
3.0.2
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_sfcw.c
/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc. See LICENSE. */
#include <inttypes.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#include <sys/queue.h>
#include "lsquic.h"
#include "lsquic_int_types.h"
#include "lsquic_conn_flow.h"
#include "lsquic_types.h"
#include "lsquic_rtt.h"
#include "lsquic_varint.h"
#include "lsquic_sfcw.h"
#include "lsquic_hq.h"
#include "lsquic_hash.h"
#include "lsquic_stream.h"
#include "lsquic_conn_public.h"
#include "lsquic_mm.h"
#include "lsquic_engine_public.h"
#include "lsquic_util.h"
#include "lsquic_conn.h"
#include "lsquic_ev_log.h"
#define LSQUIC_LOGGER_MODULE LSQLM_SFCW
#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(fc->sf_conn_pub->lconn)
#define LSQUIC_LOG_STREAM_ID fc->sf_stream_id
#include "lsquic_logger.h"
void
lsquic_sfcw_init (struct lsquic_sfcw *fc, unsigned max_recv_window,
struct lsquic_cfcw *cfcw, struct lsquic_conn_public *cpub,
lsquic_stream_id_t stream_id)
{
memset(fc, 0, sizeof(*fc));
fc->sf_max_recv_win = max_recv_window;
fc->sf_cfcw = cfcw;
fc->sf_conn_pub = cpub;
fc->sf_stream_id = stream_id;
(void) lsquic_sfcw_fc_offsets_changed(fc);
}
static void
sfcw_maybe_increase_max_window (struct lsquic_sfcw *fc)
{
unsigned new_max_window, max_conn_window;
new_max_window = fc->sf_max_recv_win * 2;
/* Do not increase past explicitly specified maximum */
if (new_max_window > fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw)
new_max_window = fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw;
if (fc->sf_cfcw)
{
/* Do not increase past the connection's maximum window size. The
* connection's window will be increased separately, if possible.
*
* The reference implementation has the logic backwards: Imagine
* several concurrent streams that are not being read from fast
* enough by the user code. Each of them uses only a fraction
* of bandwidth. Does it mean that the connection window must
* increase? No.
*/
max_conn_window = lsquic_cfcw_get_max_recv_window(fc->sf_cfcw);
if (new_max_window > max_conn_window)
new_max_window = max_conn_window;
}
else
{
/* This means that this stream is not affected by connection flow
* controller. No need to adjust under connection window.
*/
}
if (new_max_window > fc->sf_max_recv_win)
{
LSQ_DEBUG("max window increase %u -> %u",
fc->sf_max_recv_win, new_max_window);
EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID,
"max SFCW increase %u -> %u", fc->sf_max_recv_win,
new_max_window);
fc->sf_max_recv_win = new_max_window;
}
else
LSQ_DEBUG("max window could use an increase, but we're stuck "
"at %u", fc->sf_max_recv_win);
}
int
lsquic_sfcw_fc_offsets_changed (struct lsquic_sfcw *fc)
{
lsquic_time_t since_last_update, srtt, now;
if (fc->sf_recv_off - fc->sf_read_off >= fc->sf_max_recv_win / 2)
{
LSQ_DEBUG("recv_off has not changed, still at %"PRIu64,
fc->sf_recv_off);
return 0;
}
now = lsquic_time_now();
since_last_update = now - fc->sf_last_updated;
fc->sf_last_updated = now;
srtt = lsquic_rtt_stats_get_srtt(&fc->sf_conn_pub->rtt_stats);
if (since_last_update < srtt * 2)
sfcw_maybe_increase_max_window(fc);
fc->sf_recv_off = fc->sf_read_off + fc->sf_max_recv_win;
LSQ_DEBUG("recv_off changed: read_off: %"PRIu64"; "
"recv_off: %"PRIu64, fc->sf_read_off, fc->sf_recv_off);
return 1;
}
int
lsquic_sfcw_set_max_recv_off (struct lsquic_sfcw *fc, uint64_t max_recv_off)
{
if (max_recv_off <= fc->sf_recv_off)
{
if (!fc->sf_cfcw || lsquic_cfcw_incr_max_recv_off(fc->sf_cfcw,
max_recv_off - fc->sf_max_recv_off))
{
LSQ_DEBUG("max_recv_off goes from %"PRIu64" to %"PRIu64,
fc->sf_max_recv_off, max_recv_off);
fc->sf_max_recv_off = max_recv_off;
return 1;
}
else
{
/* cfcw prints its own warning */
return 0;
}
}
else
{
LSQ_INFO("flow control violation: received at offset %"PRIu64", "
"while flow control receive offset is %"PRIu64,
max_recv_off, fc->sf_recv_off);
return 0;
}
}
void
lsquic_sfcw_set_read_off (struct lsquic_sfcw *fc, uint64_t off)
{
if (fc->sf_cfcw)
lsquic_cfcw_incr_read_off(fc->sf_cfcw, off - fc->sf_read_off);
LSQ_DEBUG("read_off goes from %"PRIu64" to %"PRIu64,
fc->sf_read_off, off);
fc->sf_read_off = off;
}