test_spi.c revision 9a690580
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 unsigned flags = 0xF00; /* Arbitrary value */ 66 lsquic_stream_t *stream; 67 68 TAILQ_INIT(&streams); 69 TAILQ_INSERT_TAIL(&streams, stream_arr[0], next_write_stream); 70 stream_arr[0]->sm_qflags |= flags; 71 TAILQ_INSERT_TAIL(&streams, stream_arr[1], next_write_stream); 72 stream_arr[1]->sm_qflags |= flags; 73 TAILQ_INSERT_TAIL(&streams, stream_arr[2], next_write_stream); 74 stream_arr[2]->sm_qflags |= flags; 75 TAILQ_INSERT_TAIL(&streams, stream_arr[3], next_write_stream); 76 stream_arr[3]->sm_qflags |= flags; 77 78 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 79 TAILQ_LAST(&streams, lsquic_streams_tailq), 80 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), 81 flags, &lconn, __func__, NULL, NULL); 82 83 stream = lsquic_spi_first(&spi); 84 assert(stream == stream_arr[0]); 85 stream = lsquic_spi_next(&spi); 86 assert(stream == stream_arr[1]); 87 stream = lsquic_spi_next(&spi); 88 assert(stream == stream_arr[2]); 89 stream = lsquic_spi_next(&spi); 90 assert(stream == stream_arr[3]); 91 stream = lsquic_spi_next(&spi); 92 assert(stream == NULL); 93 94 /* Test reinitialization: */ 95 lsquic_spi_init(&spi, stream_arr[0], stream_arr[1], 96 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), 97 flags, &lconn, __func__, NULL, NULL); 98 stream = lsquic_spi_first(&spi); 99 assert(stream == stream_arr[0]); 100 stream = lsquic_spi_next(&spi); 101 assert(stream == stream_arr[1]); 102 stream = lsquic_spi_next(&spi); 103 assert(stream == NULL); 104 105 free_streams(stream_arr, sizeof(stream_arr) / sizeof(stream_arr[0])); 106} 107 108 109static void 110test_different_priorities (int *priority) 111{ 112 struct lsquic_streams_tailq streams; 113 unsigned flags = 0xC000; /* Arbitrary value */ 114 lsquic_stream_t *stream; 115 int prio, prev_prio, count, n_streams = 0; 116 117 TAILQ_INIT(&streams); 118 119 for ( ; *priority >= 0; ++priority) 120 { 121 assert(*priority < 256); 122 stream = new_stream(*priority); 123 TAILQ_INSERT_TAIL(&streams, stream, next_send_stream); 124 stream->sm_qflags |= flags; 125 ++n_streams; 126 } 127 128 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 129 TAILQ_LAST(&streams, lsquic_streams_tailq), 130 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream), 131 flags, &lconn, __func__, NULL, NULL); 132 133 for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream; 134 stream = lsquic_spi_next(&spi), ++count) 135 { 136 prio = stream->sm_priority; 137 assert(prio >= prev_prio); 138 if (prio > prev_prio) 139 prev_prio = prio; 140 } 141 142 assert(count == n_streams); 143 144 while ((stream = TAILQ_FIRST(&streams))) 145 { 146 TAILQ_REMOVE(&streams, stream, next_send_stream); 147 free(stream); 148 } 149} 150 151 152struct stream_info 153{ 154 uint32_t stream_id; 155 enum stream_b_flags bflags; 156 unsigned char prio; 157}; 158 159 160const struct stream_info infos1[] = { 161 { 1, SMBF_CRITICAL, 0, }, 162 { 3, SMBF_CRITICAL, 0, }, 163 { 5, 0, 0, }, 164 { 7, 0, 1, }, 165 { 127, 0, 200, }, 166}; 167 168 169const struct stream_info infos2[] = { 170 { 1, SMBF_CRITICAL, 0, }, 171 { 3, SMBF_CRITICAL, 0, }, 172 { 5, 0, 4, }, 173 { 7, 0, 1, }, 174 { 127, 0, 200, }, 175}; 176 177 178const struct stream_info infos3[] = { 179 { 0, 0, 0, }, 180}; 181 182 183struct drop_test 184{ 185 const struct stream_info *infos; 186 unsigned n_infos; 187 unsigned high_streams; 188}; 189 190 191static const struct drop_test drop_tests[] = { 192 { infos1, 5, 0x7, }, 193 { infos2, 5, 0x3, }, 194 { infos3, 1, 0x0, }, 195}; 196 197 198static void 199test_drop (const struct drop_test *test) 200{ 201 202 struct lsquic_stream stream_arr[20]; 203 unsigned seen_mask, n; 204 struct lsquic_streams_tailq streams; 205 lsquic_stream_t *stream; 206 int drop_high; 207 208 TAILQ_INIT(&streams); 209 for (n = 0; n < test->n_infos; ++n) 210 { 211 stream_arr[n].sm_priority = test->infos[n].prio; 212 stream_arr[n].id = test->infos[n].stream_id; 213 stream_arr[n].sm_bflags = SMBF_USE_HEADERS | test->infos[n].bflags; 214 } 215 216 for (drop_high = 0; drop_high < 2; ++drop_high) 217 { 218 TAILQ_INIT(&streams); 219 for (n = 0; n < test->n_infos; ++n) 220 TAILQ_INSERT_TAIL(&streams, &stream_arr[n], next_write_stream); 221 222 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 223 TAILQ_LAST(&streams, lsquic_streams_tailq), 224 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_write_stream), 225 SMQF_WRITE_Q_FLAGS, &lconn, __func__, NULL, NULL); 226 227 if (drop_high) 228 lsquic_spi_drop_high(&spi); 229 else 230 lsquic_spi_drop_non_high(&spi); 231 232 seen_mask = 0; 233 for (stream = lsquic_spi_first(&spi); stream; 234 stream = lsquic_spi_next(&spi)) 235 seen_mask |= 1 << (stream - stream_arr); 236 237 if (test->n_infos == 1) 238 assert(seen_mask == (1u << test->infos[0].stream_id)); 239 else if (drop_high) 240 assert((((1 << test->n_infos) - 1) & ~test->high_streams) == seen_mask); 241 else 242 assert(test->high_streams == seen_mask); 243 } 244} 245 246 247#define MAGIC 0x12312312U 248 249struct my_filter_ctx 250{ 251 unsigned magic; 252}; 253 254 255static int 256filter_out_odd_priorities (void *ctx, lsquic_stream_t *stream) 257{ 258 struct my_filter_ctx *fctx = ctx; 259 assert(fctx->magic == MAGIC); 260 return 0 == (stream->sm_priority & 1); 261} 262 263 264static void 265test_different_priorities_filter_odd (int *priority) 266{ 267 struct lsquic_streams_tailq streams; 268 unsigned flags = 0xC000; /* Arbitrary value */ 269 lsquic_stream_t *stream; 270 int prio, prev_prio, count, n_streams = 0; 271 272 TAILQ_INIT(&streams); 273 274 for ( ; *priority >= 0; ++priority) 275 { 276 assert(*priority < 256); 277 stream = new_stream(*priority); 278 TAILQ_INSERT_TAIL(&streams, stream, next_send_stream); 279 stream->stream_flags |= flags; 280 ++n_streams; 281 } 282 283 struct my_filter_ctx my_filter_ctx = { MAGIC }; 284 285 lsquic_spi_init(&spi, TAILQ_FIRST(&streams), 286 TAILQ_LAST(&streams, lsquic_streams_tailq), 287 (uintptr_t) &TAILQ_NEXT((lsquic_stream_t *) NULL, next_send_stream), 288 flags, &lconn, __func__, filter_out_odd_priorities, &my_filter_ctx); 289 290 for (prev_prio = -1, count = 0, stream = lsquic_spi_first(&spi); stream; 291 stream = lsquic_spi_next(&spi), ++count) 292 { 293 prio = stream->sm_priority; 294 assert(0 == (prio & 1)); 295 assert(prio >= prev_prio); 296 if (prio > prev_prio) 297 prev_prio = prio; 298 } 299 300 assert(count < n_streams); 301 302 while ((stream = TAILQ_FIRST(&streams))) 303 { 304 TAILQ_REMOVE(&streams, stream, next_send_stream); 305 free(stream); 306 } 307} 308 309 310int 311main (int argc, char **argv) 312{ 313 lsquic_log_to_fstream(stderr, LLTS_NONE); 314 lsq_log_levels[LSQLM_SPI] = LSQ_LOG_DEBUG; 315 316 test_same_priority(0); 317 test_same_priority(99); 318 test_same_priority(255); 319 320 { 321 int prio[] = { 1, 2, 3, 4, 5, 6, 7, -1 }; 322 test_different_priorities(prio); 323 } 324 325 { 326 int prio[] = { 7, 6, 5, 4, 3, 2, 1, -1 }; 327 test_different_priorities(prio); 328 } 329 330 { 331 int prio[] = { 7, 100, 80, 1, 0, 0, 20, 23, 255, 30, 2, 101, -1 }; 332 test_different_priorities(prio); 333 } 334 335 { 336 int prio[] = { 200, 202, 240, 201, 200, 199, -1 }; 337 test_different_priorities(prio); 338 } 339 340 { 341 int prio[] = { 200, 202, 240, 201, 200, 199, -1 }; 342 test_different_priorities_filter_odd(prio); 343 } 344 345 unsigned n; 346 for (n = 0; n < sizeof(drop_tests) / sizeof(drop_tests[0]); ++n) 347 test_drop(&drop_tests[n]); 348 349 return 0; 350} 351