First steps in fine tuning and improving error handling.
[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 "/var/local/bpdyndnsd/objects.ser"
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()
57 {
58     // Put Services and OldServices into Serviceholder.
59     SerializeServiceContainer::Ptr service_container(new SerializeServiceContainer);
60
61     BOOST_FOREACH(Service::Ptr &service, Services)
62     {
63         service_container->add_service(service);
64     }
65
66     int current_time = time(NULL);
67
68     BOOST_FOREACH(Service::Ptr &service, OldServices)
69     {
70         if ( ( service->get_last_updates().front() + (service->get_update_interval()*60) ) >= current_time )  // 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( 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( 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         IPAddrHelper::Ptr ip_addr_helper(_ip_addr_helper);
140         IPAddrHelp.swap(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 }