2017-09-22 21:00:03 +00:00
|
|
|
/* Copyright (c) 2017 LiteSpeed Technologies Inc. See LICENSE. */
|
|
|
|
#include <assert.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/queue.h>
|
|
|
|
#include <sys/time.h>
|
|
|
|
|
|
|
|
#include "lsquic.h"
|
|
|
|
#include "lsquic_types.h"
|
|
|
|
#include "lsquic_alarmset.h"
|
|
|
|
#include "lsquic_packet_common.h"
|
|
|
|
#include "lsquic_parse.h"
|
|
|
|
|
|
|
|
|
|
|
|
struct packno_bits_test {
|
|
|
|
int pbt_lineno;
|
|
|
|
/* Inputs: */
|
|
|
|
lsquic_cid_t pbt_packno,
|
|
|
|
pbt_least_unacked;
|
|
|
|
uint64_t pbt_n_in_flight;
|
|
|
|
/* Output: */
|
|
|
|
enum lsquic_packno_bits pbt_packno_bits;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const struct packno_bits_test pb_tests[] = {
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 1,
|
|
|
|
.pbt_least_unacked = 0,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_1,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 101,
|
|
|
|
.pbt_least_unacked = 100,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_1,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 10001,
|
|
|
|
.pbt_least_unacked = 10000,
|
|
|
|
.pbt_n_in_flight = 1 << 6,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_1,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 10001,
|
|
|
|
.pbt_least_unacked = 10000,
|
|
|
|
.pbt_n_in_flight = (1 << 6) + 1,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1 << 16) + 1,
|
|
|
|
.pbt_least_unacked = 1 << 16,
|
|
|
|
.pbt_n_in_flight = 1 << 14,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1 << 16) + 1,
|
|
|
|
.pbt_least_unacked = 1 << 16,
|
|
|
|
.pbt_n_in_flight = (1 << 14) + 1,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_4,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1ULL << 33) + 1,
|
|
|
|
.pbt_least_unacked = 1ULL << 33,
|
|
|
|
.pbt_n_in_flight = 1ULL << 30,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_4,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1ULL << 33) + 1,
|
|
|
|
.pbt_least_unacked = 1ULL << 33,
|
|
|
|
.pbt_n_in_flight = (1ULL << 30) + 1,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_6,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 100,
|
|
|
|
.pbt_least_unacked = 1,
|
|
|
|
.pbt_n_in_flight = 3,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 100,
|
|
|
|
.pbt_least_unacked = 1,
|
|
|
|
.pbt_n_in_flight = 99,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 1 + (1 << 6),
|
|
|
|
.pbt_least_unacked = 1,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_1,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 1 + (1 << 6) + 1,
|
|
|
|
.pbt_least_unacked = 1,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1 << 20) + (1 << 14),
|
|
|
|
.pbt_least_unacked = 1 << 20,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1 << 20) + (1 << 14) + 1,
|
|
|
|
.pbt_least_unacked = 1 << 20,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_4,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1 << 20) + (1ULL << 30),
|
|
|
|
.pbt_least_unacked = 1 << 20,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_4,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = (1 << 20) + (1ULL << 30) + 1,
|
|
|
|
.pbt_least_unacked = 1 << 20,
|
|
|
|
.pbt_n_in_flight = 0,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_6,
|
|
|
|
},
|
|
|
|
|
|
|
|
/* Tests from Chrome: */
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 65,
|
|
|
|
.pbt_least_unacked = 2,
|
|
|
|
.pbt_n_in_flight = 7,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_1,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 64 * 256 - 1,
|
|
|
|
.pbt_least_unacked = 2,
|
|
|
|
.pbt_n_in_flight = 7,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 64 * 256 * 256 - 1,
|
|
|
|
.pbt_least_unacked = 2,
|
|
|
|
.pbt_n_in_flight = 7,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_4,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 64ULL * 256 * 256 * 256 * 256 - 1,
|
|
|
|
.pbt_least_unacked = 2,
|
|
|
|
.pbt_n_in_flight = 7,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_6,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 2,
|
|
|
|
.pbt_least_unacked = 1,
|
|
|
|
.pbt_n_in_flight = 7,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_1,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 2,
|
|
|
|
.pbt_least_unacked = 1,
|
|
|
|
.pbt_n_in_flight = 1896,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_2,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 2,
|
|
|
|
.pbt_least_unacked = 1,
|
|
|
|
.pbt_n_in_flight = 48545,
|
|
|
|
.pbt_packno_bits = PACKNO_LEN_4,
|
|
|
|
},
|
|
|
|
|
|
|
|
{ .pbt_lineno = __LINE__,
|
|
|
|
.pbt_packno = 2,
|
|
|
|
.pbt_least_unacked = 1,
|
2017-09-26 15:26:05 +00:00
|
|
|
.pbt_n_in_flight = 3181457256ULL,
|
2017-09-22 21:00:03 +00:00
|
|
|
.pbt_packno_bits = PACKNO_LEN_6,
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_pbt (int i)
|
|
|
|
{
|
|
|
|
const struct packno_bits_test *const pbt = &pb_tests[i];
|
|
|
|
enum lsquic_packno_bits packno_bits = calc_packno_bits(pbt->pbt_packno,
|
|
|
|
pbt->pbt_least_unacked, pbt->pbt_n_in_flight);
|
|
|
|
assert(packno_bits == pbt->pbt_packno_bits);
|
|
|
|
/* Now see if we can restore it back: */
|
|
|
|
lsquic_packno_t cur_packno = pbt->pbt_packno &
|
|
|
|
((1ULL << (packno_bits2len(packno_bits) << 3)) - 1);
|
|
|
|
lsquic_packno_t orig_packno = restore_packno(cur_packno, packno_bits,
|
|
|
|
pbt->pbt_least_unacked);
|
|
|
|
assert(orig_packno == pbt->pbt_packno);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct restore_packno_test {
|
|
|
|
int rpt_lineno;
|
|
|
|
/* Input */
|
|
|
|
enum lsquic_packno_bits rpt_packno_bits;
|
|
|
|
lsquic_packno_t rpt_cur_packno;
|
|
|
|
lsquic_packno_t rpt_max_packno;
|
|
|
|
/* Output */
|
|
|
|
lsquic_packno_t rpt_orig_packno;
|
|
|
|
};
|
|
|
|
|
|
|
|
static const struct restore_packno_test rp_tests[] =
|
|
|
|
{
|
|
|
|
|
|
|
|
{ .rpt_lineno = __LINE__,
|
|
|
|
.rpt_max_packno = 0,
|
|
|
|
.rpt_cur_packno = 1,
|
|
|
|
.rpt_packno_bits = PACKNO_LEN_1,
|
|
|
|
.rpt_orig_packno = 1,
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_rpt (int i)
|
|
|
|
{
|
|
|
|
const struct restore_packno_test *const rpt = &rp_tests[i];
|
|
|
|
lsquic_packno_t orig_packno = restore_packno(rpt->rpt_cur_packno,
|
|
|
|
rpt->rpt_packno_bits, rpt->rpt_max_packno);
|
|
|
|
assert(orig_packno == rpt->rpt_orig_packno);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
test_restore (enum lsquic_packno_bits bits)
|
|
|
|
{
|
|
|
|
unsigned len, n;
|
|
|
|
enum { OP_PLUS, OP_MINUS, N_OPS } op;
|
|
|
|
uint64_t epoch, epoch_delta;
|
|
|
|
lsquic_packno_t orig_packno, cur_packno, restored_packno;
|
|
|
|
|
|
|
|
len = packno_bits2len(bits);
|
|
|
|
epoch_delta = 1ULL << (len << 3);
|
|
|
|
epoch = epoch_delta * 11 /* Just some number */;
|
|
|
|
|
|
|
|
/* Test current epoch: */
|
|
|
|
for (op = 0; op < N_OPS; ++op)
|
|
|
|
for (n = 0; n < 5; ++n)
|
|
|
|
{
|
|
|
|
/* Test at the ends of the epoch */
|
|
|
|
if (op == OP_MINUS)
|
|
|
|
orig_packno = epoch - epoch_delta / 2 + n;
|
|
|
|
else if (op == OP_PLUS)
|
|
|
|
orig_packno = epoch + epoch_delta / 2 - n - 1;
|
|
|
|
else
|
|
|
|
assert(0);
|
|
|
|
cur_packno = orig_packno & (epoch_delta - 1);
|
|
|
|
restored_packno = restore_packno(cur_packno, bits, epoch);
|
|
|
|
assert(orig_packno == restored_packno);
|
|
|
|
/* Test in the middle of the epoch */
|
|
|
|
if (op == OP_MINUS)
|
|
|
|
orig_packno = epoch - n;
|
|
|
|
else
|
|
|
|
orig_packno = epoch + n;
|
|
|
|
cur_packno = orig_packno & (epoch_delta - 1);
|
|
|
|
restored_packno = restore_packno(cur_packno, bits, epoch);
|
|
|
|
assert(orig_packno == restored_packno);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test previous epoch (max is to the left) */
|
|
|
|
for (n = 0; n < 5; ++n)
|
|
|
|
{
|
|
|
|
/* Test at the end of the epoch */
|
|
|
|
orig_packno = epoch + epoch_delta / 2 - n - 1;
|
|
|
|
cur_packno = orig_packno & (epoch_delta - 1);
|
|
|
|
restored_packno = restore_packno(cur_packno, bits, epoch - epoch_delta * 3 / 4);
|
|
|
|
assert(orig_packno == restored_packno + epoch_delta);
|
|
|
|
/* Test in the middle of the epoch */
|
|
|
|
orig_packno = epoch + 2 - n;
|
|
|
|
cur_packno = orig_packno & (epoch_delta - 1);
|
|
|
|
restored_packno = restore_packno(cur_packno, bits, epoch - epoch_delta * 3 / 4);
|
|
|
|
assert(orig_packno == restored_packno + epoch_delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test previous epoch (max is to the right) */
|
|
|
|
for (n = 0; n < 5; ++n)
|
|
|
|
{
|
|
|
|
/* Test at the end of the epoch */
|
|
|
|
orig_packno = epoch - epoch_delta / 2 + n;
|
|
|
|
cur_packno = orig_packno & (epoch_delta - 1);
|
|
|
|
restored_packno = restore_packno(cur_packno, bits, epoch + epoch_delta * 3 / 4);
|
|
|
|
assert(orig_packno == restored_packno - epoch_delta);
|
|
|
|
/* Test in the middle of the epoch */
|
|
|
|
orig_packno = epoch + 2 - n;
|
|
|
|
cur_packno = orig_packno & (epoch_delta - 1);
|
|
|
|
restored_packno = restore_packno(cur_packno, bits, epoch + epoch_delta * 3 / 4);
|
|
|
|
assert(orig_packno == restored_packno - epoch_delta);
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
main (void)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
for (i = 0; i < sizeof(pb_tests) / sizeof(pb_tests[0]); ++i)
|
|
|
|
run_pbt(i);
|
|
|
|
for (i = 0; i < sizeof(rp_tests) / sizeof(rp_tests[0]); ++i)
|
|
|
|
run_rpt(i);
|
|
|
|
test_restore(PACKNO_LEN_1);
|
|
|
|
test_restore(PACKNO_LEN_2);
|
|
|
|
test_restore(PACKNO_LEN_4);
|
|
|
|
test_restore(PACKNO_LEN_6);
|
|
|
|
return 0;
|
|
|
|
}
|