]>
Commit | Line | Data |
---|---|---|
508e087c | 1 | /* |
da1c088f | 2 | * Copyright 2022-2023 The OpenSSL Project Authors. All Rights Reserved. |
508e087c HL |
3 | * |
4 | * Licensed under the Apache License 2.0 (the "License"). You may not use | |
5 | * this file except in compliance with the License. You can obtain a copy | |
6 | * in the file LICENSE in the source distribution or at | |
7 | * https://www.openssl.org/source/license.html | |
8 | */ | |
9 | ||
10 | #ifndef OSSL_QUIC_FC_H | |
11 | # define OSSL_QUIC_FC_H | |
12 | ||
13 | # include <openssl/ssl.h> | |
14 | # include "internal/time.h" | |
15 | ||
6292519c HL |
16 | # ifndef OPENSSL_NO_QUIC |
17 | ||
508e087c HL |
18 | /* |
19 | * TX Flow Controller (TXFC) | |
20 | * ========================= | |
21 | * | |
22 | * For discussion, see doc/designs/quic-design/quic-fc.md. | |
23 | */ | |
24 | typedef struct quic_txfc_st QUIC_TXFC; | |
25 | ||
26 | struct quic_txfc_st { | |
27 | QUIC_TXFC *parent; /* stream-level iff non-NULL */ | |
28 | uint64_t swm, cwm; | |
29 | char has_become_blocked; | |
30 | }; | |
31 | ||
32 | /* | |
33 | * Initialises a TX flow controller. conn_txfc should be non-NULL and point to | |
34 | * the connection-level flow controller if the TXFC is for stream-level flow | |
35 | * control, and NULL otherwise. | |
36 | */ | |
37 | int ossl_quic_txfc_init(QUIC_TXFC *txfc, QUIC_TXFC *conn_txfc); | |
38 | ||
39 | /* | |
40 | * Gets the parent (i.e., connection-level) TX flow controller. Returns NULL if | |
41 | * called on a connection-level TX flow controller. | |
42 | */ | |
43 | QUIC_TXFC *ossl_quic_txfc_get_parent(QUIC_TXFC *txfc); | |
44 | ||
45 | /* | |
46 | * Bump the credit watermark (CWM) value. This is the 'On TX Window Updated' | |
47 | * operation. This function is a no-op if it has already been called with an | |
48 | * equal or higher CWM value. | |
49 | * | |
50 | * It returns 1 iff the call resulted in the CWM being bumped and 0 if it was | |
51 | * not increased because it has already been called with an equal or higher CWM | |
52 | * value. This is not an error per se but may indicate a local programming error | |
53 | * or a protocol error in a remote peer. | |
54 | */ | |
55 | int ossl_quic_txfc_bump_cwm(QUIC_TXFC *txfc, uint64_t cwm); | |
56 | ||
57 | /* | |
58 | * Get the number of bytes by which we are in credit. This is the number of | |
59 | * controlled bytes we are allowed to send. (Thus if this function returns 0, we | |
60 | * are currently blocked.) | |
61 | * | |
62 | * If called on a stream-level TXFC, ossl_quic_txfc_get_credit is called on | |
63 | * the connection-level TXFC as well, and the lesser of the two values is | |
64 | * returned. | |
65 | */ | |
66 | uint64_t ossl_quic_txfc_get_credit(QUIC_TXFC *txfc); | |
67 | ||
68 | /* | |
69 | * Like ossl_quic_txfc_get_credit(), but when called on a stream-level TXFC, | |
70 | * retrieves only the stream-level credit value and does not clamp it based on | |
71 | * connection-level flow control. | |
72 | */ | |
73 | uint64_t ossl_quic_txfc_get_credit_local(QUIC_TXFC *txfc); | |
74 | ||
75 | /* | |
76 | * Consume num_bytes of credit. This is the 'On TX' operation. This should be | |
77 | * called when we transmit any controlled bytes. Calling this with an argument | |
78 | * of 0 is a no-op. | |
79 | * | |
80 | * We must never transmit more controlled bytes than we are in credit for (see | |
81 | * the return value of ossl_quic_txfc_get_credit()). If you call this function | |
82 | * with num_bytes greater than our current credit, this function consumes the | |
83 | * remainder of the credit and returns 0. This indicates a serious programming | |
84 | * error on the caller's part. Otherwise, the function returns 1. | |
85 | * | |
86 | * If called on a stream-level TXFC, ossl_quic_txfc_consume_credit() is called | |
87 | * on the connection-level TXFC also. If the call to that function on the | |
88 | * connection-level TXFC returns zero, this function will also return zero. | |
89 | */ | |
90 | int ossl_quic_txfc_consume_credit(QUIC_TXFC *txfc, uint64_t num_bytes); | |
91 | ||
92 | /* | |
93 | * Like ossl_quic_txfc_consume_credit(), but when called on a stream-level TXFC, | |
94 | * consumes only from the stream-level credit and does not inform the | |
95 | * connection-level TXFC. | |
96 | */ | |
97 | int ossl_quic_txfc_consume_credit_local(QUIC_TXFC *txfc, uint64_t num_bytes); | |
98 | ||
99 | /* | |
100 | * This flag is provided for convenience. A caller is not required to use it. It | |
101 | * is a boolean flag set whenever our credit drops to zero. If clear is 1, the | |
102 | * flag is cleared. The old value of the flag is returned. Callers may use this | |
103 | * to determine if they need to send a DATA_BLOCKED or STREAM_DATA_BLOCKED | |
104 | * frame, which should contain the value returned by ossl_quic_txfc_get_cwm(). | |
105 | */ | |
106 | int ossl_quic_txfc_has_become_blocked(QUIC_TXFC *txfc, int clear); | |
107 | ||
108 | /* | |
109 | * Get the current CWM value. This is mainly only needed when generating a | |
110 | * DATA_BLOCKED or STREAM_DATA_BLOCKED frame, or for diagnostic purposes. | |
111 | */ | |
112 | uint64_t ossl_quic_txfc_get_cwm(QUIC_TXFC *txfc); | |
113 | ||
114 | /* | |
115 | * Get the current spent watermark (SWM) value. This is purely for diagnostic | |
116 | * use and should not be needed in normal circumstances. | |
117 | */ | |
118 | uint64_t ossl_quic_txfc_get_swm(QUIC_TXFC *txfc); | |
119 | ||
120 | /* | |
121 | * RX Flow Controller (RXFC) | |
122 | * ========================= | |
123 | */ | |
124 | typedef struct quic_rxfc_st QUIC_RXFC; | |
125 | ||
126 | struct quic_rxfc_st { | |
127 | /* | |
128 | * swm is the sent/received watermark, which tracks how much we have | |
129 | * received from the peer. rwm is the retired watermark, which tracks how | |
130 | * much has been passed to the application. esrwm is the rwm value at which | |
131 | * the current auto-tuning epoch started. hwm is the highest stream length | |
132 | * (STREAM frame offset + payload length) we have seen from a STREAM frame | |
133 | * yet. | |
134 | */ | |
135 | uint64_t cwm, swm, rwm, esrwm, hwm, cur_window_size, max_window_size; | |
136 | OSSL_TIME epoch_start; | |
137 | OSSL_TIME (*now)(void *arg); | |
138 | void *now_arg; | |
139 | QUIC_RXFC *parent; | |
1051b4a0 | 140 | unsigned char error_code, has_cwm_changed, is_fin, standalone; |
508e087c HL |
141 | }; |
142 | ||
143 | /* | |
144 | * Initialises an RX flow controller. conn_rxfc should be non-NULL and point to | |
145 | * a connection-level RXFC if the RXFC is for stream-level flow control, and | |
146 | * NULL otherwise. initial_window_size and max_window_size specify the initial | |
147 | * and absolute maximum window sizes, respectively. Window size values are | |
148 | * expressed in bytes and determine how much credit the RXFC extends to the peer | |
149 | * to transmit more data at a time. | |
150 | */ | |
151 | int ossl_quic_rxfc_init(QUIC_RXFC *rxfc, QUIC_RXFC *conn_rxfc, | |
152 | uint64_t initial_window_size, | |
153 | uint64_t max_window_size, | |
154 | OSSL_TIME (*now)(void *arg), | |
155 | void *now_arg); | |
156 | ||
5bd9ddd8 | 157 | /* |
1051b4a0 HL |
158 | * Initialises an RX flow controller which is used by itself and not under a |
159 | * connection-level RX flow controller. This can be used for stream count | |
160 | * enforcement as well as CRYPTO buffer enforcement. | |
5bd9ddd8 | 161 | */ |
1051b4a0 HL |
162 | int ossl_quic_rxfc_init_standalone(QUIC_RXFC *rxfc, |
163 | uint64_t initial_window_size, | |
164 | OSSL_TIME (*now)(void *arg), | |
165 | void *now_arg); | |
5bd9ddd8 | 166 | |
508e087c HL |
167 | /* |
168 | * Gets the parent (i.e., connection-level) RXFC. Returns NULL if called on a | |
169 | * connection-level RXFC. | |
170 | */ | |
171 | QUIC_RXFC *ossl_quic_rxfc_get_parent(QUIC_RXFC *rxfc); | |
172 | ||
173 | /* | |
174 | * Changes the current maximum window size value. | |
175 | */ | |
176 | void ossl_quic_rxfc_set_max_window_size(QUIC_RXFC *rxfc, | |
177 | size_t max_window_size); | |
178 | ||
179 | /* | |
180 | * To be called whenever a STREAM frame is received. | |
181 | * | |
182 | * end is the value (offset + len), where offset is the offset field of the | |
183 | * STREAM frame and len is the length of the STREAM frame's payload in bytes. | |
184 | * | |
185 | * is_fin should be 1 if the STREAM frame had the FIN flag set and 0 otherwise. | |
186 | * | |
a73078b7 HL |
187 | * This function may be used on a stream-level RXFC only. The connection-level |
188 | * RXFC will have its state updated by the stream-level RXFC. | |
508e087c HL |
189 | * |
190 | * You should check ossl_quic_rxfc_has_error() on both connection-level and | |
191 | * stream-level RXFCs after calling this function, as an incoming STREAM frame | |
192 | * may cause flow control limits to be exceeded by an errant peer. This | |
193 | * function still returns 1 in this case, as this is not a caller error. | |
194 | * | |
195 | * Returns 1 on success or 0 on failure. | |
196 | */ | |
197 | int ossl_quic_rxfc_on_rx_stream_frame(QUIC_RXFC *rxfc, | |
198 | uint64_t end, int is_fin); | |
199 | ||
200 | /* | |
201 | * To be called whenever controlled bytes are retired, i.e. when bytes are | |
202 | * dequeued from a QUIC stream and passed to the application. num_bytes | |
203 | * is the number of bytes which were passed to the application. | |
204 | * | |
205 | * You should call this only on a stream-level RXFC. This function will update | |
206 | * the connection-level RXFC automatically. | |
207 | * | |
208 | * rtt should be the current best understanding of the RTT to the peer, as | |
209 | * offered by the Statistics Manager. | |
210 | * | |
211 | * You should check ossl_quic_rxfc_has_cwm_changed() after calling this | |
212 | * function, as it may have caused the RXFC to decide to grant more flow control | |
213 | * credit to the peer. | |
214 | * | |
215 | * Returns 1 on success and 0 on failure. | |
216 | */ | |
217 | int ossl_quic_rxfc_on_retire(QUIC_RXFC *rxfc, | |
218 | uint64_t num_bytes, | |
219 | OSSL_TIME rtt); | |
220 | ||
221 | /* | |
222 | * Returns the current CWM which the RXFC thinks the peer should have. | |
223 | * | |
224 | * Note that the RXFC will increase this value in response to events, at which | |
225 | * time a MAX_DATA or MAX_STREAM_DATA frame must be generated. Use | |
226 | * ossl_quic_rxfc_has_cwm_changed() to detect this condition. | |
227 | * | |
228 | * This value increases monotonically. | |
229 | */ | |
230 | uint64_t ossl_quic_rxfc_get_cwm(QUIC_RXFC *rxfc); | |
231 | ||
232 | /* | |
233 | * Returns the current SWM. This is the total number of bytes the peer has | |
234 | * transmitted to us. This is intended for diagnostic use only; you should | |
235 | * not need it. | |
236 | */ | |
237 | uint64_t ossl_quic_rxfc_get_swm(QUIC_RXFC *rxfc); | |
238 | ||
239 | /* | |
240 | * Returns the current RWM. This is the total number of bytes that has been | |
241 | * retired. This is intended for diagnostic use only; you should not need it. | |
242 | */ | |
243 | uint64_t ossl_quic_rxfc_get_rwm(QUIC_RXFC *rxfc); | |
244 | ||
245 | /* | |
246 | * Returns the CWM changed flag. If clear is 1, the flag is cleared and the old | |
247 | * value is returned. | |
248 | */ | |
249 | int ossl_quic_rxfc_has_cwm_changed(QUIC_RXFC *rxfc, int clear); | |
250 | ||
251 | /* | |
252 | * Returns a QUIC_ERR_* error code if a flow control error has been detected. | |
253 | * Otherwise, returns QUIC_ERR_NO_ERROR. If clear is 1, the error is cleared | |
254 | * and the old value is returned. | |
255 | * | |
256 | * May return one of the following values: | |
257 | * | |
258 | * QUIC_ERR_FLOW_CONTROL_ERROR: | |
259 | * This indicates a flow control protocol violation by the remote peer; the | |
260 | * connection should be terminated in this event. | |
261 | * QUIC_ERR_FINAL_SIZE: | |
262 | * The peer attempted to change the stream length after ending the stream. | |
263 | */ | |
264 | int ossl_quic_rxfc_get_error(QUIC_RXFC *rxfc, int clear); | |
265 | ||
418e122c HL |
266 | /* |
267 | * Returns 1 if the RXFC is a stream-level RXFC and the RXFC knows the final | |
268 | * size for the stream in bytes. If this is the case and final_size is non-NULL, | |
269 | * writes the final size to *final_size. Otherwise, returns 0. | |
270 | */ | |
271 | int ossl_quic_rxfc_get_final_size(const QUIC_RXFC *rxfc, uint64_t *final_size); | |
272 | ||
6292519c HL |
273 | # endif |
274 | ||
508e087c | 275 | #endif |