From: Darryl L. Pierce <mcpierce(a)gmail.com>
A new type is defined, t_datahandler_payload, which carries the received
payload, the length of the payload, and the CRC value reported by the
receiver.
When a payload is processed, first its CRC32 value is verified against
the supplied CRC32 value. If it does not match, a failure response is
returned.
Next the request is parsed, it's type is validated as "request", and the
API name is extracted. If any of these fail, then a failure response is
returned.
When a response is generated, the format is validated.
The multiplexer functions were removed and replaced by simple C APIs.
The unit tests have all be moved into Check tests (C unit test
framework).
Added crc_lib, by Lammert Bies, for calculating CRC32 values.
Signed-off-by: Darryl L. Pierce <dpierce(a)redhat.com>
---
Makefile.am | 2 +-
configure.ac | 7 +-
src/Makefile.am | 10 +-
src/tests/.gitignore | 1 +
src/tests/Makefile.am | 26 ++-
src/tests/testdatahandler.c | 255 +++++++++++++++++++++++
src/tests/testmultiplexer.c | 179 ++++++++++++++++
src/tests/testmultiplexer.cpp | 109 ----------
src/tests/testmultiplexer.h | 46 ----
src/virtio/datahandler.c | 268 ++++++++++++++++++++++++
src/virtio/datahandler.h | 61 ++++++
src/virtio/lib_crc.c | 459 +++++++++++++++++++++++++++++++++++++++++
src/virtio/lib_crc.h | 66 ++++++
src/virtio/multiplexer.c | 122 +++++++++++
src/virtio/multiplexer.cpp | 62 ------
src/virtio/multiplexer.h | 46 +++--
16 files changed, 1469 insertions(+), 250 deletions(-)
create mode 100644 src/tests/testdatahandler.c
create mode 100644 src/tests/testmultiplexer.c
delete mode 100644 src/tests/testmultiplexer.cpp
delete mode 100644 src/tests/testmultiplexer.h
create mode 100644 src/virtio/datahandler.c
create mode 100644 src/virtio/datahandler.h
create mode 100644 src/virtio/lib_crc.c
create mode 100644 src/virtio/lib_crc.h
create mode 100644 src/virtio/multiplexer.c
delete mode 100644 src/virtio/multiplexer.cpp
diff --git a/Makefile.am b/Makefile.am
index defbd32..2e57d29 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1,4 +1,4 @@
-SUBDIRS = src
+SUBDIRS = src src/tests
rpm: clean
@(unset CDPATH ; $(MAKE) dist && cp $(distdir).tar.gz \
diff --git a/configure.ac b/configure.ac
index 3481c09..de181e6 100644
--- a/configure.ac
+++ b/configure.ac
@@ -6,7 +6,10 @@ AM_INIT_AUTOMAKE
# Checks for programs.
AC_PROG_CXX
AC_PROG_CC
-AC_PROG_CPP
+AM_PROG_CC_C_O
+#AC_PROG_CPP
+
+AC_CHECK_LIB(xml2, xmlParseMemory, , [AC_MSG_ERROR([Missing libxml2 libraries.])])
AC_CHECK_PROG(HASQMFGEN, qmf-gen, "yes")
@@ -14,7 +17,7 @@ if test x"$HASQMFGEN" = "x"; then
AC_MSG_ERROR([Missing QMF schema processor.])
fi
-AC_CHECK_HEADERS([arpa/inet.h netinet/in.h sys/ioctl.h sys/socket.h unistd.h libudev.h])
+AC_CHECK_HEADERS([arpa/inet.h netinet/in.h sys/ioctl.h sys/socket.h unistd.h libudev.h
libxml/parser.h])
# Checks for typedefs, structures, and compiler characteristics.
AC_HEADER_STDBOOL
diff --git a/src/Makefile.am b/src/Makefile.am
index e55b299..0d64365 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -1,4 +1,4 @@
-INCLUDES = -I$(top_srcdir)/src/qmf/com/redhat/matahari $(LIBVIRT_CFLAGS) $(PCRE_CFLAGS)
$(UDEV_CFLAGS)
+INCLUDES = -I$(top_srcdir)/src/qmf/com/redhat/matahari -I/usr/include/libxml2
$(LIBVIRT_CFLAGS) $(PCRE_CFLAGS) $(UDEV_CFLAGS)
sbin_PROGRAMS = matahari
@@ -24,7 +24,11 @@ matahari_SOURCES = \
platform.h \
qmf/hostagent.cpp \
qmf/hostagent.h \
- virtio/multiplexer.cpp \
+ virtio/datahandler.c \
+ virtio/datahandler.h \
+ virtio/lib_crc.c \
+ virtio/lib_crc.h \
+ virtio/multiplexer.c \
virtio/multiplexer.h
$(generated_file_list): $(generated_file_list)
@@ -36,6 +40,6 @@ BUILT_SOURCES = $(generated_file_list) $(first)
CLEANFILES = $(generated_file_list) $(first)
matahari_CPPFLAGS = -fno-strict-aliasing
-matahari_LDADD = -lqmf -lqpidclient -lqpidcommon $(LIBVIRT_LIBS) $(PCRE_LIBS)
$(UDEV_LIBS)
+matahari_LDADD = -lqmf -lqpidclient -lqpidcommon -lxml2 $(LIBVIRT_LIBS) $(PCRE_LIBS)
$(UDEV_LIBS)
dist_pkgdata_DATA = schema.xml
diff --git a/src/tests/.gitignore b/src/tests/.gitignore
index 6d437f4..456f85d 100644
--- a/src/tests/.gitignore
+++ b/src/tests/.gitignore
@@ -1,2 +1,3 @@
+testdatahandler
testhostapis
testmultiplexer
diff --git a/src/tests/Makefile.am b/src/tests/Makefile.am
index a461cf1..a9583d7 100644
--- a/src/tests/Makefile.am
+++ b/src/tests/Makefile.am
@@ -1,18 +1,30 @@
bin_PROGRAMS = \
testhostapis \
- testmultiplexer
+ testmultiplexer \
+ testdatahandler
INCLUDES = \
- -I$(top_srcdir)/src
+ -I$(top_srcdir)/src \
+ -I/usr/include/libxml2
+
+testdatahandler_SOURCES = \
+ $(top_srcdir)/src/virtio/datahandler.c \
+ $(top_srcdir)/src/virtio/datahandler.h \
+ $(top_srcdir)/src/virtio/lib_crc.c \
+ $(top_srcdir)/src/virtio/lib_crc.h \
+ $(top_srcdir)/src/virtio/multiplexer.c \
+ $(top_srcdir)/src/virtio/multiplexer.h \
+ testdatahandler.c
+
+testdatahandler_LDADD = -lcheck -lxml2
testmultiplexer_SOURCES = \
- $(top_srcdir)/src/virtio/multiplexer.cpp \
+ $(top_srcdir)/src/virtio/multiplexer.c \
$(top_srcdir)/src/virtio/multiplexer.h \
- testmultiplexer.cpp \
- testmultiplexer.h
+ testmultiplexer.c
-testmultiplexer_LDADD = -lcppunit
+testmultiplexer_LDADD = -lcheck
testhostapis_SOURCES = \
$(top_srcdir)/src/host.cpp \
@@ -25,4 +37,4 @@ testhostapis_SOURCES = \
testhostapis.h
testhostapis_LDFLAGS = -L/usr/local/lib
-testhostapis_LDADD = -lcppunit $(LIBVIRT_LIBS) $(PCRE_LIBS) $(UDEV_LIBS)
\ No newline at end of file
+testhostapis_LDADD = -lcppunit $(LIBVIRT_LIBS) $(PCRE_LIBS) $(UDEV_LIBS)
diff --git a/src/tests/testdatahandler.c b/src/tests/testdatahandler.c
new file mode 100644
index 0000000..09dfdb7
--- /dev/null
+++ b/src/tests/testdatahandler.c
@@ -0,0 +1,255 @@
+/* testdatahandler.c - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at
http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include <check.h>
+#include <libxml/parser.h>
+#include <libxml/xpath.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "virtio/datahandler.h"
+
+t_datahandler_payload payload;
+
+#define REPLACE_REQUEST(payload, content) {\
+ payload.request_payload = content;\
+ payload.request_length = strlen(content);\
+ payload.request_crc = datahandler_calculate_crc(content, strlen(content)); \
+ }
+
+#define APINAME "testapi"
+
+void
+setup(void)
+{
+ payload.request_payload = "\
+ <matahari type=\"request\" api=\"testapi\">\n\
+ <args>\n\
+ <arg name=\"foo\">bar</arg>\n\
+ </args>\n\
+ </matahari>";
+ payload.request_length = strlen(payload.request_payload);
+ payload.request_crc =
+ datahandler_calculate_crc(payload.request_payload,
+ payload.request_length);
+}
+
+void
+teardown(void)
+{}
+
+START_TEST (test_validate_crc)
+{
+ char* value = "123456789";
+ unsigned int length = strlen(value);
+
+ fail_unless (datahandler_calculate_crc(value, length) == 3421780262L,
+ "The returned CRC value was invalid.");
+}
+END_TEST
+
+int
+check_response(t_datahandler_payload payload, char* expression)
+{
+ int result = -1;
+
+ xmlDocPtr document = xmlParseMemory(payload.response_payload,
+ payload.response_length);
+ if(document)
+ {
+ xmlXPathContextPtr context = xmlXPathNewContext(document);
+
+ if(context)
+ {
+ xmlXPathObjectPtr xpathobj =
+ xmlXPathEvalExpression(BAD_CAST expression, context);
+
+ if(xpathobj && ! xmlXPathNodeSetIsEmpty(xpathobj->nodesetval))
+ {
+ result = 0;
+ }
+
+ if(xpathobj) xmlXPathFreeObject(xpathobj);
+ xmlXPathFreeContext(context);
+ }
+ xmlFreeDoc(document);
+ }
+
+ return result;
+}
+
+START_TEST (test_process_with_null_data)
+{
+ fail_unless (datahandler_process_payload(NULL) == -1,
+ "Call should have returned an error.");
+}
+END_TEST
+
+START_TEST (test_process_with_empty_data)
+{
+ REPLACE_REQUEST(payload, "");
+
+ fail_unless (!datahandler_process_payload(&payload),
+ "Call should not have failed.");
+ fail_unless (!check_response(payload, "/matahari[@type='failure']"),
+ "The response should have indicated a failure.");
+}
+END_TEST
+
+START_TEST (test_process_with_invalid_crc)
+{
+ payload.request_crc++;
+
+ fail_unless (!datahandler_process_payload(&payload),
+ "Called should not have failed.");
+ fail_unless (!check_response(payload, "/matahari[@type='failure']"),
+ "The response should have indicated failure.");
+}
+END_TEST
+
+#define REQUEST_SHOULD_NOT_HAVE_FAILED(payload) {\
+ fail_unless (!datahandler_process_payload(&payload),\
+ "Calls hould not have failed.");\
+ }
+
+#define RESPONSE_MUST_BE_A_FAILURE(payload) {\
+ fail_unless (!check_response(payload,
"/matahari[@type='failure']"),\
+ "The response should have indicated a failure.");\
+ }
+START_TEST (test_process_with_invalid_xml)
+{
+ REPLACE_REQUEST(payload, "<farkle>");
+
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ RESPONSE_MUST_BE_A_FAILURE(payload);
+}
+END_TEST
+
+START_TEST (test_process_request_check_root)
+{
+ REPLACE_REQUEST(payload, "<matahatrack />");
+
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ RESPONSE_MUST_BE_A_FAILURE(payload);
+}
+END_TEST
+
+START_TEST (test_process_request_without_type)
+{
+ REPLACE_REQUEST(payload, "<matahari />");
+
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ RESPONSE_MUST_BE_A_FAILURE(payload);
+}
+END_TEST
+
+START_TEST (test_process_request_check_type)
+{
+ REPLACE_REQUEST(payload, "<matahari type=\"response\"
api=\"foo\" />");
+
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ RESPONSE_MUST_BE_A_FAILURE(payload);
+}
+END_TEST
+
+START_TEST (test_process_request_without_api)
+{
+ REPLACE_REQUEST(payload, "<matahari type=\"request\" />");
+
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ RESPONSE_MUST_BE_A_FAILURE(payload);
+}
+END_TEST
+
+START_TEST (test_process_request_without_args)
+{
+ REPLACE_REQUEST(payload, "<matahari type=\"request\"
api=\"test\">\
+ </matahari>");
+
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ RESPONSE_MUST_BE_A_FAILURE(payload);
+}
+END_TEST
+
+const char*
+test_request_calls_api_callback(const char* payload)
+{
+ return "\
+ <response name=\"foo\">\
+ <element>\
+ <value name=\"bar\">Yo!</value>\
+ </element>\
+ </response>";
+}
+
+START_TEST (test_process_request_with_bad_api)
+{
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ RESPONSE_MUST_BE_A_FAILURE(payload);
+}
+END_TEST
+
+START_TEST (test_process_request_calls_api)
+{
+ multiplexer_register_api(APINAME, test_request_calls_api_callback);
+
+ REQUEST_SHOULD_NOT_HAVE_FAILED(payload);
+ fail_unless (!check_response(payload,
"/matahari[@type='response']"),
+ "Response should have been of type 'response'.");
+}
+END_TEST
+
+Suite*
+datahandler_test_suite(void)
+{
+ Suite* result = suite_create("CRC");
+
+ TCase* tc_process = tcase_create("Process");
+ tcase_add_checked_fixture(tc_process, setup, teardown);
+ tcase_add_test(tc_process, test_validate_crc);
+ tcase_add_test(tc_process, test_process_with_null_data);
+ tcase_add_test(tc_process, test_process_with_empty_data);
+ tcase_add_test(tc_process, test_process_with_invalid_crc);
+ tcase_add_test(tc_process, test_process_with_invalid_xml);
+ tcase_add_test(tc_process, test_process_request_check_root);
+ tcase_add_test(tc_process, test_process_request_without_type);
+ tcase_add_test(tc_process, test_process_request_check_type);
+ tcase_add_test(tc_process, test_process_request_without_api);
+ tcase_add_test(tc_process, test_process_request_without_args);
+ tcase_add_test(tc_process, test_process_request_with_bad_api);
+ tcase_add_test(tc_process, test_process_request_calls_api);
+ suite_add_tcase(result, tc_process);
+
+ return result;
+}
+
+int
+main(int argc, char** argv)
+{
+ int failures;
+
+ Suite* suite = datahandler_test_suite();
+ SRunner* srunner = srunner_create(suite);
+
+ srunner_run_all(srunner, CK_NORMAL);
+ failures = srunner_ntests_failed(srunner);
+ srunner_free(srunner);
+
+ return (failures == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/tests/testmultiplexer.c b/src/tests/testmultiplexer.c
new file mode 100644
index 0000000..56395bf
--- /dev/null
+++ b/src/tests/testmultiplexer.c
@@ -0,0 +1,179 @@
+/* testmultiplexer.c - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at
http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include <check.h>
+#include <stdlib.h>
+
+#include "virtio/multiplexer.h"
+
+void
+setup(void)
+{}
+
+void
+teardown(void)
+{}
+
+#define APINAME "testapi"
+#define CONTENT "<args />"
+
+const char*
+test_callback(const char* input)
+{
+ return NULL;
+}
+
+const char*
+test_new_callback(const char* input)
+{
+ return NULL;
+}
+
+START_TEST (test_register_with_null_name)
+{
+ fail_unless (multiplexer_register_api(NULL, NULL) == -1,
+ "Registration should not have succeeded");
+}
+END_TEST
+
+START_TEST (test_register_with_empty_name)
+{
+ fail_unless (multiplexer_register_api("", NULL) == -1,
+ "Registration should not have succeeded.");
+}
+END_TEST
+
+START_TEST (test_register_will_null_function)
+{
+ fail_unless (multiplexer_register_api(APINAME, NULL) == -1,
+ "Registration should not have succeeded");
+}
+END_TEST
+
+START_TEST (test_register_succeeds)
+{
+ fail_unless (!multiplexer_register_api(APINAME, test_callback),
+ "Registration should have succeeded.");
+ fail_unless (multiplexer_get_api_function(APINAME) == test_callback,
+ "The method was not actually registered.");
+}
+END_TEST
+
+START_TEST (test_register_with_existing_api_name)
+{
+ fail_unless (!multiplexer_register_api(APINAME, test_callback),
+ "Registration should have succeeded.");
+ fail_unless (!multiplexer_register_api(APINAME, test_new_callback),
+ "Registration should have succeeded.");
+ fail_unless (multiplexer_get_api_function(APINAME) == test_new_callback,
+ "The original API should have been replaced.");
+}
+END_TEST
+
+START_TEST (test_unregistered_api_returns_null)
+{
+ fail_if (multiplexer_get_api_function(APINAME),
+ "No callback should have been returned.");
+}
+END_TEST
+
+START_TEST (test_invoke_with_null_apiname)
+{
+ fail_unless (multiplexer_invoke_api(NULL, CONTENT) == NULL,
+ "The API call should have failed.");
+}
+END_TEST
+
+START_TEST (test_invoke_with_empty_apiname)
+{
+ fail_unless (multiplexer_invoke_api("", CONTENT) == NULL,
+ "The API call should have faile");
+}
+END_TEST
+
+START_TEST (test_invoke_unregistered_api)
+{
+ fail_unless (multiplexer_invoke_api("farkle", CONTENT) == NULL,
+ "The API call should have failed.");
+}
+END_TEST
+
+START_TEST (test_invoke_with_no_content)
+{
+ fail_unless (multiplexer_invoke_api(APINAME, NULL) == NULL,
+ "The API call should have failed.");
+}
+END_TEST
+
+const char*
+test_invoke_callback(const char* input)
+{
+ return input;
+}
+
+START_TEST (test_invoke_succeeds)
+{
+ multiplexer_register_api(APINAME, test_invoke_callback);
+
+ const char* result = multiplexer_invoke_api(APINAME, CONTENT);
+
+ fail_if (!result, "The API call should have succeeded.");
+ fail_unless (!strcmp(CONTENT, result), "The call returned the wrong
value.");
+}
+END_TEST
+
+Suite*
+multiplexer_test_suite(void)
+{
+ Suite* result = suite_create("Multiplexer");
+
+ TCase* tc_register = tcase_create("Register");
+ tcase_add_checked_fixture(tc_register, setup, teardown);
+ tcase_add_test(tc_register, test_register_with_null_name);
+ tcase_add_test(tc_register, test_register_with_empty_name);
+ tcase_add_test(tc_register, test_register_will_null_function);
+ tcase_add_test(tc_register, test_register_succeeds);
+ tcase_add_test(tc_register, test_register_with_existing_api_name);
+ tcase_add_test(tc_register, test_unregistered_api_returns_null);
+ suite_add_tcase(result, tc_register);
+
+ TCase* tc_invoke = tcase_create("Invoke");
+ tcase_add_checked_fixture(tc_invoke, setup, teardown);
+ tcase_add_test(tc_invoke, test_invoke_with_null_apiname);
+ tcase_add_test(tc_invoke, test_invoke_unregistered_api);
+ tcase_add_test(tc_invoke, test_invoke_with_no_content);
+ tcase_add_test(tc_invoke, test_invoke_succeeds);
+ suite_add_tcase(result, tc_invoke);
+ return result;
+}
+
+int
+main(int argc, char** argv)
+{
+ int failures;
+
+ Suite* suite = multiplexer_test_suite();
+ SRunner* srunner = srunner_create(suite);
+
+ srunner_run_all(srunner, CK_NORMAL);
+ failures = srunner_ntests_failed(srunner);
+ srunner_free(srunner);
+
+ return (failures == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
+}
diff --git a/src/tests/testmultiplexer.cpp b/src/tests/testmultiplexer.cpp
deleted file mode 100644
index 8ed77fd..0000000
--- a/src/tests/testmultiplexer.cpp
+++ /dev/null
@@ -1,109 +0,0 @@
-/* testmultiplexer.cpp - Copyright (C) 2010 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce(a)redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at
http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include "testmultiplexer.h"
-
-#include "virtio/multiplexer.h"
-
-#include <cppunit/TestAssert.h>
-#include <cppunit/TestCaller.h>
-#include <cppunit/TestResult.h>
-#include <cppunit/TestSuite.h>
-#include <cppunit/ui/text/TestRunner.h>
-
-const string APINAME("testapifunction");
-
-const char*
-test_callback_function(const char* input)
-{
- return input;
-}
-
-TestMultiplexer::TestMultiplexer()
- :TestCase("TestMultiplexer")
-{}
-
-TestSuite*
-TestMultiplexer::suite()
-{
- CppUnit::TestSuite *result = new CppUnit::TestSuite("TestMultiplexer");
-
- result->addTest(new CppUnit::TestCaller<TestMultiplexer>
- ("testBadAPINameGetsNull",
- &TestMultiplexer::testUnregisteredAPIIsNull));
- result->addTest(new CppUnit::TestCaller<TestMultiplexer>
- ("testRegisterAPIMethod",
- &TestMultiplexer::testRegisterAPIMethod));
- result->addTest(new CppUnit::TestCaller<TestMultiplexer>
- ("testEnsureCallingAnUnregisteredAPIFails",
- &TestMultiplexer::testEnsureCallingAnUnregisteredAPIFails));
- result->addTest(new CppUnit::TestCaller<TestMultiplexer>
- ("testEnsureAPIIsCalled",
- &TestMultiplexer::testEnsureAPIIsCalled));
-
- return result;
-}
-
-void
-TestMultiplexer::setUp()
-{
- Multiplexer::instance()->registerAPI(APINAME, test_callback_function);
-}
-
-void
-TestMultiplexer::testUnregisteredAPIIsNull()
-{
- CPPUNIT_ASSERT(NULL == Multiplexer::instance()->getAPI(APINAME + "!"));
-}
-
-void
-TestMultiplexer::testRegisterAPIMethod()
-{
- t_apifunction apifunction = test_callback_function;
-
- CPPUNIT_ASSERT(apifunction == Multiplexer::instance()->getAPI(APINAME));
-}
-
-void
-TestMultiplexer::testEnsureCallingAnUnregisteredAPIFails()
-{
- string input = string("This is some input");
- string result = Multiplexer::instance()->invokeAPI(APINAME + "!", input);
-
- CPPUNIT_ASSERT(string("") == result);
-}
-
-void TestMultiplexer::testEnsureAPIIsCalled()
-{
- string expected = "This is what I expected";
- string result = Multiplexer::instance()->invokeAPI(APINAME, expected);
-
- CPPUNIT_ASSERT(expected == result);
-}
-
-int
-main(int argc, char** argv)
-{
- CppUnit::TextUi::TestRunner runner;
-
- runner.addTest(TestMultiplexer::suite());
- runner.run();
-
- return 0;
-}
diff --git a/src/tests/testmultiplexer.h b/src/tests/testmultiplexer.h
deleted file mode 100644
index 04cb9e5..0000000
--- a/src/tests/testmultiplexer.h
+++ /dev/null
@@ -1,46 +0,0 @@
-#ifndef __TESTMULTIPLEXER_H
-#define __TESTMULTIPLEXER_H
-
-/* testmultiplexer.h - Copyright (C) 2010 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce(a)redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at
http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include "virtio/multiplexer.h"
-
-#include <cppunit/TestCase.h>
-#include <cppunit/TestSuite.h>
-
-using namespace CppUnit;
-using namespace std;
-
-class TestMultiplexer : public CppUnit::TestCase
-{
- public:
- TestMultiplexer();
-
- static TestSuite* suite();
-
- void setUp();
-
- void testUnregisteredAPIIsNull();
- void testRegisterAPIMethod();
- void testEnsureCallingAnUnregisteredAPIFails();
- void testEnsureAPIIsCalled();
-};
-
-#endif
diff --git a/src/virtio/datahandler.c b/src/virtio/datahandler.c
new file mode 100644
index 0000000..3bf363c
--- /dev/null
+++ b/src/virtio/datahandler.c
@@ -0,0 +1,268 @@
+/* datahandler.cpp - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at
http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "virtio/datahandler.h"
+
+#include <libxml/tree.h>
+#include <libxml/xpath.h>
+#include <libxml/xpointer.h>
+#include "virtio/multiplexer.h"
+#include <string.h>
+#include "virtio/lib_crc.h"
+
+void
+_extract_api_and_make_call(t_datahandler_payload* payload, xmlDocPtr request);
+
+char*
+_create_error_content(const char* message)
+{
+ char* result = malloc(1000);
+
+ sprintf(result, "\
+ <response name=\"error\">\
+ <element>\
+ <value name=\"message\">%s</value>\
+ </element>\
+ </response>", message);
+
+ return result;
+}
+
+void
+_create_document_with_content(t_datahandler_payload* payload,
+ char* type,
+ const char* response,
+ unsigned int length)
+{
+ xmlDocPtr content = xmlNewDoc(BAD_CAST "1.0");
+ xmlNodePtr root = xmlNewNode(NULL, BAD_CAST "matahari");
+ xmlNodePtr responses = xmlNewNode(NULL, BAD_CAST "responses");
+
+ xmlNewProp(root, BAD_CAST "type",BAD_CAST type);
+ xmlDocSetRootElement(content, root);
+ xmlAddChild(root, responses);
+
+ // parse the content
+ xmlDocPtr contentnode = xmlParseMemory(response, length);
+
+ xmlAddChild(responses, contentnode->children);
+
+ // set the payload response, crc and length
+ xmlChar* buffertext;
+ int buffersize;
+
+ xmlDocDumpFormatMemory(content, &buffertext, &buffersize, 1);
+ payload->response_payload = (char*) buffertext;
+ payload->response_length = buffersize;
+ payload->response_crc =
+ datahandler_calculate_crc(payload->response_payload,
+ payload->response_length);
+}
+
+void
+_prepare_request_payload(t_datahandler_payload* payload, const char* message,
+ t_matahari_message_type response_type)
+{
+ payload->response_type = response_type;
+
+ if(response_type == FAILURE)
+ {
+ char* response_message = _create_error_content(message);
+ _create_document_with_content(payload, "failure",
+ response_message, strlen(response_message));
+ free(response_message);
+ }
+ else
+ {
+ _create_document_with_content(payload, "response",
+ message, strlen(message));
+ }
+}
+
+void
+_request_failure(t_datahandler_payload* payload, const char* message)
+{
+ _prepare_request_payload(payload, message, FAILURE);
+}
+
+void
+_request_success(t_datahandler_payload* payload, const char* message)
+{
+ _prepare_request_payload(payload, message, RESPONSE);
+}
+
+int
+datahandler_process_payload(t_datahandler_payload* payload)
+{
+ int result = -1;
+
+ if(payload)
+ {
+ result = 0;
+
+ if(payload->request_length > 0)
+ {
+ // setup the response fields
+ payload->response_payload = 0;
+ payload->response_length = 0;
+ payload->response_crc = 0L;
+
+ unsigned long crc =
+ datahandler_calculate_crc(payload->request_payload,
+ payload->request_length);
+
+ if(crc == payload->request_crc)
+ {
+ xmlDocPtr request = xmlParseMemory(payload->request_payload,
+ payload->request_length);
+ xmlErrorPtr error = xmlGetLastError();
+
+ if(request != NULL && !error)
+ {
+ _extract_api_and_make_call(payload, request);
+ }
+ else
+ {
+ _request_failure(payload, "No request document found.");
+ }
+
+ if(request) xmlFreeDoc(request);
+ }
+ else
+ {
+ _request_failure(payload, "Request fails CRC check.");
+ }
+ }
+ else
+ {
+ _request_failure(payload, "No request payload present.");
+ }
+ }
+
+ return result;
+}
+
+unsigned long
+datahandler_calculate_crc(char* data, unsigned int length)
+{
+ unsigned long result = 0xffffffffL;
+ char* current = (char *)data;
+ unsigned int count = 0;
+
+ while(count < length)
+ {
+ result = update_crc_32(result, *current);
+ current++;
+ count++;
+ }
+
+ result ^= 0xffffffffL;
+
+ return result;
+}
+
+#define FREE_XPATH_OBJECT(pathobj) {\
+ if(pathobj) xmlXPathFreeObject(pathobj);\
+ pathobj = NULL;\
+ }
+
+void
+_extract_api_and_make_call(t_datahandler_payload* payload, xmlDocPtr request)
+{
+ xmlXPathContextPtr context = xmlXPathNewContext(request);
+ xmlXPathObjectPtr pathobj =
+ xmlXPathEvalExpression(BAD_CAST "/matahari/@type", context);
+
+ if(pathobj && !xmlXPathNodeSetIsEmpty(pathobj->nodesetval))
+ {
+ char* type = xmlXPathCastToString(pathobj);
+
+ if(!strncmp(type, "request", strlen("request")))
+ {
+ FREE_XPATH_OBJECT(pathobj);
+
+ pathobj = xmlXPathEvalExpression(BAD_CAST "/matahari/@api", context);
+
+ if(pathobj && !xmlXPathNodeSetIsEmpty(pathobj->nodesetval))
+ {
+ char* api = xmlXPathCastToString(pathobj);
+ FREE_XPATH_OBJECT(pathobj);
+
+ t_apifunction apifunction = multiplexer_get_api_function(api);
+
+ if(apifunction)
+ {
+ pathobj = xmlXPathEvalExpression(BAD_CAST "/matahari/args",
+ context);
+ if(pathobj && !xmlXPathNodeSetIsEmpty(pathobj->nodesetval))
+ {
+ xmlDocPtr args = xmlNewDoc(NULL);
+ xmlNodePtr argroot = xmlXPtrBuildNodeList(pathobj);
+
+ xmlDocSetRootElement(args, argroot);
+
+ xmlChar* contenttext;
+ int contentsize;
+
+ xmlDocDumpFormatMemory(args,
+ &contenttext, &contentsize, 1);
+
+ const char* response = apifunction(contenttext);
+ _request_success(payload, response);
+
+ free(contenttext);
+ if(args) xmlFreeDoc(args);
+ }
+ else
+ {
+ _request_failure(payload,
+ "Request did not contain arguments.");
+ }
+ }
+ else
+ {
+ _request_failure(payload, "Invalid API specified.");
+ }
+
+ free(api);
+ FREE_XPATH_OBJECT(pathobj);
+ }
+ else
+ {
+ _request_failure(payload, "Request did not specify an API.");
+ }
+
+ FREE_XPATH_OBJECT(pathobj);
+ }
+ else
+ {
+ _request_failure(payload, "Request was not of type 'request'.");
+ }
+
+ if(type) free(type);
+
+ FREE_XPATH_OBJECT(pathobj);
+ }
+ else
+ {
+ _request_failure(payload, "No API was specified.");
+ }
+
+ xmlXPathFreeContext(context);
+}
diff --git a/src/virtio/datahandler.h b/src/virtio/datahandler.h
new file mode 100644
index 0000000..4323280
--- /dev/null
+++ b/src/virtio/datahandler.h
@@ -0,0 +1,61 @@
+#ifndef __DATAHANDLER_H
+#define __DATAHANDLER_H
+
+/* datahandler.h - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at
http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef enum {REQUEST, RESPONSE, FAILURE} t_matahari_message_type;
+
+/* A t_datahandler_payload struct holds the request payload
+ received from a remote system. After processing, it will
+ also hold the response payload and details.
+*/
+typedef struct
+{
+ char* request_id;
+ unsigned long request_crc;
+ char* request_payload;
+ unsigned int request_length;
+ t_matahari_message_type response_type;
+ unsigned long response_crc;
+ char* response_payload;
+ unsigned long response_length;
+} t_datahandler_payload;
+
+/* A function thatprocesses data received from a remote
+ source extracts and validates the actual request
+ within the payload.
+
+ It takes as argument a struct holding the request details,
+ and will attach the response details on completion.
+*/
+int datahandler_process_payload(t_datahandler_payload* payload);
+
+/* Calculates a CRC value for the supplied data. */
+unsigned long datahandler_calculate_crc(char* data, unsigned int length);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/src/virtio/lib_crc.c b/src/virtio/lib_crc.c
new file mode 100644
index 0000000..26b6b99
--- /dev/null
+++ b/src/virtio/lib_crc.c
@@ -0,0 +1,459 @@
+#include "lib_crc.h"
+
+
+
+ /*******************************************************************\
+ * *
+ * Library : lib_crc *
+ * File : lib_crc.c *
+ * Author : Lammert Bies 1999-2008 *
+ * E-mail : info(a)lammertbies.nl *
+ * Language : ANSI C *
+ * *
+ * *
+ * Description *
+ * =========== *
+ * *
+ * The file lib_crc.c contains the private and public func- *
+ * tions used for the calculation of CRC-16, CRC-CCITT and *
+ * CRC-32 cyclic redundancy values. *
+ * *
+ * *
+ * Dependencies *
+ * ============ *
+ * *
+ * lib_crc.h CRC definitions and prototypes *
+ * *
+ * *
+ * Modification history *
+ * ==================== *
+ * *
+ * Date Version Comment *
+ * *
+ * 2008-04-20 1.16 Added CRC-CCITT calculation for Kermit *
+ * *
+ * 2007-04-01 1.15 Added CRC16 calculation for Modbus *
+ * *
+ * 2007-03-28 1.14 Added CRC16 routine for Sick devices *
+ * *
+ * 2005-12-17 1.13 Added CRC-CCITT with initial 0x1D0F *
+ * *
+ * 2005-05-14 1.12 Added CRC-CCITT with start value 0 *
+ * *
+ * 2005-02-05 1.11 Fixed bug in CRC-DNP routine *
+ * *
+ * 2005-02-04 1.10 Added CRC-DNP routines *
+ * *
+ * 1999-02-21 1.01 Added FALSE and TRUE mnemonics *
+ * *
+ * 1999-01-22 1.00 Initial source *
+ * *
+ \*******************************************************************/
+
+
+
+ /*******************************************************************\
+ * *
+ * #define P_xxxx *
+ * *
+ * The CRC's are computed using polynomials. The coefficients *
+ * for the algorithms are defined by the following constants. *
+ * *
+ \*******************************************************************/
+
+#define P_16 0xA001
+#define P_32 0xEDB88320L
+#define P_CCITT 0x1021
+#define P_DNP 0xA6BC
+#define P_KERMIT 0x8408
+#define P_SICK 0x8005
+
+
+
+ /*******************************************************************\
+ * *
+ * static int crc_tab...init *
+ * static unsigned ... crc_tab...[] *
+ * *
+ * The algorithms use tables with precalculated values. This *
+ * speeds up the calculation dramaticaly. The first time the *
+ * CRC function is called, the table for that specific calcu- *
+ * lation is set up. The ...init variables are used to deter- *
+ * mine if the initialization has taken place. The calculated *
+ * values are stored in the crc_tab... arrays. *
+ * *
+ * The variables are declared static. This makes them invisi- *
+ * ble for other modules of the program. *
+ * *
+ \*******************************************************************/
+
+static int crc_tab16_init = FALSE;
+static int crc_tab32_init = FALSE;
+static int crc_tabccitt_init = FALSE;
+static int crc_tabdnp_init = FALSE;
+static int crc_tabkermit_init = FALSE;
+
+static unsigned short crc_tab16[256];
+static unsigned long crc_tab32[256];
+static unsigned short crc_tabccitt[256];
+static unsigned short crc_tabdnp[256];
+static unsigned short crc_tabkermit[256];
+
+
+
+ /*******************************************************************\
+ * *
+ * static void init_crc...tab(); *
+ * *
+ * Three local functions are used to initialize the tables *
+ * with values for the algorithm. *
+ * *
+ \*******************************************************************/
+
+static void init_crc16_tab( void );
+static void init_crc32_tab( void );
+static void init_crcccitt_tab( void );
+static void init_crcdnp_tab( void );
+static void init_crckermit_tab( void );
+
+
+
+ /*******************************************************************\
+ * *
+ * unsigned short update_crc_ccitt( unsigned long crc, char c ); *
+ * *
+ * The function update_crc_ccitt calculates a new CRC-CCITT *
+ * value based on the previous value of the CRC and the next *
+ * byte of the data to be checked. *
+ * *
+ \*******************************************************************/
+
+unsigned short update_crc_ccitt( unsigned short crc, char c ) {
+
+ unsigned short tmp, short_c;
+
+ short_c = 0x00ff & (unsigned short) c;
+
+ if ( ! crc_tabccitt_init ) init_crcccitt_tab();
+
+ tmp = (crc >> 8) ^ short_c;
+ crc = (crc << 8) ^ crc_tabccitt[tmp];
+
+ return crc;
+
+} /* update_crc_ccitt */
+
+
+
+ /*******************************************************************\
+ * *
+ * unsigned short update_crc_sick( *
+ * unsigned long crc, char c, char prev_byte ); *
+ * *
+ * The function update_crc_sick calculates a new CRC-SICK *
+ * value based on the previous value of the CRC and the next *
+ * byte of the data to be checked. *
+ * *
+ \*******************************************************************/
+
+unsigned short update_crc_sick( unsigned short crc, char c, char prev_byte ) {
+
+ unsigned short short_c, short_p;
+
+ short_c = 0x00ff & (unsigned short) c;
+ short_p = ( 0x00ff & (unsigned short) prev_byte ) << 8;
+
+ if ( crc & 0x8000 ) crc = ( crc << 1 ) ^ P_SICK;
+ else crc = crc << 1;
+
+ crc &= 0xffff;
+ crc ^= ( short_c | short_p );
+
+ return crc;
+
+} /* update_crc_sick */
+
+
+
+ /*******************************************************************\
+ * *
+ * unsigned short update_crc_16( unsigned short crc, char c ); *
+ * *
+ * The function update_crc_16 calculates a new CRC-16 value *
+ * based on the previous value of the CRC and the next byte *
+ * of the data to be checked. *
+ * *
+ \*******************************************************************/
+
+unsigned short update_crc_16( unsigned short crc, char c ) {
+
+ unsigned short tmp, short_c;
+
+ short_c = 0x00ff & (unsigned short) c;
+
+ if ( ! crc_tab16_init ) init_crc16_tab();
+
+ tmp = crc ^ short_c;
+ crc = (crc >> 8) ^ crc_tab16[ tmp & 0xff ];
+
+ return crc;
+
+} /* update_crc_16 */
+
+
+
+ /*******************************************************************\
+ * *
+ * unsigned short update_crc_kermit( unsigned short crc, char c ); *
+ * *
+ * The function update_crc_kermit calculates a new CRC value *
+ * based on the previous value of the CRC and the next byte *
+ * of the data to be checked. *
+ * *
+ \*******************************************************************/
+
+unsigned short update_crc_kermit( unsigned short crc, char c ) {
+
+ unsigned short tmp, short_c;
+
+ short_c = 0x00ff & (unsigned short) c;
+
+ if ( ! crc_tabkermit_init ) init_crckermit_tab();
+
+ tmp = crc ^ short_c;
+ crc = (crc >> 8) ^ crc_tabkermit[ tmp & 0xff ];
+
+ return crc;
+
+} /* update_crc_kermit */
+
+
+
+ /*******************************************************************\
+ * *
+ * unsigned short update_crc_dnp( unsigned short crc, char c ); *
+ * *
+ * The function update_crc_dnp calculates a new CRC-DNP value *
+ * based on the previous value of the CRC and the next byte *
+ * of the data to be checked. *
+ * *
+ \*******************************************************************/
+
+unsigned short update_crc_dnp( unsigned short crc, char c ) {
+
+ unsigned short tmp, short_c;
+
+ short_c = 0x00ff & (unsigned short) c;
+
+ if ( ! crc_tabdnp_init ) init_crcdnp_tab();
+
+ tmp = crc ^ short_c;
+ crc = (crc >> 8) ^ crc_tabdnp[ tmp & 0xff ];
+
+ return crc;
+
+} /* update_crc_dnp */
+
+
+
+ /*******************************************************************\
+ * *
+ * unsigned long update_crc_32( unsigned long crc, char c ); *
+ * *
+ * The function update_crc_32 calculates a new CRC-32 value *
+ * based on the previous value of the CRC and the next byte *
+ * of the data to be checked. *
+ * *
+ \*******************************************************************/
+
+unsigned long update_crc_32( unsigned long crc, char c ) {
+
+ unsigned long tmp, long_c;
+
+ long_c = 0x000000ffL & (unsigned long) c;
+
+ if ( ! crc_tab32_init ) init_crc32_tab();
+
+ tmp = crc ^ long_c;
+ crc = (crc >> 8) ^ crc_tab32[ tmp & 0xff ];
+
+ return crc;
+
+} /* update_crc_32 */
+
+
+
+ /*******************************************************************\
+ * *
+ * static void init_crc16_tab( void ); *
+ * *
+ * The function init_crc16_tab() is used to fill the array *
+ * for calculation of the CRC-16 with values. *
+ * *
+ \*******************************************************************/
+
+static void init_crc16_tab( void ) {
+
+ int i, j;
+ unsigned short crc, c;
+
+ for (i=0; i<256; i++) {
+
+ crc = 0;
+ c = (unsigned short) i;
+
+ for (j=0; j<8; j++) {
+
+ if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ P_16;
+ else crc = crc >> 1;
+
+ c = c >> 1;
+ }
+
+ crc_tab16[i] = crc;
+ }
+
+ crc_tab16_init = TRUE;
+
+} /* init_crc16_tab */
+
+
+
+ /*******************************************************************\
+ * *
+ * static void init_crckermit_tab( void ); *
+ * *
+ * The function init_crckermit_tab() is used to fill the array *
+ * for calculation of the CRC Kermit with values. *
+ * *
+ \*******************************************************************/
+
+static void init_crckermit_tab( void ) {
+
+ int i, j;
+ unsigned short crc, c;
+
+ for (i=0; i<256; i++) {
+
+ crc = 0;
+ c = (unsigned short) i;
+
+ for (j=0; j<8; j++) {
+
+ if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ P_KERMIT;
+ else crc = crc >> 1;
+
+ c = c >> 1;
+ }
+
+ crc_tabkermit[i] = crc;
+ }
+
+ crc_tabkermit_init = TRUE;
+
+} /* init_crckermit_tab */
+
+
+
+ /*******************************************************************\
+ * *
+ * static void init_crcdnp_tab( void ); *
+ * *
+ * The function init_crcdnp_tab() is used to fill the array *
+ * for calculation of the CRC-DNP with values. *
+ * *
+ \*******************************************************************/
+
+static void init_crcdnp_tab( void ) {
+
+ int i, j;
+ unsigned short crc, c;
+
+ for (i=0; i<256; i++) {
+
+ crc = 0;
+ c = (unsigned short) i;
+
+ for (j=0; j<8; j++) {
+
+ if ( (crc ^ c) & 0x0001 ) crc = ( crc >> 1 ) ^ P_DNP;
+ else crc = crc >> 1;
+
+ c = c >> 1;
+ }
+
+ crc_tabdnp[i] = crc;
+ }
+
+ crc_tabdnp_init = TRUE;
+
+} /* init_crcdnp_tab */
+
+
+
+ /*******************************************************************\
+ * *
+ * static void init_crc32_tab( void ); *
+ * *
+ * The function init_crc32_tab() is used to fill the array *
+ * for calculation of the CRC-32 with values. *
+ * *
+ \*******************************************************************/
+
+static void init_crc32_tab( void ) {
+
+ int i, j;
+ unsigned long crc;
+
+ for (i=0; i<256; i++) {
+
+ crc = (unsigned long) i;
+
+ for (j=0; j<8; j++) {
+
+ if ( crc & 0x00000001L ) crc = ( crc >> 1 ) ^ P_32;
+ else crc = crc >> 1;
+ }
+
+ crc_tab32[i] = crc;
+ }
+
+ crc_tab32_init = TRUE;
+
+} /* init_crc32_tab */
+
+
+
+ /*******************************************************************\
+ * *
+ * static void init_crcccitt_tab( void ); *
+ * *
+ * The function init_crcccitt_tab() is used to fill the array *
+ * for calculation of the CRC-CCITT with values. *
+ * *
+ \*******************************************************************/
+
+static void init_crcccitt_tab( void ) {
+
+ int i, j;
+ unsigned short crc, c;
+
+ for (i=0; i<256; i++) {
+
+ crc = 0;
+ c = ((unsigned short) i) << 8;
+
+ for (j=0; j<8; j++) {
+
+ if ( (crc ^ c) & 0x8000 ) crc = ( crc << 1 ) ^ P_CCITT;
+ else crc = crc << 1;
+
+ c = c << 1;
+ }
+
+ crc_tabccitt[i] = crc;
+ }
+
+ crc_tabccitt_init = TRUE;
+
+} /* init_crcccitt_tab */
diff --git a/src/virtio/lib_crc.h b/src/virtio/lib_crc.h
new file mode 100644
index 0000000..ea5ca76
--- /dev/null
+++ b/src/virtio/lib_crc.h
@@ -0,0 +1,66 @@
+ /*******************************************************************\
+ * *
+ * Library : lib_crc *
+ * File : lib_crc.h *
+ * Author : Lammert Bies 1999-2008 *
+ * E-mail : info(a)lammertbies.nl *
+ * Language : ANSI C *
+ * *
+ * *
+ * Description *
+ * =========== *
+ * *
+ * The file lib_crc.h contains public definitions and proto- *
+ * types for the CRC functions present in lib_crc.c. *
+ * *
+ * *
+ * Dependencies *
+ * ============ *
+ * *
+ * none *
+ * *
+ * *
+ * Modification history *
+ * ==================== *
+ * *
+ * Date Version Comment *
+ * *
+ * 2008-04-20 1.16 Added CRC-CCITT routine for Kermit *
+ * *
+ * 2007-04-01 1.15 Added CRC16 calculation for Modbus *
+ * *
+ * 2007-03-28 1.14 Added CRC16 routine for Sick devices *
+ * *
+ * 2005-12-17 1.13 Added CRC-CCITT with initial 0x1D0F *
+ * *
+ * 2005-02-14 1.12 Added CRC-CCITT with initial 0x0000 *
+ * *
+ * 2005-02-05 1.11 Fixed bug in CRC-DNP routine *
+ * *
+ * 2005-02-04 1.10 Added CRC-DNP routines *
+ * *
+ * 2005-01-07 1.02 Changes in tst_crc.c *
+ * *
+ * 1999-02-21 1.01 Added FALSE and TRUE mnemonics *
+ * *
+ * 1999-01-22 1.00 Initial source *
+ * *
+ \*******************************************************************/
+
+
+
+#define CRC_VERSION "1.16"
+
+
+
+#define FALSE 0
+#define TRUE 1
+
+
+
+unsigned short update_crc_16( unsigned short crc, char c );
+unsigned long update_crc_32( unsigned long crc, char c );
+unsigned short update_crc_ccitt( unsigned short crc, char c );
+unsigned short update_crc_dnp( unsigned short crc, char c );
+unsigned short update_crc_kermit( unsigned short crc, char c );
+unsigned short update_crc_sick( unsigned short crc, char c, char prev_byte );
diff --git a/src/virtio/multiplexer.c b/src/virtio/multiplexer.c
new file mode 100644
index 0000000..677e24c
--- /dev/null
+++ b/src/virtio/multiplexer.c
@@ -0,0 +1,122 @@
+/* multiplexer.c - Copyright (C) 2010 Red Hat, Inc.
+ * Written by Darryl L. Pierce <dpierce(a)redhat.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; version 2 of the License.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
+ * MA 02110-1301, USA. A copy of the GNU General Public License is
+ * also available at
http://www.gnu.org/copyleft/gpl.html.
+ */
+
+#include "multiplexer.h"
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+
+#define APINAMELENGTH 255
+
+typedef struct _apifunction_list
+{
+ char apiname[APINAMELENGTH];
+ t_apifunction callback;
+ struct _apifunction_list* next;
+} t_apifunction_list;
+
+t_apifunction_list* _callbacks = NULL;
+
+int
+multiplexer_register_api(const char* apiname, t_apifunction callback)
+{
+ int result = -1;
+
+ if(apiname && strlen(apiname) && callback)
+ {
+ t_apifunction_list* newapi = NULL;
+ int existing = 0;
+
+ /* first see if the api is already registered */
+ newapi = _callbacks;
+ while(newapi && !existing)
+ {
+ if(!strcmp(newapi->apiname, apiname))
+ {
+ existing = 1;
+ }
+ else
+ {
+ newapi = newapi->next;
+ }
+ }
+
+ if(!newapi)
+ {
+ newapi = malloc(sizeof(t_apifunction_list));
+
+ strncpy(newapi->apiname, apiname, APINAMELENGTH);
+ newapi->callback = callback;
+ newapi->next = NULL;
+
+ if(_callbacks)
+ {
+ t_apifunction_list* tail = NULL;
+
+ while(tail->next) tail = tail->next;
+ tail->next = newapi;
+ }
+ else
+ {
+ _callbacks = newapi;
+ }
+ }
+ else
+ {
+ newapi->callback = callback;
+ }
+
+ result = 0;
+ }
+
+ return result;
+}
+
+t_apifunction
+multiplexer_get_api_function(const char* apiname)
+{
+ t_apifunction_list* current = _callbacks;
+
+ while(current)
+ {
+ if(!strcmp(apiname, current->apiname))
+ {
+ return current->callback;
+ }
+ current = current->next;
+ }
+
+ return NULL;
+}
+
+const char*
+multiplexer_invoke_api(const char* apiname, const char* content)
+{
+ const char* result = NULL;
+
+ t_apifunction api = multiplexer_get_api_function(apiname);
+
+ if(api)
+ {
+ result = api(content);
+ }
+
+ return result;
+}
diff --git a/src/virtio/multiplexer.cpp b/src/virtio/multiplexer.cpp
deleted file mode 100644
index 79f8b35..0000000
--- a/src/virtio/multiplexer.cpp
+++ /dev/null
@@ -1,62 +0,0 @@
-#include "multiplexer.h"
-
-/* multiplexer.cpp - Copyright (C) 2010 Red Hat, Inc.
- * Written by Darryl L. Pierce <dpierce(a)redhat.com>
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; version 2 of the License.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
- * MA 02110-1301, USA. A copy of the GNU General Public License is
- * also available at
http://www.gnu.org/copyleft/gpl.html.
- */
-
-#include "multiplexer.h"
-
-// the singleton
-Multiplexer* Multiplexer::_instance = new Multiplexer();
-
-typedef map<string, t_apifunction> APIMAP;
-
-Multiplexer::Multiplexer()
-{}
-
-Multiplexer*
-Multiplexer::instance()
-{
- return _instance;
-}
-
-void
-Multiplexer::registerAPI(string name, t_apifunction apifunction)
-{
- _apis.insert(APIMAP::value_type(string(name), apifunction));
-}
-
-t_apifunction
-Multiplexer::getAPI(string name)
-{
- return (*_apis.find(name)).second;
-}
-
-string
-Multiplexer::invokeAPI(string name, string input)
-{
- string result = string("");
- t_apifunction funcptr = (*_apis.find(name)).second;
-
- if(funcptr)
- {
- result = funcptr(input.c_str());
- }
-
- return result;
-}
diff --git a/src/virtio/multiplexer.h b/src/virtio/multiplexer.h
index 26a288c..5d00adf 100644
--- a/src/virtio/multiplexer.h
+++ b/src/virtio/multiplexer.h
@@ -20,29 +20,35 @@
* also available at
http://www.gnu.org/copyleft/gpl.html.
*/
-#include <map>
-#include <string>
-
-using namespace std;
-
+/* Defines a function type that can be used as a callback
+ * for an API.
+ */
typedef const char*(*t_apifunction)(const char*);
-// Multiplexer processes the content received from a remote system.
-class Multiplexer
-{
- private:
- Multiplexer();
-
- static Multiplexer* _instance;
-
- map<string, t_apifunction> _apis;
+/* Registers a new API that can be called back.
+ *
+ * INPUT: The name of the api.
+ * The callback function to be invoked.
+ * OUTPUT: 0 on success, -1 on failure.
+ */
+int
+multiplexer_register_api(const char* name, t_apifunction callback);
- public:
- static Multiplexer* instance();
+/* Returns a pointer to the callback registered for an API.
+ *
+ * INPUT: The name of the API.
+ * OUTPUT: A pointer to the function, or NULL if the API is not registered.
+ */
+t_apifunction
+multiplexer_get_api_function(const char* name);
- void registerAPI(string apiname, t_apifunction apifunction);
- t_apifunction getAPI(string apiname);
- string invokeAPI(string apiname, string input);
-};
+/* Invokes the named API, passing in the supplied argument.
+ *
+ * INPUT: The name of the API.
+ * The content to pass to the API.
+ * OUTPUT: The result of the API call, or NULL if the API call failed.
+ */
+const char*
+multiplexer_invoke_api(const char* name, const char* content);
#endif
--
1.7.0.1