Commit | Line | Data |
---|---|---|
b1be615b BS |
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 | ||
4de6a9b8 | 10 | #include "updater.hpp" |
4545a371 | 11 | |
4de6a9b8 | 12 | #include "serviceholder.hpp" |
e0080b78 | 13 | |
e0080b78 | 14 | |
ca5d6889 BS |
15 | #include <boost/foreach.hpp> |
16 | #include <boost/serialization/export.hpp> | |
b30f392d | 17 | |
e0080b78 | 18 | |
8bca3c5d | 19 | using namespace std; |
527536b3 | 20 | |
ca5d6889 | 21 | |
ae0e404f TJ |
22 | /// Server error threshold: When the host IP is not current, the DNS TTL expired |
23 | /// and we already sent an update. | |
24 | const int ServerErrorTTLExpiredThreshold = 15 * 60; | |
25 | ||
26 | ||
b1be615b BS |
27 | /** |
28 | * Default constructor which initializes the member Conf. | |
29 | */ | |
4545a371 | 30 | Updater::Updater() |
ad0e5016 | 31 | : IPAddrHelp(new IPAddrHelper) |
4545a371 | 32 | { |
2e956a36 | 33 | // Initialize program wide Logger, at this point we don't know where to log and with which loglevel. |
c3c84086 | 34 | Log = Logger::Ptr(new Logger); |
4545a371 | 35 | |
e0080b78 | 36 | // initialize Serviceholder |
c3c84086 | 37 | ServiceHolder = Serviceholder::Ptr(new Serviceholder(Log)); |
e0080b78 | 38 | |
254bbf53 | 39 | // initialize Config |
c3c84086 | 40 | Conf = Config::Ptr(new Config(Log,ServiceHolder)); |
4545a371 BS |
41 | } |
42 | ||
527536b3 | 43 | |
b1be615b BS |
44 | /** |
45 | * Default destructor. | |
46 | */ | |
4545a371 BS |
47 | Updater::~Updater() |
48 | { | |
49 | } | |
50 | ||
527536b3 | 51 | |
efbde536 BS |
52 | |
53 | /** | |
54 | * Load config and initialize helper classes. | |
55 | * @param argc Number of arguments in array | |
56 | * @param argv Array with cmd options | |
57 | */ | |
58 | int Updater::load_config(int argc, char *argv[]) | |
59 | { | |
60 | // load the cmd options | |
61 | if ( init_config_from_cmd(argc,argv) != 0 ) | |
62 | return -1; | |
63 | ||
64 | // load the config and service files | |
65 | if ( init_config_from_files() != 0 ) | |
66 | return -1; | |
67 | ||
68 | // init all helper classes | |
69 | if ( init_helper_classes() != 0 ) | |
70 | return -1; | |
71 | ||
72 | return 0; | |
73 | } | |
74 | ||
75 | ||
76 | /** | |
77 | * Reloading the config. Delete all Service objects and then init new Service objects from config files. | |
78 | */ | |
79 | int Updater::reload_config() | |
80 | { | |
81 | // serialize all service objects | |
82 | if ( ServiceHolder->serialize_services() != 0 ) | |
83 | return -1; | |
84 | ||
85 | // delete all service objects | |
86 | ServiceHolder->delete_services(); | |
87 | ||
88 | // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options. | |
89 | Conf->delete_variables_map(); | |
90 | ||
e8787e2e BS |
91 | // clear the external send messages. |
92 | Log->clear_external_send_messages(); | |
93 | ||
efbde536 BS |
94 | // load only config files |
95 | if ( init_config_from_files() != 0 ) | |
96 | return -1; | |
97 | ||
98 | // init all helper classes | |
99 | if ( init_helper_classes() != 0 ) | |
100 | return -1; | |
101 | ||
102 | return 0; | |
103 | } | |
104 | ||
105 | ||
b1be615b | 106 | /** |
254bbf53 BS |
107 | * Parse the command line arguments and initialize corresponding options. |
108 | * @param argc Number command line arguments. | |
109 | * @param argv[] Array with arguments. | |
110 | * @return 0 if cmd options successfully parsed, 1 if usage or version. | |
38060291 | 111 | */ |
08a5a621 | 112 | int Updater::init_config_from_cmd(int argc, char *argv[]) const |
38060291 BS |
113 | { |
114 | // Load the command line parameters | |
e95a6634 | 115 | if( Conf->parse_cmd_line( argc, argv) != 0) |
667c672c | 116 | return -1; |
38060291 | 117 | |
59c8d63c BS |
118 | // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd. |
119 | init_log_facility(); | |
120 | ||
254bbf53 BS |
121 | // successful parsed |
122 | Log->print_cmd_parsed(); | |
38060291 BS |
123 | return 0; |
124 | } | |
125 | ||
126 | ||
127 | /** | |
254bbf53 | 128 | * Load the main config and the service definition files in config path. |
4de6a9b8 | 129 | * @return 0 if all is fine, |
b1be615b | 130 | */ |
08a5a621 | 131 | int Updater::init_config_from_files() const |
4545a371 | 132 | { |
254bbf53 | 133 | // Load the main and service config files in config path |
e95a6634 | 134 | if ( Conf->load_config_from_files() != 0 ) |
667c672c | 135 | return -1; |
4545a371 | 136 | |
59c8d63c BS |
137 | // Re-init log facility, perhaps new config file options for logger are set. |
138 | // These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught. | |
139 | init_log_facility(); | |
140 | ||
27baf279 | 141 | // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them. |
e0080b78 | 142 | if ( ServiceHolder->deserialize_services() != 0 ) |
667c672c | 143 | return -1; |
27baf279 | 144 | |
254bbf53 | 145 | // successful loaded |
667c672c | 146 | Log->print_conf_files_parsed(); |
254bbf53 | 147 | return 0; |
4545a371 BS |
148 | } |
149 | ||
527536b3 | 150 | |
b1be615b | 151 | /** |
efbde536 | 152 | * Init all Helper classes |
4de6a9b8 | 153 | * @return |
3434b35f | 154 | */ |
efbde536 | 155 | int Updater::init_helper_classes() |
3434b35f | 156 | { |
efbde536 BS |
157 | // Initialize IPHelper |
158 | if ( init_ip_helper() != 0 ) | |
159 | return -1; | |
3434b35f | 160 | |
efbde536 | 161 | return 0; |
3434b35f BS |
162 | } |
163 | ||
164 | ||
165 | /** | |
0665b239 BS |
166 | * Init the IPHelp member with needed values. |
167 | * @return 0 if all is fine, -1 otherwise. | |
168 | */ | |
169 | int Updater::init_ip_helper() | |
170 | { | |
20399847 BS |
171 | // Try to get deserialized IPAddrHelper from ServiceHolder |
172 | IPAddrHelper::Ptr _ip_addr_help = ServiceHolder->get_ip_addr_helper(); | |
173 | if ( _ip_addr_help.use_count() != 0 ) | |
174 | { | |
175 | // Initialize IPHelper | |
c3c84086 | 176 | 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() ) ); |
20399847 BS |
177 | } |
178 | else | |
179 | { | |
180 | // IPAddrHelper from ServiceHolder was not declared, so init oen with LastWebcheck 0 | |
08a5a621 | 181 | 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() ) ); |
20399847 BS |
182 | } |
183 | ||
184 | // Put the IPAddrHelper into ServiceHolder, so the LastWebcheck state will be serialized too. | |
185 | ServiceHolder->set_ip_addr_helper(IPAddrHelp); | |
0665b239 BS |
186 | |
187 | return 0; | |
188 | } | |
189 | ||
190 | ||
191 | /** | |
efbde536 BS |
192 | * Getter for member Config. |
193 | * @return Member Config. | |
194 | */ | |
195 | Config::Ptr Updater::get_config() const | |
196 | { | |
197 | return Conf; | |
198 | } | |
667c672c | 199 | |
efbde536 BS |
200 | |
201 | /** | |
202 | * Getter for member Logger. | |
203 | * @return Member Logger. | |
204 | */ | |
205 | Logger::Ptr Updater::get_logger() const | |
206 | { | |
207 | return Log; | |
8bca3c5d BS |
208 | } |
209 | ||
210 | ||
2bc1878a BS |
211 | /** |
212 | * Initialize the logging facility with loglevel and syslog. | |
213 | */ | |
c730deea | 214 | void Updater::init_log_facility() const |
8bca3c5d | 215 | { |
e8787e2e | 216 | 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()); |
8bca3c5d | 217 | Log->print_init_log_facility(); |
c5675c01 BS |
218 | } |
219 | ||
220 | ||
221 | /** | |
b1be615b | 222 | * Update all configured services. |
d55e13a6 | 223 | * @param changed_to_online True if we just changed to online, false if we were already online |
b1be615b | 224 | */ |
d55e13a6 | 225 | void Updater::update_services(bool changed_to_online) const |
4545a371 | 226 | { |
1af7c124 | 227 | // Get all services from the ServiceHolder. |
e0080b78 | 228 | list<Service::Ptr> services = ServiceHolder->get_services(); |
4545a371 | 229 | |
1af7c124 | 230 | // Get the actual IP of this host. |
6114d87c | 231 | string ip_host = IPAddrHelp->get_actual_ip(Conf->get_webcheck_enabled(), changed_to_online, Conf->get_wan_ip_override()); |
a7beeb20 TJ |
232 | if ( ip_host.empty() ) |
233 | { | |
f3141675 | 234 | Log->print_no_wan_ip(changed_to_online); |
a7beeb20 | 235 | return; |
62956d9a TJ |
236 | } else |
237 | { | |
238 | Log->print_external_wan_ip(changed_to_online, ip_host); | |
a7beeb20 | 239 | } |
4545a371 | 240 | |
a7beeb20 | 241 | BOOST_FOREACH(Service::Ptr &service, services ) |
4545a371 | 242 | { |
a7beeb20 TJ |
243 | string ip_last_update = service->get_actual_ip(); |
244 | string hostname = service->get_hostname(); | |
245 | time_t lastupdated = 0; | |
246 | time_t current_time = time(NULL); | |
c3dea5dc | 247 | |
a7beeb20 | 248 | // Try to get the lastupdated time of the actual service if there is one. |
4553e833 BS |
249 | // And check for burnt IP, too. |
250 | std::map<time_t,std::string> last_updates = service->get_last_updates(); /*lint !e1793 */ | |
251 | if ( last_updates.size() > 0 ) | |
252 | { | |
253 | bool ip_burnt = true; | |
4553e833 BS |
254 | int max_equal_updates_in_succession = service->get_max_equal_updates_in_succession(); |
255 | int i = 0; | |
0c0344aa | 256 | for ( std::map<time_t,std::string>::reverse_iterator r_iter = last_updates.rbegin(); (r_iter != last_updates.rend()) && (i < max_equal_updates_in_succession); r_iter++ ) |
4553e833 BS |
257 | { |
258 | if ( i == 0 ) | |
259 | lastupdated = r_iter->first; | |
260 | ||
261 | if ( ip_host != r_iter->second ) | |
262 | { | |
263 | ip_burnt = false; | |
264 | break; | |
265 | } | |
266 | ||
267 | i++; | |
268 | } | |
269 | ||
270 | Log->print_last_updates(ip_host,max_equal_updates_in_succession,last_updates,service->get_hostname()); | |
271 | ||
272 | if ( ip_burnt ) | |
273 | { | |
274 | // IP Address is burnt. Too many updates in succession with the same IP. | |
275 | Log->print_ip_burnt(ip_host,service->get_hostname()); | |
276 | continue; | |
277 | } | |
278 | } | |
c3dea5dc | 279 | |
a7beeb20 | 280 | Log->print_check_service_update(hostname, current_time, lastupdated); |
1af7c124 | 281 | |
a7beeb20 TJ |
282 | // Do a DNS Query for the dynamic hostname. |
283 | string ip_dns_recheck = IPAddrHelp->dns_query(hostname); | |
1af7c124 | 284 | |
a7beeb20 | 285 | Log->print_cached_dns_entry(hostname, ip_dns_recheck, ip_last_update, ip_host); |
1af7c124 | 286 | |
a7beeb20 TJ |
287 | // Test if the DNS-Record could not be found. |
288 | if ( ip_dns_recheck.empty() ) | |
f3141675 TJ |
289 | { |
290 | Log->print_dns_lookup_failed(changed_to_online, hostname); | |
3fdee948 | 291 | continue; |
f3141675 | 292 | } |
3fdee948 TJ |
293 | |
294 | // Test if the actual DNS-Record differs from the host's IP. | |
295 | if (ip_host == ip_dns_recheck ) | |
a7beeb20 | 296 | { |
d55e13a6 | 297 | Log->print_no_update_needed(changed_to_online, hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated); |
de2abebd | 298 | // No update needed |
3fdee948 | 299 | continue; |
a7beeb20 | 300 | } |
3fdee948 | 301 | |
6643431d | 302 | // Check if the IP set in last update differs from the actual host's ip. |
de2abebd TJ |
303 | if ( ip_last_update != ip_host ) |
304 | { | |
305 | // Update | |
306 | Log->print_update_service(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated); | |
0ebcd4ef | 307 | service->update(ip_host, current_time, changed_to_online); |
3fdee948 TJ |
308 | } |
309 | else | |
a7beeb20 | 310 | { |
de2abebd | 311 | int dns_cache_ttl = service->get_dns_cache_ttl(); |
ae0e404f TJ |
312 | |
313 | // Add server error threshold so we don't jam the server with updates for the same IP | |
314 | // in case the server doesn't hand out the already sent IP via DNS | |
315 | // (might indicate a server error). | |
316 | dns_cache_ttl += ServerErrorTTLExpiredThreshold; | |
317 | ||
de2abebd TJ |
318 | // Check if DNS Cache TTL is expired, if so, then update the same IP again. |
319 | if ( (lastupdated + dns_cache_ttl) < current_time ) | |
a7c1e271 | 320 | { |
3fdee948 | 321 | // Update |
de2abebd | 322 | Log->print_update_service_ttl_expired(hostname, ip_dns_recheck, ip_last_update, ip_host, lastupdated, dns_cache_ttl, current_time); |
0ebcd4ef | 323 | service->update(ip_host, current_time, changed_to_online); |
a7c1e271 | 324 | } |
a7beeb20 | 325 | else |
0541cd71 | 326 | { |
de2abebd | 327 | // DNS cache TTL isn't expired |
d55e13a6 | 328 | 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); |
1af7c124 | 329 | } |
3c0cd271 | 330 | } |
1d2e2f56 | 331 | } |
b1be615b | 332 | } |
e0080b78 BS |
333 | |
334 | ||
335 | /** | |
336 | * Getter for member ServiceHolder. | |
337 | * @return ServiceHolder | |
338 | */ | |
339 | Serviceholder::Ptr Updater::get_service_holder() const | |
340 | { | |
341 | return ServiceHolder; | |
342 | } |