[Spice-devel] [PATCH v3 15/51] Generate scheleton for messages and channels
Christophe Fergeau
cfergeau at redhat.com
Thu Jul 23 06:13:59 PDT 2015
'skeleton' in the subject.
On Tue, Jul 21, 2015 at 05:45:45PM +0100, Frediano Ziglio wrote:
> Messages are not generated as stub.
> Code partially from demarshaller.
>
> Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
> ---
> 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 at lists.freedesktop.org
> http://lists.freedesktop.org/mailman/listinfo/spice-devel
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 819 bytes
Desc: not available
URL: <http://lists.freedesktop.org/archives/spice-devel/attachments/20150723/2451fcf8/attachment.sig>
More information about the Spice-devel
mailing list