From 2796995d29bb5d25bd1eefdfa9a9b09127cb797d Mon Sep 17 00:00:00 2001 From: manupap1 Date: Tue, 11 Nov 2014 22:46:58 +0100 Subject: [PATCH] Update ImageAnalyser class --- src/zm_image_analyser.cpp | 451 ++++++++++++++++++++++++++++++++++++-- src/zm_image_analyser.h | 114 +++++++++- 2 files changed, 548 insertions(+), 17 deletions(-) diff --git a/src/zm_image_analyser.cpp b/src/zm_image_analyser.cpp index 1445e9864..20e02fda6 100644 --- a/src/zm_image_analyser.cpp +++ b/src/zm_image_analyser.cpp @@ -1,6 +1,16 @@ #include "zm_image_analyser.h" - +ImageAnalyser::ImageAnalyser( int nMonitorId ) +{ + if ( nMonitorId > 0 ) + { + m_nMonitorId = nMonitorId; + m_bIsAnalyserEnabled = getMonitorZones(); + } + else + m_bIsAnalyserEnabled = false; + m_bIsNativeDetEnabled = false; +} /*!\fn ImageAnalyser::ImageAnalyser(const ImageAnalyser& source) * \param source is the object to copy @@ -33,32 +43,445 @@ ImageAnalyser::~ImageAnalyser() -/*!\fn ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, int n_numZones, Event::StringSetMap noteSetMap, std::string& det_cause) +/*!\fn ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, Event::StringSetMap noteSetMap, string& det_cause) * \param comp_image is the image to analyse * \param zones is the zones array to analyse - * \param n_numZones is the number of zones * \param noteSetMap is the map of events descriptions * \param det_cause is a string describing detection cause + * \param score is the plugin score */ -int ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, int n_numZones, Event::StringSetMap noteSetMap, std::string& det_cause) +bool ImageAnalyser::DoDetection(const Image &comp_image, Zone** zones, Event::StringSetMap& noteSetMap, string& det_cause, unsigned int& score) { Event::StringSet zoneSet; - int score = 0; + score = 0; + bool alarm = false; - for(DetectorsList::iterator It = m_Detectors.begin(); + for ( DetectorsList::iterator It = m_Detectors.begin(); It != m_Detectors.end(); - ++It) + ++It ) { - int detect_score = (*It)->Detect(comp_image, zones, n_numZones, zoneSet); - if (detect_score) + unsigned int detect_score = 0; + if ( (*It)->Detect( comp_image, zones, zoneSet, detect_score ) ) { + alarm = true; score += detect_score; - noteSetMap[(*It)->getDetectionCause()] = zoneSet; - if (det_cause.length()) - det_cause += ", "; - det_cause += (*It)->getDetectionCause(); + std::string new_cause = (*It)->getDetectionCause(); + noteSetMap[new_cause] = zoneSet; + if ( det_cause.find( new_cause ) == std::string::npos ) + { + if ( det_cause.length() ) + det_cause += ", "; + det_cause += new_cause; + } } } - return score; + return alarm; } + + +/*!\fn ImageAnalyser::configurePlugins(string sConfigFileName) + *\param sConfigFileName is the path to the configuration file, where parameters for all plugins are given. + * \param bDoNativeDet is true if native detection will be performed +*/ +void ImageAnalyser::configurePlugins(string sConfigFileName, bool bDoNativeDet) +{ + string sLoadedPlugins; + if ( !m_bIsAnalyserEnabled ) return; + m_bIsNativeDetEnabled = bDoNativeDet; + for ( DetectorsList::iterator It = m_Detectors.begin(); It != m_Detectors.end(); ++It ) + { + string sPluginName = (*It)->getPluginName(); + try + { + if ( isValidConfigFile( sPluginName, sConfigFileName ) ) + { + Info("Configure plugin '%s' with config file '%s'.", sPluginName.c_str(), sConfigFileName.c_str()); + map > mapPluginConf; + vector vnPluginZones; + bool plugEnabled = getEnabledZonesForPlugin( sPluginName, vnPluginZones ); + if ( getPluginConfig( sPluginName, vnPluginZones, mapPluginConf ) + && (*It)->loadConfig( sConfigFileName, mapPluginConf ) ) + { + mapRegPluginGenConf[sPluginName].Configured = true; + if ( plugEnabled ) + { + (*It)->EnablePlugin( vnPluginZones ); + if ( sLoadedPlugins.length() ) + sLoadedPlugins += ", "; + sLoadedPlugins += "'" + sPluginName + "'"; + } + } + } + } + catch(...) + { + Error("Plugin '%s' couldn't be loaded", sPluginName.c_str()); + } + } + getZonesConfig( sLoadedPlugins ); +} + + + +/*!\fn ImageAnalyser::isValidConfigFile(string sPluginName, string sConfigFileName) + * \param sPluginName is the name of the plugin (filename without extension) + * \param sConfigFileName is the path to the configuration file which should include configuration directives for the plugin + * \return true if the config file contains the right section name + */ +bool ImageAnalyser::isValidConfigFile(string sPluginName, string sConfigFileName) +{ + ifstream ifs(sConfigFileName.c_str()); + string line; + bool rtnVal = false; + while (getline(ifs, line)) + { + if (line == "[" + sPluginName + "]") + { + rtnVal = true; + break; + } + } + ifs.close(); + return rtnVal; +} + + +/*!\fn ImageAnalyser::getMonitorZones() + * \return true if at least a zone is configured for the monitor + */ +bool ImageAnalyser::getMonitorZones() +{ + static char sql[ZM_SQL_MED_BUFSIZ]; + + // We use the same ordering as in Monitor::Load + snprintf(sql, sizeof(sql), "SELECT `Id`, `Name`, `Type` FROM `Zones` WHERE `MonitorId` = %d ORDER BY `Type`, `Id`;", m_nMonitorId); + + if (mysql_query(&dbconn, sql)) + { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + + MYSQL_RES *result = mysql_store_result(&dbconn); + if (!result) + { + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + + if (mysql_num_rows(result) > 0) + { + for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) + { + if (mysql_errno(&dbconn)) + { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + zSetting zone; + zone.id = (unsigned int)strtoul(dbrow[0], NULL, 0); + zone.name = string(dbrow[1]); + zone.type = string(dbrow[2]); + m_vMonitorZones.push_back(zone); + } + } + mysql_free_result(result); + + return ( m_vMonitorZones.size() ); +} + + + +/*!\fn ImageAnalyser::getPluginConfig(string sPluginName, map >& mapPluginConf) + * \param sPluginName is the name of the plugin (filename without extension) + * \param vnPluginZones is a vector containing the index of zones enabled for the plugin (not the zone Id in the database) + * \param mapPluginConf is the map filled with configuration parameters for the plugin + * \return true if all found parameters are applied to the map + */ +bool ImageAnalyser::getPluginConfig(string sPluginName, vector vnPluginZones, map >& mapPluginConf) +{ + static char sql[ZM_SQL_MED_BUFSIZ]; + + // Get plugin configuration parameters from `PluginsConfig` table + snprintf(sql, sizeof(sql), "SELECT `ZoneId`, `Name`, `Value` FROM `PluginsConfig` WHERE `MonitorId`=%d AND `pluginName`='%s' ORDER BY `ZoneId` ASC;", m_nMonitorId, sPluginName.c_str()); + + if (mysql_query(&dbconn, sql)) + { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + + MYSQL_RES *result = mysql_store_result(&dbconn); + if (!result) + { + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + + size_t nParamCnt = 0; + size_t nParamNum = mysql_num_rows(result); + + if (nParamNum > 0) + { + vector vRows; + for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) + { + if (mysql_errno(&dbconn)) + { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + mysql_free_result(result); + exit(mysql_errno(&dbconn)); + } + vRows.push_back(dbrow); + } + // Iterate over the zones + for (size_t i = 0; i < m_vMonitorZones.size(); i++) + { + // Iterate over the configuration parameters + for (vector::iterator it = vRows.begin(); it != vRows.end(); it++) + { + // Add the parameter to the map if the zone id is found + if ( (unsigned int)strtoul((*it)[0], NULL, 0) == m_vMonitorZones[i].id ) + { + nParamCnt++; + string name((*it)[1]); + string value((*it)[2]); + if((name == "Enabled") && (value == "Yes")) { + mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].Enabled = true; + } else if((name == "RequireNatDet") && (value == "Yes")) { + mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].RequireNatDet = true; + } else if((name == "IncludeNatDet") && (value == "Yes")) { + mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].IncludeNatDet = true; + } else if((name == "ReInitNatDet") && (value == "Yes")) { + mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].ReInitNatDet = true; + } + // Keep only enabled zones in mapPluginConf + if (binary_search(vnPluginZones.begin(), vnPluginZones.end(), i)) { + mapPluginConf[i][name] = value; + } + } + } + if ( mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].Enabled + && mapRegPluginZoneConf[sPluginName][m_vMonitorZones[i].id].RequireNatDet + && !m_bIsNativeDetEnabled ) + Warning("Plugin '%s' will never enter in alarm because native detection is required but not enabled", sPluginName.c_str()); + } + } + mysql_free_result(result); + + return ( nParamNum == nParamCnt ); +} + + + +/*!\fn ImageAnalyser::getEnabledZonesForPlugin(string sPluginName, vector& vnPluginZones) + * \param sPluginName is the name of the plugin (filename without extension) + * \param vnPluginZones is the vector list filled with zones enabled for this plugin + * \return true if at least one active or exclusive zone exist + */ +bool ImageAnalyser::getEnabledZonesForPlugin(string sPluginName, vector& vnPluginZones) +{ + static char sql[ZM_SQL_MED_BUFSIZ]; + bool bPluginEnabled = false; + string sZones; + + // Get the sorted list of zones ids which have the plugin enabled + snprintf(sql, sizeof(sql), "SELECT `ZoneId` FROM `PluginsConfig` WHERE `MonitorId`=%d AND `pluginName`='%s' AND `Name`='Enabled' AND `Value`='yes' ORDER BY `ZoneId` ASC;", m_nMonitorId, sPluginName.c_str()); + + if (mysql_query( &dbconn, sql)) + { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + + MYSQL_RES *result = mysql_store_result(&dbconn); + if (!result) + { + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + + if (mysql_num_rows(result) > 0) + { + vector vnEnabledZoneIds; + for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) + { + if (mysql_errno(&dbconn)) + { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + mysql_free_result(result); + exit(mysql_errno(&dbconn)); + } + vnEnabledZoneIds.push_back(atoi(dbrow[0])); + } + + // Iterate over the zones + for (size_t i = 0; i < m_vMonitorZones.size(); i++) + { + if (binary_search(vnEnabledZoneIds.begin(), vnEnabledZoneIds.end(), m_vMonitorZones[i].id)) + { + // Add the index to the vector if the zone id is found + vnPluginZones.push_back(i); + string sZoneType = m_vMonitorZones[i].type; + if ((sZoneType == "Active") || (sZoneType == "Exclusive")) + bPluginEnabled = true; + if ( sZones.length() ) + sZones += ", "; + sZones += m_vMonitorZones[i].name + " (" + sZoneType + ")"; + } + } + } + mysql_free_result(result); + + if (bPluginEnabled) + { + Info("Plugin '%s' is enabled for zone(s): %s", sPluginName.c_str(), sZones.c_str()); + } + else + { + Info("Plugin '%s' is disabled (not enabled for any active or exclusive zones)", sPluginName.c_str()); + } + return bPluginEnabled; +} + + +/*!\fn ImageAnalyser::getZonesConfig() + * \param sLoadedPlugins is the formatted list of loaded plugins + */ +bool ImageAnalyser::getZonesConfig(string sLoadedPlugins) +{ + static char sql[ZM_SQL_MED_BUFSIZ]; + + if ( !sLoadedPlugins.length() ) return false; + + // Get the sorted list of zones and which have a setting enabled + snprintf(sql, sizeof(sql), "SELECT DISTINCT `ZoneId`, `Name` FROM `PluginsConfig` WHERE `MonitorId` = %d AND `pluginName` IN (%s) AND `Name` IN ('RequireNatDet', 'IncludeNatDet', 'ReInitNatDet') AND `Value` = 'yes' ORDER BY `ZoneId` ASC;", m_nMonitorId, sLoadedPlugins.c_str()); + if (mysql_query(&dbconn, sql)) + { + Error("Can't run query: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + MYSQL_RES *result = mysql_store_result(&dbconn); + if (!result) + { + Error("Can't use query result: %s", mysql_error(&dbconn)); + exit(mysql_errno(&dbconn)); + } + if (mysql_num_rows(result) > 0) + { + vector vSettings; + for (unsigned int i = 0; MYSQL_ROW dbrow = mysql_fetch_row(result); i++) + { + if (mysql_errno(&dbconn)) + { + Error("Can't fetch row: %s", mysql_error(&dbconn)); + mysql_free_result(result); + exit(mysql_errno(&dbconn)); + } + zIdName setting; + setting.zoneId = (unsigned int)strtoul(dbrow[0], NULL, 0); + setting.name = dbrow[1]; + vSettings.push_back(setting); + } + + // Iterate over the zones and add the index to the vector if the zone id is found + for (size_t i = 0; i != m_vMonitorZones.size(); i++) + { + zConf zoneConf; + for (vector::iterator it = vSettings.begin(); it != vSettings.end(); it++) + { + if (it->zoneId == m_vMonitorZones[i].id) + { + if (it->name == "RequireNatDet") + zoneConf.RequireNatDet = true; + else if (it->name == "IncludeNatDet") + zoneConf.IncludeNatDet = true; + else if (it->name == "ReInitNatDet") + zoneConf.ReInitNatDet = true; + } + } + m_vZonesConfig.push_back(zoneConf); + } + } + mysql_free_result(result); + + return true; +} + + +/*!\fn ImageAnalyser::getZoneConfig(int nZone, zConf& zoneConf) + * \param nZone is the zone index (not the id in sql database) + * \param zoneConf is a structure filled with the plugin settings of nZone + */ +bool ImageAnalyser::getZoneConfig(unsigned int nZone, zConf& zoneConf) +{ + if (nZone < m_vZonesConfig.size()) + zoneConf = m_vZonesConfig[nZone]; + else + return false; + return true; +} + + +/*!\fn ImageAnalyser::getRegPluginGenConf(string sPluginName, pGenConf& regPluginGenConf) + * \param sPluginName is the name of the plugin (filename without extension) + * \param regPluginGenConf is a structure filled with the general settings of the plugin + * \return false if no setting is found + */ +bool ImageAnalyser::getRegPluginGenConf(string sPluginName, pGenConf& regPluginGenConf) +{ + map::iterator it = mapRegPluginGenConf.find( sPluginName ); + if ( it == mapRegPluginGenConf.end() ) + return false; + regPluginGenConf = it->second; + return true; +} + + +/*!\fn ImageAnalyser::getRegPluginZoneConf(string sPluginName, PluginZoneConf& regPluginZoneConf) + * \param sPluginName is the name of the plugin (filename without extension) + * \param regPluginZoneConf is a map filled with the zone settings of the plugin + */ +void ImageAnalyser::getRegPluginZoneConf(string sPluginName, PluginZoneConf& regPluginZoneConf) +{ + map::iterator it = mapRegPluginZoneConf.find( sPluginName ); + + if ( it != mapRegPluginZoneConf.end() ) + regPluginZoneConf = it->second; + + pZoneConf empty; + + for (size_t i = 0; i != m_vMonitorZones.size(); i++) + { + PluginZoneConf::iterator it2 = regPluginZoneConf.find( m_vMonitorZones[i].id ); + if ( it2 == regPluginZoneConf.end() ) + regPluginZoneConf[m_vMonitorZones[i].id] = empty; + } +} + +void ImageAnalyser::cleanupPlugins() +{ + + string sPluginsToKeep; + string sRequest; + static char sql[ZM_SQL_MED_BUFSIZ]; + + for ( DetectorsList::iterator It = m_Detectors.begin(); It != m_Detectors.end(); ++It ) + { + if ( sPluginsToKeep.length() ) + sPluginsToKeep += ", "; + sPluginsToKeep += "'" + (*It)->getPluginName() + "'"; + } + + if ( sPluginsToKeep.length() ) + sRequest = " AND `pluginName` NOT IN (" + sPluginsToKeep + ")"; + + snprintf(sql, sizeof(sql), "DELETE FROM `PluginsConfig` WHERE `MonitorId` = %d%s;", m_nMonitorId, sRequest.c_str()); + + if ( mysql_query( &dbconn, sql ) ) + { + Error( "Can't delete plugint: %s", mysql_error( &dbconn ) ); + exit( mysql_errno( &dbconn ) ); + } +} diff --git a/src/zm_image_analyser.h b/src/zm_image_analyser.h index d1d0c1da0..eb516653f 100644 --- a/src/zm_image_analyser.h +++ b/src/zm_image_analyser.h @@ -7,25 +7,58 @@ #include #include #include +#include #include +#include #include "zm.h" +#include "zm_detector.h" #include "zm_image.h" #include "zm_zone.h" #include "zm_event.h" +#include "zm_db.h" using namespace std; +//! List of available detectors. +typedef std::list DetectorsList; + +//! A structure to store the general configuration of a plugin +struct pGenConf { + bool Registered; + bool Configured; + pGenConf(): + Registered(false), + Configured(false) + {} +}; + +//! A structure to store the zone configuration of a plugin +struct pZoneConf { + bool Enabled; + bool RequireNatDet; + bool IncludeNatDet; + bool ReInitNatDet; + pZoneConf(): + Enabled(false), + RequireNatDet(false), + IncludeNatDet(false), + ReInitNatDet(false) + {} +}; + +//! Map of zone configuration for a plugin +typedef std::map PluginZoneConf; //! Class for handling image detection. class ImageAnalyser { public: - + //!Default constructor. - ImageAnalyser() {}; + ImageAnalyser( int nMonitorId = 0 ); //! Destructor. ~ImageAnalyser(); @@ -36,8 +69,83 @@ class ImageAnalyser { //! Overloaded operator=. ImageAnalyser& operator=(const ImageAnalyser& source); -private: + //! Adds new plugin's detector to the list of detectors. + void addDetector(std::auto_ptr Det) + { + m_Detectors.push_back(Det.release()); + } + //! Do detection in an image by calling all available detectors. + bool DoDetection(const Image &comp_image, Zone** zones, Event::StringSetMap& noteSetMap, std::string& det_cause, unsigned int& score); + + //! Configure all loaded plugins using given configuration file. + void configurePlugins(string sConfigFileName, bool bDoNativeDet = 0); + + //! Check if the configuration file contains the right section name + bool isValidConfigFile(string sPluginName, string sConfigFileName); + + //! Get index of enabled zones for this monitor (same ordering as in Monitor::Load) + bool getMonitorZones(); + + //! Get plugin configuration from database + bool getPluginConfig(string sPluginName, vector vnPluginZones, map >& mapPluginConf); + + //! Get enabled zones for the plugin + bool getEnabledZonesForPlugin(string sPluginName, vector& vnPluginZones); + + //! Get zones configuration from database + bool getZonesConfig(string sLoadedPlugins); + + //! Get Zone configuration from this class + bool getZoneConfig(unsigned int nZone, zConf& zoneConf); + + //! Get the general settings of a registered plugin + bool getRegPluginGenConf(string sPluginName, pGenConf& regPluginGenConf); + + //! Get the zone settings of a registered plugin + void getRegPluginZoneConf(string sPluginName, PluginZoneConf& regPluginZoneConf); + + //! Remove from db plugins no longer detected + void cleanupPlugins(); + + private: + + //! All available detectors. + DetectorsList m_Detectors; + + //! The monitor id + int m_nMonitorId; + + //! Native detection is enabled + bool m_bIsNativeDetEnabled; + + //! Analyser is enabled + bool m_bIsAnalyserEnabled; + + //! A structure to store a plugin parameter + struct zIdName { + unsigned int zoneId; + string name; + }; + + //! A vector filled with parameters of zones + vector m_vZonesConfig; + + //! A structure to store basic settings of a zone + struct zSetting { + unsigned int id; + string name; + string type; + }; + + //! A vector filled with settings of zones enabled for the monitor + vector m_vMonitorZones; + + //! A map to store the general configuration of registered plugins + map mapRegPluginGenConf; + + //! A map to store the zone configuration of registered plugins + map mapRegPluginZoneConf; };