3c1cd25b4cc7cbd0c594d9aa769e74f7c7c90021
[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.
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)
215 {
216     int i = 0;
217     for ( std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin(); (r_iter != LastUpdates.rend()) && ( i < MaxUpdatesWithinInterval ); r_iter++)
218     {
219         if ( (i == (MaxUpdatesWithinInterval-1)) && ( (r_iter->first + ((time_t)UpdateInterval*60)) >= current_time ) )
220         {
221             Log->print_update_not_allowed(changed_to_online,current_time,r_iter->first,MaxUpdatesWithinInterval,get_service_name());
222             return false;
223         }
224         i++;
225     }
226     return true;
227 }
228
229
230 /**
231  * Service update method, common to each service.
232  * @param ip The new ip to set for the hostname.
233  * @param current_time Current time
234  * @param changed_to_online True if we just changed to online, false if we were already online
235  */
236 void Service::update(const string& ip, const time_t current_time, bool changed_to_online)
237 {
238     const std::string service_name = get_service_name();
239
240     // Check if service is blocked for a short period of time (because of update errors)
241     if (ErrorServiceBlockedUntil && current_time < ErrorServiceBlockedUntil)
242     {
243         Log->print_update_service_is_blocked(service_name, ErrorServiceBlockedUntil - current_time);
244         return;
245     }
246
247     // test if update is permitted by UpdateInterval Status
248     if ( update_allowed(current_time, changed_to_online) )
249     {
250         Log->print_update_service(service_name);
251
252         if ( perform_update(ip) == 0 )
253         {
254             // if update was successful, we need to set the Lastupdated and ActualIP base member.
255             set_last_update(current_time,ip);
256             ActualIP = ip;
257             Log->print_update_service_successful(service_name);
258
259             ErrorCount = 0;
260             ErrorServiceBlockedUntil = 0;
261         }
262         else
263         {
264             // problem while trying to update service
265             Log->print_update_service_failure(service_name);
266
267             ++ErrorCount;
268             if (ErrorCount >= MaxErrorCount)
269             {
270                 Log->print_block_service(service_name, ErrorBlockServiceSeconds);
271
272                 ErrorServiceBlockedUntil = time(NULL) + ErrorBlockServiceSeconds;
273                 ErrorCount = 0;
274             }
275         }
276     }
277 }
278
279
280 /**
281 * Sets the given time into the LastUpdates member and deletes expired entries.
282 * @param _timeout Value to set into LastUpdates.
283 */
284 void Service::set_last_update(const time_t current_time, const string& ip)
285 {
286     // Insert value into the list.
287     LastUpdates.insert(make_pair(current_time,ip));
288
289     // Get the maximum of MaxUpdatesWithinInterval and MaxEqualUpdatesInSuccession
290     int maximum = max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession);
291
292     // Check for expired entries:
293
294     // MaxUpdatesWithinInterval given in service config, then use this to check for expired entries.
295     if ( maximum > 0 )
296     {
297         // Delete the oldest entry if there are more than max(MaxUpdatesWithinInterval,MaxEqualUpdatesInSuccession)+1 entries in the list.
298         if ( LastUpdates.size() > (size_t)(maximum+1) )
299             LastUpdates.erase(LastUpdates.begin());
300         return;
301     }
302     // UpdateInterval given in service config, then use this to check for expired entries.
303     else if ( UpdateInterval > 0 )
304     {
305         // Delete the oldest entry if it's older than current_time - UpdateInterval(minutes) + 1.
306         if ( (current_time - ((time_t)UpdateInterval*60) + 1) > LastUpdates.begin()->first )
307             LastUpdates.erase(LastUpdates.begin());
308         return;
309     }
310     // Neither MaxUpdatesWithinInterval nor UpdateInterval are given, so keep fix number of 10 entries.
311     else
312     {
313         if ( LastUpdates.size() > 10 )
314             LastUpdates.erase(LastUpdates.begin());
315         return;
316     }
317 }
318
319
320 /**
321  * Getter the last updated time.
322  * @return Value of the last update as time_t.
323  */
324 time_t Service::get_last_update_time( )
325 {
326     time_t last_update = 0;
327     if ( !LastUpdates.empty() )
328     {
329         std::map<time_t,std::string>::reverse_iterator r_iter = LastUpdates.rbegin();
330         if ( r_iter != LastUpdates.rend() )
331             last_update = r_iter->first;
332     }
333     return last_update;
334 }
335
336
337 /**
338  * Setter for member Timeout.
339  * @param _timeout Value to set Timeout to.
340  */
341 void Service::set_update_interval(const int _update_interval)
342 {
343     UpdateInterval = _update_interval;
344 }
345
346
347 /**
348  * Getter for member Timeout.
349  * @return Value of Timeout.
350  */
351 int Service::get_update_interval() const
352 {
353     return UpdateInterval;
354 }
355
356
357 /**
358  * Setter for member Max_updates_per_timeout.
359  * @param  _max_updates_per_timeout Value to set Max_updates_per_timeout to.
360  */
361 void Service::set_max_updates_within_interval(const int _max_updates_within_interval)
362 {
363     MaxUpdatesWithinInterval = _max_updates_within_interval;
364 }
365
366
367 /**
368  * Getter for member Max_updates_per_timeout.
369  * @return Value of Max_updates_per_timeout.
370  */
371 int Service::get_max_updates_within_interval() const
372 {
373     return MaxUpdatesWithinInterval;
374 }
375
376
377 /**
378  * Setter for member MaxEqualUpdatesInSuccession.
379  * @param  _max_equal_updates_in_succession Value to set MaxEqualUpdatesInSuccession to.
380  */
381 void Service::set_max_equal_updates_in_succession(const int _max_equal_updates_in_succession)
382 {
383     MaxEqualUpdatesInSuccession = _max_equal_updates_in_succession;
384 }
385
386
387 /**
388  * Getter for member MaxEqualUpdatesInSuccession.
389  * @return Value of MaxEqualUpdatesInSuccession.
390  */
391 int Service::get_max_equal_updates_in_succession() const
392 {
393     return MaxEqualUpdatesInSuccession;
394 }
395
396
397 /**
398  * Get a unique service identify string
399  * @return A unique service identify string
400  */
401 string Service::get_service_name() const
402 {
403     string service_name;
404
405     service_name.append(Protocol);
406     service_name.append(" ");
407     service_name.append(Hostname);
408
409     return service_name;
410 }
411
412
413 /**
414  * Get member DNSCacheTTL
415  * @return DNSCacheTTL
416  */
417 int Service::get_dns_cache_ttl() const
418 {
419     return DNSCacheTTL;
420 }
421
422
423 /**
424  * Set member DNSCacheTTL
425  * @param _dns_cache_ttl DNSCacheTTL
426  */
427 void Service::set_dns_cache_ttl(const int _dns_cache_ttl)
428 {
429     DNSCacheTTL = _dns_cache_ttl;
430 }