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_int_types.h" 1050aadb33SDmitri Tikhonov#include "lsquic_conn_flow.h" 1150aadb33SDmitri Tikhonov#include "lsquic_types.h" 1250aadb33SDmitri Tikhonov#include "lsquic_rtt.h" 135392f7a3SLiteSpeed Tech#include "lsquic_varint.h" 1450aadb33SDmitri Tikhonov#include "lsquic_sfcw.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_SFCW 265392f7a3SLiteSpeed Tech#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(fc->sf_conn_pub->lconn) 2750aadb33SDmitri Tikhonov#define LSQUIC_LOG_STREAM_ID fc->sf_stream_id 2850aadb33SDmitri Tikhonov#include "lsquic_logger.h" 2950aadb33SDmitri Tikhonov 3050aadb33SDmitri Tikhonovvoid 3150aadb33SDmitri Tikhonovlsquic_sfcw_init (struct lsquic_sfcw *fc, unsigned max_recv_window, 3250aadb33SDmitri Tikhonov struct lsquic_cfcw *cfcw, struct lsquic_conn_public *cpub, 335392f7a3SLiteSpeed Tech lsquic_stream_id_t stream_id) 3450aadb33SDmitri Tikhonov{ 3550aadb33SDmitri Tikhonov memset(fc, 0, sizeof(*fc)); 3650aadb33SDmitri Tikhonov fc->sf_max_recv_win = max_recv_window; 3750aadb33SDmitri Tikhonov fc->sf_cfcw = cfcw; 3850aadb33SDmitri Tikhonov fc->sf_conn_pub = cpub; 3950aadb33SDmitri Tikhonov fc->sf_stream_id = stream_id; 4050aadb33SDmitri Tikhonov (void) lsquic_sfcw_fc_offsets_changed(fc); 4150aadb33SDmitri Tikhonov} 4250aadb33SDmitri Tikhonov 4350aadb33SDmitri Tikhonov 4450aadb33SDmitri Tikhonovstatic void 4550aadb33SDmitri Tikhonovsfcw_maybe_increase_max_window (struct lsquic_sfcw *fc) 4650aadb33SDmitri Tikhonov{ 4750aadb33SDmitri Tikhonov unsigned new_max_window, max_conn_window; 4850aadb33SDmitri Tikhonov 4950aadb33SDmitri Tikhonov new_max_window = fc->sf_max_recv_win * 2; 5050aadb33SDmitri Tikhonov 5150aadb33SDmitri Tikhonov /* Do not increase past explicitly specified maximum */ 5250aadb33SDmitri Tikhonov if (new_max_window > fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw) 5350aadb33SDmitri Tikhonov new_max_window = fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw; 5450aadb33SDmitri Tikhonov 550ae3fccdSDmitri Tikhonov if (fc->sf_cfcw) 560ae3fccdSDmitri Tikhonov { 570ae3fccdSDmitri Tikhonov /* Do not increase past the connection's maximum window size. The 580ae3fccdSDmitri Tikhonov * connection's window will be increased separately, if possible. 590ae3fccdSDmitri Tikhonov * 600ae3fccdSDmitri Tikhonov * The reference implementation has the logic backwards: Imagine 610ae3fccdSDmitri Tikhonov * several concurrent streams that are not being read from fast 620ae3fccdSDmitri Tikhonov * enough by the user code. Each of them uses only a fraction 630ae3fccdSDmitri Tikhonov * of bandwidth. Does it mean that the connection window must 640ae3fccdSDmitri Tikhonov * increase? No. 650ae3fccdSDmitri Tikhonov */ 660ae3fccdSDmitri Tikhonov max_conn_window = lsquic_cfcw_get_max_recv_window(fc->sf_cfcw); 670ae3fccdSDmitri Tikhonov if (new_max_window > max_conn_window) 680ae3fccdSDmitri Tikhonov new_max_window = max_conn_window; 690ae3fccdSDmitri Tikhonov } 700ae3fccdSDmitri Tikhonov else 710ae3fccdSDmitri Tikhonov { 720ae3fccdSDmitri Tikhonov /* This means that this stream is not affected by connection flow 730ae3fccdSDmitri Tikhonov * controller. No need to adjust under connection window. 740ae3fccdSDmitri Tikhonov */ 750ae3fccdSDmitri Tikhonov } 7650aadb33SDmitri Tikhonov 7750aadb33SDmitri Tikhonov if (new_max_window > fc->sf_max_recv_win) 7850aadb33SDmitri Tikhonov { 7950aadb33SDmitri Tikhonov LSQ_DEBUG("max window increase %u -> %u", 8050aadb33SDmitri Tikhonov fc->sf_max_recv_win, new_max_window); 8150aadb33SDmitri Tikhonov EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, 8250aadb33SDmitri Tikhonov "max SFCW increase %u -> %u", fc->sf_max_recv_win, 8350aadb33SDmitri Tikhonov new_max_window); 8450aadb33SDmitri Tikhonov fc->sf_max_recv_win = new_max_window; 8550aadb33SDmitri Tikhonov } 8650aadb33SDmitri Tikhonov else 8750aadb33SDmitri Tikhonov LSQ_DEBUG("max window could use an increase, but we're stuck " 8850aadb33SDmitri Tikhonov "at %u", fc->sf_max_recv_win); 8950aadb33SDmitri Tikhonov} 9050aadb33SDmitri Tikhonov 9150aadb33SDmitri Tikhonov 9250aadb33SDmitri Tikhonovint 9350aadb33SDmitri Tikhonovlsquic_sfcw_fc_offsets_changed (struct lsquic_sfcw *fc) 9450aadb33SDmitri Tikhonov{ 9550aadb33SDmitri Tikhonov lsquic_time_t since_last_update, srtt, now; 9650aadb33SDmitri Tikhonov 9750aadb33SDmitri Tikhonov if (fc->sf_recv_off - fc->sf_read_off >= fc->sf_max_recv_win / 2) 9850aadb33SDmitri Tikhonov { 9950aadb33SDmitri Tikhonov LSQ_DEBUG("recv_off has not changed, still at %"PRIu64, 10050aadb33SDmitri Tikhonov fc->sf_recv_off); 10150aadb33SDmitri Tikhonov return 0; 10250aadb33SDmitri Tikhonov } 10350aadb33SDmitri Tikhonov 10450aadb33SDmitri Tikhonov now = lsquic_time_now(); 10550aadb33SDmitri Tikhonov since_last_update = now - fc->sf_last_updated; 10650aadb33SDmitri Tikhonov fc->sf_last_updated = now; 10750aadb33SDmitri Tikhonov 10850aadb33SDmitri Tikhonov srtt = lsquic_rtt_stats_get_srtt(&fc->sf_conn_pub->rtt_stats); 10950aadb33SDmitri Tikhonov if (since_last_update < srtt * 2) 11050aadb33SDmitri Tikhonov sfcw_maybe_increase_max_window(fc); 11150aadb33SDmitri Tikhonov 11250aadb33SDmitri Tikhonov fc->sf_recv_off = fc->sf_read_off + fc->sf_max_recv_win; 11350aadb33SDmitri Tikhonov LSQ_DEBUG("recv_off changed: read_off: %"PRIu64"; " 11450aadb33SDmitri Tikhonov "recv_off: %"PRIu64, fc->sf_read_off, fc->sf_recv_off); 11550aadb33SDmitri Tikhonov return 1; 11650aadb33SDmitri Tikhonov} 11750aadb33SDmitri Tikhonov 11850aadb33SDmitri Tikhonov 11950aadb33SDmitri Tikhonovint 12050aadb33SDmitri Tikhonovlsquic_sfcw_set_max_recv_off (struct lsquic_sfcw *fc, uint64_t max_recv_off) 12150aadb33SDmitri Tikhonov{ 12250aadb33SDmitri Tikhonov if (max_recv_off <= fc->sf_recv_off) 12350aadb33SDmitri Tikhonov { 12450aadb33SDmitri Tikhonov if (!fc->sf_cfcw || lsquic_cfcw_incr_max_recv_off(fc->sf_cfcw, 12550aadb33SDmitri Tikhonov max_recv_off - fc->sf_max_recv_off)) 12650aadb33SDmitri Tikhonov { 12750aadb33SDmitri Tikhonov LSQ_DEBUG("max_recv_off goes from %"PRIu64" to %"PRIu64, 12850aadb33SDmitri Tikhonov fc->sf_max_recv_off, max_recv_off); 12950aadb33SDmitri Tikhonov fc->sf_max_recv_off = max_recv_off; 13050aadb33SDmitri Tikhonov return 1; 13150aadb33SDmitri Tikhonov } 13250aadb33SDmitri Tikhonov else 13350aadb33SDmitri Tikhonov { 13450aadb33SDmitri Tikhonov /* cfcw prints its own warning */ 13550aadb33SDmitri Tikhonov return 0; 13650aadb33SDmitri Tikhonov } 13750aadb33SDmitri Tikhonov } 13850aadb33SDmitri Tikhonov else 13950aadb33SDmitri Tikhonov { 1408ae5ecb4SDmitri Tikhonov LSQ_INFO("flow control violation: received at offset %"PRIu64", " 14150aadb33SDmitri Tikhonov "while flow control receive offset is %"PRIu64, 14250aadb33SDmitri Tikhonov max_recv_off, fc->sf_recv_off); 14350aadb33SDmitri Tikhonov return 0; 14450aadb33SDmitri Tikhonov } 14550aadb33SDmitri Tikhonov} 14650aadb33SDmitri Tikhonov 14750aadb33SDmitri Tikhonov 14850aadb33SDmitri Tikhonovvoid 14950aadb33SDmitri Tikhonovlsquic_sfcw_set_read_off (struct lsquic_sfcw *fc, uint64_t off) 15050aadb33SDmitri Tikhonov{ 15150aadb33SDmitri Tikhonov if (fc->sf_cfcw) 15250aadb33SDmitri Tikhonov lsquic_cfcw_incr_read_off(fc->sf_cfcw, off - fc->sf_read_off); 15350aadb33SDmitri Tikhonov LSQ_DEBUG("read_off goes from %"PRIu64" to %"PRIu64, 15450aadb33SDmitri Tikhonov fc->sf_read_off, off); 15550aadb33SDmitri Tikhonov fc->sf_read_off = off; 15650aadb33SDmitri Tikhonov} 157