5010921c346f852a73ed7794617338b67809e8c2
[pingcheck] / src / config / configurationoptions.cpp
1 /*
2  The software in this package is distributed under the GNU General
3  Public License version 2 (with a special exception described below).
4
5  A copy of GNU General Public License (GPL) is included in this distribution,
6  in the file COPYING.GPL.
7
8  As a special exception, if other files instantiate templates or use macros
9  or inline functions from this file, or you compile this file and link it
10  with other works to produce a work based on this file, this file
11  does not by itself cause the resulting work to be covered
12  by the GNU General Public License.
13
14  However the source code for this file must still be made available
15  in accordance with section (3) of the GNU General Public License.
16
17  This exception does not invalidate any other reasons why a work based
18  on this file might be covered by the GNU General Public License.
19  */
20
21 #include "config/configurationoptions.h"
22
23 #include <iostream>
24
25 #include <boost/foreach.hpp>
26
27 #include <logfunc.hpp>
28
29 #include "boost_assert_handler.h"
30 #include "config/option/configfileoption.h"
31 #include "config/option/daemonoption.h"
32 #include "config/option/hostsdownlimitoption.h"
33 #include "config/option/hostnameoption.h"
34 #include "config/option/hostportoption.h"
35 #include "config/option/hostpingprotocoloption.h"
36 #include "config/option/hostpingintervaloption.h"
37 #include "config/option/hostsourcenetworkinterfaceoption.h"
38 #include "config/option/linkdownintervaloption.h"
39 #include "config/option/linkupintervaloption.h"
40 #include "config/option/logleveloption.h"
41 #include "config/option/logoutputoption.h"
42 #include "config/option/nameserveroption.h"
43 #include "config/option/pingfaillimitoption.h"
44 #include "config/option/sourcenetworkinterfaceoption.h"
45 #include "config/option/statusnotifiercmdoption.h"
46 #include "config/option/versionoption.h"
47 #include "config/option/ratiorandomhostsoption.h"
48 #include "config/option/pingreplytimeoutoption.h"
49 #include "config/option/maxaddressresolutionattemptsoption.h"
50 #include "config/option/resolvedipttlthresholdoption.h"
51 #include "config/option/dnscachefileoption.h"
52
53 using namespace std;
54 using boost::program_options::option_description;
55 using boost::program_options::options_description;
56 using boost::program_options::value;
57 using boost::program_options::variables_map;
58 using boost::shared_ptr;
59 using I2n::Logger::GlobalLogger;
60
61 //-----------------------------------------------------------------------------
62 // ConfigurationOptions
63 //-----------------------------------------------------------------------------
64
65 /**
66  * @brief Default constructor.
67  */
68 ConfigurationOptions::ConfigurationOptions() :
69     GenericOptions(),
70     ConfigOptions(),
71     HostOptions(),
72     HelpCmdStr( "help" ),
73     HelpCmdDesc( "Print this help and exit." )
74 {
75     ConfigurationOptionItem config_file( new ConfigFileOption );
76     GenericOptions.push_back( config_file );
77
78     ConfigurationOptionItem daemon( new DaemonOption );
79     GenericOptions.push_back( daemon );
80
81     ConfigurationOptionItem version( new VersionOption );
82     GenericOptions.push_back( version );
83
84     ConfigurationOptionItem log_level( new LogLevelOption );
85     GenericOptions.push_back( log_level );
86
87     ConfigurationOptionItem log_output( new LogOutputOption );
88     GenericOptions.push_back( log_output );
89
90     ConfigurationOptionItem hosts_down_limit( new HostsDownLimitOption );
91     ConfigOptions.push_back( hosts_down_limit );
92
93     ConfigurationOptionItem link_down_interval( new LinkDownIntervalOption );
94     ConfigOptions.push_back( link_down_interval );
95
96     ConfigurationOptionItem link_up_interval( new LinkUpIntervalOption );
97     ConfigOptions.push_back( link_up_interval );
98
99     ConfigurationOptionItem nameserver( new NameserverOption );
100     ConfigOptions.push_back( nameserver );
101
102     ConfigurationOptionItem ping_fail_limit( new PingFailLimitOption );
103     ConfigOptions.push_back( ping_fail_limit );
104
105     ConfigurationOptionItem source_network_interface( new SourceNetworkInterfaceOption );
106     ConfigOptions.push_back( source_network_interface );
107
108     ConfigurationOptionItem status_notifier_cmd( new StatusNotifierCmdOption );
109     ConfigOptions.push_back( status_notifier_cmd );
110
111     ConfigurationOptionItem ping_reply_timeout( new PingReplyTimeoutOption );
112     ConfigOptions.push_back( ping_reply_timeout );
113
114     ConfigurationOptionItem max_address_resolution_attempts( new MaxAddressResolutionAttemptsOption );
115     ConfigOptions.push_back( max_address_resolution_attempts );
116
117     ConfigurationOptionItem resolved_ip_ttl_threshold( new ResolvedIpTtlThresholdOption );
118     ConfigOptions.push_back( resolved_ip_ttl_threshold );
119
120     ConfigurationOptionItem ratio_random_hosts( new RatioRandomHostsOption );
121     ConfigOptions.push_back( ratio_random_hosts );
122
123     ConfigurationOptionItem dns_cache_file( new DnsCacheFileOption );
124     ConfigOptions.push_back( dns_cache_file );
125
126     HostConfigurationOptionItem host_name( new HostNameOption );
127     HostOptions.push_back( host_name );
128
129     HostConfigurationOptionItem host_port( new HostPortOption );
130     HostOptions.push_back( host_port );
131
132     HostConfigurationOptionItem host_source_network_interface( new HostSourceNetworkInterfaceOption );
133     HostOptions.push_back( host_source_network_interface );
134
135     HostConfigurationOptionItem host_protocol( new HostPingProtocolOption );
136     HostOptions.push_back( host_protocol );
137
138     HostConfigurationOptionItem host_interval( new HostPingIntervalOption );
139     HostOptions.push_back( host_interval );
140 }
141
142 /**
143  * @brief Destructor.
144  */
145 ConfigurationOptions::~ConfigurationOptions()
146 {
147 }
148
149 /**
150  * @return The options which are common to all kinds of applications.
151  */
152 options_description ConfigurationOptions::get_generic_options() const
153 {
154     options_description options( "Generic options" );
155
156     options.add_options()
157         ( HelpCmdStr.c_str(), HelpCmdDesc.c_str() )
158     ;
159
160     BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions )
161     {
162         // Do not pass the the underlying boost::program_options::option_description
163         // object from ConfigurationOption to the
164         // boost::program_options::options_description::add() method, because it
165         // deletes the boost::program_options::option_description, causing
166         // multiple freed when ConfigurationOption try to delete it.
167         option_description option = generic_option->get_option_description();
168         shared_ptr< option_description > ptr( new option_description( option ) );
169         options.add( ptr );
170     }
171
172     return options;
173 }
174
175 /**
176  * @return The options which are specific to this application.
177  */
178 options_description ConfigurationOptions::get_configuration_options() const
179 {
180     options_description options( "Configuration" );
181
182     BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions )
183     {
184         option_description option = configuration_option->get_option_description();
185         shared_ptr< option_description > ptr( new option_description( option ) );
186         options.add( ptr );
187     }
188
189     BOOST_FOREACH( ConfigurationOptionItem host_option, HostOptions )
190     {
191         option_description option = host_option->get_option_description();
192         shared_ptr< option_description > ptr( new option_description( option ) );
193         options.add( ptr );
194     }
195
196     return options;
197 }
198
199 /**
200  * @brief Parse the options common to all kinds of applications.
201  *
202  * @param vm The input @c boost::program_options::variables_map.
203  * @param configuration The output @c Configuration filled with the parsed
204  * generic options.
205  *
206  * @return @c true if it was parsed at least one option, or @c false if there
207  * were no options available in this category.
208  */
209 bool ConfigurationOptions::parse_generic_options(
210         const variables_map& vm,
211         Configuration *configuration
212 )
213 {
214     BOOST_ASSERT(configuration != NULL);
215
216     // help
217     if ( vm.count( HelpCmdStr ) > 0 )
218     {
219         options_description generic = get_generic_options();
220         options_description config = get_configuration_options();
221
222         options_description visible_options( "Allowed options" );
223         visible_options.add( generic ).add( config );
224
225         // TODO GlobalOutput::print( help )
226         cout << visible_options << endl;
227         return true;
228     }
229
230     BOOST_FOREACH( ConfigurationOptionItem generic_option, GenericOptions )
231     {
232         generic_option->parse( vm, configuration );
233     }
234
235     return false;
236 }
237
238 /**
239  * @brief Parse the options specific to this application.
240  *
241  * @param vm The input @c boost::program_options::variables_map.
242  * @param configuration The output @c Configuration filled with the parsed
243  * configuration options.
244  *
245  * @return @c true if it was parsed at least one option, or @c false if there
246  * were no options available in this category.
247  */
248 bool ConfigurationOptions::parse_configuration_options(
249         const variables_map &vm,
250         Configuration *configuration
251 )
252 {
253     BOOST_ASSERT(configuration != NULL);
254
255     BOOST_FOREACH( ConfigurationOptionItem configuration_option, ConfigOptions )
256     {
257         configuration_option->parse( vm, configuration );
258     }
259
260     bool hosts_parsed = parse_hosts_options(vm, configuration);
261
262     return hosts_parsed;
263 }
264
265 /**
266  * @brief Parse the hosts section options.
267  *
268  * @param vm The input @c boost::program_options::variables_map.
269  * @param configuration The output @c Configuration filled with the parsed
270  * hosts options.
271  *
272  * @return @c true if the hosts were parsed correctly, or @c false otherwise.
273  */
274 bool ConfigurationOptions::parse_hosts_options(
275         const variables_map &vm,
276         Configuration *configuration
277 )
278 {
279     BOOST_ASSERT(configuration != NULL);
280
281     size_t host_down_limit_count = static_cast<size_t>( configuration->get_hosts_down_limit() );
282
283     BOOST_FOREACH( HostConfigurationOptionItem host_option, HostOptions )
284     {
285         bool parsed = host_option->parse( vm, configuration );
286         if ( parsed )
287         {
288             // The set_hosts_count() method is called in parse() method, that is
289             // why we must parse before check the number of host options
290             size_t hosts_parsed_count = host_option->get_hosts_count();
291             bool have_minimum_hosts = ( host_down_limit_count <= hosts_parsed_count );
292             // Ensure we have all options for each host
293             if ( !have_minimum_hosts ) {
294                 // TODO GlobalOutput::print()
295                 GlobalLogger.error() << "Could not parse configuration file." <<
296                         " Missing an entry for one of the hosts." << endl;
297                 // TODO Assume default value for a missing option
298                 return false;
299             }
300
301             BOOST_ASSERT( hosts_parsed_count >= static_cast<size_t>( host_down_limit_count ) );
302         }
303     }
304
305     return true;
306 }
307
308 /**
309  * @return which options must abort the application. Like the --version.
310  */
311 bool ConfigurationOptions::halt_on_generic_options( const variables_map &vm ) const
312 {
313     VersionOption v;
314
315     bool is_help = ( vm.count( HelpCmdStr ) > 0 );
316     bool is_version = ( vm.count( v.get_command_string() ) > 0 );
317     bool terminate_app = is_help || is_version;
318
319     return terminate_app;
320 }