Fix 'occurred' typo
[bpdyndnsd] / src / serviceholder.cpp
index 4f21ffb..e4041a8 100644 (file)
@@ -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.
  *
  *
  *
@@ -7,17 +7,36 @@
  * @license GPLv2
 */
 
-#include "serviceholder.h"
+#include "serviceholder.hpp"
 
-#include <boost/serialization/list.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()
 {
 }
 
@@ -31,33 +50,191 @@ 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.
+ */
+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.
  */
-template<class Archive>
-void Serviceholder::serialize(Archive & ar, const unsigned int version)
+int Serviceholder::deserialize_services()
 {
-    ar & Hold_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 list.
- * @param service Pointer to Service object.
+ * Add service to internal service list.
+ * @param service Shared pointer to service object.
  */
 void Serviceholder::add_service(Service::Ptr service)
 {
-    Hold_services.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();
+
+    IPAddrHelp.reset();
+}
+
+
+/**
+ * Getter for member Services
+ * @return List with shared Service pointers.
+ */
+std::list<Service::Ptr> Serviceholder::get_services() const
+{
+    return Services;
+}
+
+
+/**
+ * Set member IPAddrHelp
+ * @param _ip_addr_helper The IPAddrHelper.
+ */
+void Serviceholder::set_ip_addr_helper(IPAddrHelper::Ptr _ip_addr_helper)
+{
+    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<Service::Ptr> Serviceholder::get_hold_services()
+IPAddrHelper::Ptr Serviceholder::get_ip_addr_helper() const
 {
-    return Hold_services;
+    return IPAddrHelp;
 }