From: Tomek Mrugalski Date: Fri, 28 Sep 2012 18:39:13 +0000 (+0200) Subject: [2269] dhcp6 config parser now returns status codes and does not throw. X-Git-Tag: trac2402_base~17^2~10^2~8 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=7e7171deec8d2a31147a9d5700f4315e2ea3e87b;p=thirdparty%2Fkea.git [2269] dhcp6 config parser now returns status codes and does not throw. --- diff --git a/src/bin/dhcp6/config_parser.cc b/src/bin/dhcp6/config_parser.cc index 79ec28ee7b..efe8d84d26 100644 --- a/src/bin/dhcp6/config_parser.cc +++ b/src/bin/dhcp6/config_parser.cc @@ -21,16 +21,16 @@ #include #include #include +#include #include #include -#include -#include +#include #include #include #include #include +#include #include -#include using namespace std; using namespace isc::data; @@ -43,9 +43,7 @@ typedef boost::shared_ptr ParserPtr; typedef pair ConfigPair; typedef std::vector ParserCollection; typedef Dhcp6ConfigParser* ParserFactory(const std::string& config_id); - typedef std::map FactoryMap; - typedef std::map Uint32Storage; /// @brief That is a map with global parameters that will be used as defaults Uint32Storage uint32_defaults; @@ -54,23 +52,40 @@ typedef std::map StringStorage; StringStorage string_defaults; typedef std::vector PoolStorage; -PoolStorage pool_defaults; /// @brief a dummy configuration parser /// /// It is a debugging parser. It does not configure anything, /// will accept any configuration and will just print it out -/// on commit. +/// on commit. Useful for debugging existing configurations and +/// adding new ones. class DummyParser : public Dhcp6ConfigParser { public: + + /// @brief Constructor + /// + /// See \ref Dhcp6ConfigParser class for details. + /// + /// @param param_name name of the parsed parameter DummyParser(const std::string& param_name) :param_name_(param_name) { } + + /// @brief builds parameter value + /// + /// See \ref Dhcp6ConfigParser class for details. virtual void build(ConstElementPtr new_config) { std::cout << "Build for token: [" << param_name_ << "] = [" << value_->str() << "]" << std::endl; value_ = new_config; } + + /// @brief pretends to apply the configuration + /// + /// 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 Dhcp6ConfigParser class for details. virtual void commit() { // Debug message. The whole DummyParser class is used only for parser // debugging, and is not used in production code. It is very convenient @@ -79,21 +94,45 @@ public: << value_->str() << "]" << std::endl; } + /// @brief factory that constructs DummyParser objects + /// + /// @param param_name name of the parameter to be parsed static Dhcp6ConfigParser* Factory(const std::string& param_name) { return (new DummyParser(param_name)); } protected: + /// name of the parsed parameter std::string param_name_; + + /// pointer to the actual value of the parameter ConstElementPtr value_; }; +/// @brief Configuration parser for uint32 types +/// +/// This class is a generic parser that is able to handle any uint32 integer +/// type. By default it stores the value in external global container +/// (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 Dhcp6ConfigParser. + class Uint32Parser : public Dhcp6ConfigParser { public: + + /// @brief constructor for Uint32Parser + /// @param param_name name of the parameter that is going to be parsed Uint32Parser(const std::string& param_name) :storage_(&uint32_defaults), param_name_(param_name) { } + /// @brief builds parameter value + /// + /// Parses configuration entry and stored it in storage. See + /// \ref setStorage() for details. + /// + /// @param value pointer to the content of parsed values virtual void build(ConstElementPtr value) { try { value_ = boost::lexical_cast(value->str()); @@ -104,9 +143,20 @@ public: storage_->insert(pair(param_name_, value_)); } + /// @brief does nothing + /// + /// This method is required for all parser. The value itself + /// 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 Subnet6Parser when constructing + /// the subnet. virtual void commit() { } + /// @brief factory that constructs DummyParser objects + /// + /// @param param_name name of the parameter to be parsed static Dhcp6ConfigParser* Factory(const std::string& param_name) { return (new Uint32Parser(param_name)); } @@ -325,13 +375,18 @@ public: Triplet valid = getParam("valid-lifetime"); /// @todo: Convert this to logger once the parser is working reliably - cout << "Adding subnet " << addr.toText() << "/" << (int)len - << " with params t1=" << t1 << ", t2=" << t2 << ", pref=" - << pref << ", valid=" << valid << endl; + stringstream tmp; + tmp << addr.toText() << "/" << (int)len + << " with params t1=" << t1 << ", t2=" << t2 << ", pref=" + << pref << ", valid=" << valid; - Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid)); + LOG_INFO(dhcp6_logger, DHCP6_CONFIG_NEW_SUBNET).arg(tmp.str()); + Subnet6Ptr subnet(new Subnet6(addr, len, t1, t2, pref, valid)); + for (PoolStorage::iterator it = pools_.begin(); it != pools_.end(); ++it) { + subnet->addPool6(*it); + } CfgMgr::instance().addSubnet6(subnet); } @@ -418,6 +473,12 @@ public: } void commit() { + // @todo: Implement more subtle reconfiguration than toss + // the old one and replace with the new one. + + // remove old subnets + CfgMgr::instance().deleteSubnets6(); + BOOST_FOREACH(ParserPtr subnet, subnets_) { subnet->commit(); } @@ -469,7 +530,7 @@ Dhcp6ConfigParser* createGlobalDhcp6ConfigParser(const std::string& config_id) { } ConstElementPtr -configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) { +configureDhcp6Server(Dhcpv6Srv& , ConstElementPtr config_set) { if (!config_set) { isc_throw(Dhcp6ConfigError, "Null pointer is passed to configuration parser"); @@ -488,20 +549,29 @@ configureDhcp6Server(Dhcpv6Srv& server, ConstElementPtr config_set) { parser->build(config_pair.second); parsers.push_back(parser); } - } catch (const Dhcp6ConfigError& ex) { - throw; // simply rethrowing it } catch (const isc::Exception& ex) { - isc_throw(Dhcp6ConfigError, "Server configuration failed: " << - ex.what()); + ConstElementPtr answer = isc::config::createAnswer(1, + string("Configuration parsing failed:") + ex.what()); + return (answer); + } catch (...) { + // for things like bad_cast in boost::lexical_cast + ConstElementPtr answer = isc::config::createAnswer(1, + string("Configuration parsing failed")); } try { BOOST_FOREACH(ParserPtr parser, parsers) { parser->commit(); } + } + catch (const isc::Exception& ex) { + ConstElementPtr answer = isc::config::createAnswer(2, + string("Configuration commit failed:") + ex.what()); + return (answer); } catch (...) { - isc_throw(Dhcp6ConfigError, "Unrecoverable error: " - "a configuration parser threw in commit"); + // for things like bad_cast in boost::lexical_cast + ConstElementPtr answer = isc::config::createAnswer(2, + string("Configuration commit failed")); } LOG_INFO(dhcp6_logger, DHCP6_CONFIG_COMPLETE).arg(config_details); diff --git a/src/bin/dhcp6/config_parser.h b/src/bin/dhcp6/config_parser.h index 6b71c351be..5c941d5bdd 100644 --- a/src/bin/dhcp6/config_parser.h +++ b/src/bin/dhcp6/config_parser.h @@ -162,7 +162,7 @@ configureDhcp6Server(Dhcpv6Srv& server, /// is to be created. /// \return A pointer to an \c Dhcp6ConfigParser object. Dhcp6ConfigParser* createDhcp6ConfigParser(Dhcpv6Srv& server, - const std::string& config_id); + const std::string& config_id); }; // end of isc::dhcp namespace }; // end of isc namespace diff --git a/src/bin/dhcp6/dhcp6_messages.mes b/src/bin/dhcp6/dhcp6_messages.mes index b2de63afd9..56f4b1c970 100644 --- a/src/bin/dhcp6/dhcp6_messages.mes +++ b/src/bin/dhcp6/dhcp6_messages.mes @@ -111,6 +111,10 @@ This is a debug message that is issued every time the server receives configuration. That happens during every start up and also when server configuration change is committed by the administrator. +% DHCP6_CONFIG_NEW_SUBNET A new subnet has been added to configuration: %1 +This is an informational message that the configuration has extended +and specified new subnet is now supported. + % DHCP6_CONFIG_COMPLETE DHCPv6 server has completed configuration: %1 This is an informational message that announces successful processing of a new configuration. That may happen as a result of one of two