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