diff --git a/Makefile.am b/Makefile.am index ecd36de..aeec36e 100644 --- a/Makefile.am +++ b/Makefile.am @@ -27,8 +27,7 @@ monitord/memlock.cpp \ monitord/xmltools.cpp \ monitord/MonitorSignals.cpp \ - xmlParser/xmlParser.cpp - + xmlParser/xmlParser.cpp EXTRA_DIST =\ xmlParser/xmlParser.h \ @@ -166,10 +165,10 @@ monitord_plugins_libmplugin_activemq_la_SOURCES=\ ${monitord_plugins_common} \ monitord/plugins/mplugin.cpp \ - monitord/plugins/libmplugin_activemq.cpp + monitord/plugins/libmplugin_activemq.cpp \ + monitord/plugins/base64.cpp monitord_plugins_libmplugin_activemq_la_CPPFLAGS =\ - -z,defs \ ${monitord_monitord_CPPFLAGS} \ ${ACTIVEMQ_CFLAGS} \ ${DLL} diff --git a/configure.ac b/configure.ac index f57b518..a9218e5 100644 --- a/configure.ac +++ b/configure.ac @@ -186,27 +186,17 @@ fi AS_IF([test "x$use_activemq" != xno], - [PKG_CHECK_MODULES( - [ACTIVEMQ], - [$ACTIVEMQLIBNAME], - [ - AC_MSG_NOTICE([activemq is present - ActiveMQ plugin will be created]) - AC_DEFINE([HAVE_ACTIVEMQ], [1], [Define if you have activemq-cpp]) - activemq=true - ], - [AC_MSG_FAILURE([$ACTIVEMQLIBNAME is not installed as package])] - )]) -# [AC_CHECK_LIB([$ACTIVEMQLIBNAME],[main], -# [ -# AC_SUBST([LIBACTIVEMQ], ["-l$ACTIVEMQLIBNAME"]) -# AC_DEFINE([HAVE_ACTIVEMQ], [1], [Define if you have activemq]) -# activemq=true -# ], -# [if test "x$use_activemq" != xcheck; then -# AC_MSG_FAILURE([--with-activemq but $ACTIVEMQLIBNAME failed]) -# fi -# ]) -# ]) + [AC_CHECK_LIB([$ACTIVEMQLIBNAME],[main], + [ + AC_SUBST([LIBACTIVEMQ], ["-l$ACTIVEMQLIBNAME"]) + AC_DEFINE([HAVE_ACTIVEMQ], [1], [Define if you have activemq]) + activemq=true + ], + [if test "x$use_activemq" != xcheck; then + AC_MSG_FAILURE([--with-activemq but $ACTIVEMQLIBNAME failed]) + fi + ]) + ]) LIBS= diff --git a/monitord/plugins/base64.cpp b/monitord/plugins/base64.cpp new file mode 100644 index 0000000..064b8ed --- /dev/null +++ b/monitord/plugins/base64.cpp @@ -0,0 +1,123 @@ +/** + * base64.cpp and base64.h + * + * Copyright (C) 2004-2008 René Nyffenegger + * + * This source code is provided 'as-is', without any express or implied + * warranty. In no event will the author be held liable for any damages + * arising from the use of this software. + * + * Permission is granted to anyone to use this software for any purpose, + * including commercial applications, and to alter it and redistribute it + * freely, subject to the following restrictions: + * + * 1. The origin of this source code must not be misrepresented; you must not + * claim that you wrote the original source code. If you use this source code + * in a product, an acknowledgment in the product documentation would be + * appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and must not be + * misrepresented as being the original source code. + * + * 3. This notice may not be removed or altered from any source distribution. + * + * René Nyffenegger rene.nyffenegger@adp-gmbh.ch + * + */ + +#include "base64.h" +#include + +static const std::string base64_chars = + "ABCDEFGHIJKLMNOPQRSTUVWXYZ" + "abcdefghijklmnopqrstuvwxyz" + "0123456789+/"; + + +static inline bool is_base64(unsigned char c) { + return (isalnum(c) || (c == '+') || (c == '/')); +} + +std::string base64_encode(unsigned char const* bytes_to_encode, unsigned int in_len) { + std::string ret; + int i = 0; + int j = 0; + unsigned char char_array_3[3]; + unsigned char char_array_4[4]; + + while (in_len--) { + char_array_3[i++] = *(bytes_to_encode++); + if (i == 3) { + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for(i = 0; (i <4) ; i++) + ret += base64_chars[char_array_4[i]]; + i = 0; + } + } + + if (i) + { + for(j = i; j < 3; j++) + char_array_3[j] = '\0'; + + char_array_4[0] = (char_array_3[0] & 0xfc) >> 2; + char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4); + char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6); + char_array_4[3] = char_array_3[2] & 0x3f; + + for (j = 0; (j < i + 1); j++) + ret += base64_chars[char_array_4[j]]; + + while((i++ < 3)) + ret += '='; + + } + + return ret; + +} + +std::string base64_decode(std::string const& encoded_string) { + int in_len = encoded_string.size(); + int i = 0; + int j = 0; + int in_ = 0; + unsigned char char_array_4[4], char_array_3[3]; + std::string ret; + + while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) { + char_array_4[i++] = encoded_string[in_]; in_++; + if (i ==4) { + for (i = 0; i <4; i++) + char_array_4[i] = base64_chars.find(char_array_4[i]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (i = 0; (i < 3); i++) + ret += char_array_3[i]; + i = 0; + } + } + + if (i) { + for (j = i; j <4; j++) + char_array_4[j] = 0; + + for (j = 0; j <4; j++) + char_array_4[j] = base64_chars.find(char_array_4[j]); + + char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4); + char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2); + char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3]; + + for (j = 0; (j < i - 1); j++) ret += char_array_3[j]; + } + + return ret; +} diff --git a/monitord/plugins/base64.h b/monitord/plugins/base64.h new file mode 100644 index 0000000..8a4f8bf --- /dev/null +++ b/monitord/plugins/base64.h @@ -0,0 +1,9 @@ +/** + * http://www.adp-gmbh.ch/cpp/common/base64.html + */ + +#include + +std::string base64_encode(unsigned char const* , unsigned int len); +std::string base64_decode(std::string const& s); + diff --git a/monitord/plugins/libmplugin_activemq.cpp b/monitord/plugins/libmplugin_activemq.cpp index cdaecdd..670555f 100644 --- a/monitord/plugins/libmplugin_activemq.cpp +++ b/monitord/plugins/libmplugin_activemq.cpp @@ -100,11 +100,7 @@ LOG_INFO("Preparing final alarm message") TextMessage* message = m_session->createTextMessage(); - ResultItemsMap::iterator i; - - for (i = (*pRes).m_Items.begin(); i != (*pRes).m_Items.end(); i++) { - message->setStringProperty(i->first, i->second); - } + updateTextMessage(*message, *pRes); // if sending the messasge item fails, the connection will be recovered on the next processResult call topicInfo->producer->send(message); @@ -116,6 +112,26 @@ return true; } +void MonitorPlugInActiveMQ::updateTextMessage(cms::TextMessage& textMessage, class ModuleResultBase& pRes) { + ResultItemsMap::iterator i; + + for (i = pRes.m_Items.begin(); i != pRes.m_Items.end(); i++) { + // ZABOS-150: Binary data (encrypted POCSAG messages) must be converted to Base64 so ActiveMQ can decode the data + if (i->first == "text") { + textMessage.setStringProperty( + i->first, + base64_encode( + reinterpret_cast(i->second.c_str()), + i->second.length() + ) + ); + } + else { + textMessage.setStringProperty(i->first, i->second); + } + } +} + /** * Read the .. section from the configuration XML file. * All parameters are stored as member variables of the MonitorPlugInActiveMQ instance. @@ -178,7 +194,9 @@ // create a connection try { m_connection = m_connectionFactory->createConnection(); + LOG_INFO("Connection prepared") m_connection->start(); + LOG_INFO("Connection started") if (m_bClientAck) { m_session = m_connection->createSession(Session::CLIENT_ACKNOWLEDGE); diff --git a/monitord/plugins/libmplugin_activemq.h b/monitord/plugins/libmplugin_activemq.h index cdde046..52d4f88 100644 --- a/monitord/plugins/libmplugin_activemq.h +++ b/monitord/plugins/libmplugin_activemq.h @@ -11,6 +11,7 @@ #endif #include "mplugin.h" +#include "base64.h" #include "../MonitorLogging.h" #include #include @@ -22,6 +23,7 @@ #include #include #include +#include #define ACTIVEMQ_KEY_POCSAG "pocsag" #define ACTIVEMQ_KEY_FMS "fms" @@ -84,6 +86,7 @@ bool initProcessing(class MonitorConfiguration* configPtr,XMLNode config); bool processResult(class ModuleResultBase *pRes); + void updateTextMessage(cms::TextMessage& textMessage, class ModuleResultBase& pRes); bool quitProcessing(); void Show(); diff --git a/monitord/plugins/libmplugin_activemq/MonitorPluginActiveMqTestSuite.h b/monitord/plugins/libmplugin_activemq/MonitorPluginActiveMqTestSuite.h index de10d74..ed355c4 100644 --- a/monitord/plugins/libmplugin_activemq/MonitorPluginActiveMqTestSuite.h +++ b/monitord/plugins/libmplugin_activemq/MonitorPluginActiveMqTestSuite.h @@ -14,13 +14,23 @@ using namespace std; using namespace activemq; +using namespace activemq::commands; using namespace activemq::core; using namespace cms; class MonitorPlugInActiveMqTestSuite : public CxxTest::TestSuite { public: + void tearDown() { + TS_TRACE("Shutting down library..."); + activemq::library::ActiveMQCPP::initializeLibrary(); + activemq::library::ActiveMQCPP::shutdownLibrary(); + TS_TRACE("... library shutdown"); + } + + void testMainConfiguration() { + TS_TRACE("testMainConfiguration"); MonitorPlugInActiveMQ mock; TS_ASSERT_EQUALS(mock.m_bConnected, false); TS_ASSERT_EQUALS(mock.m_bUseCompression, false); @@ -42,14 +52,13 @@ } void testInitialzeConnectionFactory() { + TS_TRACE("testInitializeConnectionFactory"); MonitorPlugInActiveMQ mock; - auto_ptr connectionFactory(new ActiveMQConnectionFactory()); - XMLSETTING(xmlString, xmlResults, xmlNode, XML_PARAMS_DEFAULT); mock.initializeConfiguration(xmlNode); - ActiveMQConnectionFactory *pCF = connectionFactory.get(); - mock.initializeConnectionFactory(pCF); + mock.initializeConnectionFactory(); + std::auto_ptr pCF = mock.m_connectionFactory; TS_ASSERT_EQUALS(pCF->getBrokerURI().toString(), "tcp://localhost"); TS_ASSERT_EQUALS(pCF->getClientId(), "new_client_id"); @@ -62,6 +71,8 @@ } void testParseTopic() { + TS_TRACE("testParseTopic"); + MonitorPlugInActiveMQ mock; XMLSETTING(xmlString, xmlResults, xmlNode, XML_PARAMS_TOPIC_DEFAULT); TopicInfo topicInfo; @@ -86,12 +97,13 @@ } void testGetTopics() { + TS_TRACE("testGetTopics"); MonitorPlugInActiveMQ mock; - Topics topics = mock.getTopics(); - TS_ASSERT_EQUALS(topics.size(), 0); + TS_ASSERT_EQUALS(mock.m_topics.size(), 0); } void testParseTopics() { + TS_TRACE("testParseTopics"); MonitorPlugInActiveMQ mock; TopicInfo referenceTopic; // Daten initalisieren @@ -112,7 +124,6 @@ "); mock.parseTopic(xmlNode, referenceTopic, referenceTopic); TS_ASSERT_EQUALS(referenceTopic.destUri, "default"); - mock.parseTopics(xmlNode, topics, referenceTopic); TS_ASSERT_EQUALS(topics.size(), 3); TS_ASSERT_EQUALS((*(topics.find(ACTIVEMQ_KEY_FMS))->second).destUri, "fms"); @@ -126,28 +137,50 @@ TS_ASSERT_EQUALS((*(topics.find(ACTIVEMQ_KEY_ZVEI))->second).bDeliveryModePersistent, false); } - void testInitializeActiveMqConnection() { + void testInitializeConnection() { + TS_SKIP("Skipping integration test"); + TS_TRACE("testInitializeConnection"); MonitorPlugInActiveMQ mock; XMLSETTING(xmlString, xmlResults, xmlNode, "default\ -tcp://192.168.1.101:61616"); +11tcp://127.0.0.1:61616?soConnectTimeout=3&transport.tcpTracingEnabled=true"); mock.initializeConfiguration(xmlNode); - bool success = mock.initializeActiveMqConnection(); + bool success = mock.initializeConnection(); TS_ASSERT_EQUALS(success, false); - + TS_TRACE("Connection attempt failed"); XMLSETTING(xmlString2, xmlResults2, xmlNode2, "default\ tcp://192.168.1.100:61616"); mock.initializeConfiguration(xmlNode2); - success = mock.initializeActiveMqConnection(); + success = mock.initializeConnection(); TS_ASSERT_EQUALS(success, true); } + void testUpdateTextMessage() { + TS_TRACE("testUpdateTextMessage"); + MonitorPlugInActiveMQ mock; + std::auto_ptr textMessage(new ActiveMQTextMessage()); + std::auto_ptr result(new ModuleResultBase()); + + result->set("key", "value"); + result->set("text", "base64"); + + mock.updateTextMessage(*textMessage, *result); //moduleResultBase); + + TS_ASSERT_EQUALS(textMessage->getStringProperty("key"), "value"); + // ensure that the "text" property has been encoded as base64 + TS_ASSERT_EQUALS(textMessage->getStringProperty("text"), "YmFzZTY0"); + TS_TRACE("text property has been base64 encoded"); + } + void testInitializeTopics() { + TS_SKIP("Skipping integration test"); + TS_TRACE("testInitializeTopics"); + MonitorPlugInActiveMQ mock; ModuleResultBase mrb; TopicInfo referenceTopic; - Topics topics = mock.getTopics(); + Topics topics = mock.m_topics; // Daten initalisieren referenceTopic.bDeliveryModePersistent = false; referenceTopic.bUseTopic = false; @@ -156,7 +189,7 @@ tcp://192.168.1.100:61616"); mock.initializeConfiguration(xmlNode); - bool success = mock.initializeActiveMqConnection(); + bool success = mock.initializeConnection(); TS_ASSERT_EQUALS(success, true); mrb.set("key1", "val1"); @@ -176,8 +209,8 @@ mock.initializeTopics(topics); TS_ASSERT_EQUALS(topics.size(), 3); - mock.setTopics(topics); - TS_ASSERT_EQUALS(mock.getTopics().size(), 3); + mock.m_topics = topics; + TS_ASSERT_EQUALS(mock.m_topics.size(), 3); success = mock.processResult(&mrb); TS_TRACE("all initialized"); diff --git a/monitord/plugins/libmplugin_activemq/unittest.sh b/monitord/plugins/libmplugin_activemq/unittest.sh index 560a4cd..437f3af 100755 --- a/monitord/plugins/libmplugin_activemq/unittest.sh +++ b/monitord/plugins/libmplugin_activemq/unittest.sh @@ -1,24 +1,49 @@ #!/bin/bash -# Dreckiges Script zum Ausfuehren der Unittests -CXXTEST=~/dev/app/cxxtest -$CXXTEST/cxxtestgen.pl --error-printer -o runner.cpp MonitorPluginActiveMqTestSuite.h -echo Unittest generated +# wrapper file for executing the cxxtests +if [ $# -eq 0 ]; then + echo "You must provide the path to the cxxtest project as first argument" + exit 1 +fi + + +CXXTEST_DIR=$1 +CXXTEST=$CXXTEST_DIR/bin/cxxtestgen +REPO_DIR=$(dirname $0)/../../.. + +if [ ! -d $CXXTEST_DIR ]; then + echo "cxxtest directory $1 does not exist" + exit 1 +fi + +if [ ! -e $CXXTEST ]; then + echo "$CXXTEST binary does not exist" + exit 1; +fi + +if [ ! `which activemqcpp-config` ]; then + echo "activemqcpp-config is required to determine the include path for ActiveMQ" + exit 1; +fi + +$CXXTEST --error-printer -o runner.cpp MonitorPluginActiveMqTestSuite.h +echo Runner for unit tests generated +mkdir -p "o" cd ../../../ echo "Compiling ..." make cd - find ../../../ -name "*.o" | xargs -i cp -v {} o/ -# Doppelte Abhaengigkeiten eentfernen + +# remove duplicate dependencies rm o/monitord_plugins_libmplugin_activemq_la-mplugin.o rm o/monitord_plugins_libmplugin_activemq_la-xml*.o -rm o/monitord_plugins_libmplugin_audiorecorder_la-xml*.o -rm o/monitord_plugins_libmplugin_audiorecorder_la-m*.o -# main() entfernen +rm o/monitord_plugins_libmplugin_audiorecorder_la-* +# main() entfernen rm o/monitord_monitord-Monitor.o -g++ -I /usr/local/include/activemq-cpp-3.4.0 -I $CXXTEST -I ~/dev/app/monitord/trunk -lasound -ldl -lpthread -lm -lactivemq-cpp -o runner o/*.o runner.cpp +g++ `activemqcpp-config --includes` -I $CXXTEST_DIR -I $REPO_DIR -I/usr/include -llua -lasound -ldl -lpthread -lm -lactivemq-cpp -o runner o/*.o runner.cpp echo "Unittest compiled" # libactivemq-cpp importieren export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib -./runner +./runner -v