From e0080b7874f4cde1e41d12621726dd88fc40d7a3 Mon Sep 17 00:00:00 2001 From: Bjoern Sikora Date: Tue, 18 Aug 2009 14:37:35 +0200 Subject: [PATCH] First steps in redesign: - Config is loading config only and holding configuration members - Updater is the gateway between all classes - Serviceholder from now on holds Services and OldServices and is responsible for serialization and deserialization - SerializeServiceContainer adopted the operations from Serviceholder and is only familiar to Serviceholder --- src/config.cpp | 183 +++---------------------------------- src/config.h | 21 +--- src/main.cpp | 6 +- src/serializeservicecontainer.cpp | 45 +++++++++ src/serializeservicecontainer.h | 46 +++++++++ src/serviceholder.cpp | 171 +++++++++++++++++++++++++++++++---- src/serviceholder.h | 22 +++-- src/updater.cpp | 38 +++++++- src/updater.h | 8 +- 9 files changed, 318 insertions(+), 222 deletions(-) create mode 100644 src/serializeservicecontainer.cpp create mode 100644 src/serializeservicecontainer.h diff --git a/src/config.cpp b/src/config.cpp index f6e2290..64b950d 100644 --- a/src/config.cpp +++ b/src/config.cpp @@ -9,7 +9,6 @@ #include "config.h" -#include "serviceholder.h" #include "dhs.h" #include "ods.h" @@ -20,16 +19,9 @@ #include #include #include -#include -#include -#include -#include -#include #include -// Following boost macros are needed for serialization of derived classes through a base class pointer (Service *). -BOOST_CLASS_EXPORT_GUID(ODS, "ODS") -BOOST_CLASS_EXPORT_GUID(DHS, "DHS") + namespace po = boost::program_options; namespace fs = boost::filesystem; @@ -40,19 +32,19 @@ using namespace std; /** * Default Constructor. Available command line and config file options with their default values are defined here. */ -Config::Config(Logger::Ptr _log) - : Log(new Logger) - , DaemonMode(false) - , Loglevel(0) +Config::Config(Logger::Ptr _log, Serviceholder::Ptr _serviceholder) + : DaemonMode(false) , Syslog(false) - , ConfigPath("/etc/bpdyndnsd") , EnableIPv6(false) - , WebcheckIpUrl("") - , WebcheckIpUrlAlt("") + , Loglevel(0) + , ConfigPath("/etc/bpdyndnsd") { // initialize Logger Log = _log; + // initialize Serviceholder + ServiceHolder = _serviceholder; + // Available service description config options po::options_description opt_desc_service("Service description options"); opt_desc_service.add_options() @@ -114,127 +106,6 @@ Config::~Config() /** - * This function serializes all Service objects in Services and OldServices (where the update Timeout isn't expired) into a specified file. - * @return 0 if all is fine, -1 if output file could not be opened for reading or error while serializing. - */ -int Config::serialize_services() -{ - // Put Services and OldServices into Serviceholder. - Serviceholder::Ptr service_holder(new Serviceholder()); - - BOOST_FOREACH(Service::Ptr &service, Services) - { - service_holder->add_service(service); - } - - int current_time = time(NULL); - - BOOST_FOREACH(Service::Ptr &service, OldServices) - { - if ( ( service->get_last_updates()->front() + (service->get_update_interval()*60) ) >= current_time ) // UpdateInterval timeout of service isn't expired. - service_holder->add_service(service); - } - - // Serialize Serviceholder into file. - ofstream ofs(OBJECT_FILE); - if ( ofs.is_open() ) - { - Serviceholder* _service_holder = service_holder.get(); - try - { - boost::archive::text_oarchive oa(ofs); - oa << _service_holder; - } - catch( boost::archive::archive_exception e ) - { - Log->print_exception_serialize(e.what()); - ofs.close(); - return -1; - } - - ofs.close(); - } - else - { - Log->print_error_opening_rw(OBJECT_FILE); - return -1; - } - - Log->print_serialized_objects_success(); - - return 0; -} - - -/** - * This function de-serializes the Serviceholder (containing Services) from the object file. - * @return 0 if all is fine, -1 if object file couldn't be opened for reading or error while de-serializing. - */ -int Config::deserialize_services() -{ - // test if OBJECT_FILE exists - fs::path object_file = fs::system_complete(fs::path(OBJECT_FILE)); - if ( !fs::exists(object_file) ) - { - // There is no object file, possibly first program start, continue without recovering old Services' state. - Log->print_no_object_file(OBJECT_FILE); - return 0; - } - - ifstream ifs(OBJECT_FILE); - if ( ifs.is_open() ) - { - // deserialize Serviceholder - Serviceholder* _service_holder; - try - { - boost::archive::text_iarchive ia(ifs); - ia >> _service_holder; // ends up in default constructor call for Serviceholder - } - catch( boost::archive::archive_exception e ) - { - Log->print_exception_deserialize(e.what()); - ifs.close(); - return -1; - } - Serviceholder::Ptr service_holder(_service_holder); - ifs.close(); - - // Get the list of old Services from de-serialized Serviceholder object. - list _old_services = service_holder->get_hold_services(); - - // Put all de-serialized Services into OldServices member and - // compare new Services (generated from config file and cmd) with old Services (de-serialized from object file) - // if identical Service was found, adopt the value from old Service to recover Services' state. - BOOST_FOREACH(Service::Ptr &old_service, _old_services) - { - OldServices.push_back(old_service); - Log->print_service_object("Deserialized following Service object:", old_service->get_protocol(), old_service->get_hostname(), old_service->get_login() ,old_service->get_password(), old_service->get_update_interval(), old_service->get_max_updates_within_interval(), old_service->get_actual_ip(), old_service->get_last_updates()); - BOOST_FOREACH(Service::Ptr &service, Services) - { - if ( *service == *old_service ) - { - service->set_last_updates(old_service->get_last_updates()); - service->set_actual_ip(old_service->get_actual_ip()); - Log->print_service_object("New Service object with adopted values:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_actual_ip(), service->get_last_updates()); - // We have adopted the values of the old_service. Just set lastupdated and timeout to 0, so this old_service wont be serialized. - old_service->set_update_interval(0); - } - } - } - Log->print_deserialized_objects_success(); - } - else - { - Log->print_error_opening_r(OBJECT_FILE); - return -1; - } - - return 0; -} - - -/** * Parses the command line arguments and does the needed actions. * @param argc Command line argument number given to main. * @param argv[] Pointer to command line argument array given to main. @@ -279,7 +150,10 @@ int Config::parse_cmd_line(int argc, char *argv[]) Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval); if ( service ) - Services.push_back(service); + { + ServiceHolder->add_service(service); + Log->print_service_object("New Service object from command line options:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_actual_ip(), service->get_last_updates()); + } else return -1; } @@ -406,9 +280,11 @@ int Config::load_service_config_file(const string& full_filename) Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval); if ( service ) { - Services.push_back(service); + ServiceHolder->add_service(service); Log->print_service_object("New Service object from config:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_actual_ip(), service->get_last_updates()); } + else + return -1; } } catch ( po::unknown_option e ) @@ -526,16 +402,6 @@ int Config::load_config_from_files() /** - * Getter method for Service list member. - * @return Pointer to a list of Service's. - */ -list Config::get_services() const -{ - return this->Services; -} - - -/** * Getter method for member OptDescCmd. * @return options_description*. */ @@ -586,25 +452,6 @@ bool Config::get_daemon_mode() const /** - * Resets all shared Service pointers and clears the Services list. - */ -void Config::delete_services() -{ - BOOST_FOREACH( Service::Ptr &service, Services ) - { - service.reset(); - } - Services.clear(); - - BOOST_FOREACH( Service::Ptr &service, OldServices ) - { - service.reset(); - } - OldServices.clear(); -} - - -/** * Deletes the map with the previously parsed options. * This is needed in case we reload the config and don't want the old cmd options to overwrite new config file options. */ diff --git a/src/config.h b/src/config.h index 496d6fc..aecb0f8 100644 --- a/src/config.h +++ b/src/config.h @@ -12,8 +12,8 @@ #include -#include "service.h" #include "logger.h" +#include "serviceholder.h" #include #include @@ -28,19 +28,16 @@ private: Options_descriptionPtr OptDescCmd; Options_descriptionPtr OptDescConfMain; Options_descriptionPtr OptDescConfService; - boost::program_options::variables_map VariablesMap; - std::list Services; // Represents all active Services. - std::list OldServices; // Represents all old Services where the timeout isn't expired (in case the same Service is redefined). - Logger::Ptr Log; + Serviceholder::Ptr ServiceHolder; bool DaemonMode; - int Loglevel; bool Syslog; - std::string ConfigPath; bool EnableIPv6; + int Loglevel; + std::string ConfigPath; std::string WebcheckIpUrl; std::string WebcheckIpUrlAlt; @@ -53,20 +50,14 @@ public: typedef boost::shared_ptr Ptr; - Config(Logger::Ptr); + Config(Logger::Ptr, Serviceholder::Ptr); ~Config(); - int serialize_services(); - - int deserialize_services(); - int parse_cmd_line(int, char **); int load_config_from_files(); - std::list get_services() const; - Options_descriptionPtr get_opt_desc_cmd() const; Options_descriptionPtr get_opt_desc_conf_main() const; @@ -75,8 +66,6 @@ public: bool get_daemon_mode() const; - void delete_services(); - int get_loglevel() const; bool get_syslog() const; diff --git a/src/main.cpp b/src/main.cpp index cd64293..3f8d16a 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -36,6 +36,7 @@ #include "serviceholder.cpp" #include "updater.cpp" #include "iphelper.cpp" +#include "serializeservicecontainer.cpp" using namespace std; @@ -104,7 +105,7 @@ void terminate(int param) // unfortunately we can't call serialize_services in any destructor // cause some singleton are already destroyed !?! - if ( updater->get_config()->serialize_services() != 0 ) + if ( updater->get_service_holder()->serialize_services() != 0 ) { updater.reset(); exit(-1); @@ -141,6 +142,7 @@ void reload_config(int param) /** * Initialize the signals we handle. + * @return 0 if all is fine, -1 on error. */ int init_signals() { @@ -263,7 +265,7 @@ int main(int argc, char *argv[]) // Serialize services to save their actual state. - if ( updater->get_config()->serialize_services() != 0 ) + if ( updater->get_service_holder()->serialize_services() != 0 ) return -1; return 0; diff --git a/src/serializeservicecontainer.cpp b/src/serializeservicecontainer.cpp new file mode 100644 index 0000000..8366a3b --- /dev/null +++ b/src/serializeservicecontainer.cpp @@ -0,0 +1,45 @@ +/** @file + * @brief SerializeServiceContainer class implementation. This class contains Service objects in a list for serialization. + * + * + * + * @copyright Intra2net AG + * @license GPLv2 +*/ + +#include "serializeservicecontainer.h" + +#include + +SerializeServiceContainer::SerializeServiceContainer() +{ +} + + +SerializeServiceContainer::~SerializeServiceContainer() +{ +} + +/** + * Serialize function needed by boost/serialization to define which members should be stored as the object state. + * In this case the STL list of Service pointers will be serialized. + * @param ar Archive + * @param version Version + */ +template +void SerializeServiceContainer::serialize(Archive & ar, const unsigned int version) +{ + ar & ContainingServices; +} + + +void SerializeServiceContainer::add_service(Service::Ptr service) +{ + ContainingServices.push_back(service); +} + + +std::list SerializeServiceContainer::get_containing_services() const +{ + return ContainingServices; +} diff --git a/src/serializeservicecontainer.h b/src/serializeservicecontainer.h new file mode 100644 index 0000000..4c3747e --- /dev/null +++ b/src/serializeservicecontainer.h @@ -0,0 +1,46 @@ +/** @file + * @brief SerializeServiceContainer class header. This class holds Service objects in a list for serialization. + * + * + * + * @copyright Intra2net AG + * @license GPLv2 +*/ + +#ifndef SERIALIZESERVICECONTAINER_H +#define SERIALIZESERVICECONTAINER_H + +#include + +#include "service.h" +#include "logger.h" + +#include +#include + +class SerializeServiceContainer +{ + +private: + + std::list ContainingServices; + + friend class boost::serialization::access; + template + void serialize(Archive &, const unsigned int); + +public: + + typedef boost::shared_ptr Ptr; + + SerializeServiceContainer(); + + ~SerializeServiceContainer(); + + void add_service(Service::Ptr service); + + std::list get_containing_services() const; + +}; + +#endif diff --git a/src/serviceholder.cpp b/src/serviceholder.cpp index a4bc90f..d45b211 100644 --- a/src/serviceholder.cpp +++ b/src/serviceholder.cpp @@ -1,5 +1,5 @@ /** @file - * @brief Serviceholder class implementation. This class holds Service objects in a list for serialization. + * @brief Serviceholder class implementation. This class holds Service and OldService lists. * * * @@ -9,16 +9,24 @@ #include "serviceholder.h" -#include +#include "serializeservicecontainer.h" + +#include +#include +#include +#include +#include +#include using namespace std; /** - * Default constructor. Invoked on serialization and deserialization. + * Default constructor with Logger object. */ -Serviceholder::Serviceholder() +Serviceholder::Serviceholder(Logger::Ptr _log) { + Log = _log; } @@ -31,33 +39,160 @@ Serviceholder::~Serviceholder() /** - * Serialize function needed by boost/serialization to define which members should be stored as the object state. - * In this case the STL list of Service pointers will be serialized. - * @param ar Archive - * @param version Version + * This function serializes all Service objects in Services and OldServices (where the update Timeout isn't expired) into a specified file. + * @return 0 if all is fine, -1 if output file could not be opened for reading or error while serializing. */ -template -void Serviceholder::serialize(Archive & ar, const unsigned int version) +int Serviceholder::serialize_services() { - ar & HoldServices; + // Put Services and OldServices into Serviceholder. + SerializeServiceContainer::Ptr service_container(new SerializeServiceContainer); + + BOOST_FOREACH(Service::Ptr &service, Services) + { + service_container->add_service(service); + } + + int current_time = time(NULL); + + BOOST_FOREACH(Service::Ptr &service, OldServices) + { + if ( ( service->get_last_updates()->front() + (service->get_update_interval()*60) ) >= current_time ) // UpdateInterval timeout of service isn't expired. + service_container->add_service(service); + } + + // Serialize Serviceholder into file. + ofstream ofs(OBJECT_FILE); + if ( ofs.is_open() ) + { + SerializeServiceContainer* _service_container = service_container.get(); + try + { + boost::archive::text_oarchive oa(ofs); + oa << _service_container; + } + catch( boost::archive::archive_exception e ) + { + Log->print_exception_serialize(e.what()); + ofs.close(); + return -1; + } + + ofs.close(); + } + else + { + Log->print_error_opening_rw(OBJECT_FILE); + return -1; + } + + Log->print_serialized_objects_success(); + + return 0; } /** - * Add Service * to internal list. - * @param service Pointer to Service object. + * This function de-serializes the SerializeServiceContainer (containing Services) from the object file. + * @return 0 if all is fine, -1 if object file couldn't be opened for reading or error while de-serializing. + */ +int Serviceholder::deserialize_services() +{ + // test if OBJECT_FILE exists + fs::path object_file = fs::system_complete(fs::path(OBJECT_FILE)); + if ( !fs::exists(object_file) ) + { + // There is no object file, possibly first program start, continue without recovering old Services' state. + Log->print_no_object_file(OBJECT_FILE); + return 0; + } + + ifstream ifs(OBJECT_FILE); + if ( ifs.is_open() ) + { + // deserialize SerializeServiceContainer + SerializeServiceContainer* _service_container; + try + { + boost::archive::text_iarchive ia(ifs); + ia >> _service_container; + } + catch( boost::archive::archive_exception e ) + { + Log->print_exception_deserialize(e.what()); + ifs.close(); + return -1; + } + SerializeServiceContainer::Ptr service_container(_service_container); + ifs.close(); + + // Get the list of old Services from de-serialized SerializeServiceContainer object. + list _old_services = service_container->get_containing_services(); + + // Put all de-serialized Services into OldServices member and + // compare new Services (generated from config file and cmd) with old Services (de-serialized from object file) + // if identical Service was found, adopt the value from old Service to recover Services' state. + BOOST_FOREACH(Service::Ptr &old_service, _old_services) + { + OldServices.push_back(old_service); + Log->print_service_object("Deserialized following Service object:", old_service->get_protocol(), old_service->get_hostname(), old_service->get_login() ,old_service->get_password(), old_service->get_update_interval(), old_service->get_max_updates_within_interval(), old_service->get_actual_ip(), old_service->get_last_updates()); + BOOST_FOREACH(Service::Ptr &service, Services) + { + if ( *service == *old_service ) + { + service->set_last_updates(old_service->get_last_updates()); + service->set_actual_ip(old_service->get_actual_ip()); + Log->print_service_object("New Service object with adopted values:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_actual_ip(), service->get_last_updates()); + // We have adopted the values of the old_service. Just set lastupdated and timeout to 0, so this old_service wont be serialized. + old_service->set_update_interval(0); + } + } + } + Log->print_deserialized_objects_success(); + } + else + { + Log->print_error_opening_r(OBJECT_FILE); + return -1; + } + + return 0; +} + + +/** + * Add service to internal service list. + * @param service Shared pointer to service object. */ void Serviceholder::add_service(Service::Ptr service) { - HoldServices.push_back(service); + Services.push_back(service); +} + + +/** + * Resets all shared Service pointers and clears the Services list. + */ +void Serviceholder::delete_services() +{ + BOOST_FOREACH( Service::Ptr &service, Services ) + { + service.reset(); + } + Services.clear(); + + BOOST_FOREACH( Service::Ptr &service, OldServices ) + { + service.reset(); + } + OldServices.clear(); } /** - * Needed after deserialization to get the valid list of Service* back. - * @return The list of Service*. + * Getter for member Services + * @return List with shared Service pointers. */ -std::list Serviceholder::get_hold_services() const +std::list Serviceholder::get_services() const { - return HoldServices; + return Services; } diff --git a/src/serviceholder.h b/src/serviceholder.h index d938b4a..f37592f 100644 --- a/src/serviceholder.h +++ b/src/serviceholder.h @@ -1,5 +1,5 @@ /** @file - * @brief Serviceholder class header. This class holds Service objects in a list for serialization. + * @brief Serviceholder class header. This class holds Service and OldService lists. * * * @@ -15,7 +15,6 @@ #include "service.h" #include "logger.h" -#include #include class Serviceholder @@ -23,25 +22,28 @@ class Serviceholder private: - std::list HoldServices; + Logger::Ptr Log; - friend class boost::serialization::access; - template - void serialize(Archive &, const unsigned int); + std::list OldServices; // Represents all old Services where the timeout isn't expired (in case the same Service is redefined). + std::list Services; // Represents all active Services. public: typedef boost::shared_ptr Ptr; - Serviceholder(); - Serviceholder(Logger::Ptr); ~Serviceholder(); - void add_service(Service::Ptr); + void add_service(Service::Ptr service); + + int deserialize_services(); + + int serialize_services(); + + void delete_services(); - std::list get_hold_services() const; + std::list get_services() const; }; #endif diff --git a/src/updater.cpp b/src/updater.cpp index a11d568..5ca26cf 100644 --- a/src/updater.cpp +++ b/src/updater.cpp @@ -9,8 +9,19 @@ #include "updater.h" +#include "serviceholder.h" +#include "dhs.h" +#include "ods.h" + #include + +// Following boost macros are needed for serialization of derived classes through a base class pointer (Service *). +BOOST_CLASS_EXPORT_GUID(ODS, "ODS") +BOOST_CLASS_EXPORT_GUID(DHS, "DHS") + +namespace fs = boost::filesystem; + using namespace std; /** @@ -24,8 +35,13 @@ Updater::Updater() Log = _log; _log.reset(); + // initialize Serviceholder + Serviceholder::Ptr _serviceholder(new Serviceholder(Log)); + ServiceHolder = _serviceholder; + _serviceholder.reset(); + // initialize Config - Config::Ptr _config(new Config(Log)); + Config::Ptr _config(new Config(Log,ServiceHolder)); Conf = _config; _config.reset(); } @@ -48,7 +64,7 @@ Updater::~Updater() int Updater::init_config_from_cmd(int argc, char *argv[]) { // Load the command line parameters - if( Conf->parse_cmd_line( argc, argv ) != 0) + if( Conf->parse_cmd_line( argc, argv) != 0) return -1; // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd. @@ -75,7 +91,7 @@ int Updater::init_config_from_files() init_log_facility(); // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them. - if ( Conf->deserialize_services() != 0 ) + if ( ServiceHolder->deserialize_services() != 0 ) return -1; // successful loaded @@ -125,11 +141,11 @@ int Updater::init_ip_helper() int Updater::reload_config() { // serialize all service objects - if ( Conf->serialize_services() != 0 ) + if ( ServiceHolder->serialize_services() != 0 ) return -1; // delete all service objects - Conf->delete_services(); + ServiceHolder->delete_services(); // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options. Conf->delete_variables_map(); @@ -157,7 +173,7 @@ void Updater::init_log_facility() */ void Updater::update_services() { - list services = this->Conf->get_services(); + list services = ServiceHolder->get_services(); string ip = IPHelp->get_actual_ip(); @@ -169,3 +185,13 @@ void Updater::update_services() } } } + + +/** + * Getter for member ServiceHolder. + * @return ServiceHolder + */ +Serviceholder::Ptr Updater::get_service_holder() const +{ + return ServiceHolder; +} diff --git a/src/updater.h b/src/updater.h index 0e3bbca..65e86ce 100644 --- a/src/updater.h +++ b/src/updater.h @@ -11,8 +11,9 @@ #define UPDATER_H #include "config.h" -#include "logger.h" #include "iphelper.h" +#include "logger.h" +#include "serviceholder.h" #include @@ -23,8 +24,9 @@ class Updater private: Config::Ptr Conf; - Logger::Ptr Log; IPHelper::Ptr IPHelp; + Logger::Ptr Log; + Serviceholder::Ptr ServiceHolder; public: @@ -44,6 +46,8 @@ public: Logger::Ptr get_logger() const; + Serviceholder::Ptr get_service_holder() const; + int reload_config(); void init_log_facility(); -- 1.7.1