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