2019-09-11 15:27:58 +00:00
|
|
|
/* Copyright (c) 2017 - 2019 LiteSpeed Technologies Inc. See LICENSE. */
|
|
|
|
/* Test both generation and parsing of IETF ACK frames */
|
|
|
|
|
|
|
|
#include <assert.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "lsquic.h"
|
|
|
|
#include "lsquic_types.h"
|
|
|
|
#include "lsquic_int_types.h"
|
|
|
|
#include "lsquic_sizes.h"
|
|
|
|
#include "lsquic_parse.h"
|
|
|
|
#include "lsquic_trans_params.h"
|
|
|
|
|
|
|
|
struct test
|
|
|
|
{
|
|
|
|
int lineno;
|
|
|
|
int skip_gen;
|
|
|
|
|
|
|
|
struct ack_info acki;
|
|
|
|
|
|
|
|
size_t encoded_sz;
|
|
|
|
unsigned char encoded[0x1000];
|
|
|
|
};
|
|
|
|
|
|
|
|
static const lsquic_time_t now = 0x12345676890;
|
|
|
|
|
|
|
|
static const struct test tests[] =
|
|
|
|
{
|
|
|
|
{
|
|
|
|
.lineno = __LINE__,
|
|
|
|
.acki =
|
|
|
|
{
|
|
|
|
.n_ranges = 2,
|
|
|
|
.lack_delta = 0xFEDCB0,
|
|
|
|
.ranges =
|
|
|
|
{
|
|
|
|
[0] = { 7, 7, },
|
|
|
|
[1] = { 0, 0, },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.encoded =
|
|
|
|
{
|
|
|
|
/* Type */ 0x02,
|
|
|
|
/* Largest acked */ 0x07,
|
|
|
|
/* ACK delay */ 0x80, 0x1F, 0xDB, 0x96,
|
|
|
|
/* Addl block count */ 0x01,
|
|
|
|
/* First ACK block */ 0x00,
|
|
|
|
/* Gap */ 0x05,
|
|
|
|
/* ACK block */ 0x00,
|
|
|
|
},
|
|
|
|
.encoded_sz = 10,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
.lineno = __LINE__,
|
|
|
|
.acki =
|
|
|
|
{
|
|
|
|
.n_ranges = 3,
|
|
|
|
.lack_delta = 0xFEDCB0,
|
|
|
|
.ranges =
|
|
|
|
{
|
|
|
|
[0] = { 10, 10, },
|
|
|
|
[1] = { 7, 7, },
|
|
|
|
[2] = { 0, 0, },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.encoded =
|
|
|
|
{
|
|
|
|
/* Type */ 0x02,
|
|
|
|
/* Largest acked */ 10,
|
|
|
|
/* ACK delay */ 0x80, 0x1F, 0xDB, 0x96,
|
|
|
|
/* Addl block count */ 2,
|
|
|
|
/* First ACK block */ 0x00,
|
|
|
|
/* Gap */ 0x01,
|
|
|
|
/* ACK block */ 0x00,
|
|
|
|
/* Gap */ 0x05,
|
|
|
|
/* ACK block */ 0x00,
|
|
|
|
},
|
|
|
|
.encoded_sz = 12,
|
|
|
|
},
|
|
|
|
|
|
|
|
{
|
|
|
|
.lineno = __LINE__,
|
|
|
|
.acki =
|
|
|
|
{
|
|
|
|
.flags = AI_ECN,
|
|
|
|
.n_ranges = 3,
|
|
|
|
.lack_delta = 0xFEDCB0,
|
|
|
|
.ecn_counts = { 0, 0x010203, 1, 0x49, },
|
|
|
|
.ranges =
|
|
|
|
{
|
|
|
|
[0] = { 10, 10, },
|
|
|
|
[1] = { 7, 7, },
|
|
|
|
[2] = { 0, 0, },
|
|
|
|
},
|
|
|
|
},
|
|
|
|
.encoded =
|
|
|
|
{
|
|
|
|
/* Type */ 0x03,
|
|
|
|
/* Largest acked */ 10,
|
|
|
|
/* ACK delay */ 0x80, 0x1F, 0xDB, 0x96,
|
|
|
|
/* Addl block count */ 2,
|
|
|
|
/* First ACK block */ 0x00,
|
|
|
|
/* Gap */ 0x01,
|
|
|
|
/* ACK block */ 0x00,
|
|
|
|
/* Gap */ 0x05,
|
|
|
|
/* ACK block */ 0x00,
|
|
|
|
/* ECT(1) count */ 0x01,
|
|
|
|
/* ECT(0) count */ 0x80, 0x01, 0x02, 0x03,
|
|
|
|
/* ECN-CE count */ 0x40, 0x49,
|
|
|
|
},
|
|
|
|
.encoded_sz = 19,
|
|
|
|
},
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
struct rechist
|
|
|
|
{
|
|
|
|
const struct ack_info *acki;
|
|
|
|
unsigned next_range;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static const struct lsquic_packno_range *
|
|
|
|
rechist_next (void *ctx)
|
|
|
|
{
|
|
|
|
struct rechist *rechist = ctx;
|
|
|
|
if (rechist->next_range < rechist->acki->n_ranges)
|
|
|
|
return rechist->acki->ranges + rechist->next_range++;
|
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
static const struct lsquic_packno_range *
|
|
|
|
rechist_first (void *ctx)
|
|
|
|
{
|
|
|
|
struct rechist *rechist = ctx;
|
|
|
|
rechist->next_range = 0;
|
|
|
|
return rechist_next(rechist);
|
|
|
|
}
|
|
|
|
|
|
|
|
static lsquic_time_t
|
|
|
|
rechist_largest_recv (void *ctx)
|
|
|
|
{
|
|
|
|
struct rechist *rechist = ctx;
|
|
|
|
return now - rechist->acki->lack_delta;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
compare_ackis (const struct ack_info *exp, const struct ack_info *got)
|
|
|
|
{
|
|
|
|
unsigned i;
|
|
|
|
|
|
|
|
assert(exp->flags == got->flags);
|
|
|
|
assert(exp->n_ranges == got->n_ranges);
|
|
|
|
assert(exp->lack_delta == got->lack_delta);
|
|
|
|
assert(exp->n_timestamps == got->n_timestamps);
|
|
|
|
|
|
|
|
for (i = 0; i < exp->n_ranges; ++i)
|
|
|
|
{
|
|
|
|
assert(exp->ranges[i].high == got->ranges[i].high);
|
|
|
|
assert(exp->ranges[i].low == got->ranges[i].low);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (exp->flags & AI_ECN)
|
|
|
|
for (i = 1; i <= 3; ++i)
|
|
|
|
assert(exp->ecn_counts[i] == got->ecn_counts[i]);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
run_test (const struct test *test)
|
|
|
|
{
|
|
|
|
int len, has_missing;
|
|
|
|
lsquic_packno_t largest_received;
|
|
|
|
const struct parse_funcs *pf;
|
|
|
|
struct rechist rechist;
|
|
|
|
struct ack_info acki;
|
|
|
|
size_t sz;
|
|
|
|
unsigned char buf[0x1000];
|
|
|
|
|
2019-09-18 15:22:20 +00:00
|
|
|
pf = select_pf_by_ver(LSQVER_ID23);
|
2019-09-11 15:27:58 +00:00
|
|
|
if (!test->skip_gen)
|
|
|
|
{
|
|
|
|
rechist.acki = &test->acki;
|
|
|
|
len = pf->pf_gen_ack_frame(buf, sizeof(buf), rechist_first, rechist_next,
|
|
|
|
rechist_largest_recv, &rechist, now, &has_missing, &largest_received,
|
|
|
|
test->acki.flags & AI_ECN ? rechist.acki->ecn_counts : NULL);
|
|
|
|
assert(len > 0);
|
|
|
|
assert(largest_received == largest_acked(&test->acki));
|
|
|
|
assert((size_t) len == test->encoded_sz);
|
|
|
|
assert(0 == memcmp(test->encoded, buf, test->encoded_sz));
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Test that shorter buffers cannot get parsed */
|
|
|
|
for (sz = 1; sz < test->encoded_sz; ++sz)
|
|
|
|
{
|
|
|
|
len = pf->pf_parse_ack_frame(test->encoded, sz, &acki,
|
|
|
|
TP_DEF_ACK_DELAY_EXP);
|
|
|
|
assert(len < 0);
|
|
|
|
}
|
|
|
|
|
|
|
|
len = pf->pf_parse_ack_frame(test->encoded, sizeof(test->encoded), &acki,
|
|
|
|
TP_DEF_ACK_DELAY_EXP);
|
|
|
|
assert(len > 0);
|
|
|
|
assert((size_t) len == test->encoded_sz);
|
|
|
|
compare_ackis(&test->acki, &acki);
|
|
|
|
}
|
|
|
|
|
|
|
|
int
|
|
|
|
main (void)
|
|
|
|
{
|
|
|
|
const struct test *test;
|
|
|
|
|
|
|
|
for (test = tests; test < tests + sizeof(tests) / sizeof(tests[0]); ++test)
|
|
|
|
run_test(test);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|