]> git.ipfire.org Git - thirdparty/openssl.git/blob - test/quic_fc_test.c
QUIC Flow Control
[thirdparty/openssl.git] / test / quic_fc_test.c
1 /*
2 * Copyright 2022 The OpenSSL Project Authors. All Rights Reserved.
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 #include "internal/quic_fc.h"
11 #include "internal/quic_error.h"
12 #include "testutil.h"
13
14 static int test_txfc(int is_stream)
15 {
16 int testresult = 0;
17 QUIC_TXFC conn_txfc, stream_txfc, *txfc, *parent_txfc;
18
19 if (!TEST_true(ossl_quic_txfc_init(&conn_txfc, 0)))
20 goto err;
21
22 if (is_stream && !TEST_true(ossl_quic_txfc_init(&stream_txfc, &conn_txfc)))
23 goto err;
24
25 txfc = is_stream ? &stream_txfc : &conn_txfc;
26 parent_txfc = is_stream ? &conn_txfc : NULL;
27
28 if (!TEST_true(ossl_quic_txfc_bump_cwm(txfc, 2000)))
29 goto err;
30
31 if (is_stream && !TEST_true(ossl_quic_txfc_bump_cwm(parent_txfc, 2000)))
32 goto err;
33
34 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 0))
35 goto err;
36
37 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_cwm(txfc), 2000))
38 goto err;
39
40 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 2000))
41 goto err;
42
43 if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
44 2000))
45 goto err;
46
47 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
48 goto err;
49
50 if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 500)))
51 goto err;
52
53 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 1500))
54 goto err;
55
56 if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
57 1500))
58 goto err;
59
60 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
61 goto err;
62
63 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 500))
64 goto err;
65
66 if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 100)))
67 goto err;
68
69 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 600))
70 goto err;
71
72 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 1400))
73 goto err;
74
75 if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
76 1400))
77 goto err;
78
79 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
80 goto err;
81
82 if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 1400)))
83 goto err;
84
85 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 0))
86 goto err;
87
88 if (is_stream && !TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc),
89 0))
90 goto err;
91
92 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 2000))
93 goto err;
94
95 if (!TEST_true(ossl_quic_txfc_has_become_blocked(txfc, 0)))
96 goto err;
97
98 if (!TEST_true(ossl_quic_txfc_has_become_blocked(txfc, 0)))
99 goto err;
100
101 if (!TEST_true(ossl_quic_txfc_has_become_blocked(txfc, 1)))
102 goto err;
103
104 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
105 goto err;
106
107 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
108 goto err;
109
110 if (!TEST_false(ossl_quic_txfc_consume_credit(txfc, 1)))
111 goto err;
112
113 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_cwm(txfc), 2000))
114 goto err;
115
116 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 2000))
117 goto err;
118
119 if (!TEST_false(ossl_quic_txfc_bump_cwm(txfc, 2000)))
120 goto err;
121
122 if (!TEST_true(ossl_quic_txfc_bump_cwm(txfc, 2500)))
123 goto err;
124
125 if (is_stream && !TEST_true(ossl_quic_txfc_bump_cwm(parent_txfc, 2400)))
126 goto err;
127
128 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_cwm(txfc), 2500))
129 goto err;
130
131 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_swm(txfc), 2000))
132 goto err;
133
134 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit_local(txfc), 500))
135 goto err;
136
137 if (is_stream)
138 ossl_quic_txfc_has_become_blocked(parent_txfc, 1);
139
140 if (is_stream) {
141 if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 399)))
142 goto err;
143
144 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
145 goto err;
146
147 if (!TEST_uint64_t_eq(ossl_quic_txfc_get_credit(txfc), 1))
148 goto err;
149
150 if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 1)))
151 goto err;
152
153 if (!TEST_true(ossl_quic_txfc_has_become_blocked(parent_txfc, 0)))
154 goto err;
155
156 if (!TEST_true(ossl_quic_txfc_has_become_blocked(parent_txfc, 1)))
157 goto err;
158
159 if (!TEST_false(ossl_quic_txfc_has_become_blocked(parent_txfc, 0)))
160 goto err;
161 } else {
162 if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 499)))
163 goto err;
164
165 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
166 goto err;
167
168 if (is_stream && !TEST_false(ossl_quic_txfc_has_become_blocked(parent_txfc, 0)))
169 goto err;
170
171 if (!TEST_true(ossl_quic_txfc_consume_credit(txfc, 1)))
172 goto err;
173
174 if (!TEST_true(ossl_quic_txfc_has_become_blocked(txfc, 0)))
175 goto err;
176
177 if (!TEST_true(ossl_quic_txfc_has_become_blocked(txfc, 1)))
178 goto err;
179
180 if (!TEST_false(ossl_quic_txfc_has_become_blocked(txfc, 0)))
181 goto err;
182 }
183
184 testresult = 1;
185 err:
186 return testresult;
187 }
188
189 static OSSL_TIME cur_time;
190
191 static OSSL_TIME fake_now(void *arg)
192 {
193 return cur_time;
194 }
195
196 #define RX_OPC_END 0
197 #define RX_OPC_INIT_CONN 1 /* arg0=initial window, arg1=max window */
198 #define RX_OPC_INIT_STREAM 2 /* arg0=initial window, arg1=max window */
199 #define RX_OPC_RX 3 /* arg0=end, arg1=is_fin */
200 #define RX_OPC_RETIRE 4 /* arg0=num_bytes, arg1=rtt in OSSL_TIME ticks, expect_fail */
201 #define RX_OPC_CHECK_CWM_CONN 5 /* arg0=expected */
202 #define RX_OPC_CHECK_CWM_STREAM 6 /* arg0=expected */
203 #define RX_OPC_CHECK_SWM_CONN 7 /* arg0=expected */
204 #define RX_OPC_CHECK_SWM_STREAM 8 /* arg0=expected */
205 #define RX_OPC_CHECK_RWM_CONN 9 /* arg0=expected */
206 #define RX_OPC_CHECK_RWM_STREAM 10 /* arg0=expected */
207 #define RX_OPC_CHECK_CHANGED_CONN 11 /* arg0=expected, arg1=clear */
208 #define RX_OPC_CHECK_CHANGED_STREAM 12 /* arg0=expected, arg1=clear */
209 #define RX_OPC_CHECK_ERROR_CONN 13 /* arg0=expected, arg1=clear */
210 #define RX_OPC_CHECK_ERROR_STREAM 14 /* arg0=expected, arg1=clear */
211 #define RX_OPC_STEP_TIME 15 /* arg0=OSSL_TIME ticks to advance */
212 #define RX_OPC_MSG 16
213
214 struct rx_test_op {
215 unsigned char op;
216 size_t stream_idx;
217 uint64_t arg0, arg1;
218 unsigned char expect_fail;
219 const char *msg;
220 };
221
222 #define RX_OP_END \
223 { RX_OPC_END }
224 #define RX_OP_INIT_CONN(init_window_size, max_window_size) \
225 { RX_OPC_INIT_CONN, 0, (init_window_size), (max_window_size) },
226 #define RX_OP_INIT_STREAM(stream_idx, init_window_size, max_window_size) \
227 { RX_OPC_INIT_STREAM, (stream_idx), (init_window_size), (max_window_size) },
228 #define RX_OP_RX(stream_idx, end, is_fin) \
229 { RX_OPC_RX, (stream_idx), (end), (is_fin) },
230 #define RX_OP_RETIRE(stream_idx, num_bytes, rtt, expect_fail) \
231 { RX_OPC_RETIRE, (stream_idx), (num_bytes), (rtt), (expect_fail) },
232 #define RX_OP_CHECK_CWM_CONN(expected) \
233 { RX_OPC_CHECK_CWM_CONN, 0, (expected) },
234 #define RX_OP_CHECK_CWM_STREAM(stream_id, expected) \
235 { RX_OPC_CHECK_CWM_STREAM, (stream_id), (expected) },
236 #define RX_OP_CHECK_SWM_CONN(expected) \
237 { RX_OPC_CHECK_SWM_CONN, 0, (expected) },
238 #define RX_OP_CHECK_SWM_STREAM(stream_id, expected) \
239 { RX_OPC_CHECK_SWM_STREAM, (stream_id), (expected) },
240 #define RX_OP_CHECK_RWM_CONN(expected) \
241 { RX_OPC_CHECK_RWM_CONN, 0, (expected) },
242 #define RX_OP_CHECK_RWM_STREAM(stream_id, expected) \
243 { RX_OPC_CHECK_RWM_STREAM, (stream_id), (expected) },
244 #define RX_OP_CHECK_CHANGED_CONN(expected, clear) \
245 { RX_OPC_CHECK_CHANGED_CONN, 0, (expected), (clear) },
246 #define RX_OP_CHECK_CHANGED_STREAM(stream_id, expected, clear) \
247 { RX_OPC_CHECK_CHANGED_STREAM, (stream_id), (expected), (clear) },
248 #define RX_OP_CHECK_ERROR_CONN(expected, clear) \
249 { RX_OPC_CHECK_ERROR_CONN, 0, (expected), (clear) },
250 #define RX_OP_CHECK_ERROR_STREAM(stream_id, expected, clear) \
251 { RX_OPC_CHECK_ERROR_STREAM, (stream_id), (expected), (clear) },
252 #define RX_OP_STEP_TIME(t) \
253 { RX_OPC_STEP_TIME, 0, (t) },
254 #define RX_OP_MSG(msg) \
255 { RX_OPC_MSG, 0, 0, 0, 0, (msg) },
256
257 #define RX_OP_INIT(init_window_size, max_window_size) \
258 RX_OP_INIT_CONN(init_window_size, max_window_size) \
259 RX_OP_INIT_STREAM(0, init_window_size, max_window_size)
260 #define RX_OP_CHECK_CWM(expected) \
261 RX_OP_CHECK_CWM_CONN(expected) \
262 RX_OP_CHECK_CWM_STREAM(0, expected)
263 #define RX_OP_CHECK_SWM(expected) \
264 RX_OP_CHECK_SWM_CONN(expected) \
265 RX_OP_CHECK_SWM_STREAM(0, expected)
266 #define RX_OP_CHECK_RWM(expected) \
267 RX_OP_CHECK_RWM_CONN(expected) \
268 RX_OP_CHECK_RWM_STREAM(0, expected)
269 #define RX_OP_CHECK_CHANGED(expected, clear) \
270 RX_OP_CHECK_CHANGED_CONN(expected, clear) \
271 RX_OP_CHECK_CHANGED_STREAM(0, expected, clear)
272 #define RX_OP_CHECK_ERROR(expected, clear) \
273 RX_OP_CHECK_ERROR_CONN(expected, clear) \
274 RX_OP_CHECK_ERROR_STREAM(0, expected, clear)
275
276 #define INIT_WINDOW_SIZE (1 * 1024 * 1024)
277 #define INIT_S_WINDOW_SIZE (384 * 1024)
278
279 /* 1. Basic RXFC Tests (stream window == connection window) */
280 static const struct rx_test_op rx_script_1[] = {
281 RX_OP_STEP_TIME(1000 * OSSL_TIME_MS)
282 RX_OP_INIT(INIT_WINDOW_SIZE, 10 * INIT_WINDOW_SIZE)
283 /* Check initial state. */
284 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE)
285 RX_OP_CHECK_ERROR(0, 0)
286 RX_OP_CHECK_CHANGED(0, 0)
287 /* We cannot retire what we have not received. */
288 RX_OP_RETIRE(0, 1, 0, 1)
289 /* Zero bytes is a no-op and always valid. */
290 RX_OP_RETIRE(0, 0, 0, 0)
291 /* Consume some window. */
292 RX_OP_RX(0, 50, 0)
293 /* CWM has not changed. */
294 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE)
295 RX_OP_CHECK_SWM(50)
296
297 /* RX, Partial retire */
298 RX_OP_RX(0, 60, 0)
299 RX_OP_CHECK_SWM(60)
300 RX_OP_RETIRE(0, 20, 50 * OSSL_TIME_MS, 0)
301 RX_OP_CHECK_RWM(20)
302 RX_OP_CHECK_SWM(60)
303 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE)
304 RX_OP_CHECK_CHANGED(0, 0)
305 RX_OP_CHECK_ERROR(0, 0)
306
307 /* Fully retired */
308 RX_OP_RETIRE(0, 41, 0, 1)
309 RX_OP_RETIRE(0, 40, 0, 0)
310 RX_OP_CHECK_SWM(60)
311 RX_OP_CHECK_RWM(60)
312 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE)
313 RX_OP_CHECK_CHANGED(0, 0)
314 RX_OP_CHECK_ERROR(0, 0)
315
316 /* Exhaustion of window - we do not enlarge the window this epoch */
317 RX_OP_STEP_TIME(201 * OSSL_TIME_MS)
318 RX_OP_RX(0, INIT_WINDOW_SIZE, 0)
319 RX_OP_RETIRE(0, INIT_WINDOW_SIZE - 60, 50 * OSSL_TIME_MS, 0)
320 RX_OP_CHECK_SWM(INIT_WINDOW_SIZE)
321 RX_OP_CHECK_CHANGED(1, 0)
322 RX_OP_CHECK_CHANGED(1, 1)
323 RX_OP_CHECK_CHANGED(0, 0)
324 RX_OP_CHECK_ERROR(0, 0)
325 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE * 2)
326
327 /* Second epoch - we still do not enlarge the window this epoch */
328 RX_OP_RX(0, INIT_WINDOW_SIZE + 1, 0)
329 RX_OP_STEP_TIME(201 * OSSL_TIME_MS)
330 RX_OP_RX(0, INIT_WINDOW_SIZE * 2, 0)
331 RX_OP_RETIRE(0, INIT_WINDOW_SIZE, 50 * OSSL_TIME_MS, 0)
332 RX_OP_CHECK_SWM(INIT_WINDOW_SIZE * 2)
333 RX_OP_CHECK_CHANGED(1, 0)
334 RX_OP_CHECK_CHANGED(1, 1)
335 RX_OP_CHECK_CHANGED(0, 0)
336 RX_OP_CHECK_ERROR(0, 0)
337 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE * 3)
338
339 /* Third epoch - we enlarge the window */
340 RX_OP_RX(0, INIT_WINDOW_SIZE * 2 + 1, 0)
341 RX_OP_STEP_TIME(199 * OSSL_TIME_MS)
342 RX_OP_RX(0, INIT_WINDOW_SIZE * 3, 0)
343 RX_OP_RETIRE(0, INIT_WINDOW_SIZE, 50 * OSSL_TIME_MS, 0)
344 RX_OP_CHECK_SWM(INIT_WINDOW_SIZE * 3)
345 RX_OP_CHECK_CHANGED(1, 0)
346 RX_OP_CHECK_CHANGED(1, 1)
347 RX_OP_CHECK_CHANGED(0, 0)
348 RX_OP_CHECK_ERROR(0, 0)
349 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE * 5)
350
351 /* Fourth epoch - peer violates flow control */
352 RX_OP_RX(0, INIT_WINDOW_SIZE * 5 - 5, 0)
353 RX_OP_STEP_TIME(250 * OSSL_TIME_MS)
354 RX_OP_RX(0, INIT_WINDOW_SIZE * 5 + 1, 0)
355 RX_OP_CHECK_SWM(INIT_WINDOW_SIZE * 5)
356 RX_OP_CHECK_ERROR(QUIC_ERR_FLOW_CONTROL_ERROR, 0)
357 RX_OP_CHECK_ERROR(QUIC_ERR_FLOW_CONTROL_ERROR, 1)
358 RX_OP_CHECK_ERROR(0, 0)
359 RX_OP_CHECK_CWM(INIT_WINDOW_SIZE * 5)
360 /*
361 * No window expansion due to flow control violation; window expansion is
362 * triggered by retirement only.
363 */
364 RX_OP_CHECK_CHANGED(0, 0)
365
366 RX_OP_END
367 };
368
369 /* 2. Interaction between connection and stream-level flow control */
370 static const struct rx_test_op rx_script_2[] = {
371 RX_OP_STEP_TIME(1000 * OSSL_TIME_MS)
372 RX_OP_INIT_CONN(INIT_WINDOW_SIZE, 10 * INIT_WINDOW_SIZE)
373 RX_OP_INIT_STREAM(0, INIT_S_WINDOW_SIZE, 30 * INIT_S_WINDOW_SIZE)
374 RX_OP_INIT_STREAM(1, INIT_S_WINDOW_SIZE, 30 * INIT_S_WINDOW_SIZE)
375
376 RX_OP_RX(0, 10, 0)
377 RX_OP_CHECK_CWM_CONN(INIT_WINDOW_SIZE)
378 RX_OP_CHECK_CWM_STREAM(0, INIT_S_WINDOW_SIZE)
379 RX_OP_CHECK_CWM_STREAM(1, INIT_S_WINDOW_SIZE)
380 RX_OP_CHECK_SWM_CONN(10)
381 RX_OP_CHECK_SWM_STREAM(0, 10)
382 RX_OP_CHECK_SWM_STREAM(1, 0)
383 RX_OP_CHECK_RWM_CONN(0)
384 RX_OP_CHECK_RWM_STREAM(0, 0)
385 RX_OP_CHECK_RWM_STREAM(1, 0)
386
387 RX_OP_RX(1, 42, 0)
388 RX_OP_RX(1, 42, 0) /* monotonic; equal or lower values ignored */
389 RX_OP_RX(1, 35, 0)
390 RX_OP_CHECK_CWM_CONN(INIT_WINDOW_SIZE)
391 RX_OP_CHECK_CWM_STREAM(0, INIT_S_WINDOW_SIZE)
392 RX_OP_CHECK_CWM_STREAM(1, INIT_S_WINDOW_SIZE)
393 RX_OP_CHECK_SWM_CONN(52)
394 RX_OP_CHECK_SWM_STREAM(0, 10)
395 RX_OP_CHECK_SWM_STREAM(1, 42)
396 RX_OP_CHECK_RWM_CONN(0)
397 RX_OP_CHECK_RWM_STREAM(0, 0)
398 RX_OP_CHECK_RWM_STREAM(1, 0)
399
400 RX_OP_RETIRE(0, 10, 50 * OSSL_TIME_MS, 0)
401 RX_OP_CHECK_RWM_CONN(10)
402 RX_OP_CHECK_RWM_STREAM(0, 10)
403 RX_OP_CHECK_CWM_CONN(INIT_WINDOW_SIZE)
404 RX_OP_CHECK_CWM_STREAM(0, INIT_S_WINDOW_SIZE)
405 RX_OP_CHECK_CWM_STREAM(1, INIT_S_WINDOW_SIZE)
406
407 RX_OP_RETIRE(1, 42, 50 * OSSL_TIME_MS, 0)
408 RX_OP_CHECK_RWM_CONN(52)
409 RX_OP_CHECK_RWM_STREAM(1, 42)
410 RX_OP_CHECK_CWM_CONN(INIT_WINDOW_SIZE)
411 RX_OP_CHECK_CWM_STREAM(0, INIT_S_WINDOW_SIZE)
412 RX_OP_CHECK_CWM_STREAM(1, INIT_S_WINDOW_SIZE)
413
414 RX_OP_CHECK_CHANGED_CONN(0, 0)
415
416 /* FC limited by stream but not connection */
417 RX_OP_STEP_TIME(1000 * OSSL_TIME_MS)
418 RX_OP_RX(0, INIT_S_WINDOW_SIZE, 0)
419 RX_OP_CHECK_SWM_CONN(INIT_S_WINDOW_SIZE + 42)
420 RX_OP_CHECK_SWM_STREAM(0, INIT_S_WINDOW_SIZE)
421 RX_OP_CHECK_SWM_STREAM(1, 42)
422 RX_OP_CHECK_CWM_CONN(INIT_WINDOW_SIZE)
423 RX_OP_CHECK_CWM_STREAM(0, INIT_S_WINDOW_SIZE)
424
425 /* We bump CWM when more than 1/4 of the window has been retired */
426 RX_OP_RETIRE(0, INIT_S_WINDOW_SIZE - 10, 50 * OSSL_TIME_MS, 0)
427 RX_OP_CHECK_CWM_STREAM(0, INIT_S_WINDOW_SIZE * 2)
428 RX_OP_CHECK_CHANGED_STREAM(0, 1, 0)
429 RX_OP_CHECK_CHANGED_STREAM(0, 1, 1)
430 RX_OP_CHECK_CHANGED_STREAM(0, 0, 0)
431
432 /*
433 * This is more than 1/4 of the connection window, so CWM will
434 * be bumped here too.
435 */
436 RX_OP_CHECK_CWM_CONN(INIT_S_WINDOW_SIZE + INIT_WINDOW_SIZE + 42)
437 RX_OP_CHECK_RWM_CONN(INIT_S_WINDOW_SIZE + 42)
438 RX_OP_CHECK_RWM_STREAM(0, INIT_S_WINDOW_SIZE)
439 RX_OP_CHECK_RWM_STREAM(1, 42)
440 RX_OP_CHECK_CHANGED_CONN(1, 0)
441 RX_OP_CHECK_CHANGED_CONN(1, 1)
442 RX_OP_CHECK_CHANGED_CONN(0, 0)
443 RX_OP_CHECK_ERROR_CONN(0, 0)
444 RX_OP_CHECK_ERROR_STREAM(0, 0, 0)
445 RX_OP_CHECK_ERROR_STREAM(1, 0, 0)
446
447 /* Test exceeding limit at stream level. */
448 RX_OP_RX(0, INIT_S_WINDOW_SIZE * 2 + 1, 0)
449 RX_OP_CHECK_ERROR_STREAM(0, QUIC_ERR_FLOW_CONTROL_ERROR, 0)
450 RX_OP_CHECK_ERROR_STREAM(0, QUIC_ERR_FLOW_CONTROL_ERROR, 1)
451 RX_OP_CHECK_ERROR_STREAM(0, 0, 0)
452 RX_OP_CHECK_ERROR_CONN(0, 0) /* doesn't affect conn */
453
454 /* Test exceeding limit at connection level. */
455 RX_OP_RX(0, INIT_WINDOW_SIZE * 2, 0)
456 RX_OP_CHECK_ERROR_CONN(QUIC_ERR_FLOW_CONTROL_ERROR, 0)
457 RX_OP_CHECK_ERROR_CONN(QUIC_ERR_FLOW_CONTROL_ERROR, 1)
458 RX_OP_CHECK_ERROR_CONN(0, 0)
459
460 RX_OP_END
461 };
462
463 static const struct rx_test_op *rx_scripts[] = {
464 rx_script_1,
465 rx_script_2
466 };
467
468 static int run_rxfc_script(const struct rx_test_op *script)
469 {
470 #define MAX_STREAMS 3
471 int testresult = 0;
472 const struct rx_test_op *op = script;
473 QUIC_RXFC conn_rxfc, stream_rxfc[MAX_STREAMS];
474 char stream_init_done[MAX_STREAMS] = {0};
475 int conn_init_done = 0;
476
477 cur_time = ossl_time_zero();
478
479 for (; op->op != RX_OPC_END; ++op) {
480 switch (op->op) {
481 case RX_OPC_INIT_CONN:
482 if (!TEST_true(ossl_quic_rxfc_init(&conn_rxfc, 0,
483 op->arg0, op->arg1,
484 fake_now, NULL)))
485 goto err;
486
487 conn_init_done = 1;
488 break;
489
490 case RX_OPC_INIT_STREAM:
491 if (!TEST_size_t_lt(op->stream_idx, OSSL_NELEM(stream_rxfc)))
492 goto err;
493
494 if (!TEST_true(ossl_quic_rxfc_init(&stream_rxfc[op->stream_idx],
495 &conn_rxfc,
496 op->arg0, op->arg1,
497 fake_now, NULL)))
498 goto err;
499
500 stream_init_done[op->stream_idx] = 1;
501 break;
502
503 case RX_OPC_RX:
504 if (!TEST_true(conn_init_done && op->stream_idx < OSSL_NELEM(stream_rxfc)
505 && stream_init_done[op->stream_idx]))
506 goto err;
507
508 if (!TEST_true(ossl_quic_rxfc_on_rx_stream_frame(&stream_rxfc[op->stream_idx],
509 op->arg0,
510 (int)op->arg1)))
511 goto err;
512
513 break;
514
515 case RX_OPC_RETIRE:
516 if (!TEST_true(conn_init_done && op->stream_idx < OSSL_NELEM(stream_rxfc)
517 && stream_init_done[op->stream_idx]))
518 goto err;
519
520 if (!TEST_int_eq(ossl_quic_rxfc_on_retire(&stream_rxfc[op->stream_idx],
521 op->arg0,
522 ossl_ticks2time(op->arg1)),
523 !op->expect_fail))
524 goto err;
525
526 break;
527 case RX_OPC_CHECK_CWM_CONN:
528 if (!TEST_true(conn_init_done))
529 goto err;
530 if (!TEST_uint64_t_eq(ossl_quic_rxfc_get_cwm(&conn_rxfc),
531 op->arg0))
532 goto err;
533 break;
534 case RX_OPC_CHECK_CWM_STREAM:
535 if (!TEST_true(op->stream_idx < OSSL_NELEM(stream_rxfc)
536 && stream_init_done[op->stream_idx]))
537 goto err;
538 if (!TEST_uint64_t_eq(ossl_quic_rxfc_get_cwm(&stream_rxfc[op->stream_idx]),
539 op->arg0))
540 goto err;
541 break;
542 case RX_OPC_CHECK_SWM_CONN:
543 if (!TEST_true(conn_init_done))
544 goto err;
545 if (!TEST_uint64_t_eq(ossl_quic_rxfc_get_swm(&conn_rxfc),
546 op->arg0))
547 goto err;
548 break;
549 case RX_OPC_CHECK_SWM_STREAM:
550 if (!TEST_true(op->stream_idx < OSSL_NELEM(stream_rxfc)
551 && stream_init_done[op->stream_idx]))
552 goto err;
553 if (!TEST_uint64_t_eq(ossl_quic_rxfc_get_swm(&stream_rxfc[op->stream_idx]),
554 op->arg0))
555 goto err;
556 break;
557 case RX_OPC_CHECK_RWM_CONN:
558 if (!TEST_true(conn_init_done))
559 goto err;
560 if (!TEST_uint64_t_eq(ossl_quic_rxfc_get_rwm(&conn_rxfc),
561 op->arg0))
562 goto err;
563 break;
564 case RX_OPC_CHECK_RWM_STREAM:
565 if (!TEST_true(op->stream_idx < OSSL_NELEM(stream_rxfc)
566 && stream_init_done[op->stream_idx]))
567 goto err;
568 if (!TEST_uint64_t_eq(ossl_quic_rxfc_get_rwm(&stream_rxfc[op->stream_idx]),
569 op->arg0))
570 goto err;
571 break;
572 case RX_OPC_CHECK_CHANGED_CONN:
573 if (!TEST_true(conn_init_done))
574 goto err;
575 if (!TEST_int_eq(ossl_quic_rxfc_has_cwm_changed(&conn_rxfc,
576 (int)op->arg1),
577 (int)op->arg0))
578 goto err;
579 break;
580 case RX_OPC_CHECK_CHANGED_STREAM:
581 if (!TEST_true(op->stream_idx < OSSL_NELEM(stream_rxfc)
582 && stream_init_done[op->stream_idx]))
583 goto err;
584 if (!TEST_int_eq(ossl_quic_rxfc_has_cwm_changed(&stream_rxfc[op->stream_idx],
585 (int)op->arg1),
586 (int)op->arg0))
587 goto err;
588 break;
589 case RX_OPC_CHECK_ERROR_CONN:
590 if (!TEST_true(conn_init_done))
591 goto err;
592 if (!TEST_int_eq(ossl_quic_rxfc_get_error(&conn_rxfc,
593 (int)op->arg1),
594 (int)op->arg0))
595 goto err;
596 break;
597 case RX_OPC_CHECK_ERROR_STREAM:
598 if (!TEST_true(op->stream_idx < OSSL_NELEM(stream_rxfc)
599 && stream_init_done[op->stream_idx]))
600 goto err;
601 if (!TEST_int_eq(ossl_quic_rxfc_get_error(&stream_rxfc[op->stream_idx],
602 (int)op->arg1),
603 (int)op->arg0))
604 goto err;
605 break;
606 case RX_OPC_STEP_TIME:
607 cur_time = ossl_time_add(cur_time, ossl_ticks2time(op->arg0));
608 break;
609 case RX_OPC_MSG:
610 fprintf(stderr, "# %s\n", op->msg);
611 break;
612 default:
613 goto err;
614 }
615 }
616
617 testresult = 1;
618 err:
619 return testresult;
620 }
621
622 static int test_rxfc(int idx)
623 {
624 return run_rxfc_script(rx_scripts[idx]);
625 }
626
627 int setup_tests(void)
628 {
629 ADD_ALL_TESTS(test_txfc, 2);
630 ADD_ALL_TESTS(test_rxfc, OSSL_NELEM(rx_scripts));
631 return 1;
632 }