test_spi.c revision cd35ff02
1/* Copyright (c) 2017 - 2020 LiteSpeed Technologies Inc. See LICENSE. */ 2#include <assert.h> 3#include <errno.h> 4#include <stdio.h> 5#include <stdlib.h> 6#include <string.h> 7#include <sys/queue.h> 8#ifndef WIN32 9#include <unistd.h> 10#endif 11 12#include "lsquic.h" 13 14#include "lsquic_int_types.h" 15#include "lsquic_packet_common.h" 16#include "lsquic_packet_in.h" 17#include "lsquic_conn_flow.h" 18#include "lsquic_sfcw.h" 19#include "lsquic_varint.h" 20#include "lsquic_hq.h" 21#include "lsquic_hash.h" 22#include "lsquic_conn.h" 23#include "lsquic_stream.h" 24#include "lsquic_types.h" 25#include "lsquic_spi.h" 26#include "lsquic_logger.h" 27 28 29/* Sharing the same SPI tests safety of reusing the same iterator object 30 * (no need to deinitialize it). 31 */ 32static struct stream_prio_iter spi; 33 34static struct lsquic_conn lconn = LSCONN_INITIALIZER_CIDLEN(lconn, 0); 35 36 37static lsquic_stream_t * 38new_stream (unsigned priority) 39{ 40 lsquic_stream_t *stream = calloc(1, sizeof(*stream)); 41 stream->sm_priority = priority; 42 return stream; 43} 44 45 46static void 47free_streams (lsquic_stream_t **streams, size_t count) 48{ 49 size_t n; 50 for (n = 0; n < count; ++n) 51 free(streams[n]); 52} 53 54 55static void 56test_same_priority (unsigned priority) 57{ 58 lsquic_stream_t *stream_arr[4] = { 59 new_stream(priority), 60 new_stream(priority), 61 new_stream(priority), 62 new_stream(priority), 63 }; 64 struct lsquic_streams_tailq streams; 65 lsquic_stream_t *stream; 66 67 TAILQ_INIT(&streams); 68 TAILQ_INSERT_TAIL(&streams, stream_arr[0], next_write_stream); 69 TAILQ_INSERT_TAIL(&streams, stream_arr[1], next_write_stream); 70 TAILQ_INSERT_TAIL(&streams, stream_arr[2], next_write_stream); 71 TAILQ_INSERT_TAIL(&streams, stream_arr[3], next_write_stream); 72 73 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 74 TAILQ_LAST(&streams, lsquic_streams_tailq), 75 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), 76 &lconn, __func__, NULL, NULL); 77 78 stream = lsquic_spi_first(&spi); 79 assert(stream == stream_arr[0]); 80 stream = lsquic_spi_next(&spi); 81 assert(stream == stream_arr[1]); 82 stream = lsquic_spi_next(&spi); 83 assert(stream == stream_arr[2]); 84 stream = lsquic_spi_next(&spi); 85 assert(stream == stream_arr[3]); 86 stream = lsquic_spi_next(&spi); 87 assert(stream == NULL); 88 89 /* Test reinitialization: */ 90 lsquic_spi_init(&spi, stream_arr[0], stream_arr[1], 91 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), 92 &lconn, __func__, NULL, NULL); 93 stream = lsquic_spi_first(&spi); 94 assert(stream == stream_arr[0]); 95 stream = lsquic_spi_next(&spi); 96 assert(stream == stream_arr[1]); 97 stream = lsquic_spi_next(&spi); 98 assert(stream == NULL); 99 100 free_streams(stream_arr, sizeof(stream_arr) / sizeof(stream_arr[0])); 101} 102 103 104static void 105test_different_priorities (int *priority) 106{ 107 struct lsquic_streams_tailq streams; 108 lsquic_stream_t *stream; 109 int prio, prev_prio, count, n_streams = 0; 110 111 TAILQ_INIT(&streams); 112 113 for ( ; *priority >= 0; ++priority) 114 { 115 assert(*priority < 256); 116 stream = new_stream(*priority); 117 TAILQ_INSERT_TAIL(&streams, stream, next_send_stream); 118 ++n_streams; 119 } 120 121 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 122 TAILQ_LAST(&streams, lsquic_streams_tailq), 123 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream), 124 &lconn, __func__, NULL, NULL); 125 for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream; 126 stream = lsquic_spi_next(&spi), ++count) 127 { 128 prio = stream->sm_priority; 129 assert(prio >= prev_prio); 130 if (prio > prev_prio) 131 prev_prio = prio; 132 } 133 134 assert(count == n_streams); 135 136 while ((stream = TAILQ_FIRST(&streams))) 137 { 138 TAILQ_REMOVE(&streams, stream, next_send_stream); 139 free(stream); 140 } 141} 142 143 144struct stream_info 145{ 146 uint32_t stream_id; 147 enum stream_b_flags bflags; 148 unsigned char prio; 149}; 150 151 152const struct stream_info infos1[] = { 153 { 1, SMBF_CRITICAL, 0, }, 154 { 3, SMBF_CRITICAL, 0, }, 155 { 5, 0, 0, }, 156 { 7, 0, 1, }, 157 { 127, 0, 200, }, 158}; 159 160 161const struct stream_info infos2[] = { 162 { 1, SMBF_CRITICAL, 0, }, 163 { 3, SMBF_CRITICAL, 0, }, 164 { 5, 0, 4, }, 165 { 7, 0, 1, }, 166 { 127, 0, 200, }, 167}; 168 169 170const struct stream_info infos3[] = { 171 { 0, 0, 0, }, 172}; 173 174 175struct drop_test 176{ 177 const struct stream_info *infos; 178 unsigned n_infos; 179 unsigned high_streams; 180}; 181 182 183static const struct drop_test drop_tests[] = { 184 { infos1, 5, 0x7, }, 185 { infos2, 5, 0x3, }, 186 { infos3, 1, 0x0, }, 187}; 188 189 190static void 191test_drop (const struct drop_test *test) 192{ 193 194 struct lsquic_stream stream_arr[20]; 195 unsigned seen_mask, n; 196 struct lsquic_streams_tailq streams; 197 lsquic_stream_t *stream; 198 int drop_high; 199 200 TAILQ_INIT(&streams); 201 for (n = 0; n < test->n_infos; ++n) 202 { 203 stream_arr[n].sm_priority = test->infos[n].prio; 204 stream_arr[n].id = test->infos[n].stream_id; 205 stream_arr[n].sm_bflags = SMBF_USE_HEADERS | test->infos[n].bflags; 206 } 207 208 for (drop_high = 0; drop_high < 2; ++drop_high) 209 { 210 TAILQ_INIT(&streams); 211 for (n = 0; n < test->n_infos; ++n) 212 TAILQ_INSERT_TAIL(&streams, &stream_arr[n], next_write_stream); 213 214 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 215 TAILQ_LAST(&streams, lsquic_streams_tailq), 216 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), 217 &lconn, __func__, NULL, NULL); 218 219 if (drop_high) 220 lsquic_spi_drop_high(&spi); 221 else 222 lsquic_spi_drop_non_high(&spi); 223 224 seen_mask = 0; 225 for (stream = lsquic_spi_first(&spi); stream; 226 stream = lsquic_spi_next(&spi)) 227 seen_mask |= 1 << (stream - stream_arr); 228 229 if (test->n_infos == 1) 230 assert(seen_mask == (1u << test->infos[0].stream_id)); 231 else if (drop_high) 232 assert((((1 << test->n_infos) - 1) & ~test->high_streams) == seen_mask); 233 else 234 assert(test->high_streams == seen_mask); 235 } 236} 237 238 239#define MAGIC 0x12312312U 240 241struct my_filter_ctx 242{ 243 unsigned magic; 244}; 245 246 247static int 248filter_out_odd_priorities (void *ctx, lsquic_stream_t *stream) 249{ 250 struct my_filter_ctx *fctx = ctx; 251 assert(fctx->magic == MAGIC); 252 return 0 == (stream->sm_priority & 1); 253} 254 255 256static void 257test_different_priorities_filter_odd (int *priority) 258{ 259 struct lsquic_streams_tailq streams; 260 lsquic_stream_t *stream; 261 int prio, prev_prio, count, n_streams = 0; 262 263 TAILQ_INIT(&streams); 264 265 for ( ; *priority >= 0; ++priority) 266 { 267 assert(*priority < 256); 268 stream = new_stream(*priority); 269 TAILQ_INSERT_TAIL(&streams, stream, next_send_stream); 270 ++n_streams; 271 } 272 273 struct my_filter_ctx my_filter_ctx = { MAGIC }; 274 275 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 276 TAILQ_LAST(&streams, lsquic_streams_tailq), 277 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream), 278 &lconn, __func__, filter_out_odd_priorities, &my_filter_ctx); 279 280 for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream; 281 stream = lsquic_spi_next(&spi), ++count) 282 { 283 prio = stream->sm_priority; 284 assert(0 == (prio & 1)); 285 assert(prio >= prev_prio); 286 if (prio > prev_prio) 287 prev_prio = prio; 288 } 289 290 assert(count < n_streams); 291 292 while ((stream = TAILQ_FIRST(&streams))) 293 { 294 TAILQ_REMOVE(&streams, stream, next_send_stream); 295 free(stream); 296 } 297} 298 299 300int 301main (int argc, char **argv) 302{ 303 lsquic_log_to_fstream(stderr, LLTS_NONE); 304 lsq_log_levels[LSQLM_SPI] = LSQ_LOG_DEBUG; 305 306 test_same_priority(0); 307 test_same_priority(99); 308 test_same_priority(255); 309 310 { 311 int prio[] = { 1, 2, 3, 4, 5, 6, 7, -1 }; 312 test_different_priorities(prio); 313 } 314 315 { 316 int prio[] = { 7, 6, 5, 4, 3, 2, 1, -1 }; 317 test_different_priorities(prio); 318 } 319 320 { 321 int prio[] = { 7, 100, 80, 1, 0, 0, 20, 23, 255, 30, 2, 101, -1 }; 322 test_different_priorities(prio); 323 } 324 325 { 326 int prio[] = { 200, 202, 240, 201, 200, 199, -1 }; 327 test_different_priorities(prio); 328 } 329 330 { 331 int prio[] = { 200, 202, 240, 201, 200, 199, -1 }; 332 test_different_priorities_filter_odd(prio); 333 } 334 335 unsigned n; 336 for (n = 0; n < sizeof(drop_tests) / sizeof(drop_tests[0]); ++n) 337 test_drop(&drop_tests[n]); 338 339 return 0; 340} 341