028a152f065f179776c347521169054744698423
[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.hpp"
11
12 #include "serviceholder.hpp"
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     // clear the external send messages.
87     Log->clear_external_send_messages();
88
89     // load only config files
90     if ( init_config_from_files() != 0 )
91         return -1;
92
93     // init all helper classes
94     if ( init_helper_classes() != 0 )
95         return -1;
96
97     return 0;
98 }
99
100
101 /**
102  * Parse the command line arguments and initialize corresponding options.
103  * @param argc Number command line arguments.
104  * @param argv[] Array with arguments.
105  * @return 0 if cmd options successfully parsed, 1 if usage or version.
106  */
107 int Updater::init_config_from_cmd(int argc, char *argv[]) const
108 {
109     // Load the command line parameters
110     if( Conf->parse_cmd_line( argc, argv) != 0)
111         return -1;
112
113     // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd.
114     init_log_facility();
115
116     // successful parsed
117     Log->print_cmd_parsed();
118     return 0;
119 }
120
121
122 /**
123  * Load the main config and the service definition files in config path.
124  * @return 0 if all is fine,
125  */
126 int Updater::init_config_from_files() const
127 {
128     // Load the main and service config files in config path
129     if ( Conf->load_config_from_files() != 0 )
130         return -1;
131
132     // Re-init log facility, perhaps new config file options for logger are set.
133     // These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught.
134     init_log_facility();
135
136     // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them.
137     if ( ServiceHolder->deserialize_services() != 0 )
138         return -1;
139
140     // successful loaded
141     Log->print_conf_files_parsed();
142     return 0;
143 }
144
145
146 /**
147  * Init all Helper classes
148  * @return
149  */
150 int Updater::init_helper_classes()
151 {
152     // Initialize IPHelper
153     if ( init_ip_helper() != 0 )
154         return -1;
155
156     return 0;
157 }
158
159
160 /**
161  * Init the IPHelp member with needed values.
162  * @return 0 if all is fine, -1 otherwise.
163  */
164 int Updater::init_ip_helper()
165 {
166     // Try to get deserialized IPAddrHelper from ServiceHolder
167     IPAddrHelper::Ptr _ip_addr_help = ServiceHolder->get_ip_addr_helper();
168     if ( _ip_addr_help.use_count() != 0 )
169     {
170         // Initialize IPHelper
171         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() ) );
172     }
173     else
174     {
175         // IPAddrHelper from ServiceHolder was not declared, so init oen with LastWebcheck 0
176         IPAddrHelp = IPAddrHelper::Ptr( new IPAddrHelper( Log, Conf->get_webcheck_ip_url(), Conf->get_webcheck_ip_url_alt(), Conf->get_webcheck_interval(), (size_t)0, Conf->get_enable_ipv6(), Conf->get_proxy(), Conf->get_proxy_port() ) );
177     }
178
179     // Put the IPAddrHelper into ServiceHolder, so the LastWebcheck state will be serialized too.
180     ServiceHolder->set_ip_addr_helper(IPAddrHelp);
181
182     return 0;
183 }
184
185
186 /**
187  * Getter for member Config.
188  * @return Member Config.
189  */
190 Config::Ptr Updater::get_config() const
191 {
192     return Conf;
193 }
194
195
196 /**
197  * Getter for member Logger.
198  * @return Member Logger.
199  */
200 Logger::Ptr Updater::get_logger() const
201 {
202     return Log;
203 }
204
205
206 /**
207  * Initialize the logging facility with loglevel and syslog.
208  */
209 void Updater::init_log_facility() const
210 {
211     Log->set_log_facility(Conf->get_loglevel(),Conf->get_syslog(),Conf->get_external_warning_log(),Conf->get_external_warning_level(),Conf->get_external_log_only_once());
212     Log->print_init_log_facility();
213 }
214
215
216 /**
217  * Update all configured services.
218  * @param changed_to_online True if we just changed to online, false if we were already online
219  */
220 void Updater::update_services(bool changed_to_online) const
221 {
222     // Get all services from the ServiceHolder.
223     list<Service::Ptr> services = ServiceHolder->get_services();
224
225     // Get the actual IP of this host.
226     string ip_host = IPAddrHelp->get_actual_ip(Conf->get_webcheck_enabled());
227     if ( ip_host.empty() )
228     {
229         Log->print_no_wan_ip();
230         return;
231     }
232
233     BOOST_FOREACH(Service::Ptr &service, services )
234     {
235         string ip_last_update = service->get_actual_ip();
236         string hostname = service->get_hostname();
237         time_t lastupdated = 0;
238         time_t current_time = time(NULL);
239
240         // Try to get the lastupdated time of the actual service if there is one.
241         if ( service->get_last_updates().size() > 0 )
242             lastupdated = service->get_last_updates().front(); /*lint !e1793 */
243
244         Log->print_check_service_update(hostname, current_time, lastupdated);
245
246         // Do a DNS Query for the dynamic hostname.
247         string ip_dns_recheck = IPAddrHelp->dns_query(hostname);
248
249         Log->print_cached_dns_entry(hostname, ip_dns_recheck, ip_last_update, ip_host);
250
251         // Test if the DNS-Record could not be found.
252         if ( ip_dns_recheck.empty() )
253             continue;
254
255         // Test if the actual DNS-Record differs from the host's IP.
256         if (ip_host == ip_dns_recheck )
257         {
258             Log->print_no_update_needed(changed_to_online, hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
259             // No update needed
260             continue;
261         }
262
263         // Check if the IP set in last update differs from the actual host's ip.
264         if ( ip_last_update != ip_host )
265         {
266             // Update
267             Log->print_update_service(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
268             service->update(ip_host,current_time);
269         }
270         else
271         {
272             int dns_cache_ttl = service->get_dns_cache_ttl();
273             // Check if DNS Cache TTL is expired, if so, then update the same IP again.
274             if ( (lastupdated + dns_cache_ttl) < current_time )
275             {
276                 // Update
277                 Log->print_update_service_ttl_expired(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
278                 service->update(ip_host,current_time);
279             }
280             else
281             {
282                 // DNS cache TTL isn't expired
283                 Log->print_update_service_ttl_not_expired(changed_to_online, hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
284             }
285         }
286     }
287 }
288
289
290 /**
291  * Getter for member ServiceHolder.
292  * @return ServiceHolder
293  */
294 Serviceholder::Ptr Updater::get_service_holder() const
295 {
296     return ServiceHolder;
297 }