758bf661298cb8f0b9b10ecc32d4fada36745e80
[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  */
219 void Updater::update_services() const
220 {
221     // Get all services from the ServiceHolder.
222     list<Service::Ptr> services = ServiceHolder->get_services();
223
224     // Get the actual IP of this host.
225     string ip_host = IPAddrHelp->get_actual_ip(Conf->get_webcheck_enabled());
226
227     if ( !ip_host.empty() )
228     {
229         BOOST_FOREACH(Service::Ptr &service, services )
230         {
231             string ip_last_update = service->get_actual_ip();
232             string hostname = service->get_hostname();
233             time_t lastupdated = 0;
234             time_t current_time = time(NULL);
235
236             // Try to get the lastupdated time of the actual service if there is one.
237             if ( service->get_last_updates().size() > 0 )
238                 lastupdated = service->get_last_updates().front(); /*lint !e1793 */
239
240             Log->print_check_service_update(hostname, current_time, lastupdated);
241
242             // Do a DNS Query for the dynamic hostname.
243             string ip_dns_recheck = IPAddrHelp->dns_query(hostname);
244
245             Log->print_cached_dns_entry(hostname, ip_dns_recheck, ip_last_update, ip_host);
246
247             // Test if the DNS-Record could not be found.
248             if ( ip_dns_recheck.empty() )
249             {
250                 // Next in BOOST_FOREACH
251             }
252             // Test if the actual DNS-Record differs from the host's IP.
253             else if ( ip_host != ip_dns_recheck )
254             {
255                 // Check if the service will be updated for the first time.
256                 if ( lastupdated == 0 )
257                 {
258                     // Update for the firt time.
259                     Log->print_update_service_firttime(hostname, ip_dns_recheck, ip_host);
260                     service->update(ip_host,current_time);
261                 }
262                 else
263                 {
264                     // We already have updated, check if the IP set in last update differs from the actual host's ip.
265                     if ( ip_last_update != ip_host )
266                     {
267                         // Update
268                         Log->print_update_service(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
269                         service->update(ip_host,current_time);
270                     }
271                     else
272                     {
273                         int dns_cache_ttl = service->get_dns_cache_ttl();
274                         // Check if DNS Cache TTL is expired, if so, then update the same IP again.
275                         if ( (lastupdated + dns_cache_ttl) < current_time )
276                         {
277                             // Update
278                             Log->print_update_service_ttl_expired(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
279                             service->update(ip_host,current_time);
280                         }
281                         else
282                         {
283                             // DNS cache TTL isn't expired
284                             Log->print_update_service_ttl_not_expired(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time);
285                         }
286                     }
287                 }
288             }
289             else
290             {
291                 Log->print_no_update_needed(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated);
292             }
293         }
294     }
295     else
296     {
297         Log->print_no_wan_ip();
298     }
299 }
300
301
302 /**
303  * Getter for member ServiceHolder.
304  * @return ServiceHolder
305  */
306 Serviceholder::Ptr Updater::get_service_holder() const
307 {
308     return ServiceHolder;
309 }