/* The software in this package is distributed under the GNU General Public License version 2 (with a special exception described below). A copy of GNU General Public License (GPL) is included in this distribution, in the file COPYING.GPL. As a special exception, if other files instantiate templates or use macros or inline functions from this file, or you compile this file and link it with other works to produce a work based on this file, this file does not by itself cause the resulting work to be covered by the GNU General Public License. However the source code for this file must still be made available in accordance with section (3) of the GNU General Public License. This exception does not invalidate any other reasons why a work based on this file might be covered by the GNU General Public License. */ #include "config/configurationoptions.h" #include #include #include #include "boost_assert_handler.h" #include "config/option/configfileoption.h" #include "config/option/daemonoption.h" #include "config/option/hostsdownlimitoption.h" #include "config/option/hostnameoption.h" #include "config/option/hostportoption.h" #include "config/option/hostpingprotocoloption.h" #include "config/option/hostpingintervaloption.h" #include "config/option/hostsourcenetworkinterfaceoption.h" #include "config/option/linkdownintervaloption.h" #include "config/option/linkupintervaloption.h" #include "config/option/logleveloption.h" #include "config/option/logoutputoption.h" #include "config/option/logfileoption.h" #include "config/option/nameserveroption.h" #include "config/option/pingfaillimitoption.h" #include "config/option/sourcenetworkinterfaceoption.h" #include "config/option/statusnotifiercmdoption.h" #include "config/option/versionoption.h" #include "config/option/ratiorandomhostsoption.h" #include "config/option/pingreplytimeoutoption.h" #include "config/option/maxaddressresolutionattemptsoption.h" #include "config/option/resolvedipttlthresholdoption.h" #include "config/option/mintimebetweenresolvesoption.h" #include "config/option/dnscachefileoption.h" using namespace std; using boost::program_options::option_description; using boost::program_options::options_description; using boost::program_options::value; using boost::program_options::variables_map; using boost::shared_ptr; using I2n::Logger::GlobalLogger; //----------------------------------------------------------------------------- // ConfigurationOptions //----------------------------------------------------------------------------- /** * @brief Default constructor. */ ConfigurationOptions::ConfigurationOptions() : GenericOptions(), ConfigOptions(), HostOptions(), HelpCmdStr( "help" ), HelpCmdDesc( "Print this help and exit." ) { ConfigurationOptionItem config_file( new ConfigFileOption ); GenericOptions.push_back( config_file ); ConfigurationOptionItem daemon( new DaemonOption ); GenericOptions.push_back( daemon ); ConfigurationOptionItem version( new VersionOption ); GenericOptions.push_back( version ); ConfigurationOptionItem log_level( new LogLevelOption ); GenericOptions.push_back( log_level ); ConfigurationOptionItem log_output( new LogOutputOption ); GenericOptions.push_back( log_output ); ConfigurationOptionItem log_file( new LogFileOption ); GenericOptions.push_back( log_file ); ConfigurationOptionItem hosts_down_limit( new HostsDownLimitOption ); ConfigOptions.push_back( hosts_down_limit ); ConfigurationOptionItem link_down_interval( new LinkDownIntervalOption ); ConfigOptions.push_back( link_down_interval ); ConfigurationOptionItem link_up_interval( new LinkUpIntervalOption ); ConfigOptions.push_back( link_up_interval ); ConfigurationOptionItem nameserver( new NameserverOption ); ConfigOptions.push_back( nameserver ); ConfigurationOptionItem ping_fail_limit( new PingFailLimitOption ); ConfigOptions.push_back( ping_fail_limit ); ConfigurationOptionItem source_network_interface( new SourceNetworkInterfaceOption ); ConfigOptions.push_back( source_network_interface ); ConfigurationOptionItem status_notifier_cmd( new StatusNotifierCmdOption ); ConfigOptions.push_back( status_notifier_cmd ); ConfigurationOptionItem ping_reply_timeout( new PingReplyTimeoutOption ); ConfigOptions.push_back( ping_reply_timeout ); ConfigurationOptionItem max_address_resolution_attempts( new MaxAddressResolutionAttemptsOption ); ConfigOptions.push_back( max_address_resolution_attempts ); ConfigurationOptionItem resolved_ip_ttl_threshold( new ResolvedIpTtlThresholdOption ); ConfigOptions.push_back( resolved_ip_ttl_threshold ); ConfigurationOptionItem min_time_between_resolves( new MinTimeBetweenResolvesOption ); ConfigOptions.push_back( min_time_between_resolves ); ConfigurationOptionItem ratio_random_hosts( new RatioRandomHostsOption ); ConfigOptions.push_back( ratio_random_hosts ); ConfigurationOptionItem dns_cache_file( new DnsCacheFileOption ); ConfigOptions.push_back( dns_cache_file ); HostConfigurationOptionItem host_name( new HostNameOption ); HostOptions.push_back( host_name ); HostConfigurationOptionItem host_port( new HostPortOption ); HostOptions.push_back( host_port ); HostConfigurationOptionItem host_source_network_interface( new HostSourceNetworkInterfaceOption ); HostOptions.push_back( host_source_network_interface ); HostConfigurationOptionItem host_protocol( new HostPingProtocolOption ); HostOptions.push_back( host_protocol ); HostConfigurationOptionItem host_interval( new HostPingIntervalOption ); HostOptions.push_back( host_interval ); } /** * @brief Destructor. */ ConfigurationOptions::~ConfigurationOptions() { } /** * @return The options which are common to all kinds of applications. */ options_description ConfigurationOptions::get_generic_options() const { options_description options( "Generic options" ); options.add_options() ( HelpCmdStr.c_str(), HelpCmdDesc.c_str() ) ; BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions ) { // Do not pass the the underlying boost::program_options::option_description // object from ConfigurationOption to the // boost::program_options::options_description::add() method, because it // deletes the boost::program_options::option_description, causing // multiple freed when ConfigurationOption try to delete it. option_description option = generic_option->get_option_description(); shared_ptr< option_description > ptr( new option_description( option ) ); options.add( ptr ); } return options; } /** * @return The options which are specific to this application. */ options_description ConfigurationOptions::get_configuration_options() const { options_description options( "Configuration" ); BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions ) { option_description option = configuration_option->get_option_description(); shared_ptr< option_description > ptr( new option_description( option ) ); options.add( ptr ); } BOOST_FOREACH( ConfigurationOptionItem host_option, HostOptions ) { option_description option = host_option->get_option_description(); shared_ptr< option_description > ptr( new option_description( option ) ); options.add( ptr ); } return options; } /** * @brief Parse the options common to all kinds of applications. * * @param vm The input @c boost::program_options::variables_map. * @param configuration The output @c Configuration filled with the parsed * generic options. * * @return @c true if it was parsed at least one option, or @c false if there * were no options available in this category. */ bool ConfigurationOptions::parse_generic_options( const variables_map& vm, Configuration *configuration ) { BOOST_ASSERT(configuration != NULL); // help if ( vm.count( HelpCmdStr ) > 0 ) { options_description generic = get_generic_options(); options_description config = get_configuration_options(); options_description visible_options( "Allowed options" ); visible_options.add( generic ).add( config ); // TODO GlobalOutput::print( help ) cout << visible_options << endl; return true; } BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions ) { generic_option->parse( vm, configuration ); } return false; } /** * @brief Parse the options specific to this application. * * @param vm The input @c boost::program_options::variables_map. * @param configuration The output @c Configuration filled with the parsed * configuration options. * * @return @c true if it was parsed at least one option, or @c false if there * were no options available in this category. */ bool ConfigurationOptions::parse_configuration_options( const variables_map &vm, Configuration *configuration ) { BOOST_ASSERT(configuration != NULL); BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions ) { configuration_option->parse( vm, configuration ); } bool hosts_parsed = parse_hosts_options(vm, configuration); return hosts_parsed; } /** * @brief Parse the hosts section options. * * @param vm The input @c boost::program_options::variables_map. * @param configuration The output @c Configuration filled with the parsed * hosts options. * * @return @c true if the hosts were parsed correctly, or @c false otherwise. */ bool ConfigurationOptions::parse_hosts_options( const variables_map &vm, Configuration *configuration ) { BOOST_ASSERT(configuration != NULL); size_t host_down_limit_count = static_cast( configuration->get_hosts_down_limit() ); BOOST_FOREACH( HostConfigurationOptionItem host_option, HostOptions ) { bool parsed = host_option->parse( vm, configuration ); if ( parsed ) { // The set_hosts_count() method is called in parse() method, that is // why we must parse before check the number of host options size_t hosts_parsed_count = host_option->get_hosts_count(); bool have_minimum_hosts = ( host_down_limit_count <= hosts_parsed_count ); // Ensure we have all options for each host if ( !have_minimum_hosts ) { // TODO GlobalOutput::print() GlobalLogger.error() << "Could not parse configuration file." << " Missing an entry for one of the hosts." << endl; // TODO Assume default value for a missing option return false; } BOOST_ASSERT( hosts_parsed_count >= static_cast( host_down_limit_count ) ); } } return true; } /** * @return which options must abort the application. Like the --version. */ bool ConfigurationOptions::halt_on_generic_options( const variables_map &vm ) const { VersionOption v; bool is_help = ( vm.count( HelpCmdStr ) > 0 ); bool is_version = ( vm.count( v.get_command_string() ) > 0 ); bool terminate_app = is_help || is_version; return terminate_app; }