Messages are not generated as stub. Code partially from demarshaller. Signed-off-by: Frediano Ziglio <fziglio@xxxxxxxxxx> --- codegen/Makefile.am | 3 +- codegen/check_dissector | 13 +++++ codegen/dissector_test.c | 54 ++++++++++++++++- python_modules/dissector.py | 138 +++++++++++++++++++++++++++++++++++++++++++- 4 files changed, 203 insertions(+), 5 deletions(-) create mode 100755 codegen/check_dissector diff --git a/codegen/Makefile.am b/codegen/Makefile.am index 129543c..b147b85 100644 --- a/codegen/Makefile.am +++ b/codegen/Makefile.am @@ -29,12 +29,13 @@ test.c: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS) test.h: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS) $(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-dissector --client $< --header $@ >/dev/null -TESTS = dissector_test +TESTS = check_dissector check_PROGRAMS = dissector_test dissector_test_SOURCES = dissector_test.c test.c test.h EXTRA_DIST = \ + check_dissector \ $(NULL) -include $(top_srcdir)/git.mk diff --git a/codegen/check_dissector b/codegen/check_dissector new file mode 100755 index 0000000..f1444a2 --- /dev/null +++ b/codegen/check_dissector @@ -0,0 +1,13 @@ +#!/bin/bash +set -e + +error() { + echo "$*" >&2 + exit 1 +} + +./dissector_test 1 100 +if ./dissector_test 1 99; then + error "This test should fail" +fi +exit 0 diff --git a/codegen/dissector_test.c b/codegen/dissector_test.c index 3212655..25a33b5 100644 --- a/codegen/dissector_test.c +++ b/codegen/dissector_test.c @@ -4,6 +4,7 @@ #include <stdlib.h> #include <unistd.h> #include <getopt.h> +#include <stdbool.h> #include <assert.h> #include <epan/expert.h> @@ -18,6 +19,7 @@ enum { static int last_hf_registered = first_hf_registered - 1; static int last_ei_registered = first_ei_registered - 1; static int last_tree_registered = first_tree_registered - 1; +static bool got_error = false; WS_DLL_PUBLIC void proto_register_field_array(const int parent, hf_register_info *hf, const int num_records) @@ -54,24 +56,46 @@ expert_register_field_array(expert_module_t* module, ei_register_info *ei, const } } +WS_DLL_PUBLIC void +expert_add_info_format(packet_info *pinfo, proto_item *pi, expert_field *eiindex, + const char *format, ...) +{ + assert(format); + got_error = true; + if (!pi) + return; +} + static const struct option long_options[] = { { "help", 0, NULL, 'h' }, + { "server", 0, NULL, 's' }, + { "client", 0, NULL, 'c' }, }; -static const char options[] = "h"; +static const char options[] = "hsc"; static void syntax(FILE *f, int exit_value) { fprintf(f, - "Usage: dissector_test [OPTIONS]\n" + "Usage: dissector_test [OPTIONS] CHANNEL MESSAGE_TYPE\n" "\n" "Options:\n" " -h, --help Show this help\n" + " -s, --server Process server messages (default)\n" + " -c, --client Process client messages\n" ); exit(exit_value); } int main(int argc, char **argv) { + int channel, message_type; + GlobalInfo glb; + proto_tree tree; + spice_dissect_func_t (*msg_func)(guint8 channel); + spice_dissect_func_t channel_func = NULL; + + msg_func = spice_server_channel_get_dissect; + while (1) { int option_index; int opt = getopt_long(argc, argv, options, long_options, &option_index); @@ -82,13 +106,37 @@ int main(int argc, char **argv) case 'h': syntax(stdout, EXIT_SUCCESS); break; + case 's': + msg_func = spice_server_channel_get_dissect; + break; + case 'c': + msg_func = spice_client_channel_get_dissect; + break; default: syntax(stderr, EXIT_FAILURE); break; } } + if (optind + 2 > argc) + syntax(stderr, EXIT_FAILURE); + + channel = strtol(argv[optind++], NULL, 0); + message_type = strtol(argv[optind++], NULL, 0); spice_register_fields(1, NULL); - return EXIT_SUCCESS; + memset(&glb, 0, sizeof(glb)); + glb.tvb = NULL; + glb.message_offset = 0; + glb.message_end = 0; + + channel_func = msg_func(channel); + assert(channel_func); + + memset(&tree, 0, sizeof(tree)); + + /* TODO check offset ?? */ + channel_func(message_type, &glb, &tree, 0); + + return got_error ? EXIT_FAILURE : EXIT_SUCCESS; } diff --git a/python_modules/dissector.py b/python_modules/dissector.py index f9ad08a..af0494c 100644 --- a/python_modules/dissector.py +++ b/python_modules/dissector.py @@ -1,4 +1,5 @@ +from . import ptypes from . import codegen import re @@ -65,6 +66,124 @@ def write_parser_helpers(writer): writer.writeln('#endif') writer.newline() +def write_msg_parser(writer, message, server): + msg_name = message.c_name() + function_name = "dissect_spice_%s_%s" % ('server' if server else 'client', msg_name) + if writer.is_generated("msg_parser", function_name): + return function_name + writer.set_is_generated("msg_parser", function_name) + + msg_type = message.c_type() + msg_sizeof = message.sizeof() + + writer.newline() + writer.ifdef(message) + parent_scope = writer.function(function_name, + "guint32", + "GlobalInfo *glb _U_, proto_tree *tree0 _U_, guint32 offset", True) + + writer.statement("return offset") + writer.end_block() + + writer.endif(message) + + return function_name + +def write_channel_parser(writer, channel, server): + writer.newline() + ids = {} + if server: + messages = channel.server_messages + else: + messages = channel.client_messages + for m in messages: + ids[m.value] = m + + ranges = [] + ids2 = ids.copy() + while len(ids2) > 0: + end = start = min(ids2.keys()) + while end in ids2: + del ids2[end] + end = end + 1 + + ranges.append( (start, end) ) + + if server: + function_name = "dissect_spice_data_server_%s" % channel.name + else: + function_name = "dissect_spice_data_client_%s" % channel.name + writer.newline() + writer.ifdef(channel) + scope = writer.function(function_name, + "guint32", + "guint16 message_type, GlobalInfo *glb _U_, proto_tree *tree _U_, guint32 offset", True) + + helpers = writer.function_helper() + + d = 0 + for r in ranges: + d = d + 1 + writer.write("static const parse_msg_func_t funcs%d[%d] = " % (d, r[1] - r[0])) + writer.begin_block() + for i in range(r[0], r[1]): + func = write_msg_parser(helpers, ids[i].message_type, server) + writer.write(func) + if i != r[1] -1: + writer.write(",") + writer.newline() + + writer.end_block(semicolon = True) + + d = 0 + for r in ranges: + d = d + 1 + with writer.if_block("message_type >= %d && message_type < %d" % (r[0], r[1]), d > 1, False): + writer.statement("return funcs%d[message_type-%d](glb, tree, offset)" % (d, r[0])) + writer.newline() + + writer.statement('expert_add_info_format(glb->pinfo, glb->msgtype_item, &ei_spice_unknown_message, "Unknown display server message - cannot dissect")') + writer.statement("return offset") + writer.end_block() + writer.endif(channel) + + return function_name + +def write_get_channel_parser(writer, channel_parsers, max_channel, is_server): + writer.newline() + function_name = "spice_%s%s_channel_get_dissect" % ('server' if is_server else 'client', writer.public_prefix) + + writer.function(function_name, "spice_dissect_func_t", "guint8 channel") + + writer.write("static const spice_dissect_func_t channels[%d] = " % (max_channel+1)) + writer.begin_block() + channel = None + for i in range(0, max_channel + 1): + if i in channel_parsers: + channel = channel_parsers[i][0] + writer.ifdef(channel) + writer.write(channel_parsers[i][1]) + else: + writer.write("NULL") + + if i != max_channel: + writer.write(",") + writer.newline() + if channel and channel.has_attr("ifdef"): + writer.ifdef_else(channel) + writer.write("NULL") + if i != max_channel: + writer.write(",") + writer.newline() + writer.endif(channel) + writer.end_block(semicolon = True) + + with writer.if_block("channel < %d" % (max_channel + 1)): + writer.statement("return channels[channel]") + + writer.statement("return NULL") + writer.end_block() + def write_protocol_definitions(writer): global hf_defs @@ -125,8 +244,25 @@ def write_protocol_parser(writer, proto): writer.newline() hf_writer = writer.get_subwriter() + # put everything else after + defs_writer = writer + writer = writer.get_subwriter() + # put fields definition at last - write_protocol_definitions(writer) + write_protocol_definitions(defs_writer) + + # scan all, looks for items and tree + # list add items and tree + # write all structure functions (get size + tree) + for is_server in (True, False): + max_channel = 0 + parsers = {} + for channel in proto.channels: + max_channel = max(max_channel, channel.value) + + parsers[channel.value] = (channel.channel_type, write_channel_parser(writer, channel.channel_type, is_server)) + + write_get_channel_parser(writer, parsers, max_channel, is_server) def write_includes(writer, dest_file): header_name = re.sub(r'\.(c|cpp|cc|cxx|C)$', '.h', dest_file) -- 2.1.0 _______________________________________________ Spice-devel mailing list Spice-devel@xxxxxxxxxxxxxxxxxxxxx http://lists.freedesktop.org/mailman/listinfo/spice-devel