Network System 0.1.1
High-performance modular networking library for scalable client-server applications
Loading...
Searching...
No Matches
flow_control.cpp
Go to the documentation of this file.
1// BSD 3-Clause License
2// Copyright (c) 2024, 🍀☀🌕🌥 🌊
3// See the LICENSE file in the project root for full license information.
4
6
7#include <algorithm>
8
10{
11
12flow_controller::flow_controller(uint64_t initial_window)
13 : send_limit_{initial_window}
14 , receive_limit_{initial_window}
15 , window_size_{initial_window}
16 , last_sent_max_data_{initial_window}
17{
18}
19
20// ============================================================================
21// Send Side
22// ============================================================================
23
24auto flow_controller::available_send_window() const noexcept -> uint64_t
25{
26 if (bytes_sent_ >= send_limit_) {
27 return 0;
28 }
29 return send_limit_ - bytes_sent_;
30}
31
33{
34 if (bytes == 0) {
35 return ok();
36 }
37
38 const uint64_t available = available_send_window();
39 if (bytes > available) {
41 "Send window exhausted",
42 "quic::flow_controller");
43 }
44
45 bytes_sent_ += bytes;
46 data_blocked_sent_ = false; // Reset blocked flag on successful send
47 return ok();
48}
49
51{
52 // Only update if new limit is higher (MAX_DATA can only increase)
53 if (max_data > send_limit_) {
55 data_blocked_sent_ = false; // Can send again, reset blocked flag
56 }
57}
58
59auto flow_controller::is_send_blocked() const noexcept -> bool
60{
61 return bytes_sent_ >= send_limit_;
62}
63
64// ============================================================================
65// Receive Side
66// ============================================================================
67
69{
70 if (bytes == 0) {
71 return ok();
72 }
73
74 const uint64_t new_total = bytes_received_ + bytes;
75 if (new_total > receive_limit_) {
77 "Received data exceeds flow control limit",
78 "quic::flow_controller");
79 }
80
81 bytes_received_ = new_total;
82 return ok();
83}
84
86{
87 bytes_consumed_ += bytes;
88 // Consumed cannot exceed received
91 }
92}
93
94// ============================================================================
95// Flow Control Frame Generation
96// ============================================================================
97
98auto flow_controller::should_send_max_data() const noexcept -> bool
99{
100 // Send MAX_DATA when we've consumed enough of the window
101 const uint64_t threshold = static_cast<uint64_t>(window_size_ * update_threshold_);
102
103 // Calculate how much of the advertised window has been consumed
104 const uint64_t consumed_from_last = bytes_consumed_ - (last_sent_max_data_ - window_size_);
105
106 return consumed_from_last >= threshold;
107}
108
109auto flow_controller::generate_max_data() -> std::optional<uint64_t>
110{
111 if (!should_send_max_data()) {
112 return std::nullopt;
113 }
114
115 // New limit is current consumption point plus window size
116 const uint64_t new_limit = bytes_consumed_ + window_size_;
117
118 // Only send if it's an increase
119 if (new_limit <= last_sent_max_data_) {
120 return std::nullopt;
121 }
122
123 receive_limit_ = new_limit;
124 last_sent_max_data_ = new_limit;
125 return new_limit;
126}
127
128auto flow_controller::should_send_data_blocked() const noexcept -> bool
129{
131}
132
137
138// ============================================================================
139// Configuration
140// ============================================================================
141
143{
144 window_size_ = window;
145}
146
148{
149 update_threshold_ = std::clamp(threshold, 0.0, 1.0);
150}
151
152// ============================================================================
153// Reset
154// ============================================================================
155
156void flow_controller::reset(uint64_t initial_window)
157{
158 send_limit_ = initial_window;
159 bytes_sent_ = 0;
160 data_blocked_sent_ = false;
161
162 receive_limit_ = initial_window;
163 bytes_received_ = 0;
164 bytes_consumed_ = 0;
165
166 window_size_ = initial_window;
167 last_sent_max_data_ = initial_window;
168}
169
170// ============================================================================
171// Statistics
172// ============================================================================
173
175{
176 flow_control_stats stats;
177
178 // Send side
179 stats.send_limit = fc.send_limit();
180 stats.bytes_sent = fc.bytes_sent();
181 stats.send_window_available = fc.available_send_window();
182 stats.send_blocked = fc.is_send_blocked();
183
184 // Receive side
185 stats.receive_limit = fc.receive_limit();
186 stats.bytes_received = fc.bytes_received();
187 stats.bytes_consumed = fc.bytes_consumed();
188 stats.receive_window_available = fc.receive_limit() - fc.bytes_received();
189
190 return stats;
191}
192
193} // namespace kcenon::network::protocols::quic
Connection-level flow control for QUIC (RFC 9000 Section 4)
auto should_send_max_data() const noexcept -> bool
Check if MAX_DATA frame should be sent.
void update_send_limit(uint64_t max_data)
Update the send limit (from peer's MAX_DATA)
auto record_received(uint64_t bytes) -> VoidResult
Record received data.
flow_controller(uint64_t initial_window=1048576)
Construct a flow controller.
auto is_send_blocked() const noexcept -> bool
Check if send is blocked.
void record_consumed(uint64_t bytes)
Record data consumed by application.
auto available_send_window() const noexcept -> uint64_t
Get available send window.
auto should_send_data_blocked() const noexcept -> bool
Check if DATA_BLOCKED frame should be sent.
void mark_data_blocked_sent()
Mark DATA_BLOCKED as sent (to avoid repeated sending)
auto consume_send_window(uint64_t bytes) -> VoidResult
Try to consume send window for outgoing data.
void reset(uint64_t initial_window)
Reset flow controller state.
void set_update_threshold(double threshold)
Set the threshold for sending MAX_DATA updates (0.0 - 1.0)
auto generate_max_data() -> std::optional< uint64_t >
Generate MAX_DATA value if update needed.
void set_window_size(uint64_t window)
Set the window size for auto-tuning.
auto get_flow_control_stats(const flow_controller &fc) -> flow_control_stats
Get flow control statistics.
VoidResult error_void(int code, const std::string &message, const std::string &source="network_system", const std::string &details="")
VoidResult ok()
Statistics for flow control monitoring.