BadVPN – Blame information for rev 1

Subversion Repositories:
Rev:
Rev Author Line No. Line
1 office 1 <?php
2  
3 function tokenize ($str, &$out) {
4 $out = array();
5  
6 while (strlen($str) > 0) {
7 if (preg_match('/^\\/\\/.*/', $str, $matches)) {
8 $str = substr($str, strlen($matches[0]));
9 }
10 else if (preg_match('/^\\s+/', $str, $matches)) {
11 $str = substr($str, strlen($matches[0]));
12 }
13 else if (preg_match('/^include/', $str, $matches)) {
14 $out[] = array('include', null);
15 $str = substr($str, strlen($matches[0]));
16 }
17 else if (preg_match('/^message/', $str, $matches)) {
18 $out[] = array('message', null);
19 $str = substr($str, strlen($matches[0]));
20 }
21 else if (preg_match('/^repeated/', $str, $matches)) {
22 $out[] = array('repeated', null);
23 $str = substr($str, strlen($matches[0]));
24 }
25 else if (preg_match('/^required/', $str, $matches)) {
26 $out[] = array('required', null);
27 $str = substr($str, strlen($matches[0]));
28 }
29 else if (preg_match('/^optional/', $str, $matches)) {
30 $out[] = array('optional', null);
31 $str = substr($str, strlen($matches[0]));
32 }
33 else if (preg_match('/^{/', $str, $matches)) {
34 $out[] = array('spar', null);
35 $str = substr($str, strlen($matches[0]));
36 }
37 else if (preg_match('/^}/', $str, $matches)) {
38 $out[] = array('epar', null);
39 $str = substr($str, strlen($matches[0]));
40 }
41 else if (preg_match('/^\(/', $str, $matches)) {
42 $out[] = array('srpar', null);
43 $str = substr($str, strlen($matches[0]));
44 }
45 else if (preg_match('/^\)/', $str, $matches)) {
46 $out[] = array('erpar', null);
47 $str = substr($str, strlen($matches[0]));
48 }
49 else if (preg_match('/^=/', $str, $matches)) {
50 $out[] = array('equals', null);
51 $str = substr($str, strlen($matches[0]));
52 }
53 else if (preg_match('/^;/', $str, $matches)) {
54 $out[] = array('semicolon', null);
55 $str = substr($str, strlen($matches[0]));
56 }
57 else if (preg_match('/^uint(8|16|32|64)/', $str, $matches)) {
58 $out[] = array('uint', $matches[1]);
59 $str = substr($str, strlen($matches[0]));
60 }
61 else if (preg_match('/^data/', $str, $matches)) {
62 $out[] = array('data', null);
63 $str = substr($str, strlen($matches[0]));
64 }
65 else if (preg_match('/^[0-9]+/', $str, $matches)) {
66 $out[] = array('number', $matches[0]);
67 $str = substr($str, strlen($matches[0]));
68 }
69 else if (preg_match('/^[a-zA-Z_][a-zA-Z0-9_]*/', $str, $matches)) {
70 $out[] = array('name', $matches[0]);
71 $str = substr($str, strlen($matches[0]));
72 }
73 else if (preg_match('/^"([^"]*)"/', $str, $matches)) {
74 $out[] = array('string', $matches[1]);
75 $str = substr($str, strlen($matches[0]));
76 }
77 else {
78 return FALSE;
79 }
80 }
81  
82 return TRUE;
83 }
84  
85 function fatal_error ($message)
86 {
87 fwrite(STDERR, "Fatal error: $message\n");
88  
89 ob_get_clean();
90 exit(1);
91 }
92  
93 function make_writer_decl ($msg, $entry)
94 {
95 switch ($entry["type"]["type"]) {
96 case "uint":
97 return "void {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, uint{$entry["type"]["size"]}_t v)";
98 case "data":
99 return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o, int len)";
100 case "constdata":
101 return "uint8_t * {$msg["name"]}Writer_Add{$entry["name"]} ({$msg["name"]}Writer *o)";
102 default:
103 assert(0);
104 }
105 }
106  
107 function make_parser_decl ($msg, $entry)
108 {
109 switch ($entry["type"]["type"]) {
110 case "uint":
111 return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint{$entry["type"]["size"]}_t *v)";
112 case "data":
113 return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data, int *data_len)";
114 case "constdata":
115 return "int {$msg["name"]}Parser_Get{$entry["name"]} ({$msg["name"]}Parser *o, uint8_t **data)";
116 default:
117 assert(0);
118 }
119 }
120  
121 function make_parser_reset_decl ($msg, $entry)
122 {
123 return "void {$msg["name"]}Parser_Reset{$entry["name"]} ({$msg["name"]}Parser *o)";
124 }
125  
126 function make_parser_forward_decl ($msg, $entry)
127 {
128 return "void {$msg["name"]}Parser_Forward{$entry["name"]} ({$msg["name"]}Parser *o)";
129 }
130  
131 function make_type_name ($msg, $entry)
132 {
133 switch ($entry["type"]["type"]) {
134 case "uint":
135 return "BPROTO_TYPE_UINT{$entry["type"]["size"]}";
136 case "data":
137 return "BPROTO_TYPE_DATA";
138 case "constdata":
139 return "BPROTO_TYPE_CONSTDATA";
140 default:
141 assert(0);
142 }
143 }
144  
145 function make_finish_assert ($msg, $entry)
146 {
147 switch ($entry["cardinality"]) {
148 case "repeated":
149 return "ASSERT(o->{$entry["name"]}_count >= 0)";
150 case "required repeated":
151 return "ASSERT(o->{$entry["name"]}_count >= 1)";
152 case "optional":
153 return "ASSERT(o->{$entry["name"]}_count >= 0 && o->{$entry["name"]}_count <= 1)";
154 case "required":
155 return "ASSERT(o->{$entry["name"]}_count == 1)";
156 default:
157 assert(0);
158 }
159 }
160  
161 function make_add_count_assert ($msg, $entry)
162 {
163 if (in_array($entry["cardinality"], array("optional", "required"))) {
164 return "ASSERT(o->{$entry["name"]}_count == 0)";
165 }
166 return "";
167 }
168  
169 function make_add_length_assert ($msg, $entry)
170 {
171 if ($entry["type"]["type"] == "data") {
172 return "ASSERT(len >= 0 && len <= UINT32_MAX)";
173 }
174 return "";
175 }
176  
177 function make_size_define ($msg, $entry)
178 {
179 switch ($entry["type"]["type"]) {
180 case "uint":
181 return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_uint{$entry["type"]["size"]}_s))";
182 case "data":
183 return "#define {$msg["name"]}_SIZE{$entry["name"]}(_len) (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + (_len))";
184 case "constdata":
185 return "#define {$msg["name"]}_SIZE{$entry["name"]} (sizeof(struct BProto_header_s) + sizeof(struct BProto_data_header_s) + ({$entry["type"]["size"]}))";
186 default:
187 assert(0);
188 }
189 }
190  
191 function generate_header ($name, $directives, $messages) {
192 ob_start();
193  
194 echo <<<EOD
195 /*
196 DO NOT EDIT THIS FILE!
197 This file was automatically generated by the bproto generator.
198 */
199  
200 #include <stdint.h>
201 #include <string.h>
202  
203 #include <misc/debug.h>
204 #include <misc/byteorder.h>
205 #include <bproto/BProto.h>
206  
207  
208 EOD;
209  
210 foreach ($directives as $directive) {
211 if ($directive["type"] == "include") {
212 echo <<<EOD
213 #include "{$directive["file"]}"
214  
215 EOD;
216 }
217 }
218  
219 echo <<<EOD
220  
221  
222 EOD;
223  
224 foreach ($messages as $msg) {
225  
226 foreach ($msg["entries"] as $entry) {
227 $def = make_size_define($msg, $entry);
228 echo <<<EOD
229 {$def}
230  
231 EOD;
232 }
233  
234 echo <<<EOD
235  
236 typedef struct {
237 uint8_t *out;
238 int used;
239  
240 EOD;
241  
242 foreach ($msg["entries"] as $entry) {
243 echo <<<EOD
244 int {$entry["name"]}_count;
245  
246 EOD;
247 }
248  
249 echo <<<EOD
250 } {$msg["name"]}Writer;
251  
252 static void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out);
253 static int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o);
254  
255 EOD;
256  
257 foreach ($msg["entries"] as $entry) {
258 $decl = make_writer_decl($msg, $entry);
259 echo <<<EOD
260 static {$decl};
261  
262 EOD;
263 }
264  
265 echo <<<EOD
266  
267 typedef struct {
268 uint8_t *buf;
269 int buf_len;
270  
271 EOD;
272 foreach ($msg["entries"] as $entry) {
273 echo <<<EOD
274 int {$entry["name"]}_start;
275 int {$entry["name"]}_span;
276 int {$entry["name"]}_pos;
277  
278 EOD;
279 }
280  
281 echo <<<EOD
282 } {$msg["name"]}Parser;
283  
284 static int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len);
285 static int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o);
286  
287 EOD;
288  
289 foreach ($msg["entries"] as $entry) {
290 $decl = make_parser_decl($msg, $entry);
291 $reset_decl = make_parser_reset_decl($msg, $entry);
292 $forward_decl = make_parser_forward_decl($msg, $entry);
293 echo <<<EOD
294 static {$decl};
295 static {$reset_decl};
296 static {$forward_decl};
297  
298 EOD;
299 }
300  
301 echo <<<EOD
302  
303 void {$msg["name"]}Writer_Init ({$msg["name"]}Writer *o, uint8_t *out)
304 {
305 o->out = out;
306 o->used = 0;
307  
308 EOD;
309  
310 foreach ($msg["entries"] as $entry) {
311 echo <<<EOD
312 o->{$entry["name"]}_count = 0;
313  
314 EOD;
315 }
316  
317 echo <<<EOD
318 }
319  
320 int {$msg["name"]}Writer_Finish ({$msg["name"]}Writer *o)
321 {
322 ASSERT(o->used >= 0)
323  
324 EOD;
325  
326 foreach ($msg["entries"] as $entry) {
327 $ass = make_finish_assert($msg, $entry);
328 echo <<<EOD
329 {$ass}
330  
331 EOD;
332 }
333  
334 echo <<<EOD
335  
336 return o->used;
337 }
338  
339  
340 EOD;
341  
342 foreach ($msg["entries"] as $entry) {
343 $decl = make_writer_decl($msg, $entry);
344 $type = make_type_name($msg, $entry);
345 $add_count_assert = make_add_count_assert($msg, $entry);
346 $add_length_assert = make_add_length_assert($msg, $entry);
347  
348 echo <<<EOD
349 {$decl}
350 {
351 ASSERT(o->used >= 0)
352 {$add_count_assert}
353 {$add_length_assert}
354  
355 struct BProto_header_s header;
356 header.id = htol16({$entry["id"]});
357 header.type = htol16({$type});
358 memcpy(o->out + o->used, &header, sizeof(header));
359 o->used += sizeof(struct BProto_header_s);
360  
361  
362 EOD;
363 switch ($entry["type"]["type"]) {
364 case "uint":
365 echo <<<EOD
366 struct BProto_uint{$entry["type"]["size"]}_s data;
367 data.v = htol{$entry["type"]["size"]}(v);
368 memcpy(o->out + o->used, &data, sizeof(data));
369 o->used += sizeof(struct BProto_uint{$entry["type"]["size"]}_s);
370  
371 EOD;
372 break;
373 case "data":
374 echo <<<EOD
375 struct BProto_data_header_s data;
376 data.len = htol32(len);
377 memcpy(o->out + o->used, &data, sizeof(data));
378 o->used += sizeof(struct BProto_data_header_s);
379  
380 uint8_t *dest = (o->out + o->used);
381 o->used += len;
382  
383 EOD;
384 break;
385 case "constdata":
386 echo <<<EOD
387 struct BProto_data_header_s data;
388 data.len = htol32({$entry["type"]["size"]});
389 memcpy(o->out + o->used, &data, sizeof(data));
390 o->used += sizeof(struct BProto_data_header_s);
391  
392 uint8_t *dest = (o->out + o->used);
393 o->used += ({$entry["type"]["size"]});
394  
395 EOD;
396 break;
397 default:
398 assert(0);
399 }
400  
401 echo <<<EOD
402  
403 o->{$entry["name"]}_count++;
404  
405 EOD;
406 if (in_array($entry["type"]["type"], array("data", "constdata"))) {
407 echo <<<EOD
408  
409 return dest;
410  
411 EOD;
412 }
413  
414 echo <<<EOD
415 }
416  
417  
418 EOD;
419 }
420  
421 echo <<<EOD
422 int {$msg["name"]}Parser_Init ({$msg["name"]}Parser *o, uint8_t *buf, int buf_len)
423 {
424 ASSERT(buf_len >= 0)
425  
426 o->buf = buf;
427 o->buf_len = buf_len;
428  
429 EOD;
430  
431 foreach ($msg["entries"] as $entry) {
432 echo <<<EOD
433 o->{$entry["name"]}_start = o->buf_len;
434 o->{$entry["name"]}_span = 0;
435 o->{$entry["name"]}_pos = 0;
436  
437 EOD;
438 }
439  
440 echo <<<EOD
441  
442  
443 EOD;
444  
445 foreach ($msg["entries"] as $entry) {
446 echo <<<EOD
447 int {$entry["name"]}_count = 0;
448  
449 EOD;
450 }
451  
452 echo <<<EOD
453  
454 int pos = 0;
455 int left = o->buf_len;
456  
457 while (left > 0) {
458 int entry_pos = pos;
459  
460 if (!(left >= sizeof(struct BProto_header_s))) {
461 return 0;
462 }
463 struct BProto_header_s header;
464 memcpy(&header, o->buf + pos, sizeof(header));
465 pos += sizeof(struct BProto_header_s);
466 left -= sizeof(struct BProto_header_s);
467 uint16_t type = ltoh16(header.type);
468 uint16_t id = ltoh16(header.id);
469  
470 switch (type) {
471  
472 EOD;
473  
474 foreach (array(8, 16, 32, 64) as $bits) {
475 echo <<<EOD
476 case BPROTO_TYPE_UINT{$bits}: {
477 if (!(left >= sizeof(struct BProto_uint{$bits}_s))) {
478 return 0;
479 }
480 pos += sizeof(struct BProto_uint{$bits}_s);
481 left -= sizeof(struct BProto_uint{$bits}_s);
482  
483 switch (id) {
484  
485 EOD;
486  
487 foreach ($msg["entries"] as $entry) {
488 if (!($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits)) {
489 continue;
490 }
491 $type = make_type_name($msg, $entry);
492 echo <<<EOD
493 case {$entry["id"]}:
494 if (o->{$entry["name"]}_start == o->buf_len) {
495 o->{$entry["name"]}_start = entry_pos;
496 }
497 o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
498 {$entry["name"]}_count++;
499 break;
500  
501 EOD;
502 }
503  
504 echo <<<EOD
505 default:
506 return 0;
507 }
508 } break;
509  
510 EOD;
511 }
512  
513 echo <<<EOD
514 case BPROTO_TYPE_DATA:
515 case BPROTO_TYPE_CONSTDATA:
516 {
517 if (!(left >= sizeof(struct BProto_data_header_s))) {
518 return 0;
519 }
520 struct BProto_data_header_s val;
521 memcpy(&val, o->buf + pos, sizeof(val));
522 pos += sizeof(struct BProto_data_header_s);
523 left -= sizeof(struct BProto_data_header_s);
524  
525 uint32_t payload_len = ltoh32(val.len);
526 if (!(left >= payload_len)) {
527 return 0;
528 }
529 pos += payload_len;
530 left -= payload_len;
531  
532 switch (id) {
533  
534 EOD;
535  
536 foreach ($msg["entries"] as $entry) {
537 if (!in_array($entry["type"]["type"], array("data", "constdata"))) {
538 continue;
539 }
540 $type = make_type_name($msg, $entry);
541 echo <<<EOD
542 case {$entry["id"]}:
543 if (!(type == {$type})) {
544 return 0;
545 }
546  
547 EOD;
548 if ($entry["type"]["type"] == "constdata") {
549 echo <<<EOD
550 if (!(payload_len == ({$entry["type"]["size"]}))) {
551 return 0;
552 }
553  
554 EOD;
555 }
556 echo <<<EOD
557 if (o->{$entry["name"]}_start == o->buf_len) {
558 o->{$entry["name"]}_start = entry_pos;
559 }
560 o->{$entry["name"]}_span = pos - o->{$entry["name"]}_start;
561 {$entry["name"]}_count++;
562 break;
563  
564 EOD;
565 }
566  
567 echo <<<EOD
568 default:
569 return 0;
570 }
571 } break;
572 default:
573 return 0;
574 }
575 }
576  
577  
578 EOD;
579  
580 foreach ($msg["entries"] as $entry) {
581 $cond = "";
582 switch ($entry["cardinality"]) {
583 case "repeated":
584 break;
585 case "required repeated":
586 $cond = "{$entry["name"]}_count >= 1";
587 break;
588 case "optional":
589 $cond = "{$entry["name"]}_count <= 1";
590 break;
591 case "required":
592 $cond = "{$entry["name"]}_count == 1";
593 break;
594 default:
595 assert(0);
596 }
597 if ($cond) {
598 echo <<<EOD
599 if (!({$cond})) {
600 return 0;
601 }
602  
603 EOD;
604 }
605 }
606  
607 echo <<<EOD
608  
609 return 1;
610 }
611  
612 int {$msg["name"]}Parser_GotEverything ({$msg["name"]}Parser *o)
613 {
614 return (
615  
616 EOD;
617  
618 $first = 1;
619 foreach ($msg["entries"] as $entry) {
620 if ($first) {
621 $first = 0;
622 } else {
623 echo <<<EOD
624 &&
625  
626 EOD;
627 }
628 echo <<<EOD
629 o->{$entry["name"]}_pos == o->{$entry["name"]}_span
630  
631 EOD;
632 }
633  
634  
635 echo <<<EOD
636 );
637 }
638  
639  
640 EOD;
641  
642 foreach ($msg["entries"] as $entry) {
643 $decl = make_parser_decl($msg, $entry);
644 $reset_decl = make_parser_reset_decl($msg, $entry);
645 $forward_decl = make_parser_forward_decl($msg, $entry);
646 $type = make_type_name($msg, $entry);
647  
648 echo <<<EOD
649 {$decl}
650 {
651 ASSERT(o->{$entry["name"]}_pos >= 0)
652 ASSERT(o->{$entry["name"]}_pos <= o->{$entry["name"]}_span)
653  
654 int left = o->{$entry["name"]}_span - o->{$entry["name"]}_pos;
655  
656 while (left > 0) {
657 ASSERT(left >= sizeof(struct BProto_header_s))
658 struct BProto_header_s header;
659 memcpy(&header, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(header));
660 o->{$entry["name"]}_pos += sizeof(struct BProto_header_s);
661 left -= sizeof(struct BProto_header_s);
662 uint16_t type = ltoh16(header.type);
663 uint16_t id = ltoh16(header.id);
664  
665 switch (type) {
666  
667 EOD;
668  
669 foreach (array(8, 16, 32, 64) as $bits) {
670 echo <<<EOD
671 case BPROTO_TYPE_UINT{$bits}: {
672 ASSERT(left >= sizeof(struct BProto_uint{$bits}_s))
673  
674 EOD;
675 if ($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits) {
676 echo <<<EOD
677 struct BProto_uint{$bits}_s val;
678 memcpy(&val, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(val));
679  
680 EOD;
681 }
682 echo <<<EOD
683 o->{$entry["name"]}_pos += sizeof(struct BProto_uint{$bits}_s);
684 left -= sizeof(struct BProto_uint{$bits}_s);
685  
686 EOD;
687 if ($entry["type"]["type"] == "uint" && $entry["type"]["size"] == $bits) {
688 echo <<<EOD
689  
690 if (id == {$entry["id"]}) {
691 *v = ltoh{$bits}(val.v);
692 return 1;
693 }
694  
695 EOD;
696 }
697  
698 echo <<<EOD
699 } break;
700  
701 EOD;
702 }
703  
704 echo <<<EOD
705 case BPROTO_TYPE_DATA:
706 case BPROTO_TYPE_CONSTDATA:
707 {
708 ASSERT(left >= sizeof(struct BProto_data_header_s))
709 struct BProto_data_header_s val;
710 memcpy(&val, o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos, sizeof(val));
711 o->{$entry["name"]}_pos += sizeof(struct BProto_data_header_s);
712 left -= sizeof(struct BProto_data_header_s);
713  
714 uint32_t payload_len = ltoh32(val.len);
715 ASSERT(left >= payload_len)
716  
717 EOD;
718 if ($entry["type"]["type"] == "data" || $entry["type"]["type"] == "constdata") {
719 echo <<<EOD
720 uint8_t *payload = o->buf + o->{$entry["name"]}_start + o->{$entry["name"]}_pos;
721  
722 EOD;
723 }
724 echo <<<EOD
725 o->{$entry["name"]}_pos += payload_len;
726 left -= payload_len;
727  
728 EOD;
729 if ($entry["type"]["type"] == "data") {
730 echo <<<EOD
731  
732 if (type == BPROTO_TYPE_DATA && id == {$entry["id"]}) {
733 *data = payload;
734 *data_len = payload_len;
735 return 1;
736 }
737  
738 EOD;
739 }
740 else if ($entry["type"]["type"] == "constdata") {
741 echo <<<EOD
742  
743 if (type == BPROTO_TYPE_CONSTDATA && id == {$entry["id"]}) {
744 *data = payload;
745 return 1;
746 }
747  
748 EOD;
749 }
750  
751 echo <<<EOD
752 } break;
753 default:
754 ASSERT(0);
755 }
756 }
757  
758 return 0;
759 }
760  
761 {$reset_decl}
762 {
763 o->{$entry["name"]}_pos = 0;
764 }
765  
766 {$forward_decl}
767 {
768 o->{$entry["name"]}_pos = o->{$entry["name"]}_span;
769 }
770  
771  
772 EOD;
773 }
774 }
775  
776 return ob_get_clean();
777 }