ed4efe083f60d4fe3cce7c021032e755d3b79c86
[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().front() + ((time_t)service->get_update_interval()*60) ) >= current_time )  /*lint !e1793 */ // UpdateInterval timeout of service isn't expired.
71             service_container->add_service(service);
72     }
73
74     // Serialize SerializeServiceContainer and IPAddrHelper into file.
75     ofstream ofs(OBJECT_FILE);
76     if ( ofs.is_open() )
77     {
78         SerializeServiceContainer* _service_container = service_container.get();
79         IPAddrHelper* _ip_addr_helper = IPAddrHelp.get();
80         try
81         {
82             boost::archive::text_oarchive oa(ofs);
83             oa << _service_container << _ip_addr_helper;
84         }
85         catch( const boost::archive::archive_exception& e )
86         {
87             Log->print_exception_serialize(e.what());
88             ofs.close();
89             return -1;
90         }
91
92         ofs.close();
93     }
94     else
95     {
96         Log->print_error_opening_rw(OBJECT_FILE);
97         return -1;
98     }
99
100     Log->print_serialized_objects_success();
101
102     return 0;
103 }
104
105
106 /**
107  * This function de-serializes the SerializeServiceContainer (containing Services) from the object file.
108  * @return 0 if all is fine, -1 if object file couldn't be opened for reading or error while de-serializing.
109  */
110 int Serviceholder::deserialize_services()
111 {
112     // test if OBJECT_FILE exists
113     fs::path object_file = fs::system_complete(fs::path(OBJECT_FILE));
114     if ( !fs::exists(object_file) )
115     {
116         // There is no object file, possibly first program start, continue without recovering old Services' state.
117         Log->print_no_object_file(OBJECT_FILE);
118         return 0;
119     }
120
121     ifstream ifs(OBJECT_FILE);
122     if ( ifs.is_open() )
123     {
124         // deserialize SerializeServiceContainer
125         SerializeServiceContainer* _service_container;
126         IPAddrHelper* _ip_addr_helper;
127         try
128         {
129             boost::archive::text_iarchive ia(ifs);
130             ia >> _service_container >> _ip_addr_helper;
131         }
132         catch( const boost::archive::archive_exception& e )
133         {
134             Log->print_exception_deserialize(e.what());
135             ifs.close();
136             return -1;
137         }
138         SerializeServiceContainer::Ptr service_container(_service_container);
139         IPAddrHelp = IPAddrHelper::Ptr(_ip_addr_helper);
140         ifs.close();
141
142         // Get the list of old Services from de-serialized SerializeServiceContainer object.
143         list<Service::Ptr> _old_services = service_container->get_containing_services();
144
145         // Put all de-serialized Services into OldServices member and
146         // compare new Services (generated from config file and cmd) with old Services (de-serialized from object file)
147         // if identical Service was found, adopt the value from old Service to recover Services' state.
148         BOOST_FOREACH(Service::Ptr &old_service, _old_services)
149         {
150             OldServices.push_back(old_service);
151             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());
152             BOOST_FOREACH(Service::Ptr &service, Services)
153             {
154                 if ( *service == *old_service )
155                 {
156                     service->set_last_updates(old_service->get_last_updates());
157                     service->set_actual_ip(old_service->get_actual_ip());
158                     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());
159                     // We have adopted the values of the old_service. Just set lastupdated and timeout to 0, so this old_service wont be serialized.
160                     old_service->set_update_interval(0);
161                 }
162             }
163         }
164         Log->print_deserialized_objects_success();
165     }
166     else
167     {
168         Log->print_error_opening_r(OBJECT_FILE);
169         return -1;
170     }
171
172     return 0;
173 }
174
175
176 /**
177  * Add service to internal service list.
178  * @param service Shared pointer to service object.
179  */
180 void Serviceholder::add_service(Service::Ptr service)
181 {
182     Services.push_back(service);
183 }
184
185
186 /**
187  * Resets all shared Service pointers and clears the Services list.
188  */
189 void Serviceholder::delete_services()
190 {
191     BOOST_FOREACH( Service::Ptr &service, Services )
192     {
193         service.reset();
194     }
195     Services.clear();
196
197     BOOST_FOREACH( Service::Ptr &service, OldServices )
198     {
199         service.reset();
200     }
201     OldServices.clear();
202
203     IPAddrHelp.reset();
204 }
205
206
207 /**
208  * Getter for member Services
209  * @return List with shared Service pointers.
210  */
211 std::list<Service::Ptr> Serviceholder::get_services() const
212 {
213     return Services;
214 }
215
216
217 /**
218  * Set member IPAddrHelp
219  * @param _ip_addr_helper The IPAddrHelper.
220  */
221 void Serviceholder::set_ip_addr_helper(IPAddrHelper::Ptr _ip_addr_helper)
222 {
223     IPAddrHelp = _ip_addr_helper;
224 }
225
226
227 /**
228  * Get member IPAddrHelp
229  * @return IPAddrHelp
230  */
231 IPAddrHelper::Ptr Serviceholder::get_ip_addr_helper() const
232 {
233     return IPAddrHelp;
234 }