1 #!/usr/bin/env python 2 # 3 # Copyright (c) 2005 Niels Provos <provos (at] citi.umich.edu> 4 # All rights reserved. 5 # 6 # Generates marshaling code based on libevent. 7 8 import sys 9 import re 10 11 # 12 _NAME = "event_rpcgen.py" 13 _VERSION = "0.1" 14 _STRUCT_RE = '[a-z][a-z_0-9]*' 15 16 # Globals 17 line_count = 0 18 19 white = re.compile(r'^\s+') 20 cppcomment = re.compile(r'\/\/.*$') 21 headerdirect = [] 22 cppdirect = [] 23 24 # Holds everything that makes a struct 25 class Struct: 26 def __init__(self, name): 27 self._name = name 28 self._entries = [] 29 self._tags = {} 30 print >>sys.stderr, ' Created struct: %s' % name 31 32 def AddEntry(self, entry): 33 if self._tags.has_key(entry.Tag()): 34 print >>sys.stderr, ( 'Entry "%s" duplicates tag number ' 35 '%d from "%s" around line %d' ) % ( 36 entry.Name(), entry.Tag(), 37 self._tags[entry.Tag()], line_count) 38 sys.exit(1) 39 self._entries.append(entry) 40 self._tags[entry.Tag()] = entry.Name() 41 print >>sys.stderr, ' Added entry: %s' % entry.Name() 42 43 def Name(self): 44 return self._name 45 46 def EntryTagName(self, entry): 47 """Creates the name inside an enumeration for distinguishing data 48 types.""" 49 name = "%s_%s" % (self._name, entry.Name()) 50 return name.upper() 51 52 def PrintIdented(self, file, ident, code): 53 """Takes an array, add indentation to each entry and prints it.""" 54 for entry in code: 55 print >>file, '%s%s' % (ident, entry) 56 57 def PrintTags(self, file): 58 """Prints the tag definitions for a structure.""" 59 print >>file, '/* Tag definition for %s */' % self._name 60 print >>file, 'enum %s_ {' % self._name.lower() 61 for entry in self._entries: 62 print >>file, ' %s=%d,' % (self.EntryTagName(entry), 63 entry.Tag()) 64 print >>file, ' %s_MAX_TAGS' % (self._name.upper()) 65 print >>file, '};\n' 66 67 def PrintForwardDeclaration(self, file): 68 print >>file, 'struct %s;' % self._name 69 70 def PrintDeclaration(self, file): 71 print >>file, '/* Structure declaration for %s */' % self._name 72 print >>file, 'struct %s_access_ {' % self._name 73 for entry in self._entries: 74 dcl = entry.AssignDeclaration('(*%s_assign)' % entry.Name()) 75 dcl.extend( 76 entry.GetDeclaration('(*%s_get)' % entry.Name())) 77 if entry.Array(): 78 dcl.extend( 79 entry.AddDeclaration('(*%s_add)' % entry.Name())) 80 self.PrintIdented(file, ' ', dcl) 81 print >>file, '};\n' 82 83 print >>file, 'struct %s {' % self._name 84 print >>file, ' struct %s_access_ *base;\n' % self._name 85 for entry in self._entries: 86 dcl = entry.Declaration() 87 self.PrintIdented(file, ' ', dcl) 88 print >>file, '' 89 for entry in self._entries: 90 print >>file, ' ev_uint8_t %s_set;' % entry.Name() 91 print >>file, '};\n' 92 93 print >>file, \ 94 """struct %(name)s *%(name)s_new(void); 95 void %(name)s_free(struct %(name)s *); 96 void %(name)s_clear(struct %(name)s *); 97 void %(name)s_marshal(struct evbuffer *, const struct %(name)s *); 98 int %(name)s_unmarshal(struct %(name)s *, struct evbuffer *); 99 int %(name)s_complete(struct %(name)s *); 100 void evtag_marshal_%(name)s(struct evbuffer *, ev_uint32_t, 101 const struct %(name)s *); 102 int evtag_unmarshal_%(name)s(struct evbuffer *, ev_uint32_t, 103 struct %(name)s *);""" % { 'name' : self._name } 104 105 106 # Write a setting function of every variable 107 for entry in self._entries: 108 self.PrintIdented(file, '', entry.AssignDeclaration( 109 entry.AssignFuncName())) 110 self.PrintIdented(file, '', entry.GetDeclaration( 111 entry.GetFuncName())) 112 if entry.Array(): 113 self.PrintIdented(file, '', entry.AddDeclaration( 114 entry.AddFuncName())) 115 116 print >>file, '/* --- %s done --- */\n' % self._name 117 118 def PrintCode(self, file): 119 print >>file, ('/*\n' 120 ' * Implementation of %s\n' 121 ' */\n') % self._name 122 123 print >>file, \ 124 'static struct %(name)s_access_ __%(name)s_base = {' % \ 125 { 'name' : self._name } 126 for entry in self._entries: 127 self.PrintIdented(file, ' ', entry.CodeBase()) 128 print >>file, '};\n' 129 130 # Creation 131 print >>file, ( 132 'struct %(name)s *\n' 133 '%(name)s_new(void)\n' 134 '{\n' 135 ' struct %(name)s *tmp;\n' 136 ' if ((tmp = malloc(sizeof(struct %(name)s))) == NULL) {\n' 137 ' event_warn("%%s: malloc", __func__);\n' 138 ' return (NULL);\n' 139 ' }\n' 140 ' tmp->base = &__%(name)s_base;\n') % { 'name' : self._name } 141 142 for entry in self._entries: 143 self.PrintIdented(file, ' ', entry.CodeNew('tmp')) 144 print >>file, ' tmp->%s_set = 0;\n' % entry.Name() 145 146 print >>file, ( 147 ' return (tmp);\n' 148 '}\n') 149 150 # Adding 151 for entry in self._entries: 152 if entry.Array(): 153 self.PrintIdented(file, '', entry.CodeAdd()) 154 print >>file, '' 155 156 # Assigning 157 for entry in self._entries: 158 self.PrintIdented(file, '', entry.CodeAssign()) 159 print >>file, '' 160 161 # Getting 162 for entry in self._entries: 163 self.PrintIdented(file, '', entry.CodeGet()) 164 print >>file, '' 165 166 # Clearing 167 print >>file, ( 'void\n' 168 '%(name)s_clear(struct %(name)s *tmp)\n' 169 '{' 170 ) % { 'name' : self._name } 171 for entry in self._entries: 172 self.PrintIdented(file, ' ', entry.CodeClear('tmp')) 173 174 print >>file, '}\n' 175 176 # Freeing 177 print >>file, ( 'void\n' 178 '%(name)s_free(struct %(name)s *tmp)\n' 179 '{' 180 ) % { 'name' : self._name } 181 182 for entry in self._entries: 183 self.PrintIdented(file, ' ', entry.CodeFree('tmp')) 184 185 print >>file, (' free(tmp);\n' 186 '}\n') 187 188 # Marshaling 189 print >>file, ('void\n' 190 '%(name)s_marshal(struct evbuffer *evbuf, ' 191 'const struct %(name)s *tmp)' 192 '{') % { 'name' : self._name } 193 for entry in self._entries: 194 indent = ' ' 195 # Optional entries do not have to be set 196 if entry.Optional(): 197 indent += ' ' 198 print >>file, ' if (tmp->%s_set) {' % entry.Name() 199 self.PrintIdented( 200 file, indent, 201 entry.CodeMarshal('evbuf', self.EntryTagName(entry), 'tmp')) 202 if entry.Optional(): 203 print >>file, ' }' 204 205 print >>file, '}\n' 206 207 # Unmarshaling 208 print >>file, ('int\n' 209 '%(name)s_unmarshal(struct %(name)s *tmp, ' 210 ' struct evbuffer *evbuf)\n' 211 '{\n' 212 ' ev_uint32_t tag;\n' 213 ' while (EVBUFFER_LENGTH(evbuf) > 0) {\n' 214 ' if (evtag_peek(evbuf, &tag) == -1)\n' 215 ' return (-1);\n' 216 ' switch (tag) {\n' 217 ) % { 'name' : self._name } 218 for entry in self._entries: 219 print >>file, ' case %s:\n' % self.EntryTagName(entry) 220 if not entry.Array(): 221 print >>file, ( 222 ' if (tmp->%s_set)\n' 223 ' return (-1);' 224 ) % (entry.Name()) 225 226 self.PrintIdented( 227 file, ' ', 228 entry.CodeUnmarshal('evbuf', 229 self.EntryTagName(entry), 'tmp')) 230 231 print >>file, ( ' tmp->%s_set = 1;\n' % entry.Name() + 232 ' break;\n' ) 233 print >>file, ( ' default:\n' 234 ' return -1;\n' 235 ' }\n' 236 ' }\n' ) 237 # Check if it was decoded completely 238 print >>file, ( ' if (%(name)s_complete(tmp) == -1)\n' 239 ' return (-1);' 240 ) % { 'name' : self._name } 241 242 # Successfully decoded 243 print >>file, ( ' return (0);\n' 244 '}\n') 245 246 # Checking if a structure has all the required data 247 print >>file, ( 248 'int\n' 249 '%(name)s_complete(struct %(name)s *msg)\n' 250 '{' ) % { 'name' : self._name } 251 for entry in self._entries: 252 self.PrintIdented( 253 file, ' ', 254 entry.CodeComplete('msg')) 255 print >>file, ( 256 ' return (0);\n' 257 '}\n' ) 258 259 # Complete message unmarshaling 260 print >>file, ( 261 'int\n' 262 'evtag_unmarshal_%(name)s(struct evbuffer *evbuf, ' 263 'ev_uint32_t need_tag, struct %(name)s *msg)\n' 264 '{\n' 265 ' ev_uint32_t tag;\n' 266 ' int res = -1;\n' 267 '\n' 268 ' struct evbuffer *tmp = evbuffer_new();\n' 269 '\n' 270 ' if (evtag_unmarshal(evbuf, &tag, tmp) == -1' 271 ' || tag != need_tag)\n' 272 ' goto error;\n' 273 '\n' 274 ' if (%(name)s_unmarshal(msg, tmp) == -1)\n' 275 ' goto error;\n' 276 '\n' 277 ' res = 0;\n' 278 '\n' 279 ' error:\n' 280 ' evbuffer_free(tmp);\n' 281 ' return (res);\n' 282 '}\n' ) % { 'name' : self._name } 283 284 # Complete message marshaling 285 print >>file, ( 286 'void\n' 287 'evtag_marshal_%(name)s(struct evbuffer *evbuf, ev_uint32_t tag, ' 288 'const struct %(name)s *msg)\n' 289 '{\n' 290 ' struct evbuffer *_buf = evbuffer_new();\n' 291 ' assert(_buf != NULL);\n' 292 ' evbuffer_drain(_buf, -1);\n' 293 ' %(name)s_marshal(_buf, msg);\n' 294 ' evtag_marshal(evbuf, tag, EVBUFFER_DATA(_buf), ' 295 'EVBUFFER_LENGTH(_buf));\n' 296 ' evbuffer_free(_buf);\n' 297 '}\n' ) % { 'name' : self._name } 298 299 class Entry: 300 def __init__(self, type, name, tag): 301 self._type = type 302 self._name = name 303 self._tag = int(tag) 304 self._ctype = type 305 self._optional = 0 306 self._can_be_array = 0 307 self._array = 0 308 self._line_count = -1 309 self._struct = None 310 self._refname = None 311 312 def GetTranslation(self): 313 return { "parent_name" : self._struct.Name(), 314 "name" : self._name, 315 "ctype" : self._ctype, 316 "refname" : self._refname 317 } 318 319 def SetStruct(self, struct): 320 self._struct = struct 321 322 def LineCount(self): 323 assert self._line_count != -1 324 return self._line_count 325 326 def SetLineCount(self, number): 327 self._line_count = number 328 329 def Array(self): 330 return self._array 331 332 def Optional(self): 333 return self._optional 334 335 def Tag(self): 336 return self._tag 337 338 def Name(self): 339 return self._name 340 341 def Type(self): 342 return self._type 343 344 def MakeArray(self, yes=1): 345 self._array = yes 346 347 def MakeOptional(self): 348 self._optional = 1 349 350 def GetFuncName(self): 351 return '%s_%s_get' % (self._struct.Name(), self._name) 352 353 def GetDeclaration(self, funcname): 354 code = [ 'int %s(struct %s *, %s *);' % ( 355 funcname, self._struct.Name(), self._ctype ) ] 356 return code 357 358 def CodeGet(self): 359 code = ( 360 'int', 361 '%(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, ' 362 '%(ctype)s *value)', 363 '{', 364 ' if (msg->%(name)s_set != 1)', 365 ' return (-1);', 366 ' *value = msg->%(name)s_data;', 367 ' return (0);', 368 '}' ) 369 code = '\n'.join(code) 370 code = code % self.GetTranslation() 371 return code.split('\n') 372 373 def AssignFuncName(self): 374 return '%s_%s_assign' % (self._struct.Name(), self._name) 375 376 def AddFuncName(self): 377 return '%s_%s_add' % (self._struct.Name(), self._name) 378 379 def AssignDeclaration(self, funcname): 380 code = [ 'int %s(struct %s *, const %s);' % ( 381 funcname, self._struct.Name(), self._ctype ) ] 382 return code 383 384 def CodeAssign(self): 385 code = [ 'int', 386 '%(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg,' 387 ' const %(ctype)s value)', 388 '{', 389 ' msg->%(name)s_set = 1;', 390 ' msg->%(name)s_data = value;', 391 ' return (0);', 392 '}' ] 393 code = '\n'.join(code) 394 code = code % self.GetTranslation() 395 return code.split('\n') 396 397 def CodeClear(self, structname): 398 code = [ '%s->%s_set = 0;' % (structname, self.Name()) ] 399 400 return code 401 402 def CodeComplete(self, structname): 403 if self.Optional(): 404 return [] 405 406 code = [ 'if (!%s->%s_set)' % (structname, self.Name()), 407 ' return (-1);' ] 408 409 return code 410 411 def CodeFree(self, name): 412 return [] 413 414 def CodeBase(self): 415 code = [ 416 '%(parent_name)s_%(name)s_assign,', 417 '%(parent_name)s_%(name)s_get,' 418 ] 419 if self.Array(): 420 code.append('%(parent_name)s_%(name)s_add,') 421 422 code = '\n'.join(code) 423 code = code % self.GetTranslation() 424 return code.split('\n') 425 426 def Verify(self): 427 if self.Array() and not self._can_be_array: 428 print >>sys.stderr, ( 429 'Entry "%s" cannot be created as an array ' 430 'around line %d' ) % (self._name, self.LineCount()) 431 sys.exit(1) 432 if not self._struct: 433 print >>sys.stderr, ( 434 'Entry "%s" does not know which struct it belongs to ' 435 'around line %d' ) % (self._name, self.LineCount()) 436 sys.exit(1) 437 if self._optional and self._array: 438 print >>sys.stderr, ( 'Entry "%s" has illegal combination of ' 439 'optional and array around line %d' ) % ( 440 self._name, self.LineCount() ) 441 sys.exit(1) 442 443 class EntryBytes(Entry): 444 def __init__(self, type, name, tag, length): 445 # Init base class 446 Entry.__init__(self, type, name, tag) 447 448 self._length = length 449 self._ctype = 'ev_uint8_t' 450 451 def GetDeclaration(self, funcname): 452 code = [ 'int %s(struct %s *, %s **);' % ( 453 funcname, self._struct.Name(), self._ctype ) ] 454 return code 455 456 def AssignDeclaration(self, funcname): 457 code = [ 'int %s(struct %s *, const %s *);' % ( 458 funcname, self._struct.Name(), self._ctype ) ] 459 return code 460 461 def Declaration(self): 462 dcl = ['ev_uint8_t %s_data[%s];' % (self._name, self._length)] 463 464 return dcl 465 466 def CodeGet(self): 467 name = self._name 468 code = [ 'int', 469 '%s_%s_get(struct %s *msg, %s **value)' % ( 470 self._struct.Name(), name, 471 self._struct.Name(), self._ctype), 472 '{', 473 ' if (msg->%s_set != 1)' % name, 474 ' return (-1);', 475 ' *value = msg->%s_data;' % name, 476 ' return (0);', 477 '}' ] 478 return code 479 480 def CodeAssign(self): 481 name = self._name 482 code = [ 'int', 483 '%s_%s_assign(struct %s *msg, const %s *value)' % ( 484 self._struct.Name(), name, 485 self._struct.Name(), self._ctype), 486 '{', 487 ' msg->%s_set = 1;' % name, 488 ' memcpy(msg->%s_data, value, %s);' % ( 489 name, self._length), 490 ' return (0);', 491 '}' ] 492 return code 493 494 def CodeUnmarshal(self, buf, tag_name, var_name): 495 code = [ 'if (evtag_unmarshal_fixed(%s, %s, ' % (buf, tag_name) + 496 '%s->%s_data, ' % (var_name, self._name) + 497 'sizeof(%s->%s_data)) == -1) {' % ( 498 var_name, self._name), 499 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( 500 self._name ), 501 ' return (-1);', 502 '}' 503 ] 504 return code 505 506 def CodeMarshal(self, buf, tag_name, var_name): 507 code = ['evtag_marshal(%s, %s, %s->%s_data, sizeof(%s->%s_data));' % ( 508 buf, tag_name, var_name, self._name, var_name, self._name )] 509 return code 510 511 def CodeClear(self, structname): 512 code = [ '%s->%s_set = 0;' % (structname, self.Name()), 513 'memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( 514 structname, self._name, structname, self._name)] 515 516 return code 517 518 def CodeNew(self, name): 519 code = ['memset(%s->%s_data, 0, sizeof(%s->%s_data));' % ( 520 name, self._name, name, self._name)] 521 return code 522 523 def Verify(self): 524 if not self._length: 525 print >>sys.stderr, 'Entry "%s" needs a length around line %d' % ( 526 self._name, self.LineCount() ) 527 sys.exit(1) 528 529 Entry.Verify(self) 530 531 class EntryInt(Entry): 532 def __init__(self, type, name, tag): 533 # Init base class 534 Entry.__init__(self, type, name, tag) 535 536 self._ctype = 'ev_uint32_t' 537 538 def CodeUnmarshal(self, buf, tag_name, var_name): 539 code = ['if (evtag_unmarshal_int(%s, %s, &%s->%s_data) == -1) {' % ( 540 buf, tag_name, var_name, self._name), 541 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( 542 self._name ), 543 ' return (-1);', 544 '}' ] 545 return code 546 547 def CodeMarshal(self, buf, tag_name, var_name): 548 code = ['evtag_marshal_int(%s, %s, %s->%s_data);' % ( 549 buf, tag_name, var_name, self._name)] 550 return code 551 552 def Declaration(self): 553 dcl = ['ev_uint32_t %s_data;' % self._name] 554 555 return dcl 556 557 def CodeNew(self, name): 558 code = ['%s->%s_data = 0;' % (name, self._name)] 559 return code 560 561 class EntryString(Entry): 562 def __init__(self, type, name, tag): 563 # Init base class 564 Entry.__init__(self, type, name, tag) 565 566 self._ctype = 'char *' 567 568 def CodeAssign(self): 569 name = self._name 570 code = """int 571 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, 572 const %(ctype)s value) 573 { 574 if (msg->%(name)s_data != NULL) 575 free(msg->%(name)s_data); 576 if ((msg->%(name)s_data = strdup(value)) == NULL) 577 return (-1); 578 msg->%(name)s_set = 1; 579 return (0); 580 }""" % self.GetTranslation() 581 582 return code.split('\n') 583 584 def CodeUnmarshal(self, buf, tag_name, var_name): 585 code = ['if (evtag_unmarshal_string(%s, %s, &%s->%s_data) == -1) {' % ( 586 buf, tag_name, var_name, self._name), 587 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( 588 self._name ), 589 ' return (-1);', 590 '}' 591 ] 592 return code 593 594 def CodeMarshal(self, buf, tag_name, var_name): 595 code = ['evtag_marshal_string(%s, %s, %s->%s_data);' % ( 596 buf, tag_name, var_name, self._name)] 597 return code 598 599 def CodeClear(self, structname): 600 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), 601 ' free (%s->%s_data);' % (structname, self.Name()), 602 ' %s->%s_data = NULL;' % (structname, self.Name()), 603 ' %s->%s_set = 0;' % (structname, self.Name()), 604 '}' 605 ] 606 607 return code 608 609 def CodeNew(self, name): 610 code = ['%s->%s_data = NULL;' % (name, self._name)] 611 return code 612 613 def CodeFree(self, name): 614 code = ['if (%s->%s_data != NULL)' % (name, self._name), 615 ' free (%s->%s_data); ' % (name, self._name)] 616 617 return code 618 619 def Declaration(self): 620 dcl = ['char *%s_data;' % self._name] 621 622 return dcl 623 624 class EntryStruct(Entry): 625 def __init__(self, type, name, tag, refname): 626 # Init base class 627 Entry.__init__(self, type, name, tag) 628 629 self._can_be_array = 1 630 self._refname = refname 631 self._ctype = 'struct %s*' % refname 632 633 def CodeGet(self): 634 name = self._name 635 code = [ 'int', 636 '%s_%s_get(struct %s *msg, %s *value)' % ( 637 self._struct.Name(), name, 638 self._struct.Name(), self._ctype), 639 '{', 640 ' if (msg->%s_set != 1) {' % name, 641 ' msg->%s_data = %s_new();' % (name, self._refname), 642 ' if (msg->%s_data == NULL)' % name, 643 ' return (-1);', 644 ' msg->%s_set = 1;' % name, 645 ' }', 646 ' *value = msg->%s_data;' % name, 647 ' return (0);', 648 '}' ] 649 return code 650 651 def CodeAssign(self): 652 name = self._name 653 code = """int 654 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, 655 const %(ctype)s value) 656 { 657 struct evbuffer *tmp = NULL; 658 if (msg->%(name)s_set) { 659 %(refname)s_clear(msg->%(name)s_data); 660 msg->%(name)s_set = 0; 661 } else { 662 msg->%(name)s_data = %(refname)s_new(); 663 if (msg->%(name)s_data == NULL) { 664 event_warn("%%s: %(refname)s_new()", __func__); 665 goto error; 666 } 667 } 668 if ((tmp = evbuffer_new()) == NULL) { 669 event_warn("%%s: evbuffer_new()", __func__); 670 goto error; 671 } 672 %(refname)s_marshal(tmp, value); 673 if (%(refname)s_unmarshal(msg->%(name)s_data, tmp) == -1) { 674 event_warnx("%%s: %(refname)s_unmarshal", __func__); 675 goto error; 676 } 677 msg->%(name)s_set = 1; 678 evbuffer_free(tmp); 679 return (0); 680 error: 681 if (tmp != NULL) 682 evbuffer_free(tmp); 683 if (msg->%(name)s_data != NULL) { 684 %(refname)s_free(msg->%(name)s_data); 685 msg->%(name)s_data = NULL; 686 } 687 return (-1); 688 }""" % self.GetTranslation() 689 return code.split('\n') 690 691 def CodeComplete(self, structname): 692 if self.Optional(): 693 code = [ 'if (%s->%s_set && %s_complete(%s->%s_data) == -1)' % ( 694 structname, self.Name(), 695 self._refname, structname, self.Name()), 696 ' return (-1);' ] 697 else: 698 code = [ 'if (%s_complete(%s->%s_data) == -1)' % ( 699 self._refname, structname, self.Name()), 700 ' return (-1);' ] 701 702 return code 703 704 def CodeUnmarshal(self, buf, tag_name, var_name): 705 code = ['%s->%s_data = %s_new();' % ( 706 var_name, self._name, self._refname), 707 'if (%s->%s_data == NULL)' % (var_name, self._name), 708 ' return (-1);', 709 'if (evtag_unmarshal_%s(%s, %s, %s->%s_data) == -1) {' % ( 710 self._refname, buf, tag_name, var_name, self._name), 711 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( 712 self._name ), 713 ' return (-1);', 714 '}' 715 ] 716 return code 717 718 def CodeMarshal(self, buf, tag_name, var_name): 719 code = ['evtag_marshal_%s(%s, %s, %s->%s_data);' % ( 720 self._refname, buf, tag_name, var_name, self._name)] 721 return code 722 723 def CodeClear(self, structname): 724 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), 725 ' %s_free(%s->%s_data);' % ( 726 self._refname, structname, self.Name()), 727 ' %s->%s_data = NULL;' % (structname, self.Name()), 728 ' %s->%s_set = 0;' % (structname, self.Name()), 729 '}' 730 ] 731 732 return code 733 734 def CodeNew(self, name): 735 code = ['%s->%s_data = NULL;' % (name, self._name)] 736 return code 737 738 def CodeFree(self, name): 739 code = ['if (%s->%s_data != NULL)' % (name, self._name), 740 ' %s_free(%s->%s_data); ' % ( 741 self._refname, name, self._name)] 742 743 return code 744 745 def Declaration(self): 746 dcl = ['%s %s_data;' % (self._ctype, self._name)] 747 748 return dcl 749 750 class EntryVarBytes(Entry): 751 def __init__(self, type, name, tag): 752 # Init base class 753 Entry.__init__(self, type, name, tag) 754 755 self._ctype = 'ev_uint8_t *' 756 757 def GetDeclaration(self, funcname): 758 code = [ 'int %s(struct %s *, %s *, ev_uint32_t *);' % ( 759 funcname, self._struct.Name(), self._ctype ) ] 760 return code 761 762 def AssignDeclaration(self, funcname): 763 code = [ 'int %s(struct %s *, const %s, ev_uint32_t);' % ( 764 funcname, self._struct.Name(), self._ctype ) ] 765 return code 766 767 def CodeAssign(self): 768 name = self._name 769 code = [ 'int', 770 '%s_%s_assign(struct %s *msg, ' 771 'const %s value, ev_uint32_t len)' % ( 772 self._struct.Name(), name, 773 self._struct.Name(), self._ctype), 774 '{', 775 ' if (msg->%s_data != NULL)' % name, 776 ' free (msg->%s_data);' % name, 777 ' msg->%s_data = malloc(len);' % name, 778 ' if (msg->%s_data == NULL)' % name, 779 ' return (-1);', 780 ' msg->%s_set = 1;' % name, 781 ' msg->%s_length = len;' % name, 782 ' memcpy(msg->%s_data, value, len);' % name, 783 ' return (0);', 784 '}' ] 785 return code 786 787 def CodeGet(self): 788 name = self._name 789 code = [ 'int', 790 '%s_%s_get(struct %s *msg, %s *value, ev_uint32_t *plen)' % ( 791 self._struct.Name(), name, 792 self._struct.Name(), self._ctype), 793 '{', 794 ' if (msg->%s_set != 1)' % name, 795 ' return (-1);', 796 ' *value = msg->%s_data;' % name, 797 ' *plen = msg->%s_length;' % name, 798 ' return (0);', 799 '}' ] 800 return code 801 802 def CodeUnmarshal(self, buf, tag_name, var_name): 803 code = ['if (evtag_payload_length(%s, &%s->%s_length) == -1)' % ( 804 buf, var_name, self._name), 805 ' return (-1);', 806 # We do not want DoS opportunities 807 'if (%s->%s_length > EVBUFFER_LENGTH(%s))' % ( 808 var_name, self._name, buf), 809 ' return (-1);', 810 'if ((%s->%s_data = malloc(%s->%s_length)) == NULL)' % ( 811 var_name, self._name, var_name, self._name), 812 ' return (-1);', 813 'if (evtag_unmarshal_fixed(%s, %s, %s->%s_data, ' 814 '%s->%s_length) == -1) {' % ( 815 buf, tag_name, var_name, self._name, var_name, self._name), 816 ' event_warnx("%%s: failed to unmarshal %s", __func__);' % ( 817 self._name ), 818 ' return (-1);', 819 '}' 820 ] 821 return code 822 823 def CodeMarshal(self, buf, tag_name, var_name): 824 code = ['evtag_marshal(%s, %s, %s->%s_data, %s->%s_length);' % ( 825 buf, tag_name, var_name, self._name, var_name, self._name)] 826 return code 827 828 def CodeClear(self, structname): 829 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), 830 ' free (%s->%s_data);' % (structname, self.Name()), 831 ' %s->%s_data = NULL;' % (structname, self.Name()), 832 ' %s->%s_length = 0;' % (structname, self.Name()), 833 ' %s->%s_set = 0;' % (structname, self.Name()), 834 '}' 835 ] 836 837 return code 838 839 def CodeNew(self, name): 840 code = ['%s->%s_data = NULL;' % (name, self._name), 841 '%s->%s_length = 0;' % (name, self._name) ] 842 return code 843 844 def CodeFree(self, name): 845 code = ['if (%s->%s_data != NULL)' % (name, self._name), 846 ' free (%s->%s_data); ' % (name, self._name)] 847 848 return code 849 850 def Declaration(self): 851 dcl = ['ev_uint8_t *%s_data;' % self._name, 852 'ev_uint32_t %s_length;' % self._name] 853 854 return dcl 855 856 class EntryArray(Entry): 857 def __init__(self, entry): 858 # Init base class 859 Entry.__init__(self, entry._type, entry._name, entry._tag) 860 861 self._entry = entry 862 self._refname = entry._refname 863 self._ctype = 'struct %s *' % self._refname 864 865 def GetDeclaration(self, funcname): 866 """Allows direct access to elements of the array.""" 867 translate = self.GetTranslation() 868 translate["funcname"] = funcname 869 code = [ 870 'int %(funcname)s(struct %(parent_name)s *, int, %(ctype)s *);' % 871 translate ] 872 return code 873 874 def AssignDeclaration(self, funcname): 875 code = [ 'int %s(struct %s *, int, const %s);' % ( 876 funcname, self._struct.Name(), self._ctype ) ] 877 return code 878 879 def AddDeclaration(self, funcname): 880 code = [ '%s %s(struct %s *);' % ( 881 self._ctype, funcname, self._struct.Name() ) ] 882 return code 883 884 def CodeGet(self): 885 code = """int 886 %(parent_name)s_%(name)s_get(struct %(parent_name)s *msg, int offset, 887 %(ctype)s *value) 888 { 889 if (!msg->%(name)s_set || offset < 0 || offset >= msg->%(name)s_length) 890 return (-1); 891 *value = msg->%(name)s_data[offset]; 892 return (0); 893 }""" % self.GetTranslation() 894 895 return code.split('\n') 896 897 def CodeAssign(self): 898 code = """int 899 %(parent_name)s_%(name)s_assign(struct %(parent_name)s *msg, int off, 900 const %(ctype)s value) 901 { 902 struct evbuffer *tmp = NULL; 903 if (!msg->%(name)s_set || off < 0 || off >= msg->%(name)s_length) 904 return (-1); 905 %(refname)s_clear(msg->%(name)s_data[off]); 906 if ((tmp = evbuffer_new()) == NULL) { 907 event_warn("%%s: evbuffer_new()", __func__); 908 goto error; 909 } 910 %(refname)s_marshal(tmp, value); 911 if (%(refname)s_unmarshal(msg->%(name)s_data[off], tmp) == -1) { 912 event_warnx("%%s: %(refname)s_unmarshal", __func__); 913 goto error; 914 } 915 evbuffer_free(tmp); 916 return (0); 917 error: 918 if (tmp != NULL) 919 evbuffer_free(tmp); 920 %(refname)s_clear(msg->%(name)s_data[off]); 921 return (-1); 922 }""" % self.GetTranslation() 923 924 return code.split('\n') 925 926 def CodeAdd(self): 927 code = \ 928 """%(ctype)s 929 %(parent_name)s_%(name)s_add(struct %(parent_name)s *msg) 930 { 931 if (++msg->%(name)s_length >= msg->%(name)s_num_allocated) { 932 int tobe_allocated = msg->%(name)s_num_allocated; 933 %(ctype)s* new_data = NULL; 934 tobe_allocated = !tobe_allocated ? 1 : tobe_allocated << 1; 935 new_data = (%(ctype)s*) realloc(msg->%(name)s_data, 936 tobe_allocated * sizeof(%(ctype)s)); 937 if (new_data == NULL) 938 goto error; 939 msg->%(name)s_data = new_data; 940 msg->%(name)s_num_allocated = tobe_allocated; 941 } 942 msg->%(name)s_data[msg->%(name)s_length - 1] = %(refname)s_new(); 943 if (msg->%(name)s_data[msg->%(name)s_length - 1] == NULL) 944 goto error; 945 msg->%(name)s_set = 1; 946 return (msg->%(name)s_data[msg->%(name)s_length - 1]); 947 error: 948 --msg->%(name)s_length; 949 return (NULL); 950 } 951 """ % self.GetTranslation() 952 953 return code.split('\n') 954 955 def CodeComplete(self, structname): 956 code = [] 957 translate = self.GetTranslation() 958 959 if self.Optional(): 960 code.append( 'if (%(structname)s->%(name)s_set)' % translate) 961 962 translate["structname"] = structname 963 tmp = """{ 964 int i; 965 for (i = 0; i < %(structname)s->%(name)s_length; ++i) { 966 if (%(refname)s_complete(%(structname)s->%(name)s_data[i]) == -1) 967 return (-1); 968 } 969 }""" % translate 970 code.extend(tmp.split('\n')) 971 972 return code 973 974 def CodeUnmarshal(self, buf, tag_name, var_name): 975 translate = self.GetTranslation() 976 translate["var_name"] = var_name 977 translate["buf"] = buf 978 translate["tag_name"] = tag_name 979 code = """if (%(parent_name)s_%(name)s_add(%(var_name)s) == NULL) 980 return (-1); 981 if (evtag_unmarshal_%(refname)s(%(buf)s, %(tag_name)s, 982 %(var_name)s->%(name)s_data[%(var_name)s->%(name)s_length - 1]) == -1) { 983 --%(var_name)s->%(name)s_length; 984 event_warnx("%%s: failed to unmarshal %(name)s", __func__); 985 return (-1); 986 }""" % translate 987 988 return code.split('\n') 989 990 def CodeMarshal(self, buf, tag_name, var_name): 991 code = ['{', 992 ' int i;', 993 ' for (i = 0; i < %s->%s_length; ++i) {' % ( 994 var_name, self._name), 995 ' evtag_marshal_%s(%s, %s, %s->%s_data[i]);' % ( 996 self._refname, buf, tag_name, var_name, self._name), 997 ' }', 998 '}' 999 ] 1000 return code 1001 1002 def CodeClear(self, structname): 1003 code = [ 'if (%s->%s_set == 1) {' % (structname, self.Name()), 1004 ' int i;', 1005 ' for (i = 0; i < %s->%s_length; ++i) {' % ( 1006 structname, self.Name()), 1007 ' %s_free(%s->%s_data[i]);' % ( 1008 self._refname, structname, self.Name()), 1009 ' }', 1010 ' free(%s->%s_data);' % (structname, self.Name()), 1011 ' %s->%s_data = NULL;' % (structname, self.Name()), 1012 ' %s->%s_set = 0;' % (structname, self.Name()), 1013 ' %s->%s_length = 0;' % (structname, self.Name()), 1014 ' %s->%s_num_allocated = 0;' % (structname, self.Name()), 1015 '}' 1016 ] 1017 1018 return code 1019 1020 def CodeNew(self, name): 1021 code = ['%s->%s_data = NULL;' % (name, self._name), 1022 '%s->%s_length = 0;' % (name, self._name), 1023 '%s->%s_num_allocated = 0;' % (name, self._name)] 1024 return code 1025 1026 def CodeFree(self, name): 1027 code = ['if (%s->%s_data != NULL) {' % (name, self._name), 1028 ' int i;', 1029 ' for (i = 0; i < %s->%s_length; ++i) {' % ( 1030 name, self._name), 1031 ' %s_free(%s->%s_data[i]); ' % ( 1032 self._refname, name, self._name), 1033 ' %s->%s_data[i] = NULL;' % (name, self._name), 1034 ' }', 1035 ' free(%s->%s_data);' % (name, self._name), 1036 ' %s->%s_data = NULL;' % (name, self._name), 1037 ' %s->%s_length = 0;' % (name, self._name), 1038 ' %s->%s_num_allocated = 0;' % (name, self._name), 1039 '}' 1040 ] 1041 1042 return code 1043 1044 def Declaration(self): 1045 dcl = ['struct %s **%s_data;' % (self._refname, self._name), 1046 'int %s_length;' % self._name, 1047 'int %s_num_allocated;' % self._name ] 1048 1049 return dcl 1050 1051 def NormalizeLine(line): 1052 global white 1053 global cppcomment 1054 1055 line = cppcomment.sub('', line) 1056 line = line.strip() 1057 line = white.sub(' ', line) 1058 1059 return line 1060 1061 def ProcessOneEntry(newstruct, entry): 1062 optional = 0 1063 array = 0 1064 entry_type = '' 1065 name = '' 1066 tag = '' 1067 tag_set = None 1068 separator = '' 1069 fixed_length = '' 1070 1071 tokens = entry.split(' ') 1072 while tokens: 1073 token = tokens[0] 1074 tokens = tokens[1:] 1075 1076 if not entry_type: 1077 if not optional and token == 'optional': 1078 optional = 1 1079 continue 1080 1081 if not array and token == 'array': 1082 array = 1 1083 continue 1084 1085 if not entry_type: 1086 entry_type = token 1087 continue 1088 1089 if not name: 1090 res = re.match(r'^([^\[\]]+)(\[.*\])?$', token) 1091 if not res: 1092 print >>sys.stderr, 'Cannot parse name: \"%s\" around %d' % ( 1093 entry, line_count) 1094 sys.exit(1) 1095 name = res.group(1) 1096 fixed_length = res.group(2) 1097 if fixed_length: 1098 fixed_length = fixed_length[1:-1] 1099 continue 1100 1101 if not separator: 1102 separator = token 1103 if separator != '=': 1104 print >>sys.stderr, 'Expected "=" after name \"%s\" got %s' % ( 1105 name, token) 1106 sys.exit(1) 1107 continue 1108 1109 if not tag_set: 1110 tag_set = 1 1111 if not re.match(r'^(0x)?[0-9]+$', token): 1112 print >>sys.stderr, 'Expected tag number: \"%s\"' % entry 1113 sys.exit(1) 1114 tag = int(token, 0) 1115 continue 1116 1117 print >>sys.stderr, 'Cannot parse \"%s\"' % entry 1118 sys.exit(1) 1119 1120 if not tag_set: 1121 print >>sys.stderr, 'Need tag number: \"%s\"' % entry 1122 sys.exit(1) 1123 1124 # Create the right entry 1125 if entry_type == 'bytes': 1126 if fixed_length: 1127 newentry = EntryBytes(entry_type, name, tag, fixed_length) 1128 else: 1129 newentry = EntryVarBytes(entry_type, name, tag) 1130 elif entry_type == 'int' and not fixed_length: 1131 newentry = EntryInt(entry_type, name, tag) 1132 elif entry_type == 'string' and not fixed_length: 1133 newentry = EntryString(entry_type, name, tag) 1134 else: 1135 res = re.match(r'^struct\[(%s)\]$' % _STRUCT_RE, 1136 entry_type, re.IGNORECASE) 1137 if res: 1138 # References another struct defined in our file 1139 newentry = EntryStruct(entry_type, name, tag, res.group(1)) 1140 else: 1141 print >>sys.stderr, 'Bad type: "%s" in "%s"' % (entry_type, entry) 1142 sys.exit(1) 1143 1144 structs = [] 1145 1146 if optional: 1147 newentry.MakeOptional() 1148 if array: 1149 newentry.MakeArray() 1150 1151 newentry.SetStruct(newstruct) 1152 newentry.SetLineCount(line_count) 1153 newentry.Verify() 1154 1155 if array: 1156 # We need to encapsulate this entry into a struct 1157 newname = newentry.Name()+ '_array' 1158 1159 # Now borgify the new entry. 1160 newentry = EntryArray(newentry) 1161 newentry.SetStruct(newstruct) 1162 newentry.SetLineCount(line_count) 1163 newentry.MakeArray() 1164 1165 newstruct.AddEntry(newentry) 1166 1167 return structs 1168 1169 def ProcessStruct(data): 1170 tokens = data.split(' ') 1171 1172 # First three tokens are: 'struct' 'name' '{' 1173 newstruct = Struct(tokens[1]) 1174 1175 inside = ' '.join(tokens[3:-1]) 1176 1177 tokens = inside.split(';') 1178 1179 structs = [] 1180 1181 for entry in tokens: 1182 entry = NormalizeLine(entry) 1183 if not entry: 1184 continue 1185 1186 # It's possible that new structs get defined in here 1187 structs.extend(ProcessOneEntry(newstruct, entry)) 1188 1189 structs.append(newstruct) 1190 return structs 1191 1192 def GetNextStruct(file): 1193 global line_count 1194 global cppdirect 1195 1196 got_struct = 0 1197 1198 processed_lines = [] 1199 1200 have_c_comment = 0 1201 data = '' 1202 while 1: 1203 line = file.readline() 1204 if not line: 1205 break 1206 1207 line_count += 1 1208 line = line[:-1] 1209 1210 if not have_c_comment and re.search(r'/\*', line): 1211 if re.search(r'/\*.*\*/', line): 1212 line = re.sub(r'/\*.*\*/', '', line) 1213 else: 1214 line = re.sub(r'/\*.*$', '', line) 1215 have_c_comment = 1 1216 1217 if have_c_comment: 1218 if not re.search(r'\*/', line): 1219 continue 1220 have_c_comment = 0 1221 line = re.sub(r'^.*\*/', '', line) 1222 1223 line = NormalizeLine(line) 1224 1225 if not line: 1226 continue 1227 1228 if not got_struct: 1229 if re.match(r'#include ["<].*[>"]', line): 1230 cppdirect.append(line) 1231 continue 1232 1233 if re.match(r'^#(if( |def)|endif)', line): 1234 cppdirect.append(line) 1235 continue 1236 1237 if re.match(r'^#define', line): 1238 headerdirect.append(line) 1239 continue 1240 1241 if not re.match(r'^struct %s {$' % _STRUCT_RE, 1242 line, re.IGNORECASE): 1243 print >>sys.stderr, 'Missing struct on line %d: %s' % ( 1244 line_count, line) 1245 sys.exit(1) 1246 else: 1247 got_struct = 1 1248 data += line 1249 continue 1250 1251 # We are inside the struct 1252 tokens = line.split('}') 1253 if len(tokens) == 1: 1254 data += ' ' + line 1255 continue 1256 1257 if len(tokens[1]): 1258 print >>sys.stderr, 'Trailing garbage after struct on line %d' % ( 1259 line_count ) 1260 sys.exit(1) 1261 1262 # We found the end of the struct 1263 data += ' %s}' % tokens[0] 1264 break 1265 1266 # Remove any comments, that might be in there 1267 data = re.sub(r'/\*.*\*/', '', data) 1268 1269 return data 1270 1271 1272 def Parse(file): 1273 """ 1274 Parses the input file and returns C code and corresponding header file. 1275 """ 1276 1277 entities = [] 1278 1279 while 1: 1280 # Just gets the whole struct nicely formatted 1281 data = GetNextStruct(file) 1282 1283 if not data: 1284 break 1285 1286 entities.extend(ProcessStruct(data)) 1287 1288 return entities 1289 1290 def GuardName(name): 1291 name = '_'.join(name.split('.')) 1292 name = '_'.join(name.split('/')) 1293 guard = '_'+name.upper()+'_' 1294 1295 return guard 1296 1297 def HeaderPreamble(name): 1298 guard = GuardName(name) 1299 pre = ( 1300 '/*\n' 1301 ' * Automatically generated from %s\n' 1302 ' */\n\n' 1303 '#ifndef %s\n' 1304 '#define %s\n\n' ) % ( 1305 name, guard, guard) 1306 1307 # insert stdint.h - let's hope everyone has it 1308 pre += ( 1309 '#include <event-config.h>\n' 1310 '#ifdef _EVENT_HAVE_STDINT_H\n' 1311 '#include <stdint.h>\n' 1312 '#endif\n' ) 1313 1314 for statement in headerdirect: 1315 pre += '%s\n' % statement 1316 if headerdirect: 1317 pre += '\n' 1318 1319 pre += ( 1320 '#define EVTAG_HAS(msg, member) ((msg)->member##_set == 1)\n' 1321 '#ifdef __GNUC__\n' 1322 '#define EVTAG_ASSIGN(msg, member, args...) ' 1323 '(*(msg)->base->member##_assign)(msg, ## args)\n' 1324 '#define EVTAG_GET(msg, member, args...) ' 1325 '(*(msg)->base->member##_get)(msg, ## args)\n' 1326 '#else\n' 1327 '#define EVTAG_ASSIGN(msg, member, ...) ' 1328 '(*(msg)->base->member##_assign)(msg, ## __VA_ARGS__)\n' 1329 '#define EVTAG_GET(msg, member, ...) ' 1330 '(*(msg)->base->member##_get)(msg, ## __VA_ARGS__)\n' 1331 '#endif\n' 1332 '#define EVTAG_ADD(msg, member) (*(msg)->base->member##_add)(msg)\n' 1333 '#define EVTAG_LEN(msg, member) ((msg)->member##_length)\n' 1334 ) 1335 1336 return pre 1337 1338 1339 def HeaderPostamble(name): 1340 guard = GuardName(name) 1341 return '#endif /* %s */' % guard 1342 1343 def BodyPreamble(name): 1344 global _NAME 1345 global _VERSION 1346 1347 header_file = '.'.join(name.split('.')[:-1]) + '.gen.h' 1348 1349 pre = ( '/*\n' 1350 ' * Automatically generated from %s\n' 1351 ' * by %s/%s. DO NOT EDIT THIS FILE.\n' 1352 ' */\n\n' ) % (name, _NAME, _VERSION) 1353 pre += ( '#include <sys/types.h>\n' 1354 '#ifdef _EVENT_HAVE_SYS_TIME_H\n' 1355 '#include <sys/time.h>\n' 1356 '#endif\n' 1357 '#include <stdlib.h>\n' 1358 '#include <string.h>\n' 1359 '#include <assert.h>\n' 1360 '#define EVENT_NO_STRUCT\n' 1361 '#include <event.h>\n\n' 1362 '#ifdef _EVENT___func__\n' 1363 '#define __func__ _EVENT___func__\n' 1364 '#endif\n' ) 1365 1366 for statement in cppdirect: 1367 pre += '%s\n' % statement 1368 1369 pre += '\n#include "%s"\n\n' % header_file 1370 1371 pre += 'void event_err(int eval, const char *fmt, ...);\n' 1372 pre += 'void event_warn(const char *fmt, ...);\n' 1373 pre += 'void event_errx(int eval, const char *fmt, ...);\n' 1374 pre += 'void event_warnx(const char *fmt, ...);\n\n' 1375 1376 return pre 1377 1378 def main(argv): 1379 if len(argv) < 2 or not argv[1]: 1380 print >>sys.stderr, 'Need RPC description file as first argument.' 1381 sys.exit(1) 1382 1383 filename = argv[1] 1384 1385 ext = filename.split('.')[-1] 1386 if ext != 'rpc': 1387 print >>sys.stderr, 'Unrecognized file extension: %s' % ext 1388 sys.exit(1) 1389 1390 print >>sys.stderr, 'Reading \"%s\"' % filename 1391 1392 fp = open(filename, 'r') 1393 entities = Parse(fp) 1394 fp.close() 1395 1396 header_file = '.'.join(filename.split('.')[:-1]) + '.gen.h' 1397 impl_file = '.'.join(filename.split('.')[:-1]) + '.gen.c' 1398 1399 print >>sys.stderr, '... creating "%s"' % header_file 1400 header_fp = open(header_file, 'w') 1401 print >>header_fp, HeaderPreamble(filename) 1402 1403 # Create forward declarations: allows other structs to reference 1404 # each other 1405 for entry in entities: 1406 entry.PrintForwardDeclaration(header_fp) 1407 print >>header_fp, '' 1408 1409 for entry in entities: 1410 entry.PrintTags(header_fp) 1411 entry.PrintDeclaration(header_fp) 1412 print >>header_fp, HeaderPostamble(filename) 1413 header_fp.close() 1414 1415 print >>sys.stderr, '... creating "%s"' % impl_file 1416 impl_fp = open(impl_file, 'w') 1417 print >>impl_fp, BodyPreamble(filename) 1418 for entry in entities: 1419 entry.PrintCode(impl_fp) 1420 impl_fp.close() 1421 1422 if __name__ == '__main__': 1423 main(sys.argv) 1424