[Spice-devel] [PATCH v2 12/43] Generate some definition for dissector

Frediano Ziglio fziglio at redhat.com
Wed Jul 22 02:08:00 PDT 2015


Generate global definitions.
Generate function to registers various dissector components.
For the moment the field array is empty but we save some global to
be able to register new ones.
Add a base test for generated dissector.

Signed-off-by: Frediano Ziglio <fziglio at redhat.com>
---
 Makefile.am                 |  2 +-
 codegen/Makefile.am         | 42 ++++++++++++++++++++++
 codegen/dissector_test.c    | 81 +++++++++++++++++++++++++++++++++++++++++
 configure.ac                |  5 +++
 python_modules/dissector.py | 87 +++++++++++++++++++++++++++++++++++++++++++--
 spice_codegen.py            |  2 +-
 6 files changed, 214 insertions(+), 5 deletions(-)
 create mode 100644 codegen/Makefile.am
 create mode 100644 codegen/dissector_test.c

Changes from v3:
- do not fail compiling if wireshark is not found;
- use BUILT_SOURCES to generate sources instead of manual dependency;
- fix typo in comment.

diff --git a/Makefile.am b/Makefile.am
index 380bf24..382a0ea 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,7 +1,7 @@
 NULL =
 ACLOCAL_AMFLAGS = -I m4
 
-SUBDIRS = python_modules common
+SUBDIRS = python_modules common codegen
 DIST_SUBDIRS = spice-protocol $(SUBDIRS)
 
 EXTRA_DIST =				\
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
new file mode 100644
index 0000000..2bbfc2a
--- /dev/null
+++ b/codegen/Makefile.am
@@ -0,0 +1,42 @@
+NULL =
+
+if WIRESHARK
+AM_CPPFLAGS =				\
+	-I$(top_srcdir)			\
+	$(WIRESHARK_CFLAGS)		\
+	$(SPICE_COMMON_CFLAGS)		\
+	$(NULL)
+
+dissector_test_LDADD =			\
+	$(SPICE_COMMON_LIBS)		\
+	$(NULL)
+
+MARSHALLERS_DEPS =					\
+	$(top_srcdir)/python_modules/__init__.py	\
+	$(top_srcdir)/python_modules/codegen.py		\
+	$(top_srcdir)/python_modules/demarshal.py	\
+	$(top_srcdir)/python_modules/marshal.py		\
+	$(top_srcdir)/python_modules/ptypes.py		\
+	$(top_srcdir)/python_modules/spice_parser.py	\
+	$(top_srcdir)/python_modules/dissector.py	\
+	$(top_srcdir)/spice_codegen.py			\
+	$(NULL)
+
+BUILT_SOURCES = test.h
+
+test.c: $(top_srcdir)/spice.proto $(MARSHALLERS_DEPS)
+	$(AM_V_GEN)$(PYTHON) $(top_srcdir)/spice_codegen.py --generate-dissector --client $< $@ >/dev/null
+
+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
+check_PROGRAMS = dissector_test
+
+dissector_test_SOURCES = dissector_test.c test.c test.h
+endif
+
+EXTRA_DIST =				\
+	$(NULL)
+
+-include $(top_srcdir)/git.mk
diff --git a/codegen/dissector_test.c b/codegen/dissector_test.c
new file mode 100644
index 0000000..6189da0
--- /dev/null
+++ b/codegen/dissector_test.c
@@ -0,0 +1,81 @@
+#undef NDEBUG
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <getopt.h>
+#include <assert.h>
+
+#include <epan/expert.h>
+
+#include <test.h>
+
+enum {
+	first_hf_registered = 0x10000,
+	first_ei_registered = 0x20000,
+};
+static int last_hf_registered = first_hf_registered - 1;
+static int last_ei_registered = first_ei_registered - 1;
+
+WS_DLL_PUBLIC void
+proto_register_field_array(const int parent, hf_register_info *hf, const int num_records)
+{
+	int i;
+	assert(num_records >= 0);
+	for (i = 0; i < num_records; ++i) {
+		assert(hf);
+		assert(hf[i].p_id);
+		assert(*hf[i].p_id == -1);
+		*hf[i].p_id = ++last_hf_registered;
+	}
+}
+
+WS_DLL_PUBLIC void
+expert_register_field_array(expert_module_t* module, ei_register_info *ei, const int num_records)
+{
+	int i;
+	assert(num_records >= 0);
+	for (i = 0; i < num_records; ++i) {
+		assert(ei && ei[i].ids->ei == -1);
+		ei[i].ids->ei = ++last_ei_registered;
+	}
+}
+
+static const struct option long_options[] = {
+	{ "help", 0, NULL, 'h' },
+};
+static const char options[] = "h";
+
+static void syntax(FILE *f, int exit_value)
+{
+	fprintf(f,
+		"Usage: dissector_test [OPTIONS]\n"
+		"\n"
+		"Options:\n"
+		"  -h, --help               Show this help\n"
+	);
+	exit(exit_value);
+}
+
+int main(int argc, char **argv)
+{
+	while (1) {
+		int option_index;
+		int opt = getopt_long(argc, argv, options, long_options, &option_index);
+		if (opt == -1)
+			break;
+
+		switch (opt) {
+		case 'h':
+			syntax(stdout, EXIT_SUCCESS);
+			break;
+		default:
+			syntax(stderr, EXIT_FAILURE);
+			break;
+		}
+	}
+
+	spice_register_fields(1, NULL);
+
+	return EXIT_SUCCESS;
+}
diff --git a/configure.ac b/configure.ac
index 4287f92..0bfc90c 100644
--- a/configure.ac
+++ b/configure.ac
@@ -38,6 +38,10 @@ SPICE_CHECK_PIXMAN(SPICE_COMMON)
 SPICE_CHECK_SMARTCARD(SPICE_COMMON)
 SPICE_CHECK_CELT051(SPICE_COMMON)
 SPICE_CHECK_GLIB2(SPICE_COMMON)
+PKG_CHECK_MODULES(WIRESHARK, wireshark,
+	AM_CONDITIONAL(WIRESHARK, true),
+	AM_CONDITIONAL(WIRESHARK, false)
+)
 SPICE_CHECK_OPUS(SPICE_COMMON)
 SPICE_CHECK_OPENGL(SPICE_COMMON)
 AC_SUBST(SPICE_COMMON_CFLAGS)
@@ -48,6 +52,7 @@ AC_CONFIG_FILES([
   Makefile
   common/Makefile
   python_modules/Makefile
+  codegen/Makefile
 ])
 
 AH_BOTTOM([
diff --git a/python_modules/dissector.py b/python_modules/dissector.py
index 90ba498..45f8737 100644
--- a/python_modules/dissector.py
+++ b/python_modules/dissector.py
@@ -1,14 +1,95 @@
 
 from . import codegen
+import re
+
+hf_writer = None
+hf_defs = None
+
+
+def write_parser_helpers(writer):
+    if writer.is_generated("helper", "demarshaller"):
+        return
+
+    writer.set_is_generated("helper", "demarshaller")
+
+    header = writer.header
+
+    header.writeln('#include <epan/packet.h>')
+    header.newline()
+
+    header.begin_block("typedef struct GlobalInfo")
+    header.variable_def("tvbuff_t *", "tvb")
+    header.variable_def("packet_info *", "pinfo")
+    header.variable_def("proto_item *", "msgtype_item")
+    header.variable_def("guint32", "message_offset")
+    header.variable_def("guint32", "message_end")
+    header.end_block(newline=False)
+    header.writeln(' GlobalInfo;')
+
+    header.newline()
+    header.statement('typedef guint32 (*spice_dissect_func_t)(guint16 message_type, GlobalInfo *glb, proto_tree *tree, guint32 offset)')
+
+    header.newline()
+    header.statement('void spice_register_fields(int proto, expert_module_t* expert_proto)')
+    header.statement('spice_dissect_func_t spice_client_channel_get_dissect(guint8 channel)')
+    header.statement('spice_dissect_func_t spice_server_channel_get_dissect(guint8 channel)')
+
+    writer = writer.function_helper()
+
+    writer.newline()
+    writer.statement('typedef guint32 (*parse_msg_func_t)(GlobalInfo *glb, proto_tree *tree, guint32 offset)')
+    writer.newline()
+    writer.statement('static expert_field ei_spice_unknown_message = EI_INIT')
+
+    writer.newline()
+    writer.writeln('#ifndef _U_')
+    writer.writeln('#define _U_')
+    writer.writeln('#endif')
+    writer.newline()
+
+
+def write_protocol_definitions(writer):
+    global hf_defs
+
+    writer.newline()
+    writer.function('spice_register_fields', 'void', 'int proto, expert_module_t* expert_proto')
+
+    writer.write("static hf_register_info hf[] = ")
+    writer.begin_block()
+    hf_defs = writer.get_subwriter()
+    writer.end_block(semicolon = True)
+    writer.newline()
+
+    writer.write('static ei_register_info ei[] =')
+    writer.begin_block()
+    writer.writeln('{ &ei_spice_unknown_message, { "spice.unknown_message", PI_UNDECODED, PI_WARN, "Unknown message - cannot dissect", EXPFILL }},')
+    writer.end_block(semicolon = True)
+    writer.newline()
+
+    writer.statement('proto_register_field_array(proto, hf, array_length(hf))')
+    writer.statement('expert_register_field_array(expert_proto, ei, array_length(ei))')
+    writer.end_block()
+
 
 def write_protocol_parser(writer, proto):
-    pass
+    global hf_writer
+
+    write_parser_helpers(writer)
+
+    # put fields declaration first
+    hf_writer = writer.get_subwriter()
+
+    # put fields definition at last
+    write_protocol_definitions(writer)
 
-def write_includes(writer):
+def write_includes(writer, dest_file):
+    header_name = re.sub(r'\.(c|cpp|cc|cxx|C)$', '.h', dest_file)
+    if header_name == dest_file:
+        header_name += '.h'
     writer.newline()
-    writer.writeln('#include <epan/packet.h>')
     writer.writeln('#include <epan/conversation.h>')
     writer.writeln('#include <epan/expert.h>')
     writer.newline()
+    writer.writeln('#include "%s"' % header_name)
     writer.writeln('#include "packet-spice.h"')
     writer.newline()
diff --git a/spice_codegen.py b/spice_codegen.py
index 8cfec1a..74d774f 100755
--- a/spice_codegen.py
+++ b/spice_codegen.py
@@ -224,7 +224,7 @@ if options.generate_dissector:
     if options.generate_demarshallers:
         print >> sys.stderr, "You can't specify --generate-demarshallers with --generate-dissector"
         sys.exit(1)
-    dissector.write_includes(writer)
+    dissector.write_includes(writer, dest_file)
     dissector.write_protocol_parser(writer, proto)
 
 if options.generate_demarshallers:
-- 
2.1.0


More information about the Spice-devel mailing list