Refactoring: Class renaming. All service implementaion classes should start with...
[bpdyndnsd] / src / updater.cpp
1 /** @file
2  * @brief The updater class implementation. This class implements the updater logic.
3  *
4  *
5  *
6  * @copyright Intra2net AG
7  * @license GPLv2
8 */
9
10 #include "updater.h"
11
12 #include "serviceholder.h"
13 #include "service_dhs.h"
14 #include "service_ods.h"
15 #include "service_dyndns.h"
16 #include "service_dyns.h"
17 #include "service_easydns.h"
18 #include "service_tzo.h"
19 #include "service_zoneedit.h"
20
21 #include <boost/foreach.hpp>
22
23
24 // Following boost macros are needed for serialization of derived classes through a base class pointer (Service *).
25 BOOST_CLASS_EXPORT_GUID(SERVICE_ODS, "SERVICE_ODS")
26 BOOST_CLASS_EXPORT_GUID(SERVICE_DHS, "SERVICE_DHS")
27 BOOST_CLASS_EXPORT_GUID(SERVICE_DYNS, "SERVICE_DYNS")
28 BOOST_CLASS_EXPORT_GUID(SERVICE_DYNDNS, "SERVICE_DYNDNS")
29 BOOST_CLASS_EXPORT_GUID(SERVICE_EASYDNS, "SERVICE_EASYDNS")
30 BOOST_CLASS_EXPORT_GUID(SERVICE_TZO, "SERVICE_TZO")
31 BOOST_CLASS_EXPORT_GUID(SERVICE_ZONEEDIT, "SERVICE_ZONEEDIT")
32
33
34 namespace fs = boost::filesystem;
35
36 using namespace std;
37
38 /**
39  * Default constructor which initializes the member Conf.
40  */
41 Updater::Updater()
42     : IPHelp(new IPHelper)
43 {
44     // Initialize program wide Logger, at this point we don't know where to log and with which loglevel.
45     Logger::Ptr _log(new Logger);
46     Log = _log;
47     _log.reset();
48
49     // initialize Serviceholder
50     Serviceholder::Ptr _serviceholder(new Serviceholder(Log));
51     ServiceHolder = _serviceholder;
52     _serviceholder.reset();
53
54     // initialize Config
55     Config::Ptr _config(new Config(Log,ServiceHolder));
56     Conf = _config;
57     _config.reset();
58 }
59
60
61 /**
62  * Default destructor.
63  */
64 Updater::~Updater()
65 {
66 }
67
68
69
70 /**
71  * Load config and initialize helper classes.
72  * @param argc Number of arguments in array
73  * @param argv Array with cmd options
74  */
75 int Updater::load_config(int argc, char *argv[])
76 {
77     // load the cmd options
78     if ( init_config_from_cmd(argc,argv) != 0 )
79         return -1;
80
81     // load the config and service files
82     if ( init_config_from_files() != 0 )
83         return -1;
84
85     // init all helper classes
86     if ( init_helper_classes() != 0 )
87         return -1;
88
89     return 0;
90 }
91
92
93 /**
94  * Reloading the config. Delete all Service objects and then init new Service objects from config files.
95  */
96 int Updater::reload_config()
97 {
98     // serialize all service objects
99     if ( ServiceHolder->serialize_services() != 0 )
100         return -1;
101
102     // delete all service objects
103     ServiceHolder->delete_services();
104
105     // delete the actual Variables_map, perhaps with old cmd options which would overwrite new config file options.
106     Conf->delete_variables_map();
107
108     // load only config files
109     if ( init_config_from_files() != 0 )
110         return -1;
111
112     // init all helper classes
113     if ( init_helper_classes() != 0 )
114         return -1;
115
116     return 0;
117 }
118
119
120 /**
121  * Parse the command line arguments and initialize corresponding options.
122  * @param argc Number command line arguments.
123  * @param argv[] Array with arguments.
124  * @return 0 if cmd options successfully parsed, 1 if usage or version.
125  */
126 int Updater::init_config_from_cmd(int argc, char *argv[])
127 {
128     // Load the command line parameters
129     if( Conf->parse_cmd_line( argc, argv) != 0)
130         return -1;
131
132     // If we have loaded the cmd options we need to init the log facility immediately in case debugging is enabled from cmd.
133     init_log_facility();
134
135     // successful parsed
136     Log->print_cmd_parsed();
137     return 0;
138 }
139
140
141 /**
142  * Load the main config and the service definition files in config path.
143  * @return 0 if all is fine, 
144  */
145 int Updater::init_config_from_files()
146 {
147     // Load the main and service config files in config path
148     if ( Conf->load_config_from_files() != 0 )
149         return -1;
150
151     // Re-init log facility, perhaps new config file options for logger are set.
152     // These config file options will only overwrite the cmd options if the SIGHUP (reload config) is caught.
153     init_log_facility();
154
155     // Here we are. All Service Objects should be initialized, so it is time to deserialize the old service objects and compare them.
156     if ( ServiceHolder->deserialize_services() != 0 )
157         return -1;
158
159     // successful loaded
160     Log->print_conf_files_parsed();
161     return 0;
162 }
163
164
165 /**
166  * Init all Helper classes
167  * @return 
168  */
169 int Updater::init_helper_classes()
170 {
171     // Initialize IPHelper
172     if ( init_ip_helper() != 0 )
173         return -1;
174
175     return 0;
176 }
177
178
179 /**
180  * Init the IPHelp member with needed values.
181  * @return 0 if all is fine, -1 otherwise.
182  */
183 int Updater::init_ip_helper()
184 {
185     // initialize IPHelper
186     IPHelper::Ptr _iphelp(new IPHelper(Log,Conf->get_webcheck_ip_url(),Conf->get_webcheck_ip_url_alt(),Conf->get_enable_ipv6(),Conf->get_proxy(),Conf->get_proxy_port()));
187     IPHelp = _iphelp;
188     _iphelp.reset();
189
190     return 0;
191 }
192
193
194 /**
195  * Getter for member Config.
196  * @return Member Config.
197  */
198 Config::Ptr Updater::get_config() const
199 {
200     return Conf;
201 }
202
203
204 /**
205  * Getter for member Logger.
206  * @return Member Logger.
207  */
208 Logger::Ptr Updater::get_logger() const
209 {
210     return Log;
211 }
212
213
214 /**
215  * Initialize the logging facility with loglevel and syslog.
216  */
217 void Updater::init_log_facility()
218 {
219     Log->set_log_facility(Conf->get_loglevel(),Conf->get_syslog(),Conf->get_external_warning_log(),Conf->get_external_warning_level());
220     Log->print_init_log_facility();
221 }
222
223
224 /**
225  * Update all configured services.
226  */
227 void Updater::update_services()
228 {
229     list<Service::Ptr> services = ServiceHolder->get_services();
230
231     string ip = IPHelp->get_actual_ip();
232
233     if ( !ip.empty() )
234     {
235         BOOST_FOREACH(Service::Ptr &service, services )
236         {
237             string dns_recheck_ip = ip;
238             int current_time = time(NULL);
239
240             int lastupdated = 0;
241             if ( service->get_last_updates()->size() > 0 )
242                 lastupdated = service->get_last_updates()->front();
243
244             // If the dns cache ttl is expired or the service is updated for the first time, then get the actual ip of the dns record (this should be the IP in the last update)
245             if ( ((lastupdated != 0) && ((lastupdated + service->get_dns_cache_ttl()) < current_time)) || (lastupdated == 0) )
246             {
247                 Log->print_recheck_dns_entry(service->get_hostname(),lastupdated,service->get_dns_cache_ttl(),current_time);
248                 string _dns_recheck_ip = IPHelp->dns_query(service->get_hostname());
249                 Log->print_cached_dns_entry(service->get_hostname(), _dns_recheck_ip, service->get_actual_ip());
250                 if (!_dns_recheck_ip.empty())
251                     dns_recheck_ip = _dns_recheck_ip;
252             }
253
254             // In case the local hosts IP (ip) differ from the IP set in the last update (actual_ip) or
255             // the IP of the dns record (dns_recheck_ip) differs from the IP of the local host (ip)
256             // then perform an update. This implies that the update is not performed if actual_ip == dns_recheck_ip.
257             // Special case when latupdated == 0 then only perform the update if dns_rechek_ip differs from ip
258             if ( ((service->get_actual_ip() != ip) && (lastupdated != 0)) || (dns_recheck_ip != ip)  )
259                 service->update(ip,current_time);
260             else if ( (service->get_actual_ip() != ip) && (lastupdated == 0)  )
261                 service->set_actual_ip(ip);
262         }
263     }
264 }
265
266
267 /**
268  * Getter for member ServiceHolder.
269  * @return ServiceHolder
270  */
271 Serviceholder::Ptr Updater::get_service_holder() const
272 {
273     return ServiceHolder;
274 }