1 /*
2 * Copyright (c) 2017 Fastly, Kazuho Oku
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining a copy
5 * of this software and associated documentation files (the "Software"), to
6 * deal in the Software without restriction, including without limitation the
7 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
8 * sell copies of the Software, and to permit persons to whom the Software is
9 * furnished to do so, subject to the following conditions:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
19 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
20 * IN THE SOFTWARE.
21 */
22 #include "quicly/frame.h"
23 #include "test.h"
24
test_ack_decode_underflow(void)25 static void test_ack_decode_underflow(void)
26 {
27 quicly_ack_frame_t decoded;
28
29 { /* ack pn=0 */
30 const uint8_t pat[] = {0, 0, 0, 0}, *src = pat;
31 ok(quicly_decode_ack_frame(&src, pat + sizeof(pat), &decoded, 0) == 0);
32 ok(src == pat + sizeof(pat));
33 ok(decoded.largest_acknowledged == 0);
34 ok(decoded.num_gaps == 0);
35 ok(decoded.ack_block_lengths[0] == 1);
36 ok(decoded.smallest_acknowledged == 0);
37 }
38 { /* underflow in first block length */
39 const uint8_t pat[] = {0, 0, 0, 1}, *src = pat;
40 ok(quicly_decode_ack_frame(&src, pat + sizeof(pat), &decoded, 0) != 0);
41 }
42
43 { /* frame with gap going down to pn=0 */
44 const uint8_t pat[] = {2, 0, 1, 0, 0, 0}, *src = pat;
45 ok(quicly_decode_ack_frame(&src, pat + sizeof(pat), &decoded, 0) == 0);
46 ok(src == pat + sizeof(pat));
47 ok(decoded.largest_acknowledged == 2);
48 ok(decoded.num_gaps == 1);
49 ok(decoded.ack_block_lengths[0] == 1);
50 ok(decoded.ack_block_lengths[1] == 1);
51 ok(decoded.smallest_acknowledged == 0);
52 }
53
54 { /* additional block length going negative */
55 const uint8_t pat[] = {2, 0, 1, 0, 0, 1}, *src = pat;
56 ok(quicly_decode_ack_frame(&src, pat + sizeof(pat), &decoded, 0) != 0);
57 }
58 { /* gap going negative */
59 const uint8_t pat[] = {2, 0, 1, 0, 3, 0}, *src = pat;
60 ok(quicly_decode_ack_frame(&src, pat + sizeof(pat), &decoded, 0) != 0);
61 }
62 }
63
test_ack_decode(void)64 static void test_ack_decode(void)
65 {
66 {
67 const uint8_t pat[] = {0x34, 0x00, 0x00, 0x11}, *src = pat;
68 quicly_ack_frame_t decoded;
69 ok(quicly_decode_ack_frame(&src, pat + sizeof(pat), &decoded, 0) == 0);
70 ok(src == pat + sizeof(pat));
71 ok(decoded.largest_acknowledged == 0x34);
72 ok(decoded.num_gaps == 0);
73 ok(decoded.ack_block_lengths[0] == 0x12);
74 ok(decoded.smallest_acknowledged == 0x34 - 0x12 + 1);
75 }
76
77 {
78 const uint8_t pat[] = {0x34, 0x00, 0x02, 0x00, 0x01, 0x02, 0x03, 0x04}, *src = pat;
79 quicly_ack_frame_t decoded;
80 ok(quicly_decode_ack_frame(&src, pat + sizeof(pat), &decoded, 0) == 0);
81 ok(src == pat + sizeof(pat));
82 ok(decoded.largest_acknowledged == 0x34);
83 ok(decoded.num_gaps == 2);
84 ok(decoded.ack_block_lengths[0] == 1);
85 ok(decoded.gaps[0] == 2);
86 ok(decoded.ack_block_lengths[1] == 3);
87 ok(decoded.gaps[1] == 4);
88 ok(decoded.ack_block_lengths[2] == 5);
89 ok(decoded.smallest_acknowledged == 0x34 - 1 - 2 - 3 - 4 - 5 + 1);
90 }
91
92 { /* Bogus ACK Frame larger than the internal buffer */
93 uint8_t pat[1024], *end = pat;
94 const uint8_t *src = pat;
95 uint64_t i, range_sum;
96 quicly_ack_frame_t decoded;
97 end = quicly_encodev(end, 0xFA00);
98 end = quicly_encodev(end, 0);
99 end = quicly_encodev(end, QUICLY_ACK_MAX_GAPS + 30); // with excess ranges
100 end = quicly_encodev(end, 8);
101 for (i = 0; i < QUICLY_ACK_MAX_GAPS + 30; ++i) {
102 end = quicly_encodev(end, i); // gap
103 end = quicly_encodev(end, i % 10); // ack-range
104 }
105
106 ok(quicly_decode_ack_frame(&src, end, &decoded, 0) == 0);
107 ok(decoded.largest_acknowledged == 0xFA00);
108 ok(decoded.ack_delay == 0);
109 ok(decoded.num_gaps == QUICLY_ACK_MAX_GAPS);
110 ok(decoded.ack_block_lengths[0] == 8 + 1); // first ack-range
111 range_sum = decoded.ack_block_lengths[0];
112 for (i = 0; i < decoded.num_gaps; ++i) {
113 ok(decoded.gaps[i] == i + 1);
114 ok(decoded.ack_block_lengths[i + 1] == (i % 10) + 1);
115 range_sum += decoded.gaps[i] + decoded.ack_block_lengths[i + 1];
116 }
117 ok(src == end); // decoded the entire frame
118 ok(decoded.smallest_acknowledged == 0xFA00 - range_sum + 1);
119 }
120
121 subtest("underflow", test_ack_decode_underflow);
122 }
123
test_ack_encode(void)124 static void test_ack_encode(void)
125 {
126 quicly_ranges_t ranges;
127 uint8_t buf[256], *end;
128 const uint8_t *src;
129 quicly_ack_frame_t decoded;
130
131 quicly_ranges_init(&ranges);
132 quicly_ranges_add(&ranges, 0x12, 0x14);
133
134 /* encode */
135 end = quicly_encode_ack_frame(buf, buf + sizeof(buf), &ranges, 63);
136 ok(end - buf == 5);
137 /* decode */
138 src = buf + 1;
139 ok(quicly_decode_ack_frame(&src, end, &decoded, 0) == 0);
140 ok(src == end);
141 ok(decoded.ack_delay == 63);
142 ok(decoded.num_gaps == 0);
143 ok(decoded.largest_acknowledged == 0x13);
144 ok(decoded.ack_block_lengths[0] == 2);
145
146 quicly_ranges_add(&ranges, 0x10, 0x11);
147
148 /* encode */
149 end = quicly_encode_ack_frame(buf, buf + sizeof(buf), &ranges, 63);
150 ok(end - buf == 7);
151 /* decode */
152 src = buf + 1;
153 ok(quicly_decode_ack_frame(&src, end, &decoded, 0) == 0);
154 ok(src == end);
155 ok(decoded.ack_delay == 63);
156 ok(decoded.num_gaps == 1);
157 ok(decoded.largest_acknowledged == 0x13);
158 ok(decoded.ack_block_lengths[0] == 2);
159 ok(decoded.gaps[0] == 1);
160 ok(decoded.ack_block_lengths[1] == 1);
161
162 quicly_ranges_clear(&ranges);
163 }
164
test_mozquic(void)165 static void test_mozquic(void)
166 {
167 quicly_stream_frame_t frame;
168 static const char *mess = "\xc5\0\0\0\0\0\0\xb6\x16\x03";
169 const uint8_t *p = (void *)mess, type_flags = *p++;
170 quicly_decode_stream_frame(type_flags, &p, p + 9, &frame);
171 }
172
test_frame(void)173 void test_frame(void)
174 {
175 subtest("ack-decode", test_ack_decode);
176 subtest("ack-encode", test_ack_encode);
177 subtest("mozquic", test_mozquic);
178 }
179