1eee942dec453851c9001065e8e907dca3f8ee4d
[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_updates().front() + ((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 boost::archive::archive_exception& e )
134         {
135             Log->print_exception_deserialize(e.what());
136             ifs.close();
137             return -1;
138         }
139         SerializeServiceContainer::Ptr service_container(_service_container);
140         IPAddrHelp = IPAddrHelper::Ptr(_ip_addr_helper);
141         ifs.close();
142
143         // Get the list of old Services from de-serialized SerializeServiceContainer object.
144         list<Service::Ptr> _old_services = service_container->get_containing_services();
145
146         // Put all de-serialized Services into OldServices member and
147         // compare new Services (generated from config file and cmd) with old Services (de-serialized from object file)
148         // if identical Service was found, adopt the value from old Service to recover Services' state.
149         BOOST_FOREACH(Service::Ptr &old_service, _old_services)
150         {
151             OldServices.push_back(old_service);
152             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());
153             BOOST_FOREACH(Service::Ptr &service, Services)
154             {
155                 if ( *service == *old_service )
156                 {
157                     service->set_last_updates(old_service->get_last_updates());
158                     service->set_actual_ip(old_service->get_actual_ip());
159                     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());
160                     // We have adopted the values of the old_service. Just set lastupdated and timeout to 0, so this old_service wont be serialized.
161                     old_service->set_update_interval(0);
162                 }
163             }
164         }
165         Log->print_deserialized_objects_success();
166     }
167     else
168     {
169         Log->print_error_opening_r(OBJECT_FILE);
170         return -1;
171     }
172
173     return 0;
174 }
175
176
177 /**
178  * Add service to internal service list.
179  * @param service Shared pointer to service object.
180  */
181 void Serviceholder::add_service(Service::Ptr service)
182 {
183     Services.push_back(service);
184 }
185
186
187 /**
188  * Resets all shared Service pointers and clears the Services list.
189  */
190 void Serviceholder::delete_services()
191 {
192     BOOST_FOREACH( Service::Ptr &service, Services )
193     {
194         service.reset();
195     }
196     Services.clear();
197
198     BOOST_FOREACH( Service::Ptr &service, OldServices )
199     {
200         service.reset();
201     }
202     OldServices.clear();
203
204     IPAddrHelp.reset();
205 }
206
207
208 /**
209  * Getter for member Services
210  * @return List with shared Service pointers.
211  */
212 std::list<Service::Ptr> Serviceholder::get_services() const
213 {
214     return Services;
215 }
216
217
218 /**
219  * Set member IPAddrHelp
220  * @param _ip_addr_helper The IPAddrHelper.
221  */
222 void Serviceholder::set_ip_addr_helper(IPAddrHelper::Ptr _ip_addr_helper)
223 {
224     IPAddrHelp = _ip_addr_helper;
225 }
226
227
228 /**
229  * Get member IPAddrHelp
230  * @return IPAddrHelp
231  */
232 IPAddrHelper::Ptr Serviceholder::get_ip_addr_helper() const
233 {
234     return IPAddrHelp;
235 }