Fix 'occurred' typo
[bpdyndnsd] / src / service.cpp
1 /** @file
2  * @brief The abstract service class. This class represents all services.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #include "service.hpp"
11 #include <boost/foreach.hpp>
12
13 using namespace std;
14
15 /// Number of update errors until a service will be blocked
16 const int MaxErrorCount = 3;
17 /// Number of seconds a service will be blocked if MaxErrorCount is reached
18 const int ErrorBlockServiceSeconds = 15 * 60;
19
20 /**
21  * Default Constructor
22  */
23 Service::Service()
24     : Login("NOT SERIALIZED")
25     , Password("NOT SERIALIZED")
26     , ActualIP("0.0.0.0")
27     , ActualIPIsBurnt(false)
28     , Activated(false)
29     , UpdateInterval(15)
30     , MaxUpdatesWithinInterval(3)
31     , MaxEqualUpdatesInSuccession(2)
32     , DNSCacheTTL(0)
33     , ErrorCount(0)
34     , ErrorServiceBlockedUntil(0)
35     , Log(new Logger())
36 {
37 }
38
39
40 /**
41  * Default Destructor needed for deserialization.
42  */
43 Service::~Service()
44 {
45 }
46
47
48 /**
49  * Setter for member Protocol.
50  * @param _protocol Value to set Protocol to.
51  */
52 void 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  */
62 string Service::get_protocol() const
63 {
64     return Protocol;
65 }
66
67
68 /**
69  * Setter for member Hostname.
70  * @param _hostname Value to set Hostname to.
71  */
72 void 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  */
82 string Service::get_hostname() const
83 {
84     return Hostname;
85 }
86
87
88 /**
89  * Setter for member Login.
90  * @param _login Value to set Login to.
91  */
92 void 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  */
102 string Service::get_login() const
103 {
104     return Login;
105 }
106
107
108 /**
109  * Setter for member Password.
110  * @param _password Value to set Password to.
111  */
112 void 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  */
122 string Service::get_password() const
123 {
124     return Password;
125 }
126
127
128
129 void Service::set_logger(const Logger::Ptr& _log)
130 {
131     Log = _log;
132 }
133
134
135 /**
136  * Getter for member Log.
137  * @return Shared pointer to Logger object.
138  */
139 Logger::Ptr Service::get_logger() const
140 {
141     return Log;
142 }
143
144
145 /**
146  * Setter for member LastUpdates.
147  * @param _last_updates Value to set LastUpdates to.
148  */
149 void Service::set_last_updates(std::map<time_t,std::string> _last_updates)
150 {
151     std::map<time_t,std::string> temp = _last_updates;
152     LastUpdates.swap(temp);
153 }
154
155
156 /**
157  * Getter for member LastUpdates.
158  * @return Value of member LastUpdates.
159  */
160 const std::map<time_t,std::string> Service::get_last_updates() const
161 {
162     return LastUpdates;
163 }
164
165
166 /**
167  * Setter for member ActualIP.
168  * @param _actual_ip Value to set ActualIP to.
169  */
170 void Service::set_actual_ip(const std::string& _actual_ip)
171 {
172     ActualIP = _actual_ip;
173 }
174
175
176 /**
177  * Getter for member ActualIP.
178  * @return Value of member ActualIP.
179  */
180 std::string Service::get_actual_ip() const
181 {
182     return ActualIP;
183 }
184
185
186 /**
187  * Overloading of comparison operator.
188  * @param other Reference to other Service object.
189  * @return True if they equal, false if not.
190  */
191 bool Service::operator== (const Service& other) const
192 {
193     if ( ( this->Protocol == other.Protocol ) && ( this->Hostname == other.Hostname ) )
194         return true;
195     return false;
196 }
197
198
199 /**
200  * Overloading of disparate operator.
201  * @param other Reference to other Service object.
202  * @return True if they differ, false if they are equal.
203  */
204 bool Service::operator!= (const Service& other) const
205 {
206     return !(*this == other);
207 }
208
209
210 /**
211  * Checks if update will exceed max update interval or if the IP address is burnt.
212  * @param current_time Current time.
213  * @param changed_to_online True if we just changed to online, false if we were already online
214  * @param ip_host The new ip to set for the hostname.
215  * @return True if update is allowed, false if update would exceed max update interval.
216  */
217 bool Service::update_allowed(const time_t current_time, bool changed_to_online, const std::string& ip_host)
218 {
219     Log->print_last_updates(ip_host,current_time,UpdateInterval,MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession,LastUpdates,get_service_name());
220
221     // Check for update interval overstepping.
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++)
224     {
225         if ( (i == (MaxUpdatesWithinInterval-1)) && ( (r_iter->first + ((time_t)UpdateInterval*60)) >= current_time ) )
226         {
227             Log->print_update_not_allowed(changed_to_online,current_time,r_iter->first,MaxUpdatesWithinInterval,get_service_name());
228             return false;
229         }
230         i++;
231     }
232
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
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         {
266             // IP Address is burnt. Too many updates in succession with the same IP. Log once.
267             Log->print_ip_burnt(ip_host,get_service_name());
268             ActualIPIsBurnt = true;
269             return false;
270         }
271     }
272
273     return true;
274 }
275
276
277 /**
278  * Service update method, common to each service.
279  * @param ip The new ip to set for the hostname.
280  * @param current_time Current time
281  * @param changed_to_online True if we just changed to online, false if we were already online
282  */
283 void Service::update(const string& ip, const time_t current_time, bool changed_to_online)
284 {
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
294     // test if update is permitted by UpdateInterval Status
295     if ( update_allowed(current_time, changed_to_online, ip) )
296     {
297         Log->print_update_service(service_name);
298
299         UpdateErrorCode update_res = perform_update(ip);
300
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
305         if (update_res == UpdateOk)
306         {
307             // if update was successful, we need to set the Lastupdated and ActualIP base member.
308             set_last_update(current_time,ip);
309             ActualIP = ip;
310             Log->print_update_service_successful(service_name,ip);
311
312             ErrorCount = 0;
313             ErrorServiceBlockedUntil = 0;
314         }
315         else
316         {
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
324             // problem while trying to update service
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             }
335         }
336     }
337 }
338
339
340 /**
341 * Sets the given time into the LastUpdates member and deletes expired entries.
342 * @param _timeout Value to set into LastUpdates.
343 */
344 void Service::set_last_update(const time_t current_time, const string& ip)
345 {
346     // Insert value into the list.
347     LastUpdates.insert(make_pair(current_time,ip));
348
349     // Get the maximum of MaxUpdatesWithinInterval and MaxEqualUpdatesInSuccession
350     int maximum = max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession);
351
352     // Check for expired entries:
353
354     // MaxUpdatesWithinInterval given in service config, then use this to check for expired entries.
355     if ( maximum > 0 )
356     {
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) )
359             LastUpdates.erase(LastUpdates.begin());
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.
366         if ( (current_time - ((time_t)UpdateInterval*60) + 1) > LastUpdates.begin()->first )
367             LastUpdates.erase(LastUpdates.begin());
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 )
374             LastUpdates.erase(LastUpdates.begin());
375         return;
376     }
377 }
378
379
380 /**
381  * Getter the last updated time.
382  * @return Value of the last update as time_t.
383  */
384 time_t Service::get_last_update_time( )
385 {
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;
394 }
395
396
397 /**
398  * Setter for member Timeout.
399  * @param _timeout Value to set Timeout to.
400  */
401 void 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  */
411 int 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  */
421 void 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  */
431 int Service::get_max_updates_within_interval() const
432 {
433     return MaxUpdatesWithinInterval;
434 }
435
436
437 /**
438  * Setter for member MaxEqualUpdatesInSuccession.
439  * @param  _max_equal_updates_in_succession Value to set MaxEqualUpdatesInSuccession to.
440  */
441 void 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  */
451 int Service::get_max_equal_updates_in_succession() const
452 {
453     return MaxEqualUpdatesInSuccession;
454 }
455
456
457 /**
458  * Get a unique service identify string
459  * @return A unique service identify string
460  */
461 string 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  */
477 int 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  */
487 void Service::set_dns_cache_ttl(const int _dns_cache_ttl)
488 {
489     DNSCacheTTL = _dns_cache_ttl;
490 }
491
492
493 /**
494  * Get member Activated
495  * @return Activated
496  */
497 bool Service::get_activated() const
498 {
499     return Activated;
500 }
501
502
503 /**
504  * Set member Activated
505  * @param _activated Activated
506  */
507 void Service::set_activated()
508 {
509     Activated = true;
510 }