lsquic_sfcw.c revision 7d09751d
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <inttypes.h> 3#include <stdint.h> 4#include <stdlib.h> 5#include <string.h> 6#include <sys/queue.h> 7 8#include "lsquic.h" 9#include "lsquic_int_types.h" 10#include "lsquic_conn_flow.h" 11#include "lsquic_types.h" 12#include "lsquic_rtt.h" 13#include "lsquic_varint.h" 14#include "lsquic_sfcw.h" 15#include "lsquic_varint.h" 16#include "lsquic_hq.h" 17#include "lsquic_hash.h" 18#include "lsquic_stream.h" 19#include "lsquic_conn_public.h" 20#include "lsquic_mm.h" 21#include "lsquic_engine_public.h" 22#include "lsquic_util.h" 23#include "lsquic_conn.h" 24#include "lsquic_ev_log.h" 25 26#define LSQUIC_LOGGER_MODULE LSQLM_SFCW 27#define LSQUIC_LOG_CONN_ID lsquic_conn_log_cid(fc->sf_conn_pub->lconn) 28#define LSQUIC_LOG_STREAM_ID fc->sf_stream_id 29#include "lsquic_logger.h" 30 31void 32lsquic_sfcw_init (struct lsquic_sfcw *fc, unsigned max_recv_window, 33 struct lsquic_cfcw *cfcw, struct lsquic_conn_public *cpub, 34 lsquic_stream_id_t stream_id) 35{ 36 memset(fc, 0, sizeof(*fc)); 37 fc->sf_max_recv_win = max_recv_window; 38 fc->sf_cfcw = cfcw; 39 fc->sf_conn_pub = cpub; 40 fc->sf_stream_id = stream_id; 41 (void) lsquic_sfcw_fc_offsets_changed(fc); 42} 43 44 45static void 46sfcw_maybe_increase_max_window (struct lsquic_sfcw *fc) 47{ 48 unsigned new_max_window, max_conn_window; 49 50 new_max_window = fc->sf_max_recv_win * 2; 51 52 /* Do not increase past explicitly specified maximum */ 53 if (new_max_window > fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw) 54 new_max_window = fc->sf_conn_pub->enpub->enp_settings.es_max_sfcw; 55 56 if (fc->sf_cfcw) 57 { 58 /* Do not increase past the connection's maximum window size. The 59 * connection's window will be increased separately, if possible. 60 * 61 * The reference implementation has the logic backwards: Imagine 62 * several concurrent streams that are not being read from fast 63 * enough by the user code. Each of them uses only a fraction 64 * of bandwidth. Does it mean that the connection window must 65 * increase? No. 66 */ 67 max_conn_window = lsquic_cfcw_get_max_recv_window(fc->sf_cfcw); 68 if (new_max_window > max_conn_window) 69 new_max_window = max_conn_window; 70 } 71 else 72 { 73 /* This means that this stream is not affected by connection flow 74 * controller. No need to adjust under connection window. 75 */ 76 } 77 78 if (new_max_window > fc->sf_max_recv_win) 79 { 80 LSQ_DEBUG("max window increase %u -> %u", 81 fc->sf_max_recv_win, new_max_window); 82 EV_LOG_CONN_EVENT(LSQUIC_LOG_CONN_ID, 83 "max SFCW increase %u -> %u", fc->sf_max_recv_win, 84 new_max_window); 85 fc->sf_max_recv_win = new_max_window; 86 } 87 else 88 LSQ_DEBUG("max window could use an increase, but we're stuck " 89 "at %u", fc->sf_max_recv_win); 90} 91 92 93int 94lsquic_sfcw_fc_offsets_changed (struct lsquic_sfcw *fc) 95{ 96 lsquic_time_t since_last_update, srtt, now; 97 98 if (fc->sf_recv_off - fc->sf_read_off >= fc->sf_max_recv_win / 2) 99 { 100 LSQ_DEBUG("recv_off has not changed, still at %"PRIu64, 101 fc->sf_recv_off); 102 return 0; 103 } 104 105 now = lsquic_time_now(); 106 since_last_update = now - fc->sf_last_updated; 107 fc->sf_last_updated = now; 108 109 srtt = lsquic_rtt_stats_get_srtt(&fc->sf_conn_pub->rtt_stats); 110 if (since_last_update < srtt * 2) 111 sfcw_maybe_increase_max_window(fc); 112 113 fc->sf_recv_off = fc->sf_read_off + fc->sf_max_recv_win; 114 LSQ_DEBUG("recv_off changed: read_off: %"PRIu64"; " 115 "recv_off: %"PRIu64, fc->sf_read_off, fc->sf_recv_off); 116 return 1; 117} 118 119 120int 121lsquic_sfcw_set_max_recv_off (struct lsquic_sfcw *fc, uint64_t max_recv_off) 122{ 123 if (max_recv_off <= fc->sf_recv_off) 124 { 125 if (!fc->sf_cfcw || lsquic_cfcw_incr_max_recv_off(fc->sf_cfcw, 126 max_recv_off - fc->sf_max_recv_off)) 127 { 128 LSQ_DEBUG("max_recv_off goes from %"PRIu64" to %"PRIu64, 129 fc->sf_max_recv_off, max_recv_off); 130 fc->sf_max_recv_off = max_recv_off; 131 return 1; 132 } 133 else 134 { 135 /* cfcw prints its own warning */ 136 return 0; 137 } 138 } 139 else 140 { 141 LSQ_WARN("flow control violation: received at offset %"PRIu64", " 142 "while flow control receive offset is %"PRIu64, 143 max_recv_off, fc->sf_recv_off); 144 return 0; 145 } 146} 147 148 149void 150lsquic_sfcw_set_read_off (struct lsquic_sfcw *fc, uint64_t off) 151{ 152 if (fc->sf_cfcw) 153 lsquic_cfcw_incr_read_off(fc->sf_cfcw, off - fc->sf_read_off); 154 LSQ_DEBUG("read_off goes from %"PRIu64" to %"PRIu64, 155 fc->sf_read_off, off); 156 fc->sf_read_off = off; 157} 158