2
0
mirror of https://gitlab.isc.org/isc-projects/kea synced 2025-09-03 15:35:17 +00:00

[2270] Changes after review

- added boundary checks for Uint32Parser
- fixed #include order
- Class renamed to Dhcp4ConfigParser
- added extra test for Uint32Parser
- Many Doxygen fixes and clean-ups
This commit is contained in:
Tomek Mrugalski
2012-12-05 15:27:30 +01:00
parent bdeb3c67d1
commit c84efb2586
8 changed files with 235 additions and 151 deletions

View File

@@ -1,4 +1,4 @@
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
@@ -12,25 +12,21 @@
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
// We want UINT32_MAX macro to be defined in stdint.h
#define __STDC_LIMIT_MACROS
#include <boost/foreach.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <config/ccsession.h>
#include <dhcp/cfgmgr.h>
#include <dhcp4/config_parser.h>
#include <dhcp4/dhcp4_log.h>
#include <stdint.h>
#include <iostream>
#include <vector>
#include <map>
#include <boost/foreach.hpp>
#include <boost/shared_ptr.hpp>
#include <boost/scoped_ptr.hpp>
#include <boost/lexical_cast.hpp>
#include <boost/algorithm/string.hpp>
#include <asiolink/io_address.h>
#include <cc/data.h>
#include <config/ccsession.h>
#include <log/logger_support.h>
#include <dhcp/triplet.h>
#include <dhcp/pool.h>
#include <dhcp/subnet.h>
#include <dhcp/cfgmgr.h>
#include <dhcp4/config_parser.h>
#include <dhcp4/dhcp4_log.h>
using namespace std;
using namespace isc::data;
@@ -43,17 +39,11 @@ namespace dhcp {
typedef pair<string, ConstElementPtr> ConfigPair;
/// @brief a factory method that will create a parser for a given element name
typedef DhcpConfigParser* ParserFactory(const std::string& config_id);
typedef Dhcp4ConfigParser* ParserFactory(const std::string& config_id);
/// @brief a collection of factories that creates parsers for specified element names
typedef std::map<std::string, ParserFactory*> FactoryMap;
/// @brief a collection of elements that store uint32 values (e.g. renew-timer = 900)
typedef std::map<string, uint32_t> Uint32Storage;
/// @brief a collection of elements that store string values
typedef std::map<string, string> StringStorage;
/// @brief a collection of pools
///
/// That type is used as intermediate storage, when pools are parsed, but there is
@@ -72,12 +62,12 @@ StringStorage string_defaults;
/// will accept any configuration and will just print it out
/// on commit. Useful for debugging existing configurations and
/// adding new ones.
class DebugParser : public DhcpConfigParser {
class DebugParser : public Dhcp4ConfigParser {
public:
/// @brief Constructor
///
/// See \ref DhcpConfigParser class for details.
/// See \ref Dhcp4ConfigParser class for details.
///
/// @param param_name name of the parsed parameter
DebugParser(const std::string& param_name)
@@ -86,7 +76,7 @@ public:
/// @brief builds parameter value
///
/// See \ref DhcpConfigParser class for details.
/// See \ref Dhcp4ConfigParser class for details.
///
/// @param new_config pointer to the new configuration
virtual void build(ConstElementPtr new_config) {
@@ -100,7 +90,7 @@ public:
/// This is a method required by base class. It pretends to apply the
/// configuration, but in fact it only prints the parameter out.
///
/// See \ref DhcpConfigParser class for details.
/// See \ref Dhcp4ConfigParser class for details.
virtual void commit() {
// Debug message. The whole DebugParser class is used only for parser
// debugging, and is not used in production code. It is very convenient
@@ -112,11 +102,11 @@ public:
/// @brief factory that constructs DebugParser objects
///
/// @param param_name name of the parameter to be parsed
static DhcpConfigParser* Factory(const std::string& param_name) {
static Dhcp4ConfigParser* Factory(const std::string& param_name) {
return (new DebugParser(param_name));
}
protected:
private:
/// name of the parsed parameter
std::string param_name_;
@@ -131,11 +121,11 @@ protected:
/// (uint32_defaults). If used in smaller scopes (e.g. to parse parameters
/// in subnet config), it can be pointed to a different storage, using
/// setStorage() method. This class follows the parser interface, laid out
/// in its base class, \ref DhcpConfigParser.
/// in its base class, \ref Dhcp4ConfigParser.
///
/// For overview of usability of this generic purpose parser, see
/// \ref dhcpv4-config-inherit page.
class Uint32Parser : public DhcpConfigParser {
/// \ref dhcp4-config-inherit page.
class Uint32Parser : public Dhcp4ConfigParser {
public:
/// @brief constructor for Uint32Parser
@@ -150,13 +140,30 @@ public:
/// \ref setStorage() for details.
///
/// @param value pointer to the content of parsed values
/// @throw BadValue if supplied value could not be base to uint32_t
virtual void build(ConstElementPtr value) {
int64_t check;
string x = value->str();
try {
value_ = boost::lexical_cast<uint32_t>(value->str());
check = boost::lexical_cast<int64_t>(x);
} catch (const boost::bad_lexical_cast &) {
isc_throw(BadValue, "Failed to parse value " << value->str()
<< " as unsigned 32-bit integer.");
}
if (check > UINT32_MAX) {
isc_throw(BadValue, "Value " << value->str() << "is too large"
<< " for unsigned 32-bit integer.");
}
if (check < 0) {
isc_throw(BadValue, "Value " << value->str() << "is negative."
<< " Only 0 or larger are allowed for unsigned 32-bit integer.");
}
// value is small enough to fit
value_ = static_cast<uint32_t>(check);
/// @todo: check if there is no such name in the map. Otherwise
/// the insert will fail silently
storage_->insert(pair<string, uint32_t>(param_name_, value_));
}
@@ -166,7 +173,7 @@ public:
/// is not commited anywhere. Higher level parsers are expected to
/// use values stored in the storage, e.g. renew-timer for a given
/// subnet is stored in subnet-specific storage. It is not commited
/// here, but is rather used by \ref Subnet4Parser when constructing
/// here, but is rather used by \ref Subnet4ConfigParser when constructing
/// the subnet.
virtual void commit() {
}
@@ -174,13 +181,13 @@ public:
/// @brief factory that constructs Uint32Parser objects
///
/// @param param_name name of the parameter to be parsed
static DhcpConfigParser* Factory(const std::string& param_name) {
static Dhcp4ConfigParser* Factory(const std::string& param_name) {
return (new Uint32Parser(param_name));
}
/// @brief sets storage for value of this parameter
///
/// See \ref dhcpv4-config-inherit for details.
/// See \ref dhcp4-config-inherit for details.
///
/// @param storage pointer to the storage container
void setStorage(Uint32Storage* storage) {
@@ -205,11 +212,11 @@ protected:
/// (string_defaults). If used in smaller scopes (e.g. to parse parameters
/// in subnet config), it can be pointed to a different storage, using
/// setStorage() method. This class follows the parser interface, laid out
/// in its base class, \ref DhcpConfigParser.
/// in its base class, \ref Dhcp4ConfigParser.
///
/// For overview of usability of this generic purpose parser, see
/// \ref dhcpv4-config-inherit page.
class StringParser : public DhcpConfigParser {
/// \ref dhcp4-config-inherit page.
class StringParser : public Dhcp4ConfigParser {
public:
/// @brief constructor for StringParser
@@ -227,6 +234,8 @@ public:
virtual void build(ConstElementPtr value) {
value_ = value->str();
boost::erase_all(value_, "\"");
/// @todo: check if there is no such name in the map. Otherwise
/// the insert will fail silently
storage_->insert(pair<string, string>(param_name_, value_));
}
@@ -244,13 +253,13 @@ public:
/// @brief factory that constructs StringParser objects
///
/// @param param_name name of the parameter to be parsed
static DhcpConfigParser* Factory(const std::string& param_name) {
static Dhcp4ConfigParser* Factory(const std::string& param_name) {
return (new StringParser(param_name));
}
/// @brief sets storage for value of this parameter
///
/// See \ref dhcpv4-config-inherit for details.
/// See \ref dhcp4-config-inherit for details.
///
/// @param storage pointer to the storage container
void setStorage(StringStorage* storage) {
@@ -277,7 +286,7 @@ protected:
/// designates all interfaces.
///
/// It is useful for parsing Dhcp4/interface parameter.
class InterfaceListConfigParser : public DhcpConfigParser {
class InterfaceListConfigParser : public Dhcp4ConfigParser {
public:
/// @brief constructor
@@ -286,17 +295,18 @@ public:
/// "interface" parameter only. All other types will throw exception.
///
/// @param param_name name of the configuration parameter being parsed
/// @throw BadValue if supplied parameter name is not "interface"
InterfaceListConfigParser(const std::string& param_name) {
if (param_name != "interface") {
isc_throw(NotImplemented, "Internal error. Interface configuration "
isc_throw(BadValue, "Internal error. Interface configuration "
"parser called for the wrong parameter: " << param_name);
}
}
/// @brief parses parameters value
///
/// Parses configuration entry (list of parameters) and stores it in
/// storage. See \ref setStorage() for details.
/// Parses configuration entry (list of parameters) and adds each element
/// to the interfaces list.
///
/// @param value pointer to the content of parsed values
virtual void build(ConstElementPtr value) {
@@ -314,7 +324,7 @@ public:
/// @brief factory that constructs InterfaceListConfigParser objects
///
/// @param param_name name of the parameter to be parsed
static DhcpConfigParser* Factory(const std::string& param_name) {
static Dhcp4ConfigParser* Factory(const std::string& param_name) {
return (new InterfaceListConfigParser(param_name));
}
@@ -333,7 +343,7 @@ protected:
/// before build(). Otherwise exception will be thrown.
///
/// It is useful for parsing Dhcp4/subnet4[X]/pool parameters.
class PoolParser : public DhcpConfigParser {
class PoolParser : public Dhcp4ConfigParser {
public:
/// @brief constructor.
@@ -347,10 +357,13 @@ public:
/// This method parses the actual list of interfaces.
/// No validation is done at this stage, everything is interpreted as
/// interface name.
/// @param pools_list list of pools defined for a subnet
/// @throw InvalidOperation if storage was not specified (setStorage() not called)
/// @throw Dhcp4ConfigError when pool parsing fails
void build(ConstElementPtr pools_list) {
// setStorage() should have been called before build
if (!pools_) {
isc_throw(NotImplemented, "Parser logic error. No pool storage set,"
isc_throw(InvalidOperation, "Parser logic error. No pool storage set,"
" but pool parser asked to parse pools");
}
@@ -416,7 +429,7 @@ public:
/// @brief sets storage for value of this parameter
///
/// See \ref dhcpv4-config-inherit for details.
/// See \ref dhcp4-config-inherit for details.
///
/// @param storage pointer to the storage container
void setStorage(PoolStorage* storage) {
@@ -433,7 +446,7 @@ public:
/// @brief factory that constructs PoolParser objects
///
/// @param param_name name of the parameter to be parsed
static DhcpConfigParser* Factory(const std::string& param_name) {
static Dhcp4ConfigParser* Factory(const std::string& param_name) {
return (new PoolParser(param_name));
}
@@ -449,7 +462,7 @@ protected:
///
/// This class parses the whole subnet definition. It creates parsers
/// for received configuration parameters as needed.
class Subnet4ConfigParser : public DhcpConfigParser {
class Subnet4ConfigParser : public Dhcp4ConfigParser {
public:
/// @brief constructor
@@ -469,22 +482,22 @@ public:
// if this is an Uint32 parser, tell it to store the values
// in values_, rather than in global storage
boost::shared_ptr<Uint32Parser> uintParser =
boost::shared_ptr<Uint32Parser> uint_parser =
boost::dynamic_pointer_cast<Uint32Parser>(parser);
if (uintParser) {
uintParser->setStorage(&uint32_values_);
if (uint_parser) {
uint_parser->setStorage(&uint32_values_);
} else {
boost::shared_ptr<StringParser> stringParser =
boost::shared_ptr<StringParser> string_parser =
boost::dynamic_pointer_cast<StringParser>(parser);
if (stringParser) {
stringParser->setStorage(&string_values_);
if (string_parser) {
string_parser->setStorage(&string_values_);
} else {
boost::shared_ptr<PoolParser> poolParser =
boost::shared_ptr<PoolParser> pool_parser =
boost::dynamic_pointer_cast<PoolParser>(parser);
if (poolParser) {
poolParser->setStorage(&pools_);
if (pool_parser) {
pool_parser->setStorage(&pools_);
}
}
}
@@ -502,6 +515,7 @@ public:
/// storing the values that are actually consumed here. Pool definitions
/// created in other parsers are used here and added to newly created Subnet4
/// objects. Subnet4 are then added to DHCP CfgMgr.
/// @throw Dhcp4ConfigError if there are any issues encountered during commit
void commit() {
StringStorage::const_iterator it = string_values_.find("subnet");
@@ -549,7 +563,8 @@ protected:
///
/// @param config_id name od the entry
/// @return parser object for specified entry name
DhcpConfigParser* createSubnet4ConfigParser(const std::string& config_id) {
/// @throw NotImplemented if trying to create a parser for unknown config element
Dhcp4ConfigParser* createSubnet4ConfigParser(const std::string& config_id) {
FactoryMap factories;
factories.insert(pair<string, ParserFactory*>(
@@ -585,6 +600,7 @@ protected:
///
/// @param name name of the parameter
/// @return triplet with the parameter name
/// @throw Dhcp4ConfigError when requested parameter is not present
Triplet<uint32_t> getParam(const std::string& name) {
uint32_t value = 0;
bool found = false;
@@ -627,7 +643,7 @@ protected:
/// This is a wrapper parser that handles the whole list of Subnet4
/// definitions. It iterates over all entries and creates Subnet4ConfigParser
/// for each entry.
class Subnets4ListConfigParser : public DhcpConfigParser {
class Subnets4ListConfigParser : public Dhcp4ConfigParser {
public:
/// @brief constructor
@@ -676,7 +692,7 @@ public:
/// @brief Returns Subnet4ListConfigParser object
/// @param param_name name of the parameter
/// @return Subnets4ListConfigParser object
static DhcpConfigParser* Factory(const std::string& param_name) {
static Dhcp4ConfigParser* Factory(const std::string& param_name) {
return (new Subnets4ListConfigParser(param_name));
}
@@ -691,7 +707,8 @@ public:
///
/// @param config_id pointer to received global configuration entry
/// @return parser for specified global DHCPv4 parameter
DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
/// @throw NotImplemented if trying to create a parser for unknown config element
Dhcp4ConfigParser* createGlobalDhcp4ConfigParser(const std::string& config_id) {
FactoryMap factories;
factories.insert(pair<string, ParserFactory*>(
@@ -723,25 +740,18 @@ DhcpConfigParser* createGlobalDhcpConfigParser(const std::string& config_id) {
/// @brief configures DHCPv4 server
///
/// This function is called every time a new configuration is received. The extra
/// parameter is a reference to DHCPv4 server component. It is currently not used
/// and CfgMgr::instance() is accessed instead.
///
/// This method does not throw. It catches all exceptions and returns them as
/// reconfiguration statuses. It may return the following response codes:
/// 0 - configuration successful
/// 1 - malformed configuration (parsing failed)
/// 2 - logical error (parsing was successful, but the values are invalid)
///
/// @param config_set a new configuration for DHCPv4 server
/// @return answer that contains result of reconfiguration
isc::data::ConstElementPtr
configureDhcp4Server(Dhcpv4Srv& , ConstElementPtr config_set) {
if (!config_set) {
isc_throw(Dhcp4ConfigError,
"Null pointer is passed to configuration parser");
ConstElementPtr answer = isc::config::createAnswer(1,
string("Can't parse NULL config"));
return (answer);
}
/// Let's wipe previous configuration defaults
uint32_defaults.clear();
string_defaults.clear();
/// @todo: append most essential info here (like "2 new subnets configured")
string config_details;
@@ -751,7 +761,7 @@ configureDhcp4Server(Dhcpv4Srv& , ConstElementPtr config_set) {
try {
BOOST_FOREACH(ConfigPair config_pair, config_set->mapValue()) {
ParserPtr parser(createGlobalDhcpConfigParser(config_pair.first));
ParserPtr parser(createGlobalDhcp4ConfigParser(config_pair.first));
parser->build(config_pair.second);
parsers.push_back(parser);
}