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