3eebff0be7d8d077161aa9b685d4d1cdebf6762e
[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         UpdateErrorCode update_res = perform_update(ip);
284
285         if (update_res == UpdateOk)
286         {
287             // if update was successful, we need to set the Lastupdated and ActualIP base member.
288             set_last_update(current_time,ip);
289             ActualIP = ip;
290             Log->print_update_service_successful(service_name);
291
292             ErrorCount = 0;
293             ErrorServiceBlockedUntil = 0;
294         }
295         else
296         {
297             if (update_res == NoChange || update_res == Blocked)
298             {
299                 // Log update for burnt IP logic and update "ActualIP" of this service
300                 set_last_update(current_time,ip);
301                 ActualIP = ip;
302             }
303
304             // problem while trying to update service
305             Log->print_update_service_failure(service_name);
306
307             ++ErrorCount;
308             if (ErrorCount >= MaxErrorCount)
309             {
310                 Log->print_block_service(service_name, ErrorBlockServiceSeconds);
311
312                 ErrorServiceBlockedUntil = time(NULL) + ErrorBlockServiceSeconds;
313                 ErrorCount = 0;
314             }
315         }
316     }
317 }
318
319
320 /**
321 * Sets the given time into the LastUpdates member and deletes expired entries.
322 * @param _timeout Value to set into LastUpdates.
323 */
324 void Service::set_last_update(const time_t current_time, const string& ip)
325 {
326     // Insert value into the list.
327     LastUpdates.insert(make_pair(current_time,ip));
328
329     // Get the maximum of MaxUpdatesWithinInterval and MaxEqualUpdatesInSuccession
330     int maximum = max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession);
331
332     // Check for expired entries:
333
334     // MaxUpdatesWithinInterval given in service config, then use this to check for expired entries.
335     if ( maximum > 0 )
336     {
337         // Delete the oldest entry if there are more than max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession)+1 entries in the list.
338         if ( LastUpdates.size() > (size_t)(maximum+1) )
339             LastUpdates.erase(LastUpdates.begin());
340         return;
341     }
342     // UpdateInterval given in service config, then use this to check for expired entries.
343     else if ( UpdateInterval > 0 )
344     {
345         // Delete the oldest entry if it's older than current_time - UpdateInterval(minutes) + 1.
346         if ( (current_time - ((time_t)UpdateInterval*60) + 1) > LastUpdates.begin()->first )
347             LastUpdates.erase(LastUpdates.begin());
348         return;
349     }
350     // Neither MaxUpdatesWithinInterval nor UpdateInterval are given, so keep fix number of 10 entries.
351     else
352     {
353         if ( LastUpdates.size() > 10 )
354             LastUpdates.erase(LastUpdates.begin());
355         return;
356     }
357 }
358
359
360 /**
361  * Getter the last updated time.
362  * @return Value of the last update as time_t.
363  */
364 time_t Service::get_last_update_time( )
365 {
366     time_t last_update = 0;
367     if ( !LastUpdates.empty() )
368     {
369         std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin();
370         if ( r_iter != LastUpdates.rend() )
371             last_update = r_iter->first;
372     }
373     return last_update;
374 }
375
376
377 /**
378  * Setter for member Timeout.
379  * @param _timeout Value to set Timeout to.
380  */
381 void Service::set_update_interval(const int _update_interval)
382 {
383     UpdateInterval = _update_interval;
384 }
385
386
387 /**
388  * Getter for member Timeout.
389  * @return Value of Timeout.
390  */
391 int Service::get_update_interval() const
392 {
393     return UpdateInterval;
394 }
395
396
397 /**
398  * Setter for member Max_updates_per_timeout.
399  * @param  _max_updates_per_timeout Value to set Max_updates_per_timeout to.
400  */
401 void Service::set_max_updates_within_interval(const int _max_updates_within_interval)
402 {
403     MaxUpdatesWithinInterval = _max_updates_within_interval;
404 }
405
406
407 /**
408  * Getter for member Max_updates_per_timeout.
409  * @return Value of Max_updates_per_timeout.
410  */
411 int Service::get_max_updates_within_interval() const
412 {
413     return MaxUpdatesWithinInterval;
414 }
415
416
417 /**
418  * Setter for member MaxEqualUpdatesInSuccession.
419  * @param  _max_equal_updates_in_succession Value to set MaxEqualUpdatesInSuccession to.
420  */
421 void Service::set_max_equal_updates_in_succession(const int _max_equal_updates_in_succession)
422 {
423     MaxEqualUpdatesInSuccession = _max_equal_updates_in_succession;
424 }
425
426
427 /**
428  * Getter for member MaxEqualUpdatesInSuccession.
429  * @return Value of MaxEqualUpdatesInSuccession.
430  */
431 int Service::get_max_equal_updates_in_succession() const
432 {
433     return MaxEqualUpdatesInSuccession;
434 }
435
436
437 /**
438  * Get a unique service identify string
439  * @return A unique service identify string
440  */
441 string Service::get_service_name() const
442 {
443     string service_name;
444
445     service_name.append(Protocol);
446     service_name.append(" ");
447     service_name.append(Hostname);
448
449     return service_name;
450 }
451
452
453 /**
454  * Get member DNSCacheTTL
455  * @return DNSCacheTTL
456  */
457 int Service::get_dns_cache_ttl() const
458 {
459     return DNSCacheTTL;
460 }
461
462
463 /**
464  * Set member DNSCacheTTL
465  * @param _dns_cache_ttl DNSCacheTTL
466  */
467 void Service::set_dns_cache_ttl(const int _dns_cache_ttl)
468 {
469     DNSCacheTTL = _dns_cache_ttl;
470 }