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