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