[Spice-devel] [PATCH v5 05/41] dissector: Generate skeleton for messages and channels
Frediano Ziglio
fziglio at redhat.com
Fri Aug 7 08:00:34 PDT 2015
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 e959783..eaa0d59 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -30,13 +30,14 @@ 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
endif
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 e088cb6..b93b9ce 100644
--- a/python_modules/dissector.py
+++ b/python_modules/dissector.py
@@ -1,4 +1,5 @@
+from . import ptypes
from . import codegen
import re
@@ -66,6 +67,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
@@ -128,8 +247,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
More information about the Spice-devel
mailing list