2 * @brief Config class implementation. This class represents the actual configuration.
6 * @copyright Intra2net AG
21 #include <boost/foreach.hpp>
22 #include <boost/filesystem.hpp>
23 #include <boost/regex.hpp>
24 #include <boost/algorithm/string.hpp>
28 namespace po = boost::program_options;
29 namespace fs = boost::filesystem;
30 namespace ba = boost::algorithm;
35 * Default Constructor. Available command line and config file options with their default values are defined here.
37 Config::Config(Logger::Ptr _log, Serviceholder::Ptr _serviceholder)
39 , ServiceHolder(_serviceholder)
44 , ConfigPath("/etc/bpdyndnsd")
45 , ExternalWarningLog("")
46 , ExternalWarningLevel(0)
48 // Available service description config options
49 po::options_description opt_desc_service("Service description options");
50 opt_desc_service.add_options()
51 ("protocol",po::value<string>(),"The service protocol.")
52 ("host",po::value<string>(),"The hostname to update.")
53 ("login",po::value<string>(),"Login name.")
54 ("password",po::value<string>(),"Corresponding password.")
55 ("update_interval",po::value<int>()->default_value(-1),"Update interval in minutes.")
56 ("max_updates_within_interval",po::value<int>()->default_value(-1),"How many updates can be made in one interval.")
57 ("dns_cache_ttl",po::value<int>()->default_value(-1),"How long a dns record is valid.")
60 // Available command line only options
61 po::options_description opt_desc_cmd_only("Command line only options");
62 opt_desc_cmd_only.add_options()
63 ("help,?","Show help.")
64 ("version,v","Show version.")
65 ("config,c",po::value<string>()->default_value("/etc/bpdyndnsd"),"Set the config path.")
68 // Available generic options. Valid on cmd or in config file.
69 po::options_description opt_desc_generic("Generic config options");
70 opt_desc_generic.add_options()
71 ("daemon_mode",po::value<bool>()->default_value(false),"Run as system daemon.")
72 ("loglevel",po::value<int>()->default_value(0),"Loglevel.")
73 ("syslog",po::value<bool>()->default_value(false),"Use syslog facility.")
74 ("enable_ipv6",po::value<bool>()->default_value(false),"Try to use IPv6.")
75 ("webcheck_url",po::value<string>()->default_value(""),"Use this URL to determine IP.")
76 ("webcheck_url_alt",po::value<string>()->default_value(""),"Use this alternative URL to determine IP.")
77 ("http_proxy",po::value<string>(),"Use this proxy for all http requests.")
78 ("http_proxy_port",po::value<int>(),"Port of the proxy.")
79 ("external_warning_log",po::value<string>()->default_value(""),"External programm to pass warning log messages to.")
80 ("external_warning_level",po::value<int>()->default_value(0),"Warning messages of which loglevel should be passed to external programm.")
83 // Define valid command line parameters
84 Options_descriptionPtr _opt_desc_cmd(new po::options_description("Command line options"));
85 OptDescCmd = _opt_desc_cmd;
86 _opt_desc_cmd.reset();
87 OptDescCmd->add(opt_desc_cmd_only);
88 OptDescCmd->add(opt_desc_generic);
89 OptDescCmd->add(opt_desc_service);
91 // Define valid config file options
92 Options_descriptionPtr _opt_desc_conf_main(new po::options_description("Config file options"));
93 OptDescConfMain = _opt_desc_conf_main;
94 _opt_desc_conf_main.reset();
95 OptDescConfMain->add(opt_desc_generic);
97 // Define valid service file options
98 Options_descriptionPtr _opt_desc_conf_service(new po::options_description("Service file options"));
99 OptDescConfService = _opt_desc_conf_service;
100 _opt_desc_conf_service.reset();
101 OptDescConfService->add(opt_desc_service);
114 * Parses the command line arguments and does the needed actions.
115 * @param argc Command line argument number given to main.
116 * @param argv[] Pointer to command line argument array given to main.
117 * @return 0 if all is fine, -1 if not.
119 int Config::parse_cmd_line(int argc, char *argv[])
123 po::store(po::parse_command_line(argc, argv, *this->OptDescCmd), VariablesMap);
124 po::notify(VariablesMap);
126 if ( VariablesMap.count("help") )
128 Log->print_usage(OptDescCmd);
131 else if ( VariablesMap.count("version") )
133 Log->print_version();
137 // Create a service object if all needed options are set on the command line
138 if ( VariablesMap.count("protocol") && VariablesMap.count("host") && VariablesMap.count("login") && VariablesMap.count("password") )
140 // Get the cmd parameter values for protocol host login and password
141 string protocol = VariablesMap["protocol"].as<string>();
142 string host = VariablesMap["host"].as<string>();
143 string login = VariablesMap["login"].as<string>();
144 string password = VariablesMap["password"].as<string>();
146 protocol = ba::to_lower_copy(protocol);
148 int update_interval = 0;
149 if ( VariablesMap.count("update_interval") )
150 update_interval = VariablesMap["update_interval"].as<int>();
152 int max_updates_within_interval = 0;
153 if ( VariablesMap.count("max_updates_within_interval") )
154 max_updates_within_interval = VariablesMap["max_updates_within_interval"].as<int>();
156 int dns_cache_ttl = 0;
157 if ( VariablesMap.count("dns_cache_ttl") )
158 dns_cache_ttl = VariablesMap["dns_cache_ttl"].as<int>();
160 Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval,dns_cache_ttl);
163 ServiceHolder->add_service(service);
164 Log->print_service_object("New Service object from command line options:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_dns_cache_ttl() , service->get_actual_ip(), service->get_last_updates());
169 else if ( VariablesMap.count("protocol") || VariablesMap.count("host") || VariablesMap.count("login") || VariablesMap.count("password") )
171 Log->print_missing_cmd_service_option();
172 Log->print_usage(OptDescCmd);
176 if ( VariablesMap.count("config") )
178 fs::path full_config_path = fs::system_complete(fs::path(VariablesMap["config"].as<string>()));
179 ConfigPath = full_config_path.string();
180 if ( !fs::exists(full_config_path) || !fs::is_directory(full_config_path) )
182 // Config path doesn't exist or is not a directory
183 Log->print_error_config_path(ConfigPath);
188 if ( VariablesMap.count("daemon_mode") )
189 DaemonMode = VariablesMap["daemon_mode"].as<bool>();
191 if ( VariablesMap.count("loglevel") )
192 Loglevel = VariablesMap["loglevel"].as<int>();
194 if ( VariablesMap.count("syslog") )
195 Syslog = VariablesMap["syslog"].as<bool>();
197 if ( VariablesMap.count("enable_ipv6") )
198 EnableIPv6 = VariablesMap["enable_ipv6"].as<bool>();
200 if ( VariablesMap.count("webcheck_url") )
201 WebcheckIpUrl = VariablesMap["webcheck_url"].as<string>();
203 if ( VariablesMap.count("webcheck_url_alt") )
204 WebcheckIpUrlAlt = VariablesMap["webcheck_url_alt"].as<string>();
206 if ( VariablesMap.count("http_proxy") && VariablesMap.count("http_proxy_port") )
208 Proxy = VariablesMap["http_proxy"].as<string>();
209 ProxyPort = VariablesMap["http_proxy_port"].as<int>();
211 else if ( VariablesMap.count("http_proxy") || VariablesMap.count("http_proxy_port") )
213 Log->print_missing_cmd_proxy_option();
214 Log->print_usage(OptDescCmd);
218 if ( VariablesMap.count("external_warning_log") )
219 ExternalWarningLog = VariablesMap["external_warning_log"].as<string>();
221 if ( VariablesMap.count("external_warning_level") )
222 ExternalWarningLevel = VariablesMap["external_warning_level"].as<int>();
225 catch(po::unknown_option e)
227 Log->print_unknown_cmd_option(e.what());
228 Log->print_usage(OptDescCmd);
231 catch(po::multiple_occurrences e)
233 Log->print_multiple_cmd_option(e.what());
234 Log->print_usage(OptDescCmd);
242 * Creates a Service object from the given parameters.
243 * @param protocol Protocol to use.
244 * @param host Hostname to update.
245 * @param login Login.
246 * @param password Password.
247 * @return A pointer to the created Service object.
249 Service::Ptr Config::create_service(const string &protocol,const string &hostname, const string &login, const string &password, const int update_interval, const int max_updates_within_interval, const int dns_cache_ttl)
251 if(protocol == "dhs")
253 Service::Ptr service_dhs(new DHS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort));
256 else if(protocol == "ods")
258 Service::Ptr service_ods(new ODS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl));
261 else if(protocol == "dyndns")
263 Service::Ptr service_dyndns(new DYNDNS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort));
264 return service_dyndns;
266 else if(protocol == "dyns")
268 Service::Ptr service_dyns(new DYNS(protocol,hostname,login,password,Log,update_interval,max_updates_within_interval,dns_cache_ttl,Proxy,ProxyPort));
273 Log->print_unknown_protocol(protocol);
274 Service::Ptr service;
281 * Loads a service config file, invoked by load_config_from_files.
282 * @param full_filename Filename of the service config file to load.
283 * @return 0 if all is fine, -1 otherwise.
285 int Config::load_service_config_file(const string& full_filename)
287 Log->print_load_service_conf(full_filename);
289 ifstream service_config_file(full_filename.c_str(),ifstream::in);
290 if(service_config_file.is_open())
294 po::variables_map vm;
295 po::parsed_options parsed_service_options = po::parse_config_file(service_config_file,*this->OptDescConfService,true);
296 po::store(parsed_service_options,vm);
299 if(vm.count("protocol") && vm.count("host") && vm.count("login") && vm.count("password"))
301 // create the corresponding service
302 string protocol = vm["protocol"].as<string>();
303 string host = vm["host"].as<string>();
304 string login = vm["login"].as<string>();
305 string password = vm["password"].as<string>();
307 protocol = ba::to_lower_copy(protocol);
309 int update_interval = 0;
310 if ( vm.count("update_interval") )
311 update_interval = VariablesMap["update_interval"].as<int>();
313 int max_updates_within_interval = 0;
314 if ( vm.count("max_updates_within_interval") )
315 max_updates_within_interval = VariablesMap["max_updates_within_interval"].as<int>();
317 int dns_cache_ttl = 0;
318 if ( vm.count("dns_cache_ttl") )
319 dns_cache_ttl = VariablesMap["dns_cache_ttl"].as<int>();
321 Service::Ptr service = create_service(protocol,host,login,password,update_interval,max_updates_within_interval,dns_cache_ttl);
324 ServiceHolder->add_service(service);
325 Log->print_service_object("New Service object from config:", service->get_protocol(), service->get_hostname(), service->get_login() ,service->get_password(), service->get_update_interval(), service->get_max_updates_within_interval(), service->get_dns_cache_ttl() , service->get_actual_ip(), service->get_last_updates());
330 else if ( vm.count("protocol") || vm.count("host") || vm.count("login") || vm.count("password") )
332 service_config_file.close();
333 Log->print_missing_service_conf_option(full_filename);
337 catch ( po::unknown_option e )
339 // unknown option in config file detected
340 service_config_file.close();
341 Log->print_unknown_service_conf_option(full_filename,e.what());
344 catch(po::multiple_occurrences e)
346 service_config_file.close();
347 Log->print_multiple_service_conf_option(full_filename,e.what());
350 service_config_file.close();
354 // error opening service config file for reading
355 Log->print_error_opening_r(full_filename);
363 * Loads the main config file, invoked by load_config_from_files
364 * @param full_filename The full filename of the main config file to load
365 * @return 0 if all is fine, -1 otherwise
367 int Config::load_main_config_file(const string& full_filename)
369 Log->print_load_main_conf(full_filename);
371 ifstream main_config_file(full_filename.c_str(),ifstream::in);
372 if(main_config_file.is_open())
376 po::parsed_options parsed_main_options = po::parse_config_file(main_config_file,*this->OptDescConfMain,true);
377 po::store(parsed_main_options,VariablesMap);
378 po::notify(VariablesMap);
380 if ( VariablesMap.count("daemon_mode") )
381 DaemonMode = VariablesMap["daemon_mode"].as<bool>();
383 if ( VariablesMap.count("loglevel") )
384 Loglevel = VariablesMap["loglevel"].as<int>();
386 if ( VariablesMap.count("syslog") )
387 Syslog = VariablesMap["syslog"].as<bool>();
389 if ( VariablesMap.count("enable_ipv6") )
390 EnableIPv6 = VariablesMap["enable_ipv6"].as<bool>();
392 if ( VariablesMap.count("webcheck_url") )
393 WebcheckIpUrl = VariablesMap["webcheck_url"].as<string>();
395 if ( VariablesMap.count("webcheck_url_alt") )
396 WebcheckIpUrlAlt = VariablesMap["webcheck_url_alt"].as<string>();
398 if ( VariablesMap.count("http_proxy") && VariablesMap.count("http_proxy_port") )
400 Proxy = VariablesMap["http_proxy"].as<string>();
401 ProxyPort = VariablesMap["http_proxy_port"].as<int>();
403 else if ( VariablesMap.count("http_proxy") || VariablesMap.count("http_proxy_port") )
405 main_config_file.close();
406 Log->print_missing_conf_proxy_option(full_filename);
410 if ( VariablesMap.count("external_warning_log") )
411 ExternalWarningLog = VariablesMap["external_warning_log"].as<string>();
413 if ( VariablesMap.count("external_warning_level") )
414 ExternalWarningLevel = VariablesMap["external_warning_level"].as<int>();
417 catch ( po::unknown_option e ) // at the moment 04-08-2009 this exception is never thrown :-(
419 // unknown option in main config file detected
420 main_config_file.close();
421 Log->print_unknown_main_conf_option(e.what());
424 catch(po::multiple_occurrences e)
426 main_config_file.close();
427 Log->print_multiple_main_conf_option(full_filename,e.what());
430 main_config_file.close();
434 // error opening main config file for reading
435 Log->print_error_opening_r(full_filename);
443 * Loads the main and the service config file and does the needed action.
444 * @param config_path The path to the config directory.
445 * @return 0 if all is fine, -1 otherwise
447 int Config::load_config_from_files()
449 fs::path full_config_path = fs::path(ConfigPath);
451 fs::directory_iterator end_iter;
452 for ( fs::directory_iterator dir_itr(full_config_path) ; dir_itr != end_iter ; ++dir_itr )
454 if( fs::is_regular_file( dir_itr->status() ) )
456 string actual_file = dir_itr->path().filename();
457 boost::regex expr(".*\\.conf?");
458 // If it is the main config file do the following
459 if ( actual_file == "bpdyndnsd.conf" )
461 // Load the main config file
462 string full_filename = dir_itr->path().string();
463 if ( load_main_config_file(full_filename) != 0 )
466 // If it is a service definition file *.conf, parse it and generate the corresponding service
467 else if ( boost::regex_search( actual_file,expr ) )
469 string full_filename = dir_itr->path().string();
470 if ( load_service_config_file(full_filename) != 0 )
475 // Config file successfully loaded
476 Log->print_conf_loaded(ConfigPath);
482 * Getter method for member OptDescCmd.
483 * @return options_description*.
485 Config::Options_descriptionPtr Config::get_opt_desc_cmd() const
492 * Getter method for member OptDescConfMain.
493 * @return options_description*.
495 Config::Options_descriptionPtr Config::get_opt_desc_conf_main() const
497 return OptDescConfMain;
502 * Getter method for member OptDescConfService.
503 * @return options_description*.
505 Config::Options_descriptionPtr Config::get_opt_desc_conf_service() const
507 return OptDescConfService;
512 * Getter for member Loglevel.
513 * @return Member Loglevel.
515 int Config::get_loglevel() const
522 * Getter for member DaemonMode.
523 * @return TRUE if enabled, FALSE if disabled.
525 bool Config::get_daemon_mode() const
532 * Deletes the map with the previously parsed options.
533 * This is needed in case we reload the config and don't want the old cmd options to overwrite new config file options.
535 void Config::delete_variables_map()
537 VariablesMap.clear();
539 po::variables_map _variables_map;
540 VariablesMap = _variables_map;
545 * Getter for member Syslog.
546 * @return True if logging through syslog is enabled, false otherwise.
548 bool Config::get_syslog() const
555 * Getter for member EnableIPv6
556 * @return Wether IPv6 should be used or not.
558 bool Config::get_enable_ipv6() const
565 * Getter for member WebcheckIpUrl
566 * @return The primary IP Webcheck URL
568 string Config::get_webcheck_ip_url() const
570 return WebcheckIpUrl;
575 * Getter for member WebcheckIpUrlAlt
576 * @return The alternative IP Webcheck URL
578 string Config::get_webcheck_ip_url_alt() const
580 return WebcheckIpUrlAlt;
588 string Config::get_proxy() const
595 * Get member ProxyPort
598 int Config::get_proxy_port() const
605 * Get member ExternalWarningLog
606 * @return ExternalWarningLog
608 string Config::get_external_warning_log() const
610 return ExternalWarningLog;
615 * Get member ExternalWarningLevel
616 * @return ExternalWaringLevel
618 int Config::get_external_warning_level() const
620 return ExternalWarningLevel;