Enhanced update logic to respect not activated hostnames. If a hostname could not...
[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(), old_service->get_activated());
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                     if ( old_service->get_activated() )
162                         service->set_activated();
163
164                     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());
165                     // We have adopted the values of the old_service. Just set lastupdated and timeout to 0, so this old_service wont be serialized.
166                     old_service->set_update_interval(0);
167                 }
168             }
169         }
170         Log->print_deserialized_objects_success();
171     }
172     else
173     {
174         Log->print_error_opening_r(OBJECT_FILE);
175         return -1;
176     }
177
178     return 0;
179 }
180
181
182 /**
183  * Add service to internal service list.
184  * @param service Shared pointer to service object.
185  */
186 void Serviceholder::add_service(Service::Ptr service)
187 {
188     Services.push_back(service);
189 }
190
191
192 /**
193  * Resets all shared Service pointers and clears the Services list.
194  */
195 void Serviceholder::delete_services()
196 {
197     BOOST_FOREACH( Service::Ptr &service, Services )
198     {
199         service.reset();
200     }
201     Services.clear();
202
203     BOOST_FOREACH( Service::Ptr &service, OldServices )
204     {
205         service.reset();
206     }
207     OldServices.clear();
208
209     IPAddrHelp.reset();
210 }
211
212
213 /**
214  * Getter for member Services
215  * @return List with shared Service pointers.
216  */
217 std::list<Service::Ptr> Serviceholder::get_services() const
218 {
219     return Services;
220 }
221
222
223 /**
224  * Set member IPAddrHelp
225  * @param _ip_addr_helper The IPAddrHelper.
226  */
227 void Serviceholder::set_ip_addr_helper(IPAddrHelper::Ptr _ip_addr_helper)
228 {
229     IPAddrHelp = _ip_addr_helper;
230 }
231
232
233 /**
234  * Get member IPAddrHelp
235  * @return IPAddrHelp
236  */
237 IPAddrHelper::Ptr Serviceholder::get_ip_addr_helper() const
238 {
239     return IPAddrHelp;
240 }