Fix 'occurred' typo
[bpdyndnsd] / src / service.cpp
CommitLineData
b1be615b 1/** @file
2bc1878a 2 * @brief The abstract service class. This class represents all services.
b1be615b
BS
3 *
4 *
5 *
6 * @copyright Intra2net AG
7 * @license GPLv2
8*/
9
4de6a9b8 10#include "service.hpp"
3c0cd271 11#include <boost/foreach.hpp>
ca5d6889
BS
12
13using namespace std;
14
0f0908e1
TJ
15/// Number of update errors until a service will be blocked
16const int MaxErrorCount = 3;
17/// Number of seconds a service will be blocked if MaxErrorCount is reached
18const int ErrorBlockServiceSeconds = 15 * 60;
2bc1878a 19
85a0abf9
BS
20/**
21 * Default Constructor
22 */
4545a371 23Service::Service()
9a0aff44 24 : Login("NOT SERIALIZED")
27baf279 25 , Password("NOT SERIALIZED")
025abebb 26 , ActualIP("0.0.0.0")
7be9aed9 27 , ActualIPIsBurnt(false)
7335d7a7 28 , Activated(false)
b67d84ea
BS
29 , UpdateInterval(15)
30 , MaxUpdatesWithinInterval(3)
4553e833 31 , MaxEqualUpdatesInSuccession(2)
d5a516ba 32 , DNSCacheTTL(0)
0f0908e1
TJ
33 , ErrorCount(0)
34 , ErrorServiceBlockedUntil(0)
2e956a36 35 , Log(new Logger())
4545a371
BS
36{
37}
38
2bc1878a 39
85a0abf9 40/**
27baf279 41 * Default Destructor needed for deserialization.
85a0abf9 42 */
4545a371
BS
43Service::~Service()
44{
45}
46
47
2bc1878a 48/**
3a89ac31
BS
49 * Setter for member Protocol.
50 * @param _protocol Value to set Protocol to.
51 */
52void Service::set_protocol(const string& _protocol)
53{
54 Protocol = _protocol;
55}
56
57
58/**
59 * Getter for memeber Protocol.
60 * @return Value of member Protocol.
61 */
b38684ce 62string Service::get_protocol() const
3a89ac31
BS
63{
64 return Protocol;
65}
66
67
68/**
69 * Setter for member Hostname.
70 * @param _hostname Value to set Hostname to.
71 */
72void Service::set_hostname(const string& _hostname)
73{
74 Hostname = _hostname;
75}
76
77
78/**
79 * Getter for member Hostname.
80 * @return Value of member Hostname.
81 */
b38684ce 82string Service::get_hostname() const
3a89ac31
BS
83{
84 return Hostname;
85}
86
87
88/**
89 * Setter for member Login.
90 * @param _login Value to set Login to.
91 */
92void Service::set_login(const string& _login)
93{
94 Login = _login;
95}
96
97
98/**
99 * Getter for member Login.
100 * @return Value of member Login.
101 */
b38684ce 102string Service::get_login() const
3a89ac31
BS
103{
104 return Login;
105}
106
107
108/**
109 * Setter for member Password.
110 * @param _password Value to set Password to.
111 */
112void Service::set_password(const string& _password)
113{
114 Password = _password;
115}
116
117
118/**
119 * Getter for member Password.
120 * @return Value of member Password.
121 */
b38684ce 122string Service::get_password() const
3a89ac31
BS
123{
124 return Password;
125}
126
127
d55fbd67 128
88a594e8 129void Service::set_logger(const Logger::Ptr& _log)
3a89ac31
BS
130{
131 Log = _log;
132}
133
134
135/**
136 * Getter for member Log.
137 * @return Shared pointer to Logger object.
138 */
b38684ce 139Logger::Ptr Service::get_logger() const
3a89ac31
BS
140{
141 return Log;
2bc1878a
BS
142}
143
144
4553e833
BS
145/**
146 * Setter for member LastUpdates.
147 * @param _last_updates Value to set LastUpdates to.
148 */
149void Service::set_last_updates(std::map<time_t,std::string> _last_updates)
2bc1878a 150{
209fa505
TJ
151 std::map<time_t,std::string> temp = _last_updates;
152 LastUpdates.swap(temp);
2bc1878a
BS
153}
154
155
156/**
4553e833
BS
157 * Getter for member LastUpdates.
158 * @return Value of member LastUpdates.
2bc1878a 159 */
4553e833 160const std::map<time_t,std::string> Service::get_last_updates() const
2bc1878a 161{
c1b8cb79 162 return LastUpdates;
2bc1878a
BS
163}
164
165
166/**
025abebb
BS
167 * Setter for member ActualIP.
168 * @param _actual_ip Value to set ActualIP to.
27baf279
BS
169 */
170void Service::set_actual_ip(const std::string& _actual_ip)
171{
025abebb 172 ActualIP = _actual_ip;
27baf279
BS
173}
174
175
176/**
025abebb
BS
177 * Getter for member ActualIP.
178 * @return Value of member ActualIP.
27baf279 179 */
b38684ce 180std::string Service::get_actual_ip() const
27baf279 181{
025abebb 182 return ActualIP;
27baf279
BS
183}
184
185
27baf279 186/**
3a89ac31
BS
187 * Overloading of comparison operator.
188 * @param other Reference to other Service object.
189 * @return True if they equal, false if not.
2bc1878a 190 */
3a89ac31 191bool Service::operator== (const Service& other) const
2bc1878a 192{
3a89ac31
BS
193 if ( ( this->Protocol == other.Protocol ) && ( this->Hostname == other.Hostname ) )
194 return true;
195 return false;
2bc1878a
BS
196}
197
198
199/**
3a89ac31
BS
200 * Overloading of disparate operator.
201 * @param other Reference to other Service object.
202 * @return True if they differ, false if they are equal.
2bc1878a 203 */
3a89ac31 204bool Service::operator!= (const Service& other) const
2bc1878a 205{
3a89ac31 206 return !(*this == other);
2bc1878a 207}
3c0cd271
BS
208
209
210/**
08e6f339 211 * Checks if update will exceed max update interval or if the IP address is burnt.
3c0cd271 212 * @param current_time Current time.
0ebcd4ef 213 * @param changed_to_online True if we just changed to online, false if we were already online
7be9aed9 214 * @param ip_host The new ip to set for the hostname.
3c0cd271
BS
215 * @return True if update is allowed, false if update would exceed max update interval.
216 */
08e6f339 217bool Service::update_allowed(const time_t current_time, bool changed_to_online, const std::string& ip_host)
3c0cd271 218{
08e6f339
BS
219 Log->print_last_updates(ip_host,current_time,UpdateInterval,MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession,LastUpdates,get_service_name());
220
221 // Check for update interval overstepping.
4553e833
BS
222 int i = 0;
223 for ( std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin(); (r_iter != LastUpdates.rend()) && ( i < MaxUpdatesWithinInterval ); r_iter++)
3c0cd271 224 {
4553e833 225 if ( (i == (MaxUpdatesWithinInterval-1)) && ( (r_iter->first + ((time_t)UpdateInterval*60)) >= current_time ) )
3c0cd271 226 {
4553e833 227 Log->print_update_not_allowed(changed_to_online,current_time,r_iter->first,MaxUpdatesWithinInterval,get_service_name());
3c0cd271
BS
228 return false;
229 }
230 i++;
231 }
08e6f339 232
7be9aed9
TJ
233 if (ActualIPIsBurnt)
234 {
235 // Changed IP address removes the "burnt state"
236 if (ip_host != ActualIP)
237 ActualIPIsBurnt = false;
238 else
239 {
240 // IP is burnt and didn't change -> Update not allowed
241 return false;
242 }
243 }
244
08e6f339
BS
245 // Check for burnt IP.
246 // Only check for burnt IP address if there are at least max_equal_updates_in_succession entries in the last_updates map.
247 if ( (MaxEqualUpdatesInSuccession != 0) && ((int)LastUpdates.size() >= MaxEqualUpdatesInSuccession) )
248 {
249 bool ip_burnt = true;
250 i = 0;
251 // Reverse iterate "last_updates" list so the latest update
252 // will be the first entry (map key is the unix timestamp)
253 for ( std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin();
254 ( r_iter != LastUpdates.rend() ) && ( i < MaxEqualUpdatesInSuccession ); r_iter++ )
255 {
256 if ( ip_host != r_iter->second )
257 {
258 ip_burnt = false;
259 break;
260 }
261 i++;
262 }
263
264 if ( ip_burnt )
265 {
7be9aed9 266 // IP Address is burnt. Too many updates in succession with the same IP. Log once.
08e6f339 267 Log->print_ip_burnt(ip_host,get_service_name());
7be9aed9 268 ActualIPIsBurnt = true;
08e6f339
BS
269 return false;
270 }
271 }
272
3c0cd271
BS
273 return true;
274}
275
276
277/**
c3dea5dc
BS
278 * Service update method, common to each service.
279 * @param ip The new ip to set for the hostname.
0ebcd4ef
TJ
280 * @param current_time Current time
281 * @param changed_to_online True if we just changed to online, false if we were already online
c3dea5dc 282 */
0ebcd4ef 283void Service::update(const string& ip, const time_t current_time, bool changed_to_online)
c3dea5dc 284{
0f0908e1
TJ
285 const std::string service_name = get_service_name();
286
287 // Check if service is blocked for a short period of time (because of update errors)
288 if (ErrorServiceBlockedUntil && current_time < ErrorServiceBlockedUntil)
289 {
290 Log->print_update_service_is_blocked(service_name, ErrorServiceBlockedUntil - current_time);
291 return;
292 }
293
c3dea5dc 294 // test if update is permitted by UpdateInterval Status
08e6f339 295 if ( update_allowed(current_time, changed_to_online, ip) )
c3dea5dc 296 {
0ebcd4ef
TJ
297 Log->print_update_service(service_name);
298
cd5a41a4
TJ
299 UpdateErrorCode update_res = perform_update(ip);
300
7335d7a7
BS
301 // If update result is other than Generic or NotAuth, we assume that the hostname is activated.
302 if ( (update_res != GenericError) && (update_res != NotAuth) )
303 set_activated();
304
cd5a41a4 305 if (update_res == UpdateOk)
c3dea5dc
BS
306 {
307 // if update was successful, we need to set the Lastupdated and ActualIP base member.
4553e833 308 set_last_update(current_time,ip);
c3dea5dc 309 ActualIP = ip;
75a3fba6 310 Log->print_update_service_successful(service_name,ip);
0f0908e1
TJ
311
312 ErrorCount = 0;
313 ErrorServiceBlockedUntil = 0;
c3dea5dc
BS
314 }
315 else
316 {
cd5a41a4
TJ
317 if (update_res == NoChange || update_res == Blocked)
318 {
319 // Log update for burnt IP logic and update "ActualIP" of this service
320 set_last_update(current_time,ip);
321 ActualIP = ip;
322 }
323
c3dea5dc 324 // problem while trying to update service
0f0908e1
TJ
325 Log->print_update_service_failure(service_name);
326
327 ++ErrorCount;
328 if (ErrorCount >= MaxErrorCount)
329 {
330 Log->print_block_service(service_name, ErrorBlockServiceSeconds);
331
332 ErrorServiceBlockedUntil = time(NULL) + ErrorBlockServiceSeconds;
333 ErrorCount = 0;
334 }
c3dea5dc
BS
335 }
336 }
337}
338
339
340/**
fc613942
BS
341* Sets the given time into the LastUpdates member and deletes expired entries.
342* @param _timeout Value to set into LastUpdates.
343*/
4553e833 344void Service::set_last_update(const time_t current_time, const string& ip)
fc613942
BS
345{
346 // Insert value into the list.
4553e833
BS
347 LastUpdates.insert(make_pair(current_time,ip));
348
349 // Get the maximum of MaxUpdatesWithinInterval and MaxEqualUpdatesInSuccession
350 int maximum = max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession);
fc613942
BS
351
352 // Check for expired entries:
353
354 // MaxUpdatesWithinInterval given in service config, then use this to check for expired entries.
4553e833 355 if ( maximum > 0 )
fc613942 356 {
4553e833
BS
357 // Delete the oldest entry if there are more than max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession)+1 entries in the list.
358 if ( LastUpdates.size() > (size_t)(maximum+1) )
34016300 359 LastUpdates.erase(LastUpdates.begin());
fc613942
BS
360 return;
361 }
362 // UpdateInterval given in service config, then use this to check for expired entries.
363 else if ( UpdateInterval > 0 )
364 {
365 // Delete the oldest entry if it's older than current_time - UpdateInterval(minutes) + 1.
34016300
TJ
366 if ( (current_time - ((time_t)UpdateInterval*60) + 1) > LastUpdates.begin()->first )
367 LastUpdates.erase(LastUpdates.begin());
fc613942
BS
368 return;
369 }
370 // Neither MaxUpdatesWithinInterval nor UpdateInterval are given, so keep fix number of 10 entries.
371 else
372 {
373 if ( LastUpdates.size() > 10 )
34016300 374 LastUpdates.erase(LastUpdates.begin());
fc613942
BS
375 return;
376 }
377}
378
379
380/**
4553e833
BS
381 * Getter the last updated time.
382 * @return Value of the last update as time_t.
383 */
384time_t Service::get_last_update_time( )
385{
0c0344aa
BS
386 time_t last_update = 0;
387 if ( !LastUpdates.empty() )
388 {
389 std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin();
390 if ( r_iter != LastUpdates.rend() )
391 last_update = r_iter->first;
392 }
393 return last_update;
4553e833
BS
394}
395
396
397/**
3c0cd271
BS
398 * Setter for member Timeout.
399 * @param _timeout Value to set Timeout to.
400 */
401void Service::set_update_interval(const int _update_interval)
402{
403 UpdateInterval = _update_interval;
404}
405
406
407/**
408 * Getter for member Timeout.
409 * @return Value of Timeout.
410 */
411int Service::get_update_interval() const
412{
413 return UpdateInterval;
414}
415
416
417/**
418 * Setter for member Max_updates_per_timeout.
419 * @param _max_updates_per_timeout Value to set Max_updates_per_timeout to.
420 */
421void Service::set_max_updates_within_interval(const int _max_updates_within_interval)
422{
423 MaxUpdatesWithinInterval = _max_updates_within_interval;
424}
425
426
427/**
428 * Getter for member Max_updates_per_timeout.
429 * @return Value of Max_updates_per_timeout.
430 */
431int Service::get_max_updates_within_interval() const
432{
433 return MaxUpdatesWithinInterval;
434}
c3dea5dc
BS
435
436
437/**
4553e833
BS
438 * Setter for member MaxEqualUpdatesInSuccession.
439 * @param _max_equal_updates_in_succession Value to set MaxEqualUpdatesInSuccession to.
440 */
441void Service::set_max_equal_updates_in_succession(const int _max_equal_updates_in_succession)
442{
443 MaxEqualUpdatesInSuccession = _max_equal_updates_in_succession;
444}
445
446
447/**
448 * Getter for member MaxEqualUpdatesInSuccession.
449 * @return Value of MaxEqualUpdatesInSuccession.
450 */
451int Service::get_max_equal_updates_in_succession() const
452{
453 return MaxEqualUpdatesInSuccession;
454}
455
456
457/**
c3dea5dc
BS
458 * Get a unique service identify string
459 * @return A unique service identify string
460 */
461string Service::get_service_name() const
462{
463 string service_name;
464
465 service_name.append(Protocol);
466 service_name.append(" ");
467 service_name.append(Hostname);
468
469 return service_name;
470}
471
472
473/**
474 * Get member DNSCacheTTL
475 * @return DNSCacheTTL
476 */
477int Service::get_dns_cache_ttl() const
478{
479 return DNSCacheTTL;
480}
481
482
483/**
484 * Set member DNSCacheTTL
485 * @param _dns_cache_ttl DNSCacheTTL
486 */
487void Service::set_dns_cache_ttl(const int _dns_cache_ttl)
488{
489 DNSCacheTTL = _dns_cache_ttl;
490}
7335d7a7
BS
491
492
493/**
494 * Get member Activated
495 * @return Activated
496 */
497bool Service::get_activated() const
498{
499 return Activated;
500}
501
502
503/**
504 * Set member Activated
505 * @param _activated Activated
506 */
507void Service::set_activated()
508{
509 Activated = true;
510}