Bugfix: Catch also generic program_options error.
[bpdyndnsd] / src / serviceholder.cpp
1 /** @file
2  * @brief Serviceholder class implementation. This class holds Service and OldService lists.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #include "serviceholder.h"
11
12 #include <fstream>
13
14 #include <boost/foreach.hpp>
15 #include <boost/filesystem.hpp>
16
17 #define OBJECT_FILE "/home/bjoern/intranator/bpdyndnsd/objects.ser"
18
19 using namespace std;
20
21 namespace fs = boost::filesystem;
22
23
24 /**
25  * Default constructor with Logger object.
26  */
27 Serviceholder::Serviceholder(Logger::Ptr _log)
28     :Log(_log)
29 {
30 }
31
32
33 /**
34  * Default destructor. While serializing and deserializing we use boost/shared_ptr, the resources are managed correctly.
35  */
36 Serviceholder::~Serviceholder()
37 {
38 }
39
40
41 /**
42  * This function serializes all Service objects in Services and OldServices (where the update Timeout isn't expired) into a specified file.
43  * @return 0 if all is fine, -1 if output file could not be opened for reading or error while serializing.
44  */
45 int Serviceholder::serialize_services()
46 {
47     // Put Services and OldServices into Serviceholder.
48     SerializeServiceContainer::Ptr service_container(new SerializeServiceContainer);
49
50     BOOST_FOREACH(Service::Ptr &service, Services)
51     {
52         service_container->add_service(service);
53     }
54
55     int current_time = time(NULL);
56
57     BOOST_FOREACH(Service::Ptr &service, OldServices)
58     {
59         if ( ( service->get_last_updates().front() + (service->get_update_interval()*60) ) >= current_time )  // UpdateInterval timeout of service isn't expired.
60             service_container->add_service(service);
61     }
62
63     // Serialize Serviceholder into file.
64     ofstream ofs(OBJECT_FILE);
65     if ( ofs.is_open() )
66     {
67         SerializeServiceContainer* _service_container = service_container.get();
68         try
69         {
70             boost::archive::text_oarchive oa(ofs);
71             oa << _service_container;
72         }
73         catch( boost::archive::archive_exception e )
74         {
75             Log->print_exception_serialize(e.what());
76             ofs.close();
77             return -1;
78         }
79
80         ofs.close();
81     }
82     else
83     {
84         Log->print_error_opening_rw(OBJECT_FILE);
85         return -1;
86     }
87
88     Log->print_serialized_objects_success();
89
90     return 0;
91 }
92
93
94 /**
95  * This function de-serializes the SerializeServiceContainer (containing Services) from the object file.
96  * @return 0 if all is fine, -1 if object file couldn't be opened for reading or error while de-serializing.
97  */
98 int Serviceholder::deserialize_services()
99 {
100     // test if OBJECT_FILE exists
101     fs::path object_file = fs::system_complete(fs::path(OBJECT_FILE));
102     if ( !fs::exists(object_file) )
103     {
104         // There is no object file, possibly first program start, continue without recovering old Services' state.
105         Log->print_no_object_file(OBJECT_FILE);
106         return 0;
107     }
108
109     ifstream ifs(OBJECT_FILE);
110     if ( ifs.is_open() )
111     {
112         // deserialize SerializeServiceContainer
113         SerializeServiceContainer* _service_container;
114         try
115         {
116             boost::archive::text_iarchive ia(ifs);
117             ia >> _service_container;
118         }
119         catch( boost::archive::archive_exception e )
120         {
121             Log->print_exception_deserialize(e.what());
122             ifs.close();
123             return -1;
124         }
125         SerializeServiceContainer::Ptr service_container(_service_container);
126         ifs.close();
127
128         // Get the list of old Services from de-serialized SerializeServiceContainer object.
129         list<Service::Ptr> _old_services = service_container->get_containing_services();
130
131         // Put all de-serialized Services into OldServices member and
132         // compare new Services (generated from config file and cmd) with old Services (de-serialized from object file)
133         // if identical Service was found, adopt the value from old Service to recover Services' state.
134         BOOST_FOREACH(Service::Ptr &old_service, _old_services)
135         {
136             OldServices.push_back(old_service);
137             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_dns_cache_ttl() , old_service->get_actual_ip(), old_service->get_last_updates());
138             BOOST_FOREACH(Service::Ptr &service, Services)
139             {
140                 if ( *service == *old_service )
141                 {
142                     service->set_last_updates(old_service->get_last_updates());
143                     service->set_actual_ip(old_service->get_actual_ip());
144                     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_dns_cache_ttl() , service->get_actual_ip(), service->get_last_updates());
145                     // We have adopted the values of the old_service. Just set lastupdated and timeout to 0, so this old_service wont be serialized.
146                     old_service->set_update_interval(0);
147                 }
148             }
149         }
150         Log->print_deserialized_objects_success();
151     }
152     else
153     {
154         Log->print_error_opening_r(OBJECT_FILE);
155         return -1;
156     }
157
158     return 0;
159 }
160
161
162 /**
163  * Add service to internal service list.
164  * @param service Shared pointer to service object.
165  */
166 void Serviceholder::add_service(Service::Ptr service)
167 {
168     Services.push_back(service);
169 }
170
171
172 /**
173  * Resets all shared Service pointers and clears the Services list.
174  */
175 void Serviceholder::delete_services()
176 {
177     BOOST_FOREACH( Service::Ptr &service, Services )
178     {
179         service.reset();
180     }
181     Services.clear();
182
183     BOOST_FOREACH( Service::Ptr &service, OldServices )
184     {
185         service.reset();
186     }
187     OldServices.clear();
188 }
189
190
191 /**
192  * Getter for member Services
193  * @return List with shared Service pointers.
194  */
195 std::list<Service::Ptr> Serviceholder::get_services() const
196 {
197     return Services;
198 }