Avoid using swap to initialize boost:shared_ptr members.
[bpdyndnsd] / src / updater.cpp
1 /** @file
2  * @brief The updater class implementation. This class implements the updater logic.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #include "updater.h"
11
12 #include "serviceholder.h"
13
14
15 #include <boost/foreach.hpp>
16 #include <boost/serialization/export.hpp>
17
18
19 using namespace std;
20
21
22 /**
23  * Default constructor which initializes the member Conf.
24  */
25 Updater::Updater()
26     : IPAddrHelp(new IPAddrHelper)
27 {
28     // Initialize program wide Logger, at this point we don't know where to log and with which loglevel.
29     Log = Logger::Ptr(new Logger);
30
31     // initialize Serviceholder
32     ServiceHolder = Serviceholder::Ptr(new Serviceholder(Log));
33
34     // initialize Config
35     Conf = Config::Ptr(new Config(Log,ServiceHolder));
36 }
37
38
39 /**
40  * Default destructor.
41  */
42 Updater::~Updater()
43 {
44 }
45
46
47
48 /**
49  * Load config and initialize helper classes.
50  * @param argc Number of arguments in array
51  * @param argv Array with cmd options
52  */
53 int Updater::load_config(int argc, char *argv[])
54 {
55     // load the cmd options
56     if ( init_config_from_cmd(argc,argv) != 0 )
57         return -1;
58
59     // load the config and service files
60     if ( init_config_from_files() != 0 )
61         return -1;
62
63     // init all helper classes
64     if ( init_helper_classes() != 0 )
65         return -1;
66
67     return 0;
68 }
69
70
71 /**
72  * Reloading the config. Delete all Service objects and then init new Service objects from config files.
73  */
74 int Updater::reload_config()
75 {
76     // serialize all service objects
77     if ( ServiceHolder->serialize_services() != 0 )
78         return -1;
79
80     // delete all service objects
81     ServiceHolder->delete_services();
82
83     // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options.
84     Conf->delete_variables_map();
85
86     // load only config files
87     if ( init_config_from_files() != 0 )
88         return -1;
89
90     // init all helper classes
91     if ( init_helper_classes() != 0 )
92         return -1;
93
94     return 0;
95 }
96
97
98 /**
99  * Parse the command line arguments and initialize corresponding options.
100  * @param argc Number command line arguments.
101  * @param argv[] Array with arguments.
102  * @return 0 if cmd options successfully parsed, 1 if usage or version.
103  */
104 int Updater::init_config_from_cmd(int argc, char *argv[])
105 {
106     // Load the command line parameters
107     if( Conf->parse_cmd_line( argc, argv) != 0)
108         return -1;
109
110     // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd.
111     init_log_facility();
112
113     // successful parsed
114     Log->print_cmd_parsed();
115     return 0;
116 }
117
118
119 /**
120  * Load the main config and the service definition files in config path.
121  * @return 0 if all is fine, 
122  */
123 int Updater::init_config_from_files()
124 {
125     // Load the main and service config files in config path
126     if ( Conf->load_config_from_files() != 0 )
127         return -1;
128
129     // Re-init log facility, perhaps new config file options for logger are set.
130     // These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught.
131     init_log_facility();
132
133     // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them.
134     if ( ServiceHolder->deserialize_services() != 0 )
135         return -1;
136
137     // successful loaded
138     Log->print_conf_files_parsed();
139     return 0;
140 }
141
142
143 /**
144  * Init all Helper classes
145  * @return 
146  */
147 int Updater::init_helper_classes()
148 {
149     // Initialize IPHelper
150     if ( init_ip_helper() != 0 )
151         return -1;
152
153     return 0;
154 }
155
156
157 /**
158  * Init the IPHelp member with needed values.
159  * @return 0 if all is fine, -1 otherwise.
160  */
161 int Updater::init_ip_helper()
162 {
163     // Try to get deserialized IPAddrHelper from ServiceHolder
164     IPAddrHelper::Ptr _ip_addr_help = ServiceHolder->get_ip_addr_helper();
165     if ( _ip_addr_help.use_count() != 0 )
166     {
167         // Initialize IPHelper
168         IPAddrHelp = IPAddrHelper::Ptr( new IPAddrHelper( Log, Conf->get_webcheck_ip_url(), Conf->get_webcheck_ip_url_alt(), Conf->get_webcheck_interval(), _ip_addr_help->get_last_webcheck(), Conf->get_enable_ipv6(), Conf->get_proxy(), Conf->get_proxy_port() ) );
169     }
170     else
171     {
172         // IPAddrHelper from ServiceHolder was not declared, so init oen with LastWebcheck 0
173         IPAddrHelp = IPAddrHelper::Ptr( new IPAddrHelper( Log, Conf->get_webcheck_ip_url(), Conf->get_webcheck_ip_url_alt(), Conf->get_webcheck_interval(), 0, Conf->get_enable_ipv6(), Conf->get_proxy(), Conf->get_proxy_port() ) );
174     }
175
176     // Put the IPAddrHelper into ServiceHolder, so the LastWebcheck state will be serialized too.
177     ServiceHolder->set_ip_addr_helper(IPAddrHelp);
178
179     return 0;
180 }
181
182
183 /**
184  * Getter for member Config.
185  * @return Member Config.
186  */
187 Config::Ptr Updater::get_config() const
188 {
189     return Conf;
190 }
191
192
193 /**
194  * Getter for member Logger.
195  * @return Member Logger.
196  */
197 Logger::Ptr Updater::get_logger() const
198 {
199     return Log;
200 }
201
202
203 /**
204  * Initialize the logging facility with loglevel and syslog.
205  */
206 void Updater::init_log_facility()
207 {
208     Log->set_log_facility(Conf->get_loglevel(),Conf->get_syslog(),Conf->get_external_warning_log(),Conf->get_external_warning_level());
209     Log->print_init_log_facility();
210 }
211
212
213 /**
214  * Update all configured services.
215  */
216 void Updater::update_services()
217 {
218     // Get all services from the ServiceHolder.
219     list<Service::Ptr> services = ServiceHolder->get_services();
220
221     // Get the actual IP of this host.
222     string ip_host = IPAddrHelp->get_actual_ip();
223
224     if ( !ip_host.empty() )
225     {
226         BOOST_FOREACH(Service::Ptr &service, services )
227         {
228             string ip_last_update = service->get_actual_ip();
229             string hostname = service->get_hostname();
230             int lastupdated = 0;
231             int current_time = time(NULL);
232
233             // Try to get the lastupdated time of the actual service if there is one.
234             if ( service->get_last_updates().size() > 0 )
235                 lastupdated = service->get_last_updates().front();
236
237             Log->print_check_service_update(hostname, current_time, lastupdated);
238
239             // Do a DNS Query for the dynamic hostname.
240             string ip_dns_recheck = IPAddrHelp->dns_query(hostname);
241
242             Log->print_cached_dns_entry(hostname, ip_dns_recheck, ip_last_update, ip_host);
243
244             // Test if the DNS-Record could not be found.
245             if ( ip_dns_recheck.empty() )
246             {
247                 // Next in BOOST_FOREACH
248             }
249             // Test if the actual DNS-Record differs from the host's IP.
250             else if ( ip_host != ip_dns_recheck )
251             {
252                 // Check if the service will be updated for the first time.
253                 if ( lastupdated == 0 )
254                 {
255                     // Update for the firt time.
256                     Log->print_update_service_firttime(hostname, ip_dns_recheck, ip_host);
257                     service->update(ip_host,current_time);
258                 }
259                 else
260                 {
261                     // We already have updated, check if the IP set in last update differs from the actual host's ip.
262                     if ( ip_last_update != ip_host )
263                     {
264                         // Update
265                         Log->print_update_service(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
266                         service->update(ip_host,current_time);
267                     }
268                     else
269                     {
270                         int dns_cache_ttl = service->get_dns_cache_ttl();
271                         // Check if DNS Cache TTL is expired, if so, then update the same IP again.
272                         if ( (lastupdated + dns_cache_ttl) < current_time )
273                         {
274                             // Update
275                             Log->print_update_service_ttl_expired(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
276                             service->update(ip_host,current_time);
277                         }
278                         else
279                         {
280                             // DNS cache TTL isn't expired
281                             Log->print_update_service_ttl_not_expired(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
282                         }
283                     }
284                 }
285             }
286             else
287             {
288                 Log->print_no_update_needed(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
289             }
290         }
291     }
292     else
293     {
294         Log->print_no_wan_ip();
295     }
296 }
297
298
299 /**
300  * Getter for member ServiceHolder.
301  * @return ServiceHolder
302  */
303 Serviceholder::Ptr Updater::get_service_holder() const
304 {
305     return ServiceHolder;
306 }