/** @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.
*
*
*
* @license GPLv2
*/
-#include "serviceholder.h"
+#include "serviceholder.hpp"
+
+#include <fstream>
+
+#include <boost/foreach.hpp>
+#include <boost/filesystem.hpp>
+
+#define OBJECT_FILE "/var/state/bpdyndnsd/bpdyndnsd.state"
using namespace std;
+namespace fs = boost::filesystem;
+
/**
- * Default constructor. Invoked on serialization and deserialization.
+ * Default constructor.
*/
Serviceholder::Serviceholder()
+ :Log(new Logger)
+ ,IPAddrHelp()
+{
+}
+
+
+/**
+ * Constructor with Logger object.
+ */
+Serviceholder::Serviceholder(Logger::Ptr _log)
+ :Log(_log)
+ ,IPAddrHelp()
{
}
/**
- * 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.
+ */
+int Serviceholder::serialize_services() const
+{
+ // Put Services and OldServices into Serviceholder.
+ SerializeServiceContainer::Ptr service_container(new SerializeServiceContainer);
+
+ BOOST_FOREACH(const Service::Ptr &service, Services)
+ {
+ service_container->add_service(service);
+ }
+
+ time_t current_time = time(NULL);
+
+ BOOST_FOREACH(const Service::Ptr &service, OldServices)
+ {
+ if ( !service->get_last_updates().empty() &&
+ ( service->get_last_update_time() + ((time_t)service->get_update_interval()*60) ) >= current_time ) /*lint !e1793 */ // UpdateInterval timeout of service isn't expired.
+ service_container->add_service(service);
+ }
+
+ // Serialize SerializeServiceContainer and IPAddrHelper into file.
+ ofstream ofs(OBJECT_FILE);
+ if ( ofs.is_open() )
+ {
+ SerializeServiceContainer* _service_container = service_container.get();
+ IPAddrHelper* _ip_addr_helper = IPAddrHelp.get();
+ try
+ {
+ boost::archive::text_oarchive oa(ofs);
+ oa << _service_container << _ip_addr_helper;
+ }
+ catch( const 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 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;
+ IPAddrHelper* _ip_addr_helper;
+ try
+ {
+ boost::archive::text_iarchive ia(ifs);
+ ia >> _service_container >> _ip_addr_helper;
+ }
+ catch( const std::exception& e )
+ {
+ // There is a corrupted object file, continue without recovering old Services' state.
+ Log->print_exception_deserialize(e.what());
+ ifs.close();
+ return 0;
+ }
+
+ SerializeServiceContainer::Ptr service_container(_service_container);
+ IPAddrHelp = IPAddrHelper::Ptr(_ip_addr_helper);
+ ifs.close();
+
+ // Get the list of old Services from de-serialized SerializeServiceContainer object.
+ list<Service::Ptr> _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_max_equal_updates_in_succession(), old_service->get_dns_cache_ttl() , old_service->get_actual_ip(), old_service->get_last_updates(), old_service->get_activated());
+ 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());
+ if ( old_service->get_activated() )
+ service->set_activated();
+
+ 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_max_equal_updates_in_succession(), service->get_dns_cache_ttl() , service->get_actual_ip(), service->get_last_updates(), service->get_activated());
+ // 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)
+{
+ 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();
+
+ IPAddrHelp.reset();
+}
+
+
+/**
+ * Getter for member Services
+ * @return List with shared Service pointers.
*/
-template<class Archive>
-void Serviceholder::serialize(Archive & ar, const unsigned int version)
+std::list<Service::Ptr> Serviceholder::get_services() const
{
- ar & Hold_services;
+ return Services;
}
/**
- * Add Service * to internal list.
- * @param service Pointer to Service object.
+ * Set member IPAddrHelp
+ * @param _ip_addr_helper The IPAddrHelper.
*/
-void Serviceholder::add_service(ServicePtr service)
+void Serviceholder::set_ip_addr_helper(IPAddrHelper::Ptr _ip_addr_helper)
{
- Hold_services.push_back(service);
+ IPAddrHelp = _ip_addr_helper;
}
/**
- * Needed after deserialization to get the valid list of Service* back.
- * @return The list of Service*.
+ * Get member IPAddrHelp
+ * @return IPAddrHelp
*/
-std::list<ServicePtr> Serviceholder::get_hold_services()
+IPAddrHelper::Ptr Serviceholder::get_ip_addr_helper() const
{
- return Hold_services;
+ return IPAddrHelp;
}