Browse Source

MT#63317 support ext filter in kernel

Change-Id: Ic98dde266c7707dd3350d651032d989511ee3bee
pull/2008/head
Richard Fuchs 3 months ago
parent
commit
1b05cb043e
8 changed files with 682 additions and 9 deletions
  1. +39
    -1
      daemon/media_socket.c
  2. +1
    -0
      include/media_socket.h
  3. +128
    -0
      kernel-module/extmap_filter.inc.c
  4. +28
    -6
      kernel-module/xt_RTPENGINE.c
  5. +6
    -1
      kernel-module/xt_RTPENGINE.h
  6. +1
    -0
      t/.gitignore
  7. +5
    -1
      t/Makefile
  8. +474
    -0
      t/kernel-extmap-filter.c

+ 39
- 1
daemon/media_socket.c View File

@ -1728,7 +1728,6 @@ static const char *kernelize_target(kernelize_state *s, struct packet_stream *st
* The linkage between userspace and kernel module is in the kernelize_one().
*
* Called with stream->lock held.
* sink_handler can be NULL.
*/
__attribute__((nonnull(1, 2, 3)))
static const char *kernelize_one(kernelize_state *s,
@ -1836,6 +1835,7 @@ static const char *kernelize_one(kernelize_state *s,
}
handler->out->kernel(&redi->output.encrypt, sink);
sink_handler->rtpext->kernel(&redi->output, media, sink->media);
if (sink != stream)
mutex_unlock(&sink->lock);
@ -2071,9 +2071,15 @@ static size_t rtpext_printer_copy_print(struct rtp_header *rh, void *dst, const
return mp->extensions.len;
}
static void rtpext_printer_copy_kernel(struct rtpengine_output_info *roi,
struct call_media *src, struct call_media *dst)
{
}
const struct rtpext_printer rtpext_printer_copy = {
.length = rtpext_printer_copy_length,
.print = rtpext_printer_copy_print,
.kernel = rtpext_printer_copy_kernel,
.may_copy = true,
};
@ -2154,9 +2160,41 @@ static size_t rtpext_printer_extmap_print(struct rtp_header *rh, void *dst, cons
return padded;
}
static int uint8_sort(const void *a, const void *b) {
const uint8_t *A = a, *B = b;
if (*A < *B)
return -1;
if (*A > *B)
return 1;
return 0;
}
static void rtpext_printer_extmap_kernel(struct rtpengine_output_info *roi,
struct call_media *src, struct call_media *dst)
{
roi->extmap = 1;
unsigned int u = 0;
for (__auto_type l = dst->extmap.head; l; l = l->next) {
__auto_type ext = l->data;
if (u >= RTPE_NUM_EXTMAP_FILTER) {
ilog(LOG_WARN, "Too many RTP header extensions for kernel module");
break;
}
roi->extmap_filter[u] = ext->id;
u++;
}
qsort(roi->extmap_filter, u, sizeof(*roi->extmap_filter), uint8_sort);
}
static const struct rtpext_printer rtpext_printer_extmap = {
.length = rtpext_printer_extmap_length,
.print = rtpext_printer_extmap_print,
.kernel = rtpext_printer_extmap_kernel,
.may_copy = false,
};


+ 1
- 0
include/media_socket.h View File

@ -257,6 +257,7 @@ struct sink_attrs {
struct rtpext_printer {
size_t (*length)(const struct media_packet *);
size_t (*print)(struct rtp_header *, void *dst, const struct media_packet *);
void (*kernel)(struct rtpengine_output_info *, struct call_media *, struct call_media *);
bool may_copy;
};


+ 128
- 0
kernel-module/extmap_filter.inc.c View File

@ -0,0 +1,128 @@
static int extmap_find(const void *key, const void *ele) {
const uint8_t *k = key, *e = ele;
if (*k < *e)
return -1;
if (*k > *e)
return 1;
return 0;
}
static bool extmap_has_ext(uint8_t id, struct rtpengine_output *o) {
uint8_t *const *match = bsearch(&id, o->output.extmap_filter, o->output.num_extmap_filter,
sizeof(*o->output.extmap_filter), extmap_find);
return match != NULL;
}
static bool apply_extmap_filter_ext(uint8_t id, size_t len, size_t size,
unsigned char **r, unsigned char **w, unsigned char *end,
unsigned int *count,
struct rtpengine_output *o)
{
if (*r + size + len > end)
return false;
if (extmap_has_ext(id, o)) {
// retain ext
if (*r != *w)
memmove(*w, *r, len + size);
*w += len + size;
(*count)++;
}
// else: skip over & filter out
*r += len + size;
return true;
}
static void apply_extmap_filter_finish(unsigned char *r, unsigned char *w, unsigned int count,
struct sk_buff *skb, struct rtp_parsed *rtp)
{
if (r == w)
return; // everything left as it was
if (count == 0) {
// no extensions, remove header and trim packet
rtp->rtp_header->v_p_x_cc &= ~0x10;
size_t pull = rtp->payload - (unsigned char *) rtp->ext_hdr;
memmove(rtp->ext_hdr, rtp->payload, rtp->payload_len);
rtp->payload = (unsigned char *) rtp->ext_hdr;
rtp->ext_hdr = NULL;
rtp->extension_len = 0;
skb_trim(skb, skb->len - pull);
return;
}
// shift up payload and trim packet
size_t size = w - rtp->extension;
size_t padded = (size + 3L) & ~3L;
memset(w, 0, padded - size);
rtp->ext_hdr->length = htons(padded / 4);
size_t pull = rtp->extension_len - padded;
rtp->extension_len = padded;
memmove(rtp->payload - pull, rtp->payload, rtp->payload_len);
rtp->payload -= pull;
skb_trim(skb, skb->len - pull);
}
static void apply_extmap_filter_short(struct sk_buff *skb, struct rtpengine_output *o, struct rtp_parsed *rtp) {
unsigned char *r = rtp->extension; // reader
unsigned char *end = r + rtp->extension_len;
unsigned char *w = r; // writer
unsigned int count = 0; // non-padding extensions
// XXX partly shared code
while (r < end) {
uint8_t id_len = r[0];
if (id_len == '\0') {
// padding
r++; // don't copy padding to *w
continue;
}
uint8_t id = id_len >> 4;
uint8_t len = (id_len & 0xf) + 1;
if (!apply_extmap_filter_ext(id, len, 1, &r, &w, end, &count, o))
break;
}
apply_extmap_filter_finish(r, w, count, skb, rtp);
}
static void apply_extmap_filter_long(struct sk_buff *skb, struct rtpengine_output *o, struct rtp_parsed *rtp) {
unsigned char *r = rtp->extension; // reader
unsigned char *end = r + rtp->extension_len;
unsigned char *w = r; // writer
unsigned int count = 0; // non-padding extensions
// XXX partly shared code
while (r < end) {
uint8_t id = r[0];
if (id == '\0') {
// padding
r++; // don't copy padding to *w
continue;
}
uint8_t len = r[1];
if (!apply_extmap_filter_ext(id, len, 2, &r, &w, end, &count, o))
break;
}
apply_extmap_filter_finish(r, w, count, skb, rtp);
}
static void apply_extmap_filter(struct sk_buff *skb, struct rtpengine_output *o, struct rtp_parsed *rtp) {
if (!rtp->ext_hdr)
return;
if (ntohs(rtp->ext_hdr->undefined) == 0xbede)
apply_extmap_filter_short(skb, o, rtp);
else if ((ntohs(rtp->ext_hdr->undefined) & 0xfff0) == 0x0100)
apply_extmap_filter_long(skb, o, rtp);
// else: leave untouched
}

+ 28
- 6
kernel-module/xt_RTPENGINE.c View File

@ -510,9 +510,12 @@ struct rtp_parsed {
struct rtp_header *rtp_header;
struct rtcp_header *rtcp_header;
};
unsigned int header_len;
size_t header_len;
unsigned char *payload;
unsigned int payload_len;
size_t payload_len;
struct rtp_exthdr *ext_hdr;
unsigned char *extension;
size_t extension_len;
int ok;
int rtcp;
};
@ -1804,6 +1807,13 @@ static int proc_list_show(struct seq_file *f, void *v) {
g->target.pt_stats[j]->payload_type);
}
if (o->output.extmap) {
seq_printf(f, " Allowed RTP extensions:");
for (j = 0; j < o->output.num_extmap_filter; j++)
seq_printf(f, " %u", (unsigned int) o->output.extmap_filter[j]);
seq_printf(f, "\n");
}
proc_list_crypto_print(f, &o->encrypt_rtp, &o->output.encrypt, "encryption");
}
@ -5131,7 +5141,6 @@ drop:
/* XXX shared code */
static void parse_rtp(struct rtp_parsed *rtp, struct sk_buff *skb) {
struct rtp_exthdr *ext;
size_t ext_len;
if (skb->len < sizeof(*rtp->rtp_header))
@ -5150,16 +5159,20 @@ static void parse_rtp(struct rtp_parsed *rtp, struct sk_buff *skb) {
if ((rtp->rtp_header->v_p_x_cc & 0x10)) {
/* extension */
if (rtp->payload_len < sizeof(*ext))
if (rtp->payload_len < sizeof(*rtp->ext_hdr))
goto error;
ext = (void *) rtp->payload;
ext_len = sizeof(*ext) + ntohs(ext->length) * 4;
rtp->ext_hdr = (struct rtp_exthdr *) rtp->payload;
rtp->extension_len = ntohs(rtp->ext_hdr->length) * 4;
ext_len = sizeof(*rtp->ext_hdr) + rtp->extension_len;
if (rtp->payload_len < ext_len)
goto error;
rtp->extension = rtp->payload + sizeof(*rtp->ext_hdr);
rtp->payload += ext_len;
rtp->payload_len -= ext_len;
rtp->header_len += ext_len;
}
else
rtp->ext_hdr = NULL;
DBG("rtp header parsed, payload length is %u\n", rtp->payload_len);
@ -6065,6 +6078,8 @@ static uint32_t proxy_packet_srtp_encrypt(struct sk_buff *skb, struct re_crypto_
return pkt_idx;
}
#include "extmap_filter.inc.c"
static bool proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpengine_output *o,
int rtp_pt_idx,
struct rtp_parsed *rtp, int ssrc_idx)
@ -6077,6 +6092,9 @@ static bool proxy_packet_output_rtXp(struct sk_buff *skb, struct rtpengine_outpu
return true;
}
if (o->output.extmap)
apply_extmap_filter(skb, o, rtp);
if (rtp_pt_idx >= 0) {
// blackhole?
if (o->output.pt_output[rtp_pt_idx].blackhole)
@ -6465,6 +6483,10 @@ static unsigned int rtpengine46(struct sk_buff *skb, struct sk_buff *oskb,
if (rtp.rtp_header)
rtp2.rtp_header = (void *) (((char *) rtp2.rtp_header) + offset);
rtp2.payload = (void *) (((char *) rtp2.payload) + offset);
if (rtp2.extension)
rtp2.extension = (void *) (((char *) rtp2.extension) + offset);
if (rtp2.ext_hdr)
rtp2.ext_hdr = (void *) (((char *) rtp2.ext_hdr) + offset);
datalen_out = skb2->len;


+ 6
- 1
kernel-module/xt_RTPENGINE.h View File

@ -8,6 +8,7 @@
#define RTPE_NUM_PAYLOAD_TYPES 32
#define RTPE_MAX_FORWARD_DESTINATIONS 32
#define RTPE_NUM_SSRC_TRACKING 4
#define RTPE_NUM_EXTMAP_FILTER 32
@ -125,12 +126,16 @@ struct rtpengine_output_info {
uint32_t seq_offset[RTPE_NUM_SSRC_TRACKING]; // Rewrite output seq
struct rtpengine_pt_output pt_output[RTPE_NUM_PAYLOAD_TYPES]; // same indexes as pt_input
uint8_t extmap_filter[RTPE_NUM_EXTMAP_FILTER]; // must be sorted
unsigned int num_extmap_filter;
struct interface_stats_block *iface_stats; // for egress stats
struct stream_stats *stats; // for egress stats
struct ssrc_stats *ssrc_stats[RTPE_NUM_SSRC_TRACKING];
unsigned char tos;
unsigned int ssrc_subst:1;
unsigned int ssrc_subst:1,
extmap:1;
};
struct rtpengine_destination_info {


+ 1
- 0
t/.gitignore View File

@ -29,3 +29,4 @@ test-amr-decode
test-amr-encode
aead-decrypt
s3-auth
kernel-extmap-filter

+ 5
- 1
t/Makefile View File

@ -97,6 +97,8 @@ endif
SRCS+= s3-auth.c
LIBSRCS+= s3utils.c
SRCS+= kernel-extmap-filter.c
COMMONOBJS= str.o auxlib.o rtplib.o loglib.o ssllib.o
include ../lib/common.Makefile
@ -129,7 +131,7 @@ all-tests: unit-tests
endif
true # override linking recipe from common.Makefile
unit-tests: $(TESTS) aead-decrypt
unit-tests: $(TESTS) aead-decrypt kernel-extmap-filter
failed="" ; \
for x in $(TESTS); do \
echo `date +"%Y-%m-%d %H:%M:%S"` testing: $$x ; \
@ -343,6 +345,8 @@ test-const_str_hash.strhash: test-const_str_hash.strhash.o $(COMMONOBJS) bencode
s3-auth: s3-auth.o s3utils.o
kernel-extmap-filter: kernel-extmap-filter.o
PRELOAD_CFLAGS += -D_GNU_SOURCE -std=c11
PRELOAD_LIBS += -ldl


+ 474
- 0
t/kernel-extmap-filter.c View File

@ -0,0 +1,474 @@
#include <sys/types.h>
#include <stdint.h>
#include <stdlib.h>
#include <stdbool.h>
#include <string.h>
#include <arpa/inet.h>
#include <assert.h>
#include <stdio.h>
struct rtpengine_output {
struct {
uint8_t extmap_filter[32];
unsigned int num_extmap_filter;
} output;
};
struct sk_buff {
unsigned int len;
};
struct rtp_header {
unsigned char v_p_x_cc;
unsigned char _pad[3];
};
struct rtp_exthdr {
uint16_t undefined;
uint16_t length;
} __attribute__ ((packed));
struct rtp_parsed {
struct rtp_header *rtp_header;
unsigned char *payload;
size_t payload_len;
struct rtp_exthdr *ext_hdr;
unsigned char *extension;
size_t extension_len;
};
static void skb_trim(struct sk_buff *s, unsigned int len) {
s->len = len;
}
#include "../kernel-module/extmap_filter.inc.c"
static void pkt(unsigned char *d, struct sk_buff *skb, struct rtp_parsed *r,
uint8_t hdr_val,
size_t ext_hdr_len, const unsigned char *ext_hdr,
size_t extensions_len, const unsigned char *extensions)
{
*d = hdr_val;
r->rtp_header = (struct rtp_header *) d;
memset(r->rtp_header, 0, sizeof(*r->rtp_header));
d += sizeof(struct rtp_header);
if (ext_hdr_len == 0) {
assert(extensions_len == 0);
r->ext_hdr = NULL;
}
else if (ext_hdr_len == 2) {
r->ext_hdr = (struct rtp_exthdr *) d;
*d++ = ext_hdr[0];
*d++ = ext_hdr[1];
size_t padded = (extensions_len + 3L) & ~3L;
// verify math
assert((padded & 0x3) == 0);
assert(padded >= extensions_len);
size_t padding = padded - extensions_len;
assert(padding < 4);
size_t blocks = padded / 4L;
assert(blocks <= 0xffff);
*d++ = blocks >> 8;
*d++ = blocks & 0xff;
r->extension = d;
memcpy(d, extensions, extensions_len);
d += extensions_len;
memset(d, 0, padding);
d += padding;
r->extension_len = padded;
}
else
abort();
// fixed dummy payload
r->payload = d;
for (unsigned i = 0; i < 128; i++)
*d++ = i + 64;
r->payload_len = 128;
skb->len = d - (unsigned char *) r->rtp_header;
}
static void dump(uint8_t *d, size_t len) {
for (size_t i = 0; i < len; i++)
printf("%02x ", d[i]);
printf("\n");
}
static void tester(
unsigned int line,
uint8_t rtp_hdr_val_in, size_t ext_hdr_in_len, const unsigned char *ext_hdr_in,
size_t extensions_in_len, const unsigned char *extensions_in,
unsigned int filter_len, const uint8_t *filter,
uint8_t rtp_hdr_val_exp, size_t ext_hdr_exp_len, const unsigned char *ext_hdr_exp,
size_t extensions_exp_len, const unsigned char *extensions_exp)
{
printf("test @ line %u\n", line);
// build packets
unsigned char in [sizeof(struct rtp_header) + ext_hdr_in_len + 2 + extensions_in_len + 3 + 128];
unsigned char exp[sizeof(struct rtp_header) + ext_hdr_exp_len + 2 + extensions_exp_len + 3 + 128];
struct sk_buff is;
struct sk_buff es;
struct rtp_parsed ip;
struct rtp_parsed ep;
pkt(in, &is, &ip, rtp_hdr_val_in, ext_hdr_in_len, ext_hdr_in, extensions_in_len, extensions_in);
pkt(exp, &es, &ep, rtp_hdr_val_exp, ext_hdr_exp_len, ext_hdr_exp, extensions_exp_len, extensions_exp);
struct rtpengine_output o = {0};
assert(filter_len <= sizeof(o.output.extmap_filter));
o.output.num_extmap_filter = filter_len;
memcpy(o.output.extmap_filter, filter, filter_len);
apply_extmap_filter(&is, &o, &ip);
if (is.len != es.len) {
printf("%u != %u\n", is.len, es.len);
assert(0);
}
if (memcmp(in, exp, is.len)) {
dump(in, is.len);
dump(exp, is.len);
assert(0);
}
assert(ip.payload_len == ep.payload_len);
assert(memcmp(ip.payload, ep.payload, ip.payload_len) == 0);
printf("ok\n");
}
#define TEST( \
rtp_hdr_val_in, ext_hdr_in, extensions_in, \
filter, \
rtp_hdr_val_exp, ext_hdr_exp, extensions_exp \
) \
tester( \
__LINE__, \
rtp_hdr_val_in, \
sizeof(ext_hdr_in) - 1, (unsigned char *) ext_hdr_in, \
sizeof(extensions_in) - 1, (unsigned char *) extensions_in, \
sizeof(filter) - 1, (uint8_t *) filter, \
rtp_hdr_val_exp, \
sizeof(ext_hdr_exp) - 1, (unsigned char *) ext_hdr_exp, \
sizeof(extensions_exp) - 1, (unsigned char *) extensions_exp \
);
int main(void) {
// no extensions, no filter
TEST(
0x80, "", "",
"",
0x80, "", ""
);
// no extensions, filter
TEST(
0x80, "", "",
"\x01\x02\x03\x04",
0x80, "", ""
);
// one-byte extension, empty filter (not allowed)
TEST(
0x90, "\xbe\xde", "\x12" "foo",
"",
0x80, "", ""
);
TEST(
0x90, "\xbe\xde", "\x10" "x",
"",
0x80, "", ""
);
// multiple one-byte extensions, empty filter (not allowed)
TEST(
0x90, "\xbe\xde", "\x12" "foo" "\x22" "bar" "\x32" "yax" "\x42" "wuz",
"",
0x80, "", ""
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\x20" "y" "\x30" "z" "\x40" "p",
"",
0x80, "", ""
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\0\0" "\x20" "y" "\0\0" "\x30" "z" "\0\0" "\x40" "p",
"",
0x80, "", ""
);
// multiple one-byte extensions, allow first
TEST(
0x90, "\xbe\xde", "\x12" "foo" "\x22" "bar" "\x32" "yax" "\x42" "wuz",
"\x01",
0x90, "\xbe\xde", "\x12" "foo"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\x20" "y" "\x30" "z" "\x40" "p",
"\x01",
0x90, "\xbe\xde", "\x10" "x"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\0\0" "\x20" "y" "\0\0" "\x30" "z" "\0\0" "\x40" "p",
"\x01",
0x90, "\xbe\xde", "\x10" "x"
);
// multiple one-byte extensions, allow second
TEST(
0x90, "\xbe\xde", "\x12" "foo" "\x22" "bar" "\x32" "yax" "\x42" "wuz",
"\x02",
0x90, "\xbe\xde", "\x22" "bar"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\x20" "y" "\x30" "z" "\x40" "p",
"\x02",
0x90, "\xbe\xde", "\x20" "y"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\0\0" "\x20" "y" "\0\0" "\x30" "z" "\0\0" "\x40" "p",
"\x02",
0x90, "\xbe\xde", "\x20" "y"
);
// multiple one-byte extensions, allow last
TEST(
0x90, "\xbe\xde", "\x12" "foo" "\x22" "bar" "\x32" "yax" "\x42" "wuz",
"\x04",
0x90, "\xbe\xde", "\x42" "wuz"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\x20" "y" "\x30" "z" "\x40" "p",
"\x04",
0x90, "\xbe\xde", "\x40" "p"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\0\0" "\x20" "y" "\0\0" "\x30" "z" "\0\0" "\x40" "p",
"\x04",
0x90, "\xbe\xde", "\x40" "p"
);
// multiple one-byte extensions, allow first and third
TEST(
0x90, "\xbe\xde", "\x12" "foo" "\x22" "bar" "\x32" "yax" "\x42" "wuz",
"\x01\x03",
0x90, "\xbe\xde", "\x12" "foo" "\x32" "yax"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\x20" "y" "\x30" "z" "\x40" "p",
"\x01\x03",
0x90, "\xbe\xde", "\x10" "x" "\x30" "z"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\0\0" "\x20" "y" "\0\0" "\x30" "z" "\0\0" "\x40" "p",
"\x01\x03",
0x90, "\xbe\xde", "\x10" "x" "\x30" "z"
);
// multiple one-byte extensions, allow second and last
TEST(
0x90, "\xbe\xde", "\x12" "foo" "\x22" "bar" "\x32" "yax" "\x42" "wuz",
"\x02\x04",
0x90, "\xbe\xde", "\x22" "bar" "\x42" "wuz"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\x20" "y" "\x30" "z" "\x40" "p",
"\x02\x04",
0x90, "\xbe\xde", "\x20" "y" "\x40" "p"
);
TEST(
0x90, "\xbe\xde", "\x10" "x" "\0\0" "\x20" "y" "\0\0" "\x30" "z" "\0\0" "\x40" "p",
"\x02\x04",
0x90, "\xbe\xde", "\x20" "y" "\x40" "p"
);
// random padding, allow multiple
TEST(
0x90, "\xbe\xde",
"\x10" "a" "\x20" "b" "\0" "\x30" "c" "\0\0" "\x40" "d" "\0\0\0"
"\x51" "ee" "\x61" "ff" "\0" "\x71" "gg" "\0\0" "\x81" "hh" "\0\0\0"
"\x92" "kkk" "\xa2" "lll" "\0" "\xb2" "mmm" "\0\0" "\xc2" "nnn" "\0\0\0"
"\xd3" "oooo",
"\x01\x04\x07\x0a\x0c\x0d",
0x90, "\xbe\xde", "\x10" "a" "\x40" "d" "\x71" "gg" "\xa2" "lll" "\xc2" "nnn" "\xd3" "oooo"
);
TEST(
0x90, "\xbe\xde",
"\x10" "a" "\x20" "b" "\0" "\x30" "c" "\0\0" "\x40" "d" "\0\0\0"
"\x51" "ee" "\x61" "ff" "\0" "\x71" "gg" "\0\0" "\x81" "hh" "\0\0\0"
"\x92" "kkk" "\xa2" "lll" "\0" "\xb2" "mmm" "\0\0" "\xc2" "nnn" "\0\0\0"
"\xd5" "oooooo",
"\x01\x04\x07\x0a\x0c\x0d",
0x90, "\xbe\xde", "\x10" "a" "\x40" "d" "\x71" "gg" "\xa2" "lll" "\xc2" "nnn" "\xd5" "oooooo"
);
// two-byte extension, empty filter (not allowed)
TEST(
0x90, "\x01\x00", "\x01\x03" "foo",
"",
0x80, "", ""
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x",
"",
0x80, "", ""
);
// multiple one-byte extensions, empty filter (not allowed)
TEST(
0x90, "\x01\x00", "\x01\x03" "foo" "\x02\x03" "bar" "\x03\x03" "yax" "\x04\x03" "wuz",
"",
0x80, "", ""
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\x02\x01" "y" "\x03\x01" "z" "\x40" "p",
"",
0x80, "", ""
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\0\0" "\x02\x01" "y" "\0\0" "\x03\x01" "z" "\0\0" "\x40" "p",
"",
0x80, "", ""
);
// multiple one-byte extensions, allow first
TEST(
0x90, "\x01\x00", "\x01\x03" "foo" "\x02\x03" "bar" "\x03\x03" "yax" "\x04\x03" "wuz",
"\x01",
0x90, "\x01\x00", "\x01\x03" "foo"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\x02\x01" "y" "\x03\x01" "z" "\x40" "p",
"\x01",
0x90, "\x01\x00", "\x01\x01" "x"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\0\0" "\x02\x01" "y" "\0\0" "\x03\x01" "z" "\0\0" "\x40" "p",
"\x01",
0x90, "\x01\x00", "\x01\x01" "x"
);
// multiple one-byte extensions, allow second
TEST(
0x90, "\x01\x00", "\x01\x03" "foo" "\x02\x03" "bar" "\x03\x03" "yax" "\x04\x03" "wuz",
"\x02",
0x90, "\x01\x00", "\x02\x03" "bar"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\x02\x01" "y" "\x03\x01" "z" "\x40" "p",
"\x02",
0x90, "\x01\x00", "\x02\x01" "y"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\0\0" "\x02\x01" "y" "\0\0" "\x03\x01" "z" "\0\0" "\x40" "p",
"\x02",
0x90, "\x01\x00", "\x02\x01" "y"
);
// multiple one-byte extensions, allow last
TEST(
0x90, "\x01\x00", "\x01\x03" "foo" "\x02\x03" "bar" "\x03\x03" "yax" "\x04\x03" "wuz",
"\x04",
0x90, "\x01\x00", "\x04\x03" "wuz"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\x02\x01" "y" "\x03\x01" "z" "\x04\x01" "p",
"\x04",
0x90, "\x01\x00", "\x04\x01" "p"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\0\0" "\x02\x01" "y" "\0\0" "\x03\x01" "z" "\0\0" "\x04\x01" "p",
"\x04",
0x90, "\x01\x00", "\x04\x01" "p"
);
// multiple one-byte extensions, allow first and third
TEST(
0x90, "\x01\x00", "\x01\x03" "foo" "\x02\x03" "bar" "\x03\x03" "yax" "\x04\x03" "wuz",
"\x01\x03",
0x90, "\x01\x00", "\x01\x03" "foo" "\x03\x03" "yax"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\x02\x01" "y" "\x03\x01" "z" "\x04\x01" "p",
"\x01\x03",
0x90, "\x01\x00", "\x01\x01" "x" "\x03\x01" "z"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\0\0" "\x02\x01" "y" "\0\0" "\x03\x01" "z" "\0\0" "\x04\x01" "p",
"\x01\x03",
0x90, "\x01\x00", "\x01\x01" "x" "\x03\x01" "z"
);
// multiple one-byte extensions, allow second and last
TEST(
0x90, "\x01\x00", "\x01\x03" "foo" "\x02\x03" "bar" "\x03\x03" "yax" "\x04\x03" "wuz",
"\x02\x04",
0x90, "\x01\x00", "\x02\x03" "bar" "\x04\x03" "wuz"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\x02\x01" "y" "\x03\x01" "z" "\x04\x01" "p",
"\x02\x04",
0x90, "\x01\x00", "\x02\x01" "y" "\x04\x01" "p"
);
TEST(
0x90, "\x01\x00", "\x01\x01" "x" "\0\0" "\x02\x01" "y" "\0\0" "\x03\x01" "z" "\0\0" "\x04\x01" "p",
"\x02\x04",
0x90, "\x01\x00", "\x02\x01" "y" "\x04\x01" "p"
);
// random padding, allow multiple
TEST(
0x90, "\x01\x00",
"\x01\x01" "a" "\x02\x01" "b" "\0" "\x03\x01" "c" "\0\0" "\x04\x01" "d" "\0\0\0"
"\x05\x02" "ee" "\x06\x02" "ff" "\0" "\x07\x02" "gg" "\0\0" "\x08\x02" "hh" "\0\0\0"
"\x09\x03" "kkk" "\x0a\x03" "lll" "\0" "\x0b\x03" "mmm" "\0\0" "\x0c\x03" "nnn" "\0\0\0"
"\x0d\x04" "oooo",
"\x01\x04\x07\x0a\x0c\x0d",
0x90, "\x01\x00", "\x01\x01" "a" "\x04\x01" "d" "\x07\x02" "gg" "\x0a\x03" "lll" "\x0c\x03" "nnn" "\x0d\04" "oooo"
);
TEST(
0x90, "\x01\x00",
"\x01\x01" "a" "\x02\x01" "b" "\0" "\x03\x01" "c" "\0\0" "\x04\x01" "d" "\0\0\0"
"\x05\x02" "ee" "\x06\x02" "ff" "\0" "\x07\x02" "gg" "\0\0" "\x08\x02" "hh" "\0\0\0"
"\x09\x03" "kkk" "\x0a\x03" "lll" "\0" "\x0b\x03" "mmm" "\0\0" "\x0c\x03" "nnn" "\0\0\0"
"\x0d\x06" "oooooo",
"\x01\x04\x07\x0a\x0c\x0d",
0x90, "\x01\x00", "\x01\x01" "a" "\x04\x01" "d" "\x07\x02" "gg" "\x0a\x03" "lll" "\x0c\x03" "nnn" "\x0d\x06" "oooooo"
);
// higher IDs and longer values
TEST(
0x90, "\x01\x00",
"\x31\x01" "a" "\x32\x21" "bxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\0" "\x33\x01" "c" "\0\0" "\x34\x21" "dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\0\0\0"
"\x35\x02" "ee" "\x36\x22" "ffxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\0" "\x37\x02" "gg" "\0\0" "\x38\x22" "hhxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\0\0\0"
"\x39\x03" "kkk" "\x3a\x23" "lllxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\0" "\x3b\x03" "mmm" "\0\0" "\x3c\x23" "nnnxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\0\0\0"
"\x3d\x04" "oooo",
"\x31\x34\x37\x3a\x3c\x3d",
0x90, "\x01\x00", "\x31\x01" "a" "\x34\x21" "dxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\x37\x02" "gg" "\x3a\x23" "lllxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\x3c\x23" "nnnxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" "\x3d\04" "oooo"
);
return 0;
}

Loading…
Cancel
Save