1 /*
2  * Copyright (c) 2014 by Farsight Security, Inc.
3  *
4  * Permission is hereby granted, free of charge, to any person obtaining
5  * a copy of this software and associated documentation files (the
6  * "Software"), to deal in the Software without restriction, including
7  * without limitation the rights to use, copy, modify, merge, publish,
8  * distribute, sublicense, and/or sell copies of the Software, and to
9  * permit persons to whom the Software is furnished to do so, subject to
10  * the following conditions:
11  *
12  * The above copyright notice and this permission notice shall be included
13  * in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16  * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19  * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22  *
23  */
24 
25 #include <assert.h>
26 #include <stdint.h>
27 #include <stdio.h>
28 #include <stdlib.h>
29 #include <string.h>
30 
31 #include <fstrm.h>
32 
33 #include "libmy/print_string.h"
34 
35 /* Placeholder "Content Type" values. */
36 static const uint8_t wharrgarbl[] = "wharr\x00garbl";
37 static const uint8_t wharrgarblv2[] = "wharrgarblv2";
38 
39 /*
40  * Valid control frames. These come in two variants, the *_wh suffixed ones that
41  * include the escape sequence and control frame length header which must be
42  * encoded/decoded with the FSTRM_CONTROL_FLAG_WITH_HEADER flag, and the
43  * un-suffixed ones which must be encoded/decoded without the
44  * FSTRM_CONTROL_FLAG_WITH_HEADER flag.
45  */
46 
47 static const uint8_t accept_1[] = {
48 	/* FSTRM_CONTROL_ACCEPT. */
49 	0x00, 0x00, 0x00, 0x01,
50 };
51 
52 static const uint8_t accept_1_wh[] = {
53 	/* Escape sequence. */
54 	0x00, 0x00, 0x00, 0x00,
55 
56 	/* Control frame length: 4 bytes of control frame payload. */
57 	0x00, 0x00, 0x00, 0x04,
58 
59 	/* FSTRM_CONTROL_ACCEPT. */
60 	0x00, 0x00, 0x00, 0x01,
61 };
62 
63 static const uint8_t accept_2[] = {
64 	/* FSTRM_CONTROL_ACCEPT. */
65 	0x00, 0x00, 0x00, 0x01,
66 
67 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
68 	0x00, 0x00, 0x00, 0x01,
69 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
70 	0x00, 0x00, 0x00, 0x0b,
71 	/* The CONTENT_TYPE field payload. */
72 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l',
73 };
74 
75 static const uint8_t accept_2_wh[] = {
76 	/* Escape sequence. */
77 	0x00, 0x00, 0x00, 0x00,
78 
79 	/* Control frame length: 23 bytes of control frame payload. */
80 	0x00, 0x00, 0x00, 0x17,
81 
82 	/* FSTRM_CONTROL_ACCEPT. */
83 	0x00, 0x00, 0x00, 0x01,
84 
85 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
86 	0x00, 0x00, 0x00, 0x01,
87 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
88 	0x00, 0x00, 0x00, 0x0b,
89 	/* The CONTENT_TYPE field payload. */
90 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l',
91 };
92 
93 static const uint8_t accept_3[] = {
94 	/* FSTRM_CONTROL_ACCEPT. */
95 	0x00, 0x00, 0x00, 0x01,
96 
97 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
98 	0x00, 0x00, 0x00, 0x01,
99 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
100 	0x00, 0x00, 0x00, 0x0b,
101 	/* The CONTENT_TYPE field payload. */
102 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l',
103 
104 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
105 	0x00, 0x00, 0x00, 0x01,
106 	/* 0x0c (12 bytes) of CONTENT_TYPE field payload follow. */
107 	0x00, 0x00, 0x00, 0x0c,
108 	/* The CONTENT_TYPE field payload. */
109 	'w', 'h', 'a', 'r', 'r', 'g', 'a', 'r', 'b', 'l', 'v', '2',
110 };
111 
112 static const uint8_t accept_3_wh[] = {
113 	/* Escape sequence. */
114 	0x00, 0x00, 0x00, 0x00,
115 
116 	/* Control frame length: 43 bytes of control frame payload. */
117 	0x00, 0x00, 0x00, 0x2b,
118 
119 	/* FSTRM_CONTROL_ACCEPT. */
120 	0x00, 0x00, 0x00, 0x01,
121 
122 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
123 	0x00, 0x00, 0x00, 0x01,
124 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
125 	0x00, 0x00, 0x00, 0x0b,
126 	/* The CONTENT_TYPE field payload. */
127 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l',
128 
129 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
130 	0x00, 0x00, 0x00, 0x01,
131 	/* 0x0c (12 bytes) of CONTENT_TYPE field payload follow. */
132 	0x00, 0x00, 0x00, 0x0c,
133 	/* The CONTENT_TYPE field payload. */
134 	'w', 'h', 'a', 'r', 'r', 'g', 'a', 'r', 'b', 'l', 'v', '2',
135 };
136 
137 static const uint8_t ready_1[] = {
138 	/* FSTRM_CONTROL_READY. */
139 	0x00, 0x00, 0x00, 0x04,
140 
141 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
142 	0x00, 0x00, 0x00, 0x01,
143 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
144 	0x00, 0x00, 0x00, 0x0b,
145 	/* The CONTENT_TYPE field payload. */
146 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l',
147 
148 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
149 	0x00, 0x00, 0x00, 0x01,
150 	/* 0x0c (12 bytes) of CONTENT_TYPE field payload follow. */
151 	0x00, 0x00, 0x00, 0x0c,
152 	/* The CONTENT_TYPE field payload. */
153 	'w', 'h', 'a', 'r', 'r', 'g', 'a', 'r', 'b', 'l', 'v', '2',
154 };
155 
156 static const uint8_t start_1[] = {
157 	/* FSTRM_CONTROL_START. */
158 	0x00, 0x00, 0x00, 0x02,
159 };
160 
161 static const uint8_t start_1_wh[] = {
162 	/* Escape sequence. */
163 	0x00, 0x00, 0x00, 0x00,
164 
165 	/* Control frame length: 4 bytes of control frame payload. */
166 	0x00, 0x00, 0x00, 0x04,
167 
168 	/* FSTRM_CONTROL_START. */
169 	0x00, 0x00, 0x00, 0x02,
170 };
171 
172 static const uint8_t start_2[] = {
173 	/* FSTRM_CONTROL_START. */
174 	0x00, 0x00, 0x00, 0x02,
175 
176 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
177 	0x00, 0x00, 0x00, 0x01,
178 
179 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
180 	0x00, 0x00, 0x00, 0x0b,
181 
182 	/* The CONTENT_TYPE field payload. */
183 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l',
184 };
185 
186 static const uint8_t start_2_wh[] = {
187 	/* Escape sequence. */
188 	0x00, 0x00, 0x00, 0x00,
189 
190 	/* Control frame length: 23 bytes of control frame payload. */
191 	0x00, 0x00, 0x00, 0x17,
192 
193 	/* FSTRM_CONTROL_START. */
194 	0x00, 0x00, 0x00, 0x02,
195 
196 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
197 	0x00, 0x00, 0x00, 0x01,
198 
199 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
200 	0x00, 0x00, 0x00, 0x0b,
201 
202 	/* The CONTENT_TYPE field payload. */
203 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l',
204 };
205 
206 static const uint8_t stop_1[] = {
207 	/* FSTRM_CONTROL_STOP. */
208 	0x00, 0x00, 0x00, 0x03,
209 };
210 
211 static const uint8_t stop_1_wh[] = {
212 	/* Escape sequence. */
213 	0x00, 0x00, 0x00, 0x00,
214 
215 	/* Control frame length: 4 bytes of control frame payload. */
216 	0x00, 0x00, 0x00, 0x04,
217 
218 	/* FSTRM_CONTROL_STOP. */
219 	0x00, 0x00, 0x00, 0x03,
220 };
221 
222 /*
223  * Structure for encoding parameters and expected results for the above control
224  * tests.
225  */
226 struct control_test {
227 	const uint8_t		*frame;
228 	size_t			len_frame;
229 	fstrm_control_type	type;
230 	uint32_t		flags;
231 	const uint8_t		*content_type;
232 	size_t			len_content_type;
233 	fstrm_res		match_res;
234 };
235 
236 static const struct control_test control_tests[] = {
237 	{
238 		.frame		= accept_1,
239 		.len_frame	= sizeof(accept_1),
240 		.type		= FSTRM_CONTROL_ACCEPT,
241 	},
242 	{
243 		.frame		= accept_1_wh,
244 		.len_frame	= sizeof(accept_1_wh),
245 		.type		= FSTRM_CONTROL_ACCEPT,
246 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
247 	},
248 	{
249 		.frame		= accept_2,
250 		.len_frame	= sizeof(accept_2),
251 		.type		= FSTRM_CONTROL_ACCEPT,
252 		.content_type	= wharrgarbl,
253 		.len_content_type = sizeof(wharrgarbl) - 1,
254 	},
255 	{
256 		.frame		= accept_2_wh,
257 		.len_frame	= sizeof(accept_2_wh),
258 		.type		= FSTRM_CONTROL_ACCEPT,
259 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
260 		.content_type	= wharrgarbl,
261 		.len_content_type = sizeof(wharrgarbl) - 1,
262 	},
263 	{
264 		.frame		= accept_3,
265 		.len_frame	= sizeof(accept_3),
266 		.type		= FSTRM_CONTROL_ACCEPT,
267 		.content_type	= wharrgarbl,
268 		.len_content_type = sizeof(wharrgarbl) - 1,
269 	},
270 	{
271 		.frame		= accept_3_wh,
272 		.len_frame	= sizeof(accept_3_wh),
273 		.type		= FSTRM_CONTROL_ACCEPT,
274 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
275 		.content_type	= wharrgarbl,
276 		.len_content_type = sizeof(wharrgarbl) - 1,
277 	},
278 	{
279 		.frame		= accept_3,
280 		.len_frame	= sizeof(accept_3),
281 		.type		= FSTRM_CONTROL_ACCEPT,
282 		.content_type	= wharrgarblv2,
283 		.len_content_type = sizeof(wharrgarblv2) - 1,
284 	},
285 	{
286 		.frame		= accept_3_wh,
287 		.len_frame	= sizeof(accept_3_wh),
288 		.type		= FSTRM_CONTROL_ACCEPT,
289 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
290 		.content_type	= wharrgarblv2,
291 		.len_content_type = sizeof(wharrgarblv2) - 1,
292 	},
293 	{
294 		.frame		= ready_1,
295 		.len_frame	= sizeof(ready_1),
296 		.type		= FSTRM_CONTROL_READY,
297 		.content_type	= wharrgarbl,
298 		.len_content_type = sizeof(wharrgarbl) - 1,
299 	},
300 	{
301 		.frame		= ready_1,
302 		.len_frame	= sizeof(ready_1),
303 		.type		= FSTRM_CONTROL_READY,
304 		.content_type	= wharrgarblv2,
305 		.len_content_type = sizeof(wharrgarblv2) - 1,
306 	},
307 	{
308 		.frame		= start_1,
309 		.len_frame	= sizeof(start_1),
310 		.type		= FSTRM_CONTROL_START,
311 	},
312 	{
313 		.frame		= start_1_wh,
314 		.len_frame	= sizeof(start_1_wh),
315 		.type		= FSTRM_CONTROL_START,
316 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
317 	},
318 	{
319 		.frame		= start_1,
320 		.len_frame	= sizeof(start_1),
321 		.type		= FSTRM_CONTROL_START,
322 		.content_type	= wharrgarbl,
323 		.len_content_type = sizeof(wharrgarbl) - 1,
324 	},
325 	{
326 		.frame		= start_1_wh,
327 		.len_frame	= sizeof(start_1_wh),
328 		.type		= FSTRM_CONTROL_START,
329 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
330 		.content_type	= wharrgarbl,
331 		.len_content_type = sizeof(wharrgarbl) - 1,
332 	},
333 	{
334 		.frame		= start_2,
335 		.len_frame	= sizeof(start_2),
336 		.type		= FSTRM_CONTROL_START,
337 		.content_type	= wharrgarbl,
338 		.len_content_type = sizeof(wharrgarbl) - 1,
339 	},
340 	{
341 		.frame		= start_2,
342 		.len_frame	= sizeof(start_2),
343 		.type		= FSTRM_CONTROL_START,
344 		.content_type	= wharrgarblv2,
345 		.len_content_type = sizeof(wharrgarblv2) - 1,
346 		.match_res	= fstrm_res_failure,
347 	},
348 	{
349 		.frame		= start_2_wh,
350 		.len_frame	= sizeof(start_2_wh),
351 		.type		= FSTRM_CONTROL_START,
352 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
353 		.content_type	= wharrgarbl,
354 		.len_content_type = sizeof(wharrgarbl) - 1,
355 	},
356 	{
357 		.frame		= stop_1,
358 		.len_frame	= sizeof(stop_1),
359 		.type		= FSTRM_CONTROL_STOP,
360 		.match_res	= fstrm_res_failure,
361 	},
362 	{
363 		.frame		= stop_1_wh,
364 		.len_frame	= sizeof(stop_1_wh),
365 		.type		= FSTRM_CONTROL_STOP,
366 		.flags		= FSTRM_CONTROL_FLAG_WITH_HEADER,
367 		.match_res	= fstrm_res_failure,
368 	},
369 
370 	{ .frame = NULL },
371 };
372 
373 /* Invalid control frames. */
374 
375 static const uint8_t invalid_1[] = { 0xff, };
376 
377 static const uint8_t invalid_2[] = { 0xff, 0xff, };
378 
379 static const uint8_t invalid_3[] = { 0xff, 0xff, 0xff, };
380 
381 static const uint8_t invalid_4[] = { 0xff, 0xff, 0xff, };
382 
383 static const uint8_t invalid_5[] = { 0xff, 0xff, 0xff, 0xff, };
384 
385 static const uint8_t invalid_6[] = { 0xff, 0xff, 0xff, 0xff, 0xff };
386 
387 static const uint8_t invalid_7[] = { 0xab, 0xad, 0x1d, 0xea, };
388 
389 static const uint8_t invalid_8[] = {
390 	/* FSTRM_CONTROL_START. */
391 	0x00, 0x00, 0x00, 0x02,
392 
393 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
394 	0x00, 0x00, 0x00, 0x01,
395 
396 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
397 	0x00, 0x00, 0x00, 0x0b,
398 
399 	/* The CONTENT_TYPE field payload. Only 10 bytes here. Short read! */
400 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b',
401 };
402 
403 static const uint8_t invalid_9[] = {
404 	/* FSTRM_CONTROL_START. */
405 	0x00, 0x00, 0x00, 0x02,
406 
407 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
408 	0x00, 0x00, 0x00, 0x01,
409 
410 	/* 0x0b (11 bytes) of CONTENT_TYPE field payload follow. */
411 	0x00, 0x00, 0x00, 0x0b,
412 
413 	/* The CONTENT_TYPE field payload. An extra byte here. */
414 	'w', 'h', 'a', 'r', 'r', 0x00, 'g', 'a', 'r', 'b', 'l', 'z',
415 };
416 
417 static const uint8_t invalid_10[] = {
418 	/* FSTRM_CONTROL_START. */
419 	0x00, 0x00, 0x00, 0x02,
420 
421 	/* Incomplete control field. */
422 	0x00,
423 };
424 
425 static const uint8_t invalid_11[] = {
426 	/* FSTRM_CONTROL_START. */
427 	0x00, 0x00, 0x00, 0x02,
428 
429 	/* Incomplete control field. */
430 	0x00, 0x00, 0x00,
431 };
432 
433 static const uint8_t invalid_12[] = {
434 	/* FSTRM_CONTROL_START. */
435 	0x00, 0x00, 0x00, 0x02,
436 
437 	/* FSTRM_CONTROL_FIELD_CONTENT_TYPE. */
438 	0x00, 0x00, 0x00, 0x01,
439 
440 	/* No CONTENT_TYPE field payload. This is required. */
441 };
442 
443 struct bytes {
444 	const uint8_t	*bytes;
445 	size_t		len;
446 };
447 
448 static const struct bytes invalid[] = {
449 	{ invalid_1, sizeof(invalid_1), },
450 	{ invalid_2, sizeof(invalid_2), },
451 	{ invalid_3, sizeof(invalid_3), },
452 	{ invalid_4, sizeof(invalid_4), },
453 	{ invalid_5, sizeof(invalid_5), },
454 	{ invalid_6, sizeof(invalid_6), },
455 	{ invalid_7, sizeof(invalid_7), },
456 	{ invalid_8, sizeof(invalid_8), },
457 	{ invalid_9, sizeof(invalid_9), },
458 	{ invalid_10, sizeof(invalid_10), },
459 	{ invalid_11, sizeof(invalid_11), },
460 	{ invalid_12, sizeof(invalid_12), },
461 	{ NULL, 0 },
462 };
463 
464 static fstrm_res
match_content_type(struct fstrm_control * c,const uint8_t * content_type,size_t len_content_type)465 match_content_type(struct fstrm_control *c,
466 		   const uint8_t *content_type,
467 		   size_t len_content_type)
468 {
469 	fstrm_res res;
470 
471 	res = fstrm_control_match_field_content_type(c, content_type, len_content_type);
472 	printf("  Control frame is %scompatible with CONTENT_TYPE (%zd bytes): ",
473 	       res == fstrm_res_success ? "" : "NOT ",
474 	       len_content_type);
475 	print_string(content_type, len_content_type, stdout);
476 	putchar('\n');
477 
478 	return res;
479 }
480 
481 static fstrm_res
decode_control_frame(struct fstrm_control * c,const uint8_t * control_frame,size_t len_control_frame,uint32_t flags)482 decode_control_frame(struct fstrm_control *c,
483 		     const uint8_t *control_frame,
484 		     size_t len_control_frame,
485 		     uint32_t flags)
486 {
487 	fstrm_res res;
488 	fstrm_control_type type;
489 
490 	res = fstrm_control_decode(c, control_frame, len_control_frame, flags);
491 	if (res == fstrm_res_success) {
492 		printf("Successfully decoded frame (%zd bytes):\n  ",
493 		       len_control_frame);
494 		print_string(control_frame, len_control_frame, stdout);
495 		putchar('\n');
496 	} else {
497 		printf("Failed to decode frame (%zd bytes):\n  ",
498 		       len_control_frame);
499 		print_string(control_frame, len_control_frame, stdout);
500 		putchar('\n');
501 		return res;
502 	}
503 
504 	res = fstrm_control_get_type(c, &type);
505 	if (res != fstrm_res_success) {
506 		puts("  fstrm_control_get_type() failed.");
507 		return res;
508 	}
509 	printf("  The control frame is of type %s (0x%08x).\n",
510 	       fstrm_control_type_to_str(type), type);
511 
512 	size_t n_ctype;
513 	res = fstrm_control_get_num_field_content_type(c, &n_ctype);
514 	if (res != fstrm_res_success) {
515 		puts("  fstrm_control_get_num_field_content_type() failed.");
516 		return res;
517 	}
518 	for (size_t idx = 0; idx < n_ctype; idx++) {
519 		const uint8_t *content_type;
520 		size_t len_content_type;
521 
522 		res = fstrm_control_get_field_content_type(c, idx,
523 			&content_type, &len_content_type);
524 		if (res == fstrm_res_success) {
525 			printf("  The control frame has a CONTENT_TYPE field (%zd bytes): ",
526 			       len_content_type);
527 			print_string(content_type, len_content_type, stdout);
528 			putchar('\n');
529 		} else if (res == fstrm_res_failure) {
530 			puts("  The control frame does not have any CONTENT_TYPE fields.");
531 		} else {
532 			/* Not reached. */
533 			assert(0);
534 		}
535 	}
536 
537 	return fstrm_res_success;
538 }
539 
540 static void
test_reencode_frame(struct fstrm_control * c,const uint8_t * control_frame,size_t len_control_frame,uint32_t flags)541 test_reencode_frame(struct fstrm_control *c,
542 		    const uint8_t *control_frame,
543 		    size_t len_control_frame,
544 		    uint32_t flags)
545 {
546 	printf("Running %s().\n", __func__);
547 
548 	fstrm_res res;
549 	int cmp;
550 	size_t len_new_frame = 0, len_new_frame_2 = 0;
551 
552 	res = fstrm_control_encoded_size(c, &len_new_frame, flags);
553 	assert(res == fstrm_res_success);
554 	printf("Need %zd bytes for new frame.\n", len_new_frame);
555 	assert(len_new_frame <= FSTRM_CONTROL_FRAME_LENGTH_MAX);
556 	uint8_t new_frame[len_new_frame];
557 
558 	len_new_frame_2 = len_new_frame;
559 	res = fstrm_control_encode(c, new_frame, &len_new_frame_2, flags);
560 	assert(res == fstrm_res_success);
561 	printf("Successfully encoded a new frame (%zd bytes):\n  ",
562 	       len_new_frame_2);
563 	print_string(new_frame, len_new_frame_2, stdout);
564 	putchar('\n');
565 	assert(len_new_frame == len_new_frame_2);
566 	assert(len_new_frame == len_control_frame);
567 
568 	cmp = memcmp(control_frame, new_frame, len_control_frame);
569 	assert(cmp == 0);
570 	puts("New frame is identical to original frame.");
571 }
572 
573 static void
test_reencode_frame_static(struct fstrm_control * c,const uint8_t * control_frame,size_t len_control_frame,uint32_t flags)574 test_reencode_frame_static(struct fstrm_control *c,
575 			   const uint8_t *control_frame,
576 			   size_t len_control_frame,
577 			   uint32_t flags)
578 {
579 	printf("Running %s().\n", __func__);
580 
581 	fstrm_res res;
582 	int cmp;
583 	uint8_t new_frame[FSTRM_CONTROL_FRAME_LENGTH_MAX];
584 	size_t len_new_frame = sizeof(new_frame);
585 
586 	res = fstrm_control_encode(c, new_frame, &len_new_frame, flags);
587 	assert(res == fstrm_res_success);
588 	assert(len_new_frame <= FSTRM_CONTROL_FRAME_LENGTH_MAX);
589 	printf("Successfully encoded a new frame (%zd bytes):\n  ", len_new_frame);
590 	print_string(new_frame, len_new_frame, stdout);
591 	putchar('\n');
592 
593 	cmp = memcmp(control_frame, new_frame, len_control_frame);
594 	assert(cmp == 0);
595 	puts("New frame is identical to original frame.");
596 }
597 
598 static void
test_control_test(struct fstrm_control * c,const struct control_test * test)599 test_control_test(struct fstrm_control *c, const struct control_test *test)
600 {
601 	printf("Running %s().\n", __func__);
602 
603 	if (test->flags & FSTRM_CONTROL_FLAG_WITH_HEADER)
604 		printf("Control frames include escape sequence and control frame length.\n"
605 		       "  (FSTRM_CONTROL_FLAG_WITH_HEADER enabled.)\n");
606 
607 	fstrm_res res;
608 	fstrm_control_type type;
609 
610 	res = decode_control_frame(c, test->frame, test->len_frame, test->flags);
611 	assert(res == fstrm_res_success);
612 	res = fstrm_control_get_type(c, &type);
613 	assert(res == fstrm_res_success);
614 	assert(type == test->type);
615 
616 	res = match_content_type(c, test->content_type, test->len_content_type);
617 	assert(res == test->match_res);
618 
619 	test_reencode_frame(c, test->frame, test->len_frame, test->flags);
620 	test_reencode_frame_static(c, test->frame, test->len_frame, test->flags);
621 }
622 
623 static void
test_control_tests(struct fstrm_control * c)624 test_control_tests(struct fstrm_control *c)
625 {
626 	printf("Running %s().\n\n", __func__);
627 
628 	for (const struct control_test *test = &control_tests[0];
629 	     test->frame != NULL;
630 	     test++)
631 	{
632 		test_control_test(c, test);
633 		putchar('\n');
634 	}
635 }
636 
637 static void
test_invalid(struct fstrm_control * c)638 test_invalid(struct fstrm_control *c)
639 {
640 	printf("Running %s().\n", __func__);
641 
642 	for (const struct bytes *test = &invalid[0];
643 	     test->bytes != NULL;
644 	     test++)
645 	{
646 		fstrm_res res;
647 		res = decode_control_frame(c, test->bytes, test->len, 0);
648 		assert(res != fstrm_res_success);
649 	}
650 }
651 
652 int
main(void)653 main(void)
654 {
655 	struct fstrm_control *c;
656 
657 	c = fstrm_control_init();
658 
659 	puts("====> The following tests must succeed. <====");
660 	test_control_tests(c);
661 
662 	puts("====> The following tests must fail. <====");
663 	test_invalid(c);
664 
665 	fstrm_control_destroy(&c);
666 
667 	return EXIT_SUCCESS;
668 }
669