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