1a74702c6SGeorge Wang/* Copyright (c) 2017 - 2022 LiteSpeed Technologies Inc.  See LICENSE. */
250aadb33SDmitri Tikhonov#include <inttypes.h>
350aadb33SDmitri Tikhonov#include <stdint.h>
450aadb33SDmitri Tikhonov#include <stdlib.h>
550aadb33SDmitri Tikhonov#include <string.h>
650aadb33SDmitri Tikhonov#include <sys/queue.h>
750aadb33SDmitri Tikhonov
850aadb33SDmitri Tikhonov#include "lsquic.h"
950aadb33SDmitri Tikhonov#include "lsquic_types.h"
1050aadb33SDmitri Tikhonov#include "lsquic_int_types.h"
1150aadb33SDmitri Tikhonov#include "lsquic_rtt.h"
1250aadb33SDmitri Tikhonov#include "lsquic_conn_flow.h"
1350aadb33SDmitri Tikhonov#include "lsquic_sfcw.h"
145392f7a3SLiteSpeed Tech#include "lsquic_varint.h"
155392f7a3SLiteSpeed Tech#include "lsquic_hq.h"
165392f7a3SLiteSpeed Tech#include "lsquic_hash.h"
1750aadb33SDmitri Tikhonov#include "lsquic_stream.h"
1850aadb33SDmitri Tikhonov#include "lsquic_conn_public.h"
1950aadb33SDmitri Tikhonov#include "lsquic_mm.h"
2050aadb33SDmitri Tikhonov#include "lsquic_engine_public.h"
2150aadb33SDmitri Tikhonov#include "lsquic_util.h"
2250aadb33SDmitri Tikhonov#include "lsquic_conn.h"
2350aadb33SDmitri Tikhonov#include "lsquic_ev_log.h"
2450aadb33SDmitri Tikhonov
2550aadb33SDmitri Tikhonov#define LSQUIC_LOGGER_MODULE LSQLM_CFCW
265392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(fc->cf_conn_pub->lconn)
2750aadb33SDmitri Tikhonov#include "lsquic_logger.h"
2850aadb33SDmitri Tikhonov
2950aadb33SDmitri Tikhonov
3050aadb33SDmitri Tikhonovvoid
3150aadb33SDmitri Tikhonovlsquic_cfcw_init (struct lsquic_cfcw *fc, struct lsquic_conn_public *cpub,
3250aadb33SDmitri Tikhonov                                                unsigned max_recv_window)
3350aadb33SDmitri Tikhonov{
3450aadb33SDmitri Tikhonov    memset(fc, 0, sizeof(*fc));
3550aadb33SDmitri Tikhonov    fc->cf_max_recv_win = max_recv_window;
3650aadb33SDmitri Tikhonov    fc->cf_conn_pub = cpub;
3750aadb33SDmitri Tikhonov    (void) lsquic_cfcw_fc_offsets_changed(fc);
3850aadb33SDmitri Tikhonov}
3950aadb33SDmitri Tikhonov
4050aadb33SDmitri Tikhonov
4150aadb33SDmitri Tikhonovstatic void
4250aadb33SDmitri Tikhonovcfcw_maybe_increase_max_window (struct lsquic_cfcw *fc)
4350aadb33SDmitri Tikhonov{
4450aadb33SDmitri Tikhonov    unsigned new_max_window;
4550aadb33SDmitri Tikhonov
4650aadb33SDmitri Tikhonov    new_max_window = fc->cf_max_recv_win * 2;
4750aadb33SDmitri Tikhonov
4850aadb33SDmitri Tikhonov    /* Do not increase past explicitly specified maximum */
4950aadb33SDmitri Tikhonov    if (new_max_window > fc->cf_conn_pub->enpub->enp_settings.es_max_cfcw)
5050aadb33SDmitri Tikhonov        new_max_window = fc->cf_conn_pub->enpub->enp_settings.es_max_cfcw;
5150aadb33SDmitri Tikhonov
5250aadb33SDmitri Tikhonov    if (new_max_window > fc->cf_max_recv_win)
5350aadb33SDmitri Tikhonov    {
5450aadb33SDmitri Tikhonov        LSQ_DEBUG("max window increase %u -> %u", fc->cf_max_recv_win,
5550aadb33SDmitri Tikhonov                                                            new_max_window);
5650aadb33SDmitri Tikhonov        EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID,
5750aadb33SDmitri Tikhonov            "max CFCW increase %u -> %u", fc->cf_max_recv_win,
5850aadb33SDmitri Tikhonov                                                            new_max_window);
5950aadb33SDmitri Tikhonov        fc->cf_max_recv_win = new_max_window;
6050aadb33SDmitri Tikhonov    }
6150aadb33SDmitri Tikhonov    else
6250aadb33SDmitri Tikhonov        LSQ_DEBUG("max window could use an increase, but we're stuck "
6350aadb33SDmitri Tikhonov            "at %u", fc->cf_max_recv_win);
6450aadb33SDmitri Tikhonov}
6550aadb33SDmitri Tikhonov
6650aadb33SDmitri Tikhonov
6750aadb33SDmitri Tikhonovint
6850aadb33SDmitri Tikhonovlsquic_cfcw_fc_offsets_changed (struct lsquic_cfcw *fc)
6950aadb33SDmitri Tikhonov{
7050aadb33SDmitri Tikhonov    lsquic_time_t now, since_last_update, srtt;
7150aadb33SDmitri Tikhonov
7250aadb33SDmitri Tikhonov    if (fc->cf_recv_off - fc->cf_read_off >= fc->cf_max_recv_win / 2)
7350aadb33SDmitri Tikhonov        return 0;
7450aadb33SDmitri Tikhonov
7550aadb33SDmitri Tikhonov    now = lsquic_time_now();
7650aadb33SDmitri Tikhonov    since_last_update = now - fc->cf_last_updated;
7750aadb33SDmitri Tikhonov    fc->cf_last_updated = now;
7850aadb33SDmitri Tikhonov
7950aadb33SDmitri Tikhonov    srtt = lsquic_rtt_stats_get_srtt(&fc->cf_conn_pub->rtt_stats);
8050aadb33SDmitri Tikhonov    if (since_last_update < srtt * 2)
8150aadb33SDmitri Tikhonov        cfcw_maybe_increase_max_window(fc);
8250aadb33SDmitri Tikhonov
8350aadb33SDmitri Tikhonov    fc->cf_recv_off = fc->cf_read_off + fc->cf_max_recv_win;
8450aadb33SDmitri Tikhonov    LSQ_DEBUG("recv_off changed: read_off: %"PRIu64"; recv_off: %"
8550aadb33SDmitri Tikhonov        PRIu64"", fc->cf_read_off, fc->cf_recv_off);
8650aadb33SDmitri Tikhonov    return 1;
8750aadb33SDmitri Tikhonov}
8850aadb33SDmitri Tikhonov
8950aadb33SDmitri Tikhonov
9050aadb33SDmitri Tikhonovint
9150aadb33SDmitri Tikhonovlsquic_cfcw_incr_max_recv_off (struct lsquic_cfcw *fc, uint64_t incr)
9250aadb33SDmitri Tikhonov{
9350aadb33SDmitri Tikhonov    if (fc->cf_max_recv_off + incr <= fc->cf_recv_off)
9450aadb33SDmitri Tikhonov    {
9550aadb33SDmitri Tikhonov        fc->cf_max_recv_off += incr;
9650aadb33SDmitri Tikhonov        LSQ_DEBUG("max_recv_off goes from %"PRIu64" to %"PRIu64"",
9750aadb33SDmitri Tikhonov                    fc->cf_max_recv_off - incr, fc->cf_max_recv_off);
9850aadb33SDmitri Tikhonov        return 1;
9950aadb33SDmitri Tikhonov    }
10050aadb33SDmitri Tikhonov    else
10150aadb33SDmitri Tikhonov    {
1028ae5ecb4SDmitri Tikhonov        LSQ_INFO("flow control violation: received at offset %"PRIu64", while "
10350aadb33SDmitri Tikhonov            "flow control receive offset is %"PRIu64,
10450aadb33SDmitri Tikhonov            fc->cf_max_recv_off + incr, fc->cf_recv_off);
10550aadb33SDmitri Tikhonov        return 0;
10650aadb33SDmitri Tikhonov    }
10750aadb33SDmitri Tikhonov}
10850aadb33SDmitri Tikhonov
10950aadb33SDmitri Tikhonov
11050aadb33SDmitri Tikhonovvoid
11150aadb33SDmitri Tikhonovlsquic_cfcw_incr_read_off (struct lsquic_cfcw *fc, uint64_t incr)
11250aadb33SDmitri Tikhonov{
11350aadb33SDmitri Tikhonov    fc->cf_read_off += incr;
11450aadb33SDmitri Tikhonov    LSQ_DEBUG("read_off goes from %"PRIu64" to %"PRIu64,
11550aadb33SDmitri Tikhonov        fc->cf_read_off - incr, fc->cf_read_off);
11650aadb33SDmitri Tikhonov}
117