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