mirror of
https://gitlab.isc.org/isc-projects/kea
synced 2025-08-30 21:45:37 +00:00
[4204fd] Merge original trac4204
This commit is contained in:
@@ -22,7 +22,6 @@
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/parsers/client_class_def_parser.h>
|
||||
#include <dhcp4/json_config_parser.h>
|
||||
#include <dhcpsrv/option_space_container.h>
|
||||
#include <dhcpsrv/parsers/dbaccess_parser.h>
|
||||
#include <dhcpsrv/parsers/dhcp_parsers.h>
|
||||
#include <dhcpsrv/parsers/expiration_config_parser.h>
|
||||
@@ -514,6 +513,12 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
||||
// Remove any existing timers.
|
||||
TimerMgr::instance()->unregisterTimers();
|
||||
|
||||
// Revert any runtime option definitions configured so far and not committed.
|
||||
LibDHCP::revertRuntimeOptionDefs();
|
||||
// Let's set empty container in case a user hasn't specified any configuration
|
||||
// for option definitions. This is equivalent to commiting empty container.
|
||||
LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
|
||||
|
||||
// Some of the values specified in the configuration depend on
|
||||
// other values. Typically, the values in the subnet4 structure
|
||||
// depend on the global values. Also, option values configuration
|
||||
@@ -700,6 +705,9 @@ configureDhcp4Server(Dhcpv4Srv&, isc::data::ConstElementPtr config_set) {
|
||||
// Rollback changes as the configuration parsing failed.
|
||||
if (rollback) {
|
||||
globalContext().reset(new ParserContext(original_context));
|
||||
// Revert to original configuration of runtime option definitions
|
||||
// in the libdhcp++.
|
||||
LibDHCP::revertRuntimeOptionDefs();
|
||||
return (answer);
|
||||
}
|
||||
|
||||
|
@@ -1346,6 +1346,11 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
|
||||
ASSERT_TRUE(status);
|
||||
checkResult(status, 0);
|
||||
|
||||
// We need to commit option definitions because later in this test we
|
||||
// will be checking if they get removed when "option-def" parameter
|
||||
// is removed from a configuration.
|
||||
LibDHCP::commitRuntimeOptionDefs();
|
||||
|
||||
// The option definition should now be available in the CfgMgr.
|
||||
def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->get("isc", 100);
|
||||
ASSERT_TRUE(def);
|
||||
@@ -1356,6 +1361,25 @@ TEST_F(Dhcp4ParserTest, optionDefIpv4Address) {
|
||||
EXPECT_FALSE(def->getArrayType());
|
||||
EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, def->getType());
|
||||
EXPECT_TRUE(def->getEncapsulatedSpace().empty());
|
||||
|
||||
// The copy of the option definition should be available in the libdhcp++.
|
||||
OptionDefinitionPtr def_libdhcp = LibDHCP::getRuntimeOptionDef("isc", 100);
|
||||
ASSERT_TRUE(def_libdhcp);
|
||||
|
||||
// Both definitions should be held in distinct pointers but they should
|
||||
// be equal.
|
||||
EXPECT_TRUE(def_libdhcp != def);
|
||||
EXPECT_TRUE(*def_libdhcp == *def);
|
||||
|
||||
// Let's apply empty configuration. This removes the option definitions
|
||||
// configuration and should result in removal of the option 100 from the
|
||||
// libdhcp++.
|
||||
config = "{ }";
|
||||
json = Element::fromJSON(config);
|
||||
ASSERT_NO_THROW(status = configureDhcp4Server(*srv_, json));
|
||||
checkResult(status, 0);
|
||||
|
||||
EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("isc", 100));
|
||||
}
|
||||
|
||||
// The goal of this test is to check whether an option definition
|
||||
@@ -1468,6 +1492,14 @@ TEST_F(Dhcp4ParserTest, optionDefMultiple) {
|
||||
// The goal of this test is to verify that the duplicated option
|
||||
// definition is not accepted.
|
||||
TEST_F(Dhcp4ParserTest, optionDefDuplicate) {
|
||||
// Preconfigure libdhcp++ with option definitions. The new configuration
|
||||
// should override it, but when the new configuration fails, it should
|
||||
// revert to this original configuration.
|
||||
OptionDefSpaceContainer defs;
|
||||
OptionDefinitionPtr def(new OptionDefinition("bar", 233, "string"));
|
||||
defs.addItem(def, "isc");
|
||||
LibDHCP::setRuntimeOptionDefs(defs);
|
||||
LibDHCP::commitRuntimeOptionDefs();
|
||||
|
||||
// Configuration string. Both option definitions have
|
||||
// the same code and belong to the same option space.
|
||||
@@ -1498,6 +1530,15 @@ TEST_F(Dhcp4ParserTest, optionDefDuplicate) {
|
||||
ASSERT_TRUE(status);
|
||||
checkResult(status, 1);
|
||||
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
|
||||
|
||||
// The new configuration should have inserted option 100, but
|
||||
// once configuration failed (on the duplicate option definition)
|
||||
// the original configuration in libdhcp++ should be reverted.
|
||||
EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("isc", 100));
|
||||
def = LibDHCP::getRuntimeOptionDef("isc", 233);
|
||||
ASSERT_TRUE(def);
|
||||
EXPECT_EQ("bar", def->getName());
|
||||
EXPECT_EQ(233, def->getCode());
|
||||
}
|
||||
|
||||
// The goal of this test is to verify that the option definition
|
||||
|
@@ -15,6 +15,7 @@
|
||||
#include <config.h>
|
||||
#include <cc/data.h>
|
||||
#include <config/command_mgr.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcp6/ctrl_dhcp6_srv.h>
|
||||
#include <dhcp6/dhcp6_log.h>
|
||||
@@ -219,6 +220,10 @@ ControlledDhcpv6Srv::processConfig(isc::data::ConstElementPtr config) {
|
||||
}
|
||||
}
|
||||
|
||||
// Finally, we can commit runtime option definitions in libdhcp++. This is
|
||||
// exception free.
|
||||
LibDHCP::commitRuntimeOptionDefs();
|
||||
|
||||
return (answer);
|
||||
}
|
||||
|
||||
|
@@ -752,6 +752,12 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
|
||||
// Remove any existing timers.
|
||||
TimerMgr::instance()->unregisterTimers();
|
||||
|
||||
// Revert any runtime option definitions configured so far and not committed.
|
||||
LibDHCP::revertRuntimeOptionDefs();
|
||||
// Let's set empty container in case a user hasn't specified any configuration
|
||||
// for option definitions. This is equivalent to commiting empty container.
|
||||
LibDHCP::setRuntimeOptionDefs(OptionDefSpaceContainer());
|
||||
|
||||
// Some of the values specified in the configuration depend on
|
||||
// other values. Typically, the values in the subnet6 structure
|
||||
// depend on the global values. Also, option values configuration
|
||||
@@ -945,6 +951,9 @@ configureDhcp6Server(Dhcpv6Srv&, isc::data::ConstElementPtr config_set) {
|
||||
// Rollback changes as the configuration parsing failed.
|
||||
if (rollback) {
|
||||
globalContext().reset(new ParserContext(original_context));
|
||||
// Revert to original configuration of runtime option definitions
|
||||
// in the libdhcp++.
|
||||
LibDHCP::revertRuntimeOptionDefs();
|
||||
return (answer);
|
||||
}
|
||||
|
||||
|
@@ -1583,6 +1583,12 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) {
|
||||
ConstElementPtr status;
|
||||
EXPECT_NO_THROW(status = configureDhcp6Server(srv_, json));
|
||||
ASSERT_TRUE(status);
|
||||
checkResult(status, 0);
|
||||
|
||||
// We need to commit option definitions because later in this test we
|
||||
// will be checking if they get removed when "option-def" parameter
|
||||
// is removed from a configuration.
|
||||
LibDHCP::commitRuntimeOptionDefs();
|
||||
|
||||
// The option definition should now be available in the CfgMgr.
|
||||
def = CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->get("isc", 100);
|
||||
@@ -1593,6 +1599,25 @@ TEST_F(Dhcp6ParserTest, optionDefIpv6Address) {
|
||||
EXPECT_EQ(100, def->getCode());
|
||||
EXPECT_FALSE(def->getArrayType());
|
||||
EXPECT_EQ(OPT_IPV6_ADDRESS_TYPE, def->getType());
|
||||
|
||||
// The copy of the option definition should be available in the libdhcp++.
|
||||
OptionDefinitionPtr def_libdhcp = LibDHCP::getRuntimeOptionDef("isc", 100);
|
||||
ASSERT_TRUE(def_libdhcp);
|
||||
|
||||
// Both definitions should be held in distinct pointers but they should
|
||||
// be equal.
|
||||
EXPECT_TRUE(def_libdhcp != def);
|
||||
EXPECT_TRUE(*def_libdhcp == *def);
|
||||
|
||||
// Let's apply empty configuration. This removes the option definitions
|
||||
// configuration and should result in removal of the option 100 from the
|
||||
// libdhcp++.
|
||||
config = "{ }";
|
||||
json = Element::fromJSON(config);
|
||||
ASSERT_NO_THROW(status = configureDhcp6Server(srv_, json));
|
||||
checkResult(status, 0);
|
||||
|
||||
EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("isc", 100));
|
||||
}
|
||||
|
||||
// The goal of this test is to check whether an option definition
|
||||
@@ -1702,6 +1727,14 @@ TEST_F(Dhcp6ParserTest, optionDefMultiple) {
|
||||
// The goal of this test is to verify that the duplicated option
|
||||
// definition is not accepted.
|
||||
TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
|
||||
// Preconfigure libdhcp++ with option definitions. The new configuration
|
||||
// should override it, but when the new configuration fails, it should
|
||||
// revert to this original configuration.
|
||||
OptionDefSpaceContainer defs;
|
||||
OptionDefinitionPtr def(new OptionDefinition("bar", 233, "string"));
|
||||
defs.addItem(def, "isc");
|
||||
LibDHCP::setRuntimeOptionDefs(defs);
|
||||
LibDHCP::commitRuntimeOptionDefs();
|
||||
|
||||
// Configuration string. Both option definitions have
|
||||
// the same code and belong to the same option space.
|
||||
@@ -1732,6 +1765,15 @@ TEST_F(Dhcp6ParserTest, optionDefDuplicate) {
|
||||
ASSERT_TRUE(status);
|
||||
checkResult(status, 1);
|
||||
EXPECT_TRUE(errorContainsPosition(status, "<string>"));
|
||||
|
||||
// The new configuration should have inserted option 100, but
|
||||
// once configuration failed (on the duplicate option definition)
|
||||
// the original configuration in libdhcp++ should be reverted.
|
||||
EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("isc", 100));
|
||||
def = LibDHCP::getRuntimeOptionDef("isc", 233);
|
||||
ASSERT_TRUE(def);
|
||||
EXPECT_EQ("bar", def->getName());
|
||||
EXPECT_EQ(233, def->getCode());
|
||||
}
|
||||
|
||||
// The goal of this test is to verify that the option definition
|
||||
|
@@ -43,6 +43,7 @@ libkea_dhcp___la_SOURCES += option_data_types.cc option_data_types.h
|
||||
libkea_dhcp___la_SOURCES += option_definition.cc option_definition.h
|
||||
libkea_dhcp___la_SOURCES += option_opaque_data_tuples.cc option_opaque_data_tuples.h
|
||||
libkea_dhcp___la_SOURCES += option_space.cc option_space.h
|
||||
libkea_dhcp___la_SOURCES += option_space_container.h
|
||||
libkea_dhcp___la_SOURCES += option_string.cc option_string.h
|
||||
libkea_dhcp___la_SOURCES += protocol_util.cc protocol_util.h
|
||||
libkea_dhcp___la_SOURCES += pkt.cc pkt.h
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include <boost/shared_array.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
#include <list>
|
||||
|
||||
using namespace std;
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::util;
|
||||
@@ -52,6 +54,10 @@ VendorOptionDefContainers LibDHCP::vendor4_defs_;
|
||||
|
||||
VendorOptionDefContainers LibDHCP::vendor6_defs_;
|
||||
|
||||
// Static container with option definitions created in runtime.
|
||||
StagedValue<OptionDefSpaceContainer> LibDHCP::runtime_option_defs_;
|
||||
|
||||
|
||||
// Those two vendor classes are used for cable modems:
|
||||
|
||||
/// DOCSIS3.0 compatible cable modem
|
||||
@@ -194,6 +200,66 @@ LibDHCP::getVendorOptionDef(const Option::Universe u, const uint32_t vendor_id,
|
||||
return (OptionDefinitionPtr());
|
||||
}
|
||||
|
||||
OptionDefinitionPtr
|
||||
LibDHCP::getRuntimeOptionDef(const std::string& space, const uint16_t code) {
|
||||
OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
|
||||
const OptionDefContainerTypeIndex& index = container->get<1>();
|
||||
const OptionDefContainerTypeRange& range = index.equal_range(code);
|
||||
if (range.first != range.second) {
|
||||
return (*range.first);
|
||||
}
|
||||
|
||||
return (OptionDefinitionPtr());
|
||||
}
|
||||
|
||||
OptionDefinitionPtr
|
||||
LibDHCP::getRuntimeOptionDef(const std::string& space, const std::string& name) {
|
||||
OptionDefContainerPtr container = runtime_option_defs_.getValue().getItems(space);
|
||||
const OptionDefContainerNameIndex& index = container->get<2>();
|
||||
const OptionDefContainerNameRange& range = index.equal_range(name);
|
||||
if (range.first != range.second) {
|
||||
return (*range.first);
|
||||
}
|
||||
|
||||
return (OptionDefinitionPtr());
|
||||
}
|
||||
|
||||
OptionDefContainerPtr
|
||||
LibDHCP::getRuntimeOptionDefs(const std::string& space) {
|
||||
return (runtime_option_defs_.getValue().getItems(space));
|
||||
}
|
||||
|
||||
void
|
||||
LibDHCP::setRuntimeOptionDefs(const OptionDefSpaceContainer& defs) {
|
||||
OptionDefSpaceContainer defs_copy;
|
||||
std::list<std::string> option_space_names = defs.getOptionSpaceNames();
|
||||
for (std::list<std::string>::const_iterator name = option_space_names.begin();
|
||||
name != option_space_names.end(); ++name) {
|
||||
OptionDefContainerPtr container = defs.getItems(*name);
|
||||
for (OptionDefContainer::const_iterator def = container->begin();
|
||||
def != container->end(); ++def) {
|
||||
OptionDefinitionPtr def_copy(new OptionDefinition(**def));
|
||||
defs_copy.addItem(def_copy, *name);
|
||||
}
|
||||
}
|
||||
runtime_option_defs_ = defs_copy;
|
||||
}
|
||||
|
||||
void
|
||||
LibDHCP::clearRuntimeOptionDefs() {
|
||||
runtime_option_defs_.reset();
|
||||
}
|
||||
|
||||
void
|
||||
LibDHCP::revertRuntimeOptionDefs() {
|
||||
runtime_option_defs_.revert();
|
||||
}
|
||||
|
||||
void
|
||||
LibDHCP::commitRuntimeOptionDefs() {
|
||||
runtime_option_defs_.commit();
|
||||
}
|
||||
|
||||
bool
|
||||
LibDHCP::isStandardOption(const Option::Universe u, const uint16_t code) {
|
||||
if (u == Option::V6) {
|
||||
@@ -260,7 +326,14 @@ size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
|
||||
OptionDefContainer option_defs;
|
||||
if (option_space == "dhcp6") {
|
||||
option_defs = LibDHCP::getOptionDefs(Option::V6);
|
||||
} else {
|
||||
OptionDefContainerPtr option_defs_ptr =
|
||||
LibDHCP::getRuntimeOptionDefs(option_space);
|
||||
if (option_defs_ptr) {
|
||||
option_defs = *option_defs_ptr;
|
||||
}
|
||||
}
|
||||
|
||||
// @todo Once we implement other option spaces we should add else clause
|
||||
// here and gather option definitions for them. For now leaving option_defs
|
||||
// empty will imply creation of generic Option.
|
||||
|
@@ -16,8 +16,10 @@
|
||||
#define LIBDHCP_H
|
||||
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcp/option_space_container.h>
|
||||
#include <dhcp/pkt6.h>
|
||||
#include <util/buffer.h>
|
||||
#include <util/staged_value.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
@@ -90,6 +92,36 @@ public:
|
||||
const uint32_t vendor_id,
|
||||
const std::string& name);
|
||||
|
||||
|
||||
/// @brief Returns runtime (non-standard) option definition by space and
|
||||
/// option code.
|
||||
///
|
||||
/// @param space Option space name.
|
||||
/// @param code Option code.
|
||||
///
|
||||
/// @return Pointer to option definition or NULL if it doesn't exist.
|
||||
static OptionDefinitionPtr getRuntimeOptionDef(const std::string& space,
|
||||
const uint16_t code);
|
||||
|
||||
/// @brief Returns runtime (non-standard) option definition by space and
|
||||
/// option name.
|
||||
///
|
||||
/// @param space Option space name.
|
||||
/// @param name Option name.
|
||||
///
|
||||
/// @return Pointer to option definition or NULL if it doesn't exist.
|
||||
static OptionDefinitionPtr getRuntimeOptionDef(const std::string& space,
|
||||
const std::string& name);
|
||||
|
||||
/// @brief Returns runtime (non-standard) option definitions for specified
|
||||
/// option space name.
|
||||
///
|
||||
/// @param space Option space name.
|
||||
///
|
||||
/// @return Pointer to the container holding option definitions or NULL.
|
||||
static OptionDefContainerPtr
|
||||
getRuntimeOptionDefs(const std::string& space);
|
||||
|
||||
/// @brief Check if the specified option is a standard option.
|
||||
///
|
||||
/// @param u universe (V4 or V6)
|
||||
@@ -256,6 +288,27 @@ public:
|
||||
const OptionBuffer& buf,
|
||||
isc::dhcp::OptionCollection& options);
|
||||
|
||||
|
||||
/// @brief Copies option definitions created at runtime.
|
||||
///
|
||||
/// Copied option definitions will be used as "runtime" option definitions.
|
||||
/// A typical use case is to set option definitions specified by the user
|
||||
/// in the server configuration. These option definitions should be removed
|
||||
/// or replaced with new option definitions upon reconfiguration.
|
||||
///
|
||||
/// @param defs Const reference to a container holding option definitions
|
||||
/// grouped by option spaces.
|
||||
static void setRuntimeOptionDefs(const OptionDefSpaceContainer& defs);
|
||||
|
||||
/// @brief Removes runtime option definitions.
|
||||
static void clearRuntimeOptionDefs();
|
||||
|
||||
/// @brief Reverts uncommited changes to runtime option definitions.
|
||||
static void revertRuntimeOptionDefs();
|
||||
|
||||
/// @brief Commits runtime option definitions.
|
||||
static void commitRuntimeOptionDefs();
|
||||
|
||||
private:
|
||||
|
||||
/// Initialize standard DHCPv4 option definitions.
|
||||
@@ -301,6 +354,9 @@ private:
|
||||
|
||||
/// Container for v6 vendor option definitions
|
||||
static VendorOptionDefContainers vendor6_defs_;
|
||||
|
||||
/// Container for additional option defnitions created in runtime.
|
||||
static util::StagedValue<OptionDefSpaceContainer> runtime_option_defs_;
|
||||
};
|
||||
|
||||
}
|
||||
|
@@ -220,8 +220,8 @@ Option::toString() {
|
||||
return (toText(0));
|
||||
}
|
||||
|
||||
std::string
|
||||
Option::toHexString(const bool include_header) {
|
||||
std::vector<uint8_t>
|
||||
Option::toBinary(const bool include_header) {
|
||||
OutputBuffer buf(len());
|
||||
try {
|
||||
// If the option is too long, exception will be thrown. We allow
|
||||
@@ -233,12 +233,18 @@ Option::toHexString(const bool include_header) {
|
||||
" of option " << getType() << ": " << ex.what());
|
||||
}
|
||||
const uint8_t* option_data = static_cast<const uint8_t*>(buf.getData());
|
||||
std::vector<uint8_t> option_vec;
|
||||
|
||||
// Assign option data to a vector, with or without option header depending
|
||||
// on the value of "include_header" flag.
|
||||
option_vec.assign(option_data + (include_header ? 0 : getHeaderLen()),
|
||||
option_data + buf.getLength());
|
||||
std::vector<uint8_t> option_vec(option_data + (include_header ? 0 : getHeaderLen()),
|
||||
option_data + buf.getLength());
|
||||
return (option_vec);
|
||||
}
|
||||
|
||||
std::string
|
||||
Option::toHexString(const bool include_header) {
|
||||
// Prepare binary version of the option.
|
||||
std::vector<uint8_t> option_vec = toBinary(include_header);
|
||||
|
||||
// Return hexadecimal representation prepended with 0x or empty string
|
||||
// if option has no payload and the header fields are excluded.
|
||||
|
@@ -216,6 +216,15 @@ public:
|
||||
/// @return string that represents the value of the option.
|
||||
virtual std::string toString();
|
||||
|
||||
/// @brief Returns binary representation of the option.
|
||||
///
|
||||
/// @param include_header Boolean flag which indicates if the output should
|
||||
/// also contain header fields. The default is that it shouldn't include
|
||||
/// header fields.
|
||||
///
|
||||
/// @return Vector holding binary representation of the option.
|
||||
virtual std::vector<uint8_t> toBinary(const bool include_header = false);
|
||||
|
||||
/// @brief Returns string containing hexadecimal representation of option.
|
||||
///
|
||||
/// @param include_header Boolean flag which indicates if the output should
|
||||
|
@@ -17,6 +17,7 @@
|
||||
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_data_types.h>
|
||||
#include <dhcp/option_space_container.h>
|
||||
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/mem_fun.hpp>
|
||||
@@ -766,6 +767,10 @@ typedef OptionDefContainer::nth_index<2>::type OptionDefContainerNameIndex;
|
||||
typedef std::pair<OptionDefContainerNameIndex::const_iterator,
|
||||
OptionDefContainerNameIndex::const_iterator> OptionDefContainerNameRange;
|
||||
|
||||
typedef OptionSpaceContainer<
|
||||
OptionDefContainer, OptionDefinitionPtr, std::string
|
||||
> OptionDefSpaceContainer;
|
||||
|
||||
|
||||
} // namespace isc::dhcp
|
||||
} // namespace isc
|
||||
|
@@ -147,6 +147,60 @@ public:
|
||||
return (OptionBuffer(opt_data, opt_data + sizeof(opt_data)));
|
||||
}
|
||||
|
||||
/// @brief Create option definitions and store in the container.
|
||||
///
|
||||
/// @param spaces_num Number of option spaces to be created.
|
||||
/// @param defs_num Number of option definitions to be created for
|
||||
/// each option space.
|
||||
/// @param [out] defs Container to which option definitions should be
|
||||
/// added.
|
||||
static void createRuntimeOptionDefs(const uint16_t spaces_num,
|
||||
const uint16_t defs_num,
|
||||
OptionDefSpaceContainer& defs) {
|
||||
for (uint16_t space = 0; space < spaces_num; ++space) {
|
||||
std::ostringstream space_name;
|
||||
space_name << "option-space-" << space;
|
||||
for (uint16_t code = 0; code < defs_num; ++code) {
|
||||
std::ostringstream name;
|
||||
name << "name-for-option-" << code;
|
||||
OptionDefinitionPtr opt_def(new OptionDefinition(name.str(),
|
||||
code, "string"));
|
||||
defs.addItem(opt_def, space_name.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief Test if runtime option definitions have been added.
|
||||
///
|
||||
/// This method uses the same naming conventions for space names and
|
||||
/// options names as @c createRuntimeOptionDefs method.
|
||||
///
|
||||
/// @param spaces_num Number of option spaces to be tested.
|
||||
/// @param defs_num Number of option definitions that should exist
|
||||
/// in each option space.
|
||||
/// @param should_exist Boolean value which indicates if option
|
||||
/// definitions should exist. If this is false, this function will
|
||||
/// check that they don't exist.
|
||||
static void testRuntimeOptionDefs(const uint16_t spaces_num,
|
||||
const uint16_t defs_num,
|
||||
const bool should_exist) {
|
||||
for (uint16_t space = 0; space < spaces_num; ++space) {
|
||||
std::ostringstream space_name;
|
||||
space_name << "option-space-" << space;
|
||||
for (uint16_t code = 0; code < defs_num; ++code) {
|
||||
std::ostringstream name;
|
||||
name << "name-for-option-" << code;
|
||||
OptionDefinitionPtr opt_def =
|
||||
LibDHCP::getRuntimeOptionDef(space_name.str(), name.str());
|
||||
if (should_exist) {
|
||||
ASSERT_TRUE(opt_def);
|
||||
} else {
|
||||
ASSERT_FALSE(opt_def);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Test DHCPv4 or DHCPv6 option definition.
|
||||
@@ -1319,4 +1373,28 @@ TEST_F(LibDhcpTest, vendorClass6) {
|
||||
EXPECT_EQ("eRouter1.0", vclass->getTuple(0).getText());
|
||||
}
|
||||
|
||||
// This test verifies that it is possible to add runtime option definitions,
|
||||
// retrieve them and remove them.
|
||||
TEST_F(LibDhcpTest, setRuntimeOptionDefs) {
|
||||
// Create option definitions in 5 namespaces.
|
||||
OptionDefSpaceContainer defs;
|
||||
createRuntimeOptionDefs(5, 100, defs);
|
||||
|
||||
// Apply option definitions.
|
||||
ASSERT_NO_THROW(LibDHCP::setRuntimeOptionDefs(defs));
|
||||
|
||||
// Retrieve all inserted option definitions.
|
||||
testRuntimeOptionDefs(5, 100, true);
|
||||
|
||||
// Attempting to retrieve non existing definitions.
|
||||
EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-non-existent", 1));
|
||||
EXPECT_FALSE(LibDHCP::getRuntimeOptionDef("option-space-0", 145));
|
||||
|
||||
// Remove all runtime option definitions.
|
||||
ASSERT_NO_THROW(LibDHCP::clearRuntimeOptionDefs());
|
||||
|
||||
// All option definitions should be gone now.
|
||||
testRuntimeOptionDefs(5, 100, false);
|
||||
}
|
||||
|
||||
} // end of anonymous space
|
||||
|
@@ -128,7 +128,6 @@ libkea_dhcpsrv_la_SOURCES += ncr_generator.cc ncr_generator.h
|
||||
if HAVE_PGSQL
|
||||
libkea_dhcpsrv_la_SOURCES += pgsql_lease_mgr.cc pgsql_lease_mgr.h
|
||||
endif
|
||||
libkea_dhcpsrv_la_SOURCES += option_space_container.h
|
||||
libkea_dhcpsrv_la_SOURCES += pool.cc pool.h
|
||||
libkea_dhcpsrv_la_SOURCES += srv_config.cc srv_config.h
|
||||
libkea_dhcpsrv_la_SOURCES += subnet.cc subnet.h
|
||||
|
@@ -16,8 +16,8 @@
|
||||
#define CFG_OPTION_H
|
||||
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_space_container.h>
|
||||
#include <dhcpsrv/key_from_key.h>
|
||||
#include <dhcpsrv/option_space_container.h>
|
||||
#include <boost/multi_index_container.hpp>
|
||||
#include <boost/multi_index/hashed_index.hpp>
|
||||
#include <boost/multi_index/sequenced_index.hpp>
|
||||
|
@@ -16,7 +16,7 @@
|
||||
#define CFG_OPTION_DEF_H
|
||||
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcpsrv/option_space_container.h>
|
||||
#include <dhcp/option_space_container.h>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
@@ -120,14 +120,18 @@ public:
|
||||
OptionDefinitionPtr get(const std::string& option_space,
|
||||
const std::string& option_name) const;
|
||||
|
||||
/// @brief Returns reference to container holding option definitions.
|
||||
const OptionDefSpaceContainer& getContainer() const {
|
||||
return (option_definitions_);
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief A collection of option definitions.
|
||||
///
|
||||
/// The option definitions stored in this container can be accessed
|
||||
/// using the option space name they belong to.
|
||||
OptionSpaceContainer<OptionDefContainer, OptionDefinitionPtr,
|
||||
std::string> option_definitions_;
|
||||
OptionDefSpaceContainer option_definitions_;
|
||||
|
||||
};
|
||||
|
||||
|
@@ -50,7 +50,7 @@ ExpressionParser::build(ConstElementPtr expression_cfg) {
|
||||
std::string value;
|
||||
expression_cfg->getValue(value);
|
||||
try {
|
||||
EvalContext eval_ctx;
|
||||
EvalContext eval_ctx(global_context_->universe_);
|
||||
eval_ctx.parseString(value);
|
||||
local_expression_.reset(new Expression());
|
||||
*local_expression_ = eval_ctx.expression;
|
||||
|
@@ -786,6 +786,12 @@ OptionDefParser::build(ConstElementPtr option_def) {
|
||||
isc_throw(DhcpConfigError, ex.what() << " ("
|
||||
<< option_def->getPosition() << ")");
|
||||
}
|
||||
|
||||
// All definitions have been prepared. Put them as runtime options into
|
||||
// the libdhcp++.
|
||||
const OptionDefSpaceContainer& container =
|
||||
CfgMgr::instance().getStagingCfg()->getCfgOptionDef()->getContainer();
|
||||
LibDHCP::setRuntimeOptionDefs(container);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -18,10 +18,10 @@
|
||||
#include <asiolink/io_address.h>
|
||||
#include <cc/data.h>
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcp/option_space_container.h>
|
||||
#include <dhcpsrv/d2_client_cfg.h>
|
||||
#include <dhcpsrv/cfg_iface.h>
|
||||
#include <dhcpsrv/cfg_option.h>
|
||||
#include <dhcpsrv/option_space_container.h>
|
||||
#include <dhcpsrv/subnet.h>
|
||||
#include <dhcpsrv/parsers/dhcp_config_parser.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
@@ -36,12 +36,6 @@
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
|
||||
/// @brief Storage for option definitions.
|
||||
typedef OptionSpaceContainer<OptionDefContainer,
|
||||
OptionDefinitionPtr, std::string> OptionDefStorage;
|
||||
/// @brief Shared pointer to option definitions storage.
|
||||
typedef boost::shared_ptr<OptionDefStorage> OptionDefStoragePtr;
|
||||
|
||||
/// Collection of containers holding option spaces. Each container within
|
||||
/// a particular option space holds so-called option descriptors.
|
||||
typedef OptionSpaceContainer<OptionContainer, OptionDescriptor,
|
||||
|
@@ -18,8 +18,8 @@
|
||||
#include <asiolink/io_address.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/classify.h>
|
||||
#include <dhcp/option_space_container.h>
|
||||
#include <dhcpsrv/cfg_option.h>
|
||||
#include <dhcpsrv/option_space_container.h>
|
||||
#include <dhcpsrv/pool.h>
|
||||
#include <dhcpsrv/triplet.h>
|
||||
#include <dhcpsrv/lease.h>
|
||||
|
@@ -15,6 +15,8 @@
|
||||
#include <config.h>
|
||||
|
||||
#include <cc/data.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_string.h>
|
||||
#include <dhcpsrv/cfgmgr.h>
|
||||
#include <dhcpsrv/parsers/client_class_def_parser.h>
|
||||
@@ -32,6 +34,61 @@ using namespace isc::dhcp;
|
||||
|
||||
namespace {
|
||||
|
||||
/// @brief Test fixture class for @c ExpressionParser.
|
||||
class ExpressionParserTest : public ::testing::Test {
|
||||
protected:
|
||||
|
||||
/// @brief Test that validate expression can be evaluated against v4 or
|
||||
/// v6 packet.
|
||||
///
|
||||
/// Verifies that given a valid expression, the ExpressionParser
|
||||
/// produces an Expression which can be evaluated against a v4 or v6
|
||||
/// packet.
|
||||
///
|
||||
/// @param universe V4 or V6.
|
||||
/// @param expression Textual representation of the expression to be
|
||||
/// evaluated.
|
||||
/// @param option_string String data to be placed in the hostname
|
||||
/// option, being placed in the packet used for evaluation.
|
||||
/// @tparam Type of the packet: @c Pkt4 or @c Pkt6.
|
||||
template<typename PktType>
|
||||
void testValidExpression(const Option::Universe& universe,
|
||||
const std::string& expression,
|
||||
const std::string& option_string) {
|
||||
ParserContextPtr context(new ParserContext(universe));
|
||||
ExpressionParserPtr parser;
|
||||
ExpressionPtr parsed_expr;
|
||||
|
||||
// Turn config into elements. This may emit exceptions.
|
||||
ElementPtr config_element = Element::fromJSON(expression);
|
||||
|
||||
// Create the parser.
|
||||
ASSERT_NO_THROW(parser.reset(new ExpressionParser("", parsed_expr,
|
||||
context)));
|
||||
// Expression should parse and commit.
|
||||
ASSERT_NO_THROW(parser->build(config_element));
|
||||
ASSERT_NO_THROW(parser->commit());
|
||||
|
||||
// Parsed expression should exist.
|
||||
ASSERT_TRUE(parsed_expr);
|
||||
|
||||
// Build a packet that will fail evaluation.
|
||||
boost::shared_ptr<PktType> pkt(new PktType(universe == Option::V4 ?
|
||||
DHCPDISCOVER : DHCPV6_SOLICIT,
|
||||
123));
|
||||
EXPECT_FALSE(evaluate(*parsed_expr, *pkt));
|
||||
|
||||
// Now add the option so it will pass. Use a standard option carrying a
|
||||
// single string value, i.e. hostname for DHCPv4 and bootfile url for
|
||||
// DHCPv6.
|
||||
OptionPtr opt(new OptionString(universe, universe == Option::V4 ?
|
||||
DHO_HOST_NAME : D6O_BOOTFILE_URL,
|
||||
option_string));
|
||||
pkt->addOption(opt);
|
||||
EXPECT_TRUE(evaluate(*parsed_expr, *pkt));
|
||||
}
|
||||
};
|
||||
|
||||
/// @brief Test fixture class for @c ClientClassDefParser.
|
||||
class ClientClassDefParserTest : public ::testing::Test {
|
||||
protected:
|
||||
@@ -113,69 +170,66 @@ protected:
|
||||
|
||||
// Verifies that given a valid expression, the ExpressionParser
|
||||
// produces an Expression which can be evaluated against a v4 packet.
|
||||
TEST(ExpressionParserTest, validExpression4) {
|
||||
ParserContextPtr context(new ParserContext(Option::V4));
|
||||
ExpressionParserPtr parser;
|
||||
ExpressionPtr parsed_expr;
|
||||
TEST_F(ExpressionParserTest, validExpression4) {
|
||||
testValidExpression<Pkt4>(Option::V4, "\"option[12].text == 'hundred4'\"",
|
||||
"hundred4");
|
||||
}
|
||||
|
||||
// Turn config into elements. This may emit exceptions.
|
||||
std::string cfg_txt = "\"option[100].text == 'hundred4'\"";
|
||||
ElementPtr config_element = Element::fromJSON(cfg_txt);
|
||||
// Verifies that the option name can be used in the evaluated expression.
|
||||
TEST_F(ExpressionParserTest, validExpressionWithOptionName4) {
|
||||
testValidExpression<Pkt4>(Option::V4,
|
||||
"\"option[host-name].text == 'hundred4'\"",
|
||||
"hundred4");
|
||||
}
|
||||
|
||||
// Create the parser.
|
||||
ASSERT_NO_THROW(parser.reset(new ExpressionParser("", parsed_expr,
|
||||
context)));
|
||||
// Expression should parse and commit.
|
||||
ASSERT_NO_THROW(parser->build(config_element));
|
||||
ASSERT_NO_THROW(parser->commit());
|
||||
// Verifies that given a valid expression using .hex operator for option, the
|
||||
// ExpressionParser produces an Expression which can be evaluated against
|
||||
// a v4 packet.
|
||||
TEST_F(ExpressionParserTest, validExpressionWithHex4) {
|
||||
testValidExpression<Pkt4>(Option::V4, "\"option[12].hex == 0x68756E6472656434\"",
|
||||
"hundred4");
|
||||
}
|
||||
|
||||
// Parsed expression should exist.
|
||||
ASSERT_TRUE(parsed_expr);
|
||||
|
||||
// Build a packet that will fail evaluation.
|
||||
Pkt4Ptr pkt4(new Pkt4(DHCPDISCOVER, 123));
|
||||
EXPECT_FALSE(evaluate(*parsed_expr, *pkt4));
|
||||
|
||||
// Now add the option so it will pass.
|
||||
OptionPtr opt(new OptionString(Option::V4, 100, "hundred4"));
|
||||
pkt4->addOption(opt);
|
||||
EXPECT_TRUE(evaluate(*parsed_expr, *pkt4));
|
||||
// Verifies that the option name can be used together with .hex operator in
|
||||
// the evaluated expression.
|
||||
TEST_F(ExpressionParserTest, validExpressionWithOptionNameAndHex4) {
|
||||
testValidExpression<Pkt6>(Option::V4,
|
||||
"\"option[host-name].text == 0x68756E6472656434\"",
|
||||
"hundred4");
|
||||
}
|
||||
|
||||
// Verifies that given a valid expression, the ExpressionParser
|
||||
// produces an Expression which can be evaluated against a v6 packet.
|
||||
TEST(ExpressionParserTest, validExpression6) {
|
||||
ParserContextPtr context(new ParserContext(Option::V6));
|
||||
ExpressionParserPtr parser;
|
||||
ExpressionPtr parsed_expr;
|
||||
|
||||
// Turn config into elements. This may emit exceptions.
|
||||
std::string cfg_txt = "\"option[100].text == 'hundred6'\"";
|
||||
ElementPtr config_element = Element::fromJSON(cfg_txt);
|
||||
|
||||
// Create the parser.
|
||||
ASSERT_NO_THROW(parser.reset(new ExpressionParser("", parsed_expr,
|
||||
context)));
|
||||
// Expression should parse and commit.
|
||||
ASSERT_NO_THROW(parser->build(config_element));
|
||||
ASSERT_NO_THROW(parser->commit());
|
||||
|
||||
// Parsed expression should exist.
|
||||
ASSERT_TRUE(parsed_expr);
|
||||
|
||||
// Build a packet that will fail evaluation.
|
||||
Pkt6Ptr pkt6(new Pkt6(DHCPDISCOVER, 123));
|
||||
EXPECT_FALSE(evaluate(*parsed_expr, *pkt6));
|
||||
|
||||
// Now add the option so it will pass.
|
||||
OptionPtr opt(new OptionString(Option::V6, 100, "hundred6"));
|
||||
pkt6->addOption(opt);
|
||||
EXPECT_TRUE(evaluate(*parsed_expr, *pkt6));
|
||||
TEST_F(ExpressionParserTest, validExpression6) {
|
||||
testValidExpression<Pkt6>(Option::V6, "\"option[59].text == 'hundred6'\"",
|
||||
"hundred6");
|
||||
}
|
||||
|
||||
// Verifies that the option name can be used in the evaluated expression.
|
||||
TEST_F(ExpressionParserTest, validExpressionWithOptionName6) {
|
||||
testValidExpression<Pkt6>(Option::V6,
|
||||
"\"option[bootfile-url].text == 'hundred6'\"",
|
||||
"hundred6");
|
||||
}
|
||||
|
||||
// Verifies that given a valid expression using .hex operator for option, the
|
||||
// ExpressionParser produces an Expression which can be evaluated against
|
||||
// a v6 packet.
|
||||
TEST_F(ExpressionParserTest, validExpressionWithHex6) {
|
||||
testValidExpression<Pkt6>(Option::V6, "\"option[59].hex == 0x68756E6472656436\"",
|
||||
"hundred6");
|
||||
}
|
||||
|
||||
// Verifies that the option name can be used together with .hex operator in
|
||||
// the evaluated expression.
|
||||
TEST_F(ExpressionParserTest, validExpressionWithOptionNameAndHex6) {
|
||||
testValidExpression<Pkt6>(Option::V6,
|
||||
"\"option[bootfile-url].text == 0x68756E6472656436\"",
|
||||
"hundred6");
|
||||
}
|
||||
|
||||
// Verifies that an the ExpressionParser only accepts StringElements.
|
||||
TEST(ExpressionParserTest, invalidExpressionElement) {
|
||||
TEST_F(ExpressionParserTest, invalidExpressionElement) {
|
||||
ParserContextPtr context(new ParserContext(Option::V4));
|
||||
ExpressionParserPtr parser;
|
||||
ExpressionPtr parsed_expr;
|
||||
@@ -196,7 +250,7 @@ TEST(ExpressionParserTest, invalidExpressionElement) {
|
||||
// is not intended to be an exhaustive test or expression syntax.
|
||||
// It is simply to ensure that if the parser fails, it does so
|
||||
// Properly.
|
||||
TEST(ExpressionParserTest, expressionSyntaxError) {
|
||||
TEST_F(ExpressionParserTest, expressionSyntaxError) {
|
||||
ParserContextPtr context(new ParserContext(Option::V4));
|
||||
ExpressionParserPtr parser;
|
||||
ExpressionPtr parsed_expr;
|
||||
|
@@ -495,6 +495,15 @@ TEST_F(ParseConfigTest, basicOptionDefTest) {
|
||||
EXPECT_FALSE(def->getArrayType());
|
||||
EXPECT_EQ(OPT_IPV4_ADDRESS_TYPE, def->getType());
|
||||
EXPECT_TRUE(def->getEncapsulatedSpace().empty());
|
||||
|
||||
// Check if libdhcp++ runtime options have been updated.
|
||||
OptionDefinitionPtr def_libdhcp = LibDHCP::getRuntimeOptionDef("isc", 100);
|
||||
ASSERT_TRUE(def_libdhcp);
|
||||
|
||||
// The LibDHCP should return a separate instance of the option definition
|
||||
// but the values should be equal.
|
||||
EXPECT_TRUE(def_libdhcp != def);
|
||||
EXPECT_TRUE(*def_libdhcp == *def);
|
||||
}
|
||||
|
||||
/// @brief Check minimal parsing of option definitions.
|
||||
|
@@ -15,10 +15,12 @@
|
||||
#include <eval/eval_context.h>
|
||||
#include <eval/parser.h>
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <fstream>
|
||||
|
||||
EvalContext::EvalContext()
|
||||
: trace_scanning_(false), trace_parsing_(false)
|
||||
EvalContext::EvalContext(const Option::Universe& option_universe)
|
||||
: trace_scanning_(false), trace_parsing_(false),
|
||||
option_universe_(option_universe)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -32,7 +34,7 @@ EvalContext::parseString(const std::string& str)
|
||||
file_ = "<string>";
|
||||
string_ = str;
|
||||
scanStringBegin();
|
||||
isc::eval::EvalParser parser(*this);
|
||||
isc::eval::EvalParser parser(*this, option_universe_);
|
||||
parser.set_debug_level(trace_parsing_);
|
||||
int res = parser.parse();
|
||||
scanStringEnd();
|
||||
|
@@ -42,7 +42,11 @@ class EvalContext
|
||||
{
|
||||
public:
|
||||
/// @brief Default constructor.
|
||||
EvalContext();
|
||||
///
|
||||
/// @param option_universe Option universe: DHCPv4 or DHCPv6. This is used
|
||||
/// by the parser to determine which option definitions set should be used
|
||||
/// to map option names to option codes.
|
||||
EvalContext(const Option::Universe& option_universe);
|
||||
|
||||
/// @brief destructor
|
||||
virtual ~EvalContext();
|
||||
@@ -55,7 +59,7 @@ public:
|
||||
|
||||
/// @brief Method called after the last tokens are scanned from a string.
|
||||
void scanStringEnd();
|
||||
|
||||
|
||||
/// @brief Run the parser on the string specified.
|
||||
///
|
||||
/// @param str string to be written
|
||||
@@ -87,7 +91,12 @@ public:
|
||||
|
||||
/// @brief Flag determing parser debugging.
|
||||
bool trace_parsing_;
|
||||
|
||||
|
||||
/// @brief Option universe: DHCPv4 or DHCPv6.
|
||||
///
|
||||
/// This is used by the parser to determine which option definitions
|
||||
/// set should be used to map option name to option code.
|
||||
Option::Universe option_universe_;
|
||||
};
|
||||
|
||||
}; // end of isc::eval namespace
|
||||
|
@@ -460,8 +460,8 @@ static void yy_fatal_error (yyconst char msg[] );
|
||||
(yy_c_buf_p) = yy_cp;
|
||||
|
||||
/* %% [4.0] data tables for the DFA and the user's section 1 definitions go here */
|
||||
#define YY_NUM_RULES 19
|
||||
#define YY_END_OF_BUFFER 20
|
||||
#define YY_NUM_RULES 20
|
||||
#define YY_END_OF_BUFFER 21
|
||||
/* This struct is not used in this scanner,
|
||||
but its presence is necessary. */
|
||||
struct yy_trans_info
|
||||
@@ -469,14 +469,27 @@ struct yy_trans_info
|
||||
flex_int32_t yy_verify;
|
||||
flex_int32_t yy_nxt;
|
||||
};
|
||||
static yyconst flex_int16_t yy_accept[52] =
|
||||
static yyconst flex_int16_t yy_acclist[84] =
|
||||
{ 0,
|
||||
0, 0, 20, 18, 1, 2, 18, 13, 14, 17,
|
||||
18, 12, 5, 5, 18, 15, 16, 18, 18, 18,
|
||||
18, 18, 1, 2, 0, 3, 5, 0, 6, 0,
|
||||
0, 0, 0, 0, 4, 11, 9, 0, 0, 0,
|
||||
0, 0, 8, 0, 0, 7, 0, 0, 0, 10,
|
||||
0
|
||||
21, 19, 20, 1, 19, 20, 2, 20, 19, 20,
|
||||
13, 19, 20, 14, 19, 20, 17, 19, 20, 19,
|
||||
20, 12, 19, 20, 5, 19, 20, 5, 19, 20,
|
||||
19, 20, 19, 20, 15, 19, 20, 16, 19, 20,
|
||||
19, 20, 19, 20, 19, 20, 19, 20, 19, 20,
|
||||
1, 2, 3, 5, 6,16402,16402,16402,16402,16402,
|
||||
16402, 4, 8210, 11,16402, 9,16402,16402,16402,16402,
|
||||
16402,16402, 8,16402,16402,16402, 7,16402,16402,16402,
|
||||
16402, 10,16402
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_accept[57] =
|
||||
{ 0,
|
||||
1, 1, 1, 2, 4, 7, 9, 11, 14, 17,
|
||||
20, 22, 25, 28, 31, 33, 35, 38, 41, 43,
|
||||
45, 47, 49, 51, 52, 53, 53, 54, 55, 55,
|
||||
56, 57, 58, 59, 60, 61, 62, 63, 63, 64,
|
||||
66, 68, 69, 70, 71, 72, 73, 75, 76, 77,
|
||||
79, 80, 81, 82, 84, 84
|
||||
} ;
|
||||
|
||||
static yyconst flex_int32_t yy_ec[256] =
|
||||
@@ -488,13 +501,13 @@ static yyconst flex_int32_t yy_ec[256] =
|
||||
6, 1, 1, 7, 8, 9, 1, 10, 11, 11,
|
||||
11, 11, 11, 11, 11, 11, 11, 1, 1, 1,
|
||||
12, 1, 1, 1, 13, 13, 13, 13, 13, 13,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 14, 1, 1,
|
||||
15, 1, 16, 1, 1, 1, 17, 18, 13, 13,
|
||||
14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
|
||||
14, 14, 14, 14, 14, 14, 14, 15, 14, 14,
|
||||
16, 1, 17, 1, 18, 1, 19, 20, 13, 13,
|
||||
|
||||
19, 13, 20, 21, 22, 1, 1, 23, 1, 24,
|
||||
25, 26, 1, 27, 28, 29, 30, 1, 1, 31,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
21, 13, 22, 23, 24, 14, 14, 25, 14, 26,
|
||||
27, 28, 14, 29, 30, 31, 32, 14, 14, 33,
|
||||
14, 14, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
@@ -511,88 +524,110 @@ static yyconst flex_int32_t yy_ec[256] =
|
||||
1, 1, 1, 1, 1
|
||||
} ;
|
||||
|
||||
static yyconst flex_int32_t yy_meta[32] =
|
||||
static yyconst flex_int32_t yy_meta[34] =
|
||||
{ 0,
|
||||
1, 1, 2, 1, 1, 1, 1, 1, 1, 3,
|
||||
3, 1, 3, 1, 1, 1, 3, 3, 3, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1
|
||||
1, 1, 2, 1, 1, 1, 1, 3, 1, 4,
|
||||
4, 1, 4, 3, 3, 1, 1, 3, 4, 4,
|
||||
4, 3, 3, 3, 3, 3, 3, 3, 3, 3,
|
||||
3, 3, 3
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_base[54] =
|
||||
static yyconst flex_int16_t yy_base[59] =
|
||||
{ 0,
|
||||
0, 0, 72, 73, 69, 67, 65, 73, 73, 73,
|
||||
22, 73, 24, 26, 56, 73, 73, 44, 47, 39,
|
||||
34, 44, 60, 58, 56, 73, 29, 0, 73, 36,
|
||||
26, 25, 35, 21, 0, 73, 73, 29, 22, 20,
|
||||
23, 18, 73, 22, 18, 73, 22, 19, 22, 73,
|
||||
73, 55, 38
|
||||
0, 0, 121, 122, 118, 116, 110, 122, 122, 122,
|
||||
24, 122, 26, 28, 98, 0, 122, 122, 77, 79,
|
||||
67, 61, 63, 68, 50, 47, 122, 32, 0, 122,
|
||||
38, 43, 44, 45, 46, 47, 0, 48, 122, 50,
|
||||
52, 54, 55, 56, 72, 73, 77, 79, 80, 81,
|
||||
84, 86, 89, 90, 122, 112, 114, 40
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_def[54] =
|
||||
static yyconst flex_int16_t yy_def[59] =
|
||||
{ 0,
|
||||
51, 1, 51, 51, 51, 51, 52, 51, 51, 51,
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
51, 51, 51, 51, 52, 51, 51, 53, 51, 51,
|
||||
51, 51, 51, 51, 53, 51, 51, 51, 51, 51,
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
0, 51, 51
|
||||
55, 1, 55, 55, 55, 55, 56, 55, 55, 55,
|
||||
55, 55, 55, 55, 55, 57, 55, 55, 57, 57,
|
||||
57, 57, 57, 55, 55, 56, 55, 55, 58, 55,
|
||||
57, 57, 57, 57, 57, 57, 58, 55, 55, 57,
|
||||
57, 57, 57, 57, 57, 57, 57, 57, 57, 57,
|
||||
57, 57, 57, 57, 0, 55, 55, 55
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_nxt[105] =
|
||||
static yyconst flex_int16_t yy_nxt[156] =
|
||||
{ 0,
|
||||
4, 5, 6, 7, 8, 9, 10, 11, 12, 13,
|
||||
14, 15, 4, 4, 16, 17, 18, 4, 4, 4,
|
||||
19, 4, 4, 4, 20, 4, 4, 21, 22, 4,
|
||||
4, 27, 27, 27, 27, 27, 27, 28, 27, 27,
|
||||
35, 50, 49, 48, 47, 46, 45, 44, 43, 42,
|
||||
41, 40, 39, 38, 28, 25, 37, 25, 36, 26,
|
||||
24, 23, 34, 33, 32, 31, 30, 29, 26, 24,
|
||||
23, 51, 3, 51, 51, 51, 51, 51, 51, 51,
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
14, 15, 16, 16, 16, 17, 18, 4, 19, 16,
|
||||
16, 16, 20, 16, 16, 16, 21, 16, 16, 22,
|
||||
23, 16, 16, 28, 28, 28, 28, 28, 28, 38,
|
||||
29, 28, 28, 37, 38, 38, 38, 38, 38, 38,
|
||||
27, 38, 25, 38, 39, 38, 38, 38, 29, 39,
|
||||
39, 39, 39, 39, 39, 43, 39, 40, 39, 24,
|
||||
39, 39, 39, 38, 38, 42, 41, 45, 38, 44,
|
||||
38, 38, 38, 36, 46, 38, 47, 38, 39, 39,
|
||||
38, 38, 35, 39, 34, 39, 39, 39, 48, 33,
|
||||
|
||||
51, 51, 51, 51
|
||||
39, 32, 39, 49, 50, 39, 39, 52, 51, 30,
|
||||
54, 53, 26, 27, 26, 26, 31, 31, 25, 24,
|
||||
55, 3, 55, 55, 55, 55, 55, 55, 55, 55,
|
||||
55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
|
||||
55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
|
||||
55, 55, 55, 55, 55
|
||||
} ;
|
||||
|
||||
static yyconst flex_int16_t yy_chk[105] =
|
||||
static yyconst flex_int16_t yy_chk[156] =
|
||||
{ 0,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
|
||||
1, 11, 11, 13, 13, 14, 14, 13, 27, 27,
|
||||
53, 49, 48, 47, 45, 44, 42, 41, 40, 39,
|
||||
38, 34, 33, 32, 13, 52, 31, 52, 30, 25,
|
||||
24, 23, 22, 21, 20, 19, 18, 15, 7, 6,
|
||||
5, 3, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
|
||||
1, 1, 1, 11, 11, 13, 13, 14, 14, 31,
|
||||
13, 28, 28, 58, 32, 33, 34, 35, 36, 38,
|
||||
26, 40, 25, 41, 31, 42, 43, 44, 13, 32,
|
||||
33, 34, 35, 36, 38, 35, 40, 32, 41, 24,
|
||||
42, 43, 44, 45, 46, 34, 33, 42, 47, 36,
|
||||
48, 49, 50, 23, 43, 51, 44, 52, 45, 46,
|
||||
53, 54, 22, 47, 21, 48, 49, 50, 45, 20,
|
||||
|
||||
51, 51, 51, 51
|
||||
51, 19, 52, 46, 48, 53, 54, 51, 49, 15,
|
||||
53, 52, 56, 7, 56, 56, 57, 57, 6, 5,
|
||||
3, 55, 55, 55, 55, 55, 55, 55, 55, 55,
|
||||
55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
|
||||
55, 55, 55, 55, 55, 55, 55, 55, 55, 55,
|
||||
55, 55, 55, 55, 55
|
||||
} ;
|
||||
|
||||
/* Table of booleans, true if rule could match eol. */
|
||||
static yyconst flex_int32_t yy_rule_can_match_eol[20] =
|
||||
static yyconst flex_int32_t yy_rule_can_match_eol[21] =
|
||||
{ 0,
|
||||
0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
};
|
||||
|
||||
static yy_state_type yy_last_accepting_state;
|
||||
static char *yy_last_accepting_cpos;
|
||||
0, };
|
||||
|
||||
extern int yy_flex_debug;
|
||||
int yy_flex_debug = 1;
|
||||
|
||||
static yyconst flex_int16_t yy_rule_linenum[19] =
|
||||
static yyconst flex_int16_t yy_rule_linenum[20] =
|
||||
{ 0,
|
||||
83, 87, 93, 103, 109, 123, 124, 125, 126, 127,
|
||||
128, 129, 130, 131, 132, 133, 134, 136
|
||||
128, 129, 130, 131, 132, 133, 134, 136, 143
|
||||
} ;
|
||||
|
||||
/* The intent behind this definition is that it'll catch
|
||||
* any uses of REJECT which flex missed.
|
||||
*/
|
||||
#define REJECT reject_used_but_not_detected
|
||||
static yy_state_type *yy_state_buf=0, *yy_state_ptr=0;
|
||||
static char *yy_full_match;
|
||||
static int yy_lp;
|
||||
static int yy_looking_for_trail_begin = 0;
|
||||
static int yy_full_lp;
|
||||
static int *yy_full_state;
|
||||
#define YY_TRAILING_MASK 0x2000
|
||||
#define YY_TRAILING_HEAD_MASK 0x4000
|
||||
#define REJECT \
|
||||
{ \
|
||||
*yy_cp = (yy_hold_char); /* undo effects of setting up yytext */ \
|
||||
yy_cp = (yy_full_match); /* restore poss. backed-over text */ \
|
||||
(yy_lp) = (yy_full_lp); /* restore orig. accepting pos. */ \
|
||||
(yy_state_ptr) = (yy_full_state); /* restore orig. state */ \
|
||||
yy_current_state = *(yy_state_ptr); /* restore curr. state */ \
|
||||
++(yy_lp); \
|
||||
goto find_rule; \
|
||||
}
|
||||
|
||||
#define yymore() yymore_used_but_not_detected
|
||||
#define YY_MORE_ADJ 0
|
||||
#define YY_RESTORE_YY_MORE_OFFSET
|
||||
@@ -653,7 +688,7 @@ static isc::eval::location loc;
|
||||
// by moving it ahead by yyleng bytes. yyleng specifies the length of the
|
||||
// currently matched token.
|
||||
#define YY_USER_ACTION loc.columns(yyleng);
|
||||
#line 657 "lexer.cc"
|
||||
#line 692 "lexer.cc"
|
||||
|
||||
#define INITIAL 0
|
||||
|
||||
@@ -901,7 +936,7 @@ YY_DECL
|
||||
loc.step();
|
||||
|
||||
|
||||
#line 905 "lexer.cc"
|
||||
#line 940 "lexer.cc"
|
||||
|
||||
if ( !(yy_init) )
|
||||
{
|
||||
@@ -911,6 +946,12 @@ YY_DECL
|
||||
YY_USER_INIT;
|
||||
#endif
|
||||
|
||||
/* Create the reject buffer large enough to save one state per allowed character. */
|
||||
if ( ! (yy_state_buf) )
|
||||
(yy_state_buf) = (yy_state_type *)yyalloc(YY_STATE_BUF_SIZE );
|
||||
if ( ! (yy_state_buf) )
|
||||
YY_FATAL_ERROR( "out of dynamic memory in yylex()" );
|
||||
|
||||
if ( ! (yy_start) )
|
||||
(yy_start) = 1; /* first start state */
|
||||
|
||||
@@ -952,31 +993,66 @@ YY_DECL
|
||||
|
||||
/* %% [9.0] code to set up and find next match goes here */
|
||||
yy_current_state = (yy_start);
|
||||
|
||||
(yy_state_ptr) = (yy_state_buf);
|
||||
*(yy_state_ptr)++ = yy_current_state;
|
||||
|
||||
yy_match:
|
||||
do
|
||||
{
|
||||
register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
|
||||
if ( yy_accept[yy_current_state] )
|
||||
{
|
||||
(yy_last_accepting_state) = yy_current_state;
|
||||
(yy_last_accepting_cpos) = yy_cp;
|
||||
}
|
||||
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
|
||||
{
|
||||
yy_current_state = (int) yy_def[yy_current_state];
|
||||
if ( yy_current_state >= 52 )
|
||||
if ( yy_current_state >= 56 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
*(yy_state_ptr)++ = yy_current_state;
|
||||
++yy_cp;
|
||||
}
|
||||
while ( yy_current_state != 51 );
|
||||
yy_cp = (yy_last_accepting_cpos);
|
||||
yy_current_state = (yy_last_accepting_state);
|
||||
while ( yy_current_state != 55 );
|
||||
|
||||
yy_find_action:
|
||||
/* %% [10.0] code to find the action number goes here */
|
||||
yy_act = yy_accept[yy_current_state];
|
||||
yy_current_state = *--(yy_state_ptr);
|
||||
(yy_lp) = yy_accept[yy_current_state];
|
||||
goto find_rule; /* Shut up GCC warning -Wall */
|
||||
find_rule: /* we branch to this label when backing up */
|
||||
for ( ; ; ) /* until we find what rule we matched */
|
||||
{
|
||||
if ( (yy_lp) && (yy_lp) < yy_accept[yy_current_state + 1] )
|
||||
{
|
||||
yy_act = yy_acclist[(yy_lp)];
|
||||
if ( yy_act & YY_TRAILING_HEAD_MASK ||
|
||||
(yy_looking_for_trail_begin) )
|
||||
{
|
||||
if ( yy_act == (yy_looking_for_trail_begin) )
|
||||
{
|
||||
(yy_looking_for_trail_begin) = 0;
|
||||
yy_act &= ~YY_TRAILING_HEAD_MASK;
|
||||
break;
|
||||
}
|
||||
}
|
||||
else if ( yy_act & YY_TRAILING_MASK )
|
||||
{
|
||||
(yy_looking_for_trail_begin) = yy_act & ~YY_TRAILING_MASK;
|
||||
(yy_looking_for_trail_begin) |= YY_TRAILING_HEAD_MASK;
|
||||
}
|
||||
else
|
||||
{
|
||||
(yy_full_match) = yy_cp;
|
||||
(yy_full_state) = (yy_state_ptr);
|
||||
(yy_full_lp) = (yy_lp);
|
||||
break;
|
||||
}
|
||||
++(yy_lp);
|
||||
goto find_rule;
|
||||
}
|
||||
--yy_cp;
|
||||
yy_current_state = *--(yy_state_ptr);
|
||||
(yy_lp) = yy_accept[yy_current_state];
|
||||
}
|
||||
|
||||
YY_DO_BEFORE_ACTION;
|
||||
|
||||
@@ -999,13 +1075,13 @@ do_action: /* This label is used only to access EOF actions. */
|
||||
{
|
||||
if ( yy_act == 0 )
|
||||
fprintf( stderr, "--scanner backing up\n" );
|
||||
else if ( yy_act < 19 )
|
||||
else if ( yy_act < 20 )
|
||||
fprintf( stderr, "--accepting rule at line %ld (\"%s\")\n",
|
||||
(long)yy_rule_linenum[yy_act], yytext );
|
||||
else if ( yy_act == 19 )
|
||||
else if ( yy_act == 20 )
|
||||
fprintf( stderr, "--accepting default rule (\"%s\")\n",
|
||||
yytext );
|
||||
else if ( yy_act == 20 )
|
||||
else if ( yy_act == 21 )
|
||||
fprintf( stderr, "--(end of buffer or a NUL)\n" );
|
||||
else
|
||||
fprintf( stderr, "--EOF (start condition %d)\n", YY_START );
|
||||
@@ -1014,13 +1090,6 @@ do_action: /* This label is used only to access EOF actions. */
|
||||
switch ( yy_act )
|
||||
{ /* beginning of action switch */
|
||||
/* %% [13.0] actions go here */
|
||||
case 0: /* must back up */
|
||||
/* undo the effects of YY_DO_BEFORE_ACTION */
|
||||
*yy_cp = (yy_hold_char);
|
||||
yy_cp = (yy_last_accepting_cpos);
|
||||
yy_current_state = (yy_last_accepting_state);
|
||||
goto yy_find_action;
|
||||
|
||||
case 1:
|
||||
YY_RULE_SETUP
|
||||
#line 83 "lexer.ll"
|
||||
@@ -1141,18 +1210,28 @@ return isc::eval::EvalParser::make_COMA(loc);
|
||||
case 18:
|
||||
YY_RULE_SETUP
|
||||
#line 136 "lexer.ll"
|
||||
driver.error (loc, "Invalid character: " + std::string(yytext));
|
||||
YY_BREAK
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
#line 137 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_END(loc);
|
||||
{
|
||||
// This string specifies option name starting with a letter
|
||||
// and further containing letters, digits, hyphens and
|
||||
// underscores.
|
||||
return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
|
||||
}
|
||||
YY_BREAK
|
||||
case 19:
|
||||
YY_RULE_SETUP
|
||||
#line 138 "lexer.ll"
|
||||
#line 143 "lexer.ll"
|
||||
driver.error (loc, "Invalid character: " + std::string(yytext));
|
||||
YY_BREAK
|
||||
case YY_STATE_EOF(INITIAL):
|
||||
#line 144 "lexer.ll"
|
||||
return isc::eval::EvalParser::make_END(loc);
|
||||
YY_BREAK
|
||||
case 20:
|
||||
YY_RULE_SETUP
|
||||
#line 145 "lexer.ll"
|
||||
ECHO;
|
||||
YY_BREAK
|
||||
#line 1156 "lexer.cc"
|
||||
#line 1235 "lexer.cc"
|
||||
|
||||
case YY_END_OF_BUFFER:
|
||||
{
|
||||
@@ -1218,8 +1297,7 @@ ECHO;
|
||||
else
|
||||
{
|
||||
/* %% [14.0] code to do back-up for compressed tables and set up yy_cp goes here */
|
||||
yy_cp = (yy_last_accepting_cpos);
|
||||
yy_current_state = (yy_last_accepting_state);
|
||||
yy_cp = (yy_c_buf_p);
|
||||
goto yy_find_action;
|
||||
}
|
||||
}
|
||||
@@ -1356,37 +1434,8 @@ static int yy_get_next_buffer (void)
|
||||
while ( num_to_read <= 0 )
|
||||
{ /* Not enough room in the buffer - grow it. */
|
||||
|
||||
/* just a shorter name for the current buffer */
|
||||
YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
|
||||
|
||||
int yy_c_buf_p_offset =
|
||||
(int) ((yy_c_buf_p) - b->yy_ch_buf);
|
||||
|
||||
if ( b->yy_is_our_buffer )
|
||||
{
|
||||
yy_size_t new_size = b->yy_buf_size * 2;
|
||||
|
||||
if ( new_size <= 0 )
|
||||
b->yy_buf_size += b->yy_buf_size / 8;
|
||||
else
|
||||
b->yy_buf_size *= 2;
|
||||
|
||||
b->yy_ch_buf = (char *)
|
||||
/* Include room in for 2 EOB chars. */
|
||||
yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 );
|
||||
}
|
||||
else
|
||||
/* Can't grow it, we don't own it. */
|
||||
b->yy_ch_buf = 0;
|
||||
|
||||
if ( ! b->yy_ch_buf )
|
||||
YY_FATAL_ERROR(
|
||||
"fatal error - scanner input buffer overflow" );
|
||||
|
||||
(yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
|
||||
|
||||
num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
|
||||
number_to_move - 1;
|
||||
YY_FATAL_ERROR(
|
||||
"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );
|
||||
|
||||
}
|
||||
|
||||
@@ -1452,22 +1501,21 @@ static int yy_get_next_buffer (void)
|
||||
/* %% [15.0] code to get the start state into yy_current_state goes here */
|
||||
yy_current_state = (yy_start);
|
||||
|
||||
(yy_state_ptr) = (yy_state_buf);
|
||||
*(yy_state_ptr)++ = yy_current_state;
|
||||
|
||||
for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
|
||||
{
|
||||
/* %% [16.0] code to find the next state goes here */
|
||||
register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
|
||||
if ( yy_accept[yy_current_state] )
|
||||
{
|
||||
(yy_last_accepting_state) = yy_current_state;
|
||||
(yy_last_accepting_cpos) = yy_cp;
|
||||
}
|
||||
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
|
||||
{
|
||||
yy_current_state = (int) yy_def[yy_current_state];
|
||||
if ( yy_current_state >= 52 )
|
||||
if ( yy_current_state >= 56 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
*(yy_state_ptr)++ = yy_current_state;
|
||||
}
|
||||
|
||||
return yy_current_state;
|
||||
@@ -1486,22 +1534,18 @@ static int yy_get_next_buffer (void)
|
||||
{
|
||||
register int yy_is_jam;
|
||||
/* %% [17.0] code to find the next state, and perhaps do backing up, goes here */
|
||||
register char *yy_cp = (yy_c_buf_p);
|
||||
|
||||
register YY_CHAR yy_c = 1;
|
||||
if ( yy_accept[yy_current_state] )
|
||||
{
|
||||
(yy_last_accepting_state) = yy_current_state;
|
||||
(yy_last_accepting_cpos) = yy_cp;
|
||||
}
|
||||
while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
|
||||
{
|
||||
yy_current_state = (int) yy_def[yy_current_state];
|
||||
if ( yy_current_state >= 52 )
|
||||
if ( yy_current_state >= 56 )
|
||||
yy_c = yy_meta[(unsigned int) yy_c];
|
||||
}
|
||||
yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
|
||||
yy_is_jam = (yy_current_state == 51);
|
||||
yy_is_jam = (yy_current_state == 55);
|
||||
if ( ! yy_is_jam )
|
||||
*(yy_state_ptr)++ = yy_current_state;
|
||||
|
||||
return yy_is_jam ? 0 : yy_current_state;
|
||||
}
|
||||
@@ -2154,6 +2198,11 @@ static int yy_init_globals (void)
|
||||
(yy_init) = 0;
|
||||
(yy_start) = 0;
|
||||
|
||||
(yy_state_buf) = 0;
|
||||
(yy_state_ptr) = 0;
|
||||
(yy_full_match) = 0;
|
||||
(yy_lp) = 0;
|
||||
|
||||
/* Defined in main.c */
|
||||
#ifdef YY_STDINIT
|
||||
yyin = stdin;
|
||||
@@ -2186,6 +2235,9 @@ int yylex_destroy (void)
|
||||
yyfree((yy_buffer_stack) );
|
||||
(yy_buffer_stack) = NULL;
|
||||
|
||||
yyfree ( (yy_state_buf) );
|
||||
(yy_state_buf) = NULL;
|
||||
|
||||
/* Reset the globals. This is important in a non-reentrant scanner so the next time
|
||||
* yylex() is called, initialization will occur. */
|
||||
yy_init_globals( );
|
||||
@@ -2249,7 +2301,7 @@ void yyfree (void * ptr )
|
||||
|
||||
/* %ok-for-header */
|
||||
|
||||
#line 138 "lexer.ll"
|
||||
#line 145 "lexer.ll"
|
||||
|
||||
|
||||
|
||||
|
@@ -133,6 +133,13 @@ blank [ \t]
|
||||
"]" return isc::eval::EvalParser::make_RBRACKET(loc);
|
||||
"," return isc::eval::EvalParser::make_COMA(loc);
|
||||
|
||||
[A-Za-z][A-Za-z0-9_\-]+/{blank}*] {
|
||||
// This string specifies option name starting with a letter
|
||||
// and further containing letters, digits, hyphens and
|
||||
// underscores.
|
||||
return isc::eval::EvalParser::make_OPTION_NAME(yytext, loc);
|
||||
}
|
||||
|
||||
. driver.error (loc, "Invalid character: " + std::string(yytext));
|
||||
<<EOF>> return isc::eval::EvalParser::make_END(loc);
|
||||
%%
|
||||
|
@@ -49,10 +49,10 @@
|
||||
|
||||
#line 51 "parser.cc" // lalr1.cc:412
|
||||
// Unqualified %code blocks.
|
||||
#line 39 "parser.yy" // lalr1.cc:413
|
||||
#line 40 "parser.yy" // lalr1.cc:413
|
||||
|
||||
# include "eval_context.h"
|
||||
#line 67 "parser.yy" // lalr1.cc:413
|
||||
#line 73 "parser.yy" // lalr1.cc:413
|
||||
|
||||
namespace {
|
||||
|
||||
@@ -206,13 +206,14 @@ namespace isc { namespace eval {
|
||||
|
||||
|
||||
/// Build a parser object.
|
||||
EvalParser::EvalParser (EvalContext& ctx_yyarg)
|
||||
EvalParser::EvalParser (EvalContext& ctx_yyarg, const Option::Universe& option_universe_yyarg)
|
||||
:
|
||||
#if YYDEBUG
|
||||
yydebug_ (false),
|
||||
yycdebug_ (&std::cerr),
|
||||
#endif
|
||||
ctx (ctx_yyarg)
|
||||
ctx (ctx_yyarg),
|
||||
option_universe (option_universe_yyarg)
|
||||
{}
|
||||
|
||||
EvalParser::~EvalParser ()
|
||||
@@ -280,7 +281,8 @@ namespace isc { namespace eval {
|
||||
case 15: // "constant string"
|
||||
case 16: // "integer"
|
||||
case 17: // "constant hexstring"
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
case 19: // TOKEN
|
||||
value.move< std::string > (that.value);
|
||||
break;
|
||||
|
||||
@@ -302,7 +304,8 @@ namespace isc { namespace eval {
|
||||
case 15: // "constant string"
|
||||
case 16: // "integer"
|
||||
case 17: // "constant hexstring"
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
case 19: // TOKEN
|
||||
value.copy< std::string > (that.value);
|
||||
break;
|
||||
|
||||
@@ -344,30 +347,37 @@ namespace isc { namespace eval {
|
||||
{
|
||||
case 15: // "constant string"
|
||||
|
||||
#line 64 "parser.yy" // lalr1.cc:636
|
||||
#line 70 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 350 "parser.cc" // lalr1.cc:636
|
||||
#line 353 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 16: // "integer"
|
||||
|
||||
#line 64 "parser.yy" // lalr1.cc:636
|
||||
#line 70 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 357 "parser.cc" // lalr1.cc:636
|
||||
#line 360 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 17: // "constant hexstring"
|
||||
|
||||
#line 64 "parser.yy" // lalr1.cc:636
|
||||
#line 70 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 364 "parser.cc" // lalr1.cc:636
|
||||
#line 367 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
|
||||
#line 64 "parser.yy" // lalr1.cc:636
|
||||
#line 70 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 371 "parser.cc" // lalr1.cc:636
|
||||
#line 374 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
case 19: // TOKEN
|
||||
|
||||
#line 70 "parser.yy" // lalr1.cc:636
|
||||
{ yyoutput << yysym.value.template as< std::string > (); }
|
||||
#line 381 "parser.cc" // lalr1.cc:636
|
||||
break;
|
||||
|
||||
|
||||
@@ -570,7 +580,8 @@ namespace isc { namespace eval {
|
||||
case 15: // "constant string"
|
||||
case 16: // "integer"
|
||||
case 17: // "constant hexstring"
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
case 19: // TOKEN
|
||||
yylhs.value.build< std::string > ();
|
||||
break;
|
||||
|
||||
@@ -592,90 +603,124 @@ namespace isc { namespace eval {
|
||||
switch (yyn)
|
||||
{
|
||||
case 3:
|
||||
#line 105 "parser.yy" // lalr1.cc:859
|
||||
#line 111 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr eq(new TokenEqual());
|
||||
ctx.expression.push_back(eq);
|
||||
}
|
||||
#line 601 "parser.cc" // lalr1.cc:859
|
||||
#line 612 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 4:
|
||||
#line 112 "parser.yy" // lalr1.cc:859
|
||||
#line 118 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 610 "parser.cc" // lalr1.cc:859
|
||||
#line 621 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 5:
|
||||
#line 117 "parser.yy" // lalr1.cc:859
|
||||
#line 123 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr hex(new TokenHexString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(hex);
|
||||
}
|
||||
#line 619 "parser.cc" // lalr1.cc:859
|
||||
#line 630 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 6:
|
||||
#line 122 "parser.yy" // lalr1.cc:859
|
||||
#line 128 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
|
||||
TokenPtr opt(new TokenOption(numeric_code, TokenOption::TEXTUAL));
|
||||
ctx.expression.push_back(opt);
|
||||
}
|
||||
#line 629 "parser.cc" // lalr1.cc:859
|
||||
#line 640 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 7:
|
||||
#line 128 "parser.yy" // lalr1.cc:859
|
||||
#line 134 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
uint16_t numeric_code = convert_option_code(yystack_[3].value.as< std::string > (), yystack_[3].location, ctx);
|
||||
TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
|
||||
ctx.expression.push_back(opt);
|
||||
}
|
||||
#line 639 "parser.cc" // lalr1.cc:859
|
||||
#line 650 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 8:
|
||||
#line 134 "parser.yy" // lalr1.cc:859
|
||||
#line 140 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
try {
|
||||
// This may result in exception if the specified
|
||||
// name is unknown.
|
||||
TokenPtr opt(new TokenOption(yystack_[3].value.as< std::string > (), option_universe,
|
||||
TokenOption::TEXTUAL));
|
||||
ctx.expression.push_back(opt);
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
ctx.error(yystack_[3].location, ex.what());
|
||||
}
|
||||
}
|
||||
#line 667 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 9:
|
||||
#line 153 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
try {
|
||||
// This may result in exception if the specified
|
||||
// name is unknown.
|
||||
TokenPtr opt(new TokenOption(yystack_[3].value.as< std::string > (), option_universe,
|
||||
TokenOption::HEXADECIMAL));
|
||||
ctx.expression.push_back(opt);
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
ctx.error(yystack_[3].location, ex.what());
|
||||
}
|
||||
}
|
||||
#line 684 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 10:
|
||||
#line 166 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr sub(new TokenSubstring());
|
||||
ctx.expression.push_back(sub);
|
||||
}
|
||||
#line 648 "parser.cc" // lalr1.cc:859
|
||||
#line 693 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 10:
|
||||
#line 143 "parser.yy" // lalr1.cc:859
|
||||
case 12:
|
||||
#line 175 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 657 "parser.cc" // lalr1.cc:859
|
||||
#line 702 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 11:
|
||||
#line 150 "parser.yy" // lalr1.cc:859
|
||||
case 13:
|
||||
#line 182 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr str(new TokenString(yystack_[0].value.as< std::string > ()));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 666 "parser.cc" // lalr1.cc:859
|
||||
#line 711 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
case 12:
|
||||
#line 155 "parser.yy" // lalr1.cc:859
|
||||
case 14:
|
||||
#line 187 "parser.yy" // lalr1.cc:859
|
||||
{
|
||||
TokenPtr str(new TokenString("all"));
|
||||
ctx.expression.push_back(str);
|
||||
}
|
||||
#line 675 "parser.cc" // lalr1.cc:859
|
||||
#line 720 "parser.cc" // lalr1.cc:859
|
||||
break;
|
||||
|
||||
|
||||
#line 679 "parser.cc" // lalr1.cc:859
|
||||
#line 724 "parser.cc" // lalr1.cc:859
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@@ -930,74 +975,79 @@ namespace isc { namespace eval {
|
||||
}
|
||||
|
||||
|
||||
const signed char EvalParser::yypact_ninf_ = -10;
|
||||
const signed char EvalParser::yypact_ninf_ = -14;
|
||||
|
||||
const signed char EvalParser::yytable_ninf_ = -1;
|
||||
|
||||
const signed char
|
||||
EvalParser::yypact_[] =
|
||||
{
|
||||
-4, -9, -3, -10, -10, -10, 9, -10, 12, 1,
|
||||
-4, -10, -4, -2, 6, -10, 10, 2, 0, -10,
|
||||
11, -10, -10, -6, -10, -10, 8, -10
|
||||
-4, -9, -5, -14, -14, -14, 8, -14, 9, -13,
|
||||
-4, -14, -4, 0, 6, 11, -14, 13, 14, 15,
|
||||
10, 12, -14, 16, -14, -14, -14, -14, -6, -14,
|
||||
-14, 17, -14
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yydefact_[] =
|
||||
{
|
||||
0, 0, 0, 4, 5, 9, 0, 2, 0, 0,
|
||||
0, 1, 0, 0, 0, 3, 0, 0, 0, 10,
|
||||
0, 6, 7, 0, 12, 11, 0, 8
|
||||
0, 0, 0, 4, 5, 11, 0, 2, 0, 0,
|
||||
0, 1, 0, 0, 0, 0, 3, 0, 0, 0,
|
||||
0, 0, 12, 0, 6, 7, 8, 9, 0, 14,
|
||||
13, 0, 10
|
||||
};
|
||||
|
||||
const signed char
|
||||
EvalParser::yypgoto_[] =
|
||||
{
|
||||
-10, -10, -10, -7, -10, -10
|
||||
-14, -14, -14, -3, -14, -14
|
||||
};
|
||||
|
||||
const signed char
|
||||
EvalParser::yydefgoto_[] =
|
||||
{
|
||||
-1, 6, 7, 8, 20, 26
|
||||
-1, 6, 7, 8, 23, 31
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yytable_[] =
|
||||
{
|
||||
1, 2, 24, 14, 9, 15, 21, 22, 10, 11,
|
||||
25, 3, 16, 4, 5, 12, 17, 13, 19, 18,
|
||||
27, 23
|
||||
1, 2, 29, 13, 9, 14, 10, 15, 11, 16,
|
||||
30, 3, 12, 4, 17, 5, 24, 25, 26, 27,
|
||||
18, 19, 20, 21, 0, 0, 28, 0, 0, 32,
|
||||
0, 22
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
const signed char
|
||||
EvalParser::yycheck_[] =
|
||||
{
|
||||
4, 5, 8, 10, 13, 12, 6, 7, 11, 0,
|
||||
16, 15, 14, 17, 18, 3, 10, 16, 16, 9,
|
||||
12, 10
|
||||
4, 5, 8, 16, 13, 18, 11, 10, 0, 12,
|
||||
16, 15, 3, 17, 14, 19, 6, 7, 6, 7,
|
||||
14, 10, 9, 9, -1, -1, 10, -1, -1, 12,
|
||||
-1, 16
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yystos_[] =
|
||||
{
|
||||
0, 4, 5, 15, 17, 18, 20, 21, 22, 13,
|
||||
11, 0, 3, 16, 22, 22, 14, 10, 9, 16,
|
||||
23, 6, 7, 10, 8, 16, 24, 12
|
||||
0, 4, 5, 15, 17, 19, 21, 22, 23, 13,
|
||||
11, 0, 3, 16, 18, 23, 23, 14, 14, 10,
|
||||
9, 9, 16, 24, 6, 7, 6, 7, 10, 8,
|
||||
16, 25, 12
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yyr1_[] =
|
||||
{
|
||||
0, 19, 20, 21, 22, 22, 22, 22, 22, 22,
|
||||
23, 24, 24
|
||||
0, 20, 21, 22, 23, 23, 23, 23, 23, 23,
|
||||
23, 23, 24, 25, 25
|
||||
};
|
||||
|
||||
const unsigned char
|
||||
EvalParser::yyr2_[] =
|
||||
{
|
||||
0, 2, 1, 3, 1, 1, 6, 6, 8, 1,
|
||||
1, 1, 1
|
||||
0, 2, 1, 3, 1, 1, 6, 6, 6, 6,
|
||||
8, 1, 1, 1, 1
|
||||
};
|
||||
|
||||
|
||||
@@ -1010,16 +1060,16 @@ namespace isc { namespace eval {
|
||||
"\"end of file\"", "error", "$undefined", "\"==\"", "\"option\"",
|
||||
"\"substring\"", "\"text\"", "\"hex\"", "\"all\"", "\".\"", "\",\"",
|
||||
"\"(\"", "\")\"", "\"[\"", "\"]\"", "\"constant string\"", "\"integer\"",
|
||||
"\"constant hexstring\"", "TOKEN", "$accept", "expression", "bool_expr",
|
||||
"string_expr", "start_expr", "length_expr", YY_NULLPTR
|
||||
"\"constant hexstring\"", "\"option name\"", "TOKEN", "$accept",
|
||||
"expression", "bool_expr", "string_expr", "start_expr", "length_expr", YY_NULLPTR
|
||||
};
|
||||
|
||||
#if YYDEBUG
|
||||
const unsigned char
|
||||
EvalParser::yyrline_[] =
|
||||
{
|
||||
0, 101, 101, 104, 111, 116, 121, 127, 133, 138,
|
||||
142, 149, 154
|
||||
0, 107, 107, 110, 117, 122, 127, 133, 139, 152,
|
||||
165, 170, 174, 181, 186
|
||||
};
|
||||
|
||||
// Print the state stack on the debug stream.
|
||||
@@ -1054,8 +1104,8 @@ namespace isc { namespace eval {
|
||||
|
||||
#line 21 "parser.yy" // lalr1.cc:1167
|
||||
} } // isc::eval
|
||||
#line 1058 "parser.cc" // lalr1.cc:1167
|
||||
#line 161 "parser.yy" // lalr1.cc:1168
|
||||
#line 1108 "parser.cc" // lalr1.cc:1167
|
||||
#line 193 "parser.yy" // lalr1.cc:1168
|
||||
|
||||
void
|
||||
isc::eval::EvalParser::error(const location_type& loc,
|
||||
|
@@ -45,12 +45,13 @@
|
||||
#include <string>
|
||||
#include <eval/token.h>
|
||||
#include <eval/eval_context_decl.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using namespace isc::dhcp;
|
||||
using namespace isc::eval;
|
||||
|
||||
#line 54 "parser.h" // lalr1.cc:392
|
||||
#line 55 "parser.h" // lalr1.cc:392
|
||||
|
||||
# include <cassert>
|
||||
# include <cstdlib> // std::abort
|
||||
@@ -127,7 +128,7 @@ using namespace isc::eval;
|
||||
|
||||
#line 21 "parser.yy" // lalr1.cc:392
|
||||
namespace isc { namespace eval {
|
||||
#line 131 "parser.h" // lalr1.cc:392
|
||||
#line 132 "parser.h" // lalr1.cc:392
|
||||
|
||||
|
||||
|
||||
@@ -297,6 +298,7 @@ namespace isc { namespace eval {
|
||||
// "constant string"
|
||||
// "integer"
|
||||
// "constant hexstring"
|
||||
// "option name"
|
||||
// TOKEN
|
||||
char dummy1[sizeof(std::string)];
|
||||
};
|
||||
@@ -337,7 +339,8 @@ namespace isc { namespace eval {
|
||||
TOKEN_STRING = 270,
|
||||
TOKEN_INTEGER = 271,
|
||||
TOKEN_HEXSTRING = 272,
|
||||
TOKEN_TOKEN = 273
|
||||
TOKEN_OPTION_NAME = 273,
|
||||
TOKEN_TOKEN = 274
|
||||
};
|
||||
};
|
||||
|
||||
@@ -508,13 +511,17 @@ namespace isc { namespace eval {
|
||||
symbol_type
|
||||
make_HEXSTRING (const std::string& v, const location_type& l);
|
||||
|
||||
static inline
|
||||
symbol_type
|
||||
make_OPTION_NAME (const std::string& v, const location_type& l);
|
||||
|
||||
static inline
|
||||
symbol_type
|
||||
make_TOKEN (const std::string& v, const location_type& l);
|
||||
|
||||
|
||||
/// Build a parser object.
|
||||
EvalParser (EvalContext& ctx_yyarg);
|
||||
EvalParser (EvalContext& ctx_yyarg, const Option::Universe& option_universe_yyarg);
|
||||
virtual ~EvalParser ();
|
||||
|
||||
/// Parse.
|
||||
@@ -597,7 +604,7 @@ namespace isc { namespace eval {
|
||||
// number is the opposite. If YYTABLE_NINF, syntax error.
|
||||
static const unsigned char yytable_[];
|
||||
|
||||
static const unsigned char yycheck_[];
|
||||
static const signed char yycheck_[];
|
||||
|
||||
// YYSTOS[STATE-NUM] -- The (internal number of the) accessing
|
||||
// symbol of state STATE-NUM.
|
||||
@@ -717,17 +724,18 @@ namespace isc { namespace eval {
|
||||
enum
|
||||
{
|
||||
yyeof_ = 0,
|
||||
yylast_ = 21, ///< Last index in yytable_.
|
||||
yylast_ = 31, ///< Last index in yytable_.
|
||||
yynnts_ = 6, ///< Number of nonterminal symbols.
|
||||
yyfinal_ = 11, ///< Termination state number.
|
||||
yyterror_ = 1,
|
||||
yyerrcode_ = 256,
|
||||
yyntokens_ = 19 ///< Number of tokens.
|
||||
yyntokens_ = 20 ///< Number of tokens.
|
||||
};
|
||||
|
||||
|
||||
// User arguments.
|
||||
EvalContext& ctx;
|
||||
const Option::Universe& option_universe;
|
||||
};
|
||||
|
||||
// Symbol number corresponding to token number t.
|
||||
@@ -766,9 +774,9 @@ namespace isc { namespace eval {
|
||||
2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
|
||||
2, 2, 2, 2, 2, 2, 1, 2, 3, 4,
|
||||
5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
|
||||
15, 16, 17, 18
|
||||
15, 16, 17, 18, 19
|
||||
};
|
||||
const unsigned int user_token_number_max_ = 273;
|
||||
const unsigned int user_token_number_max_ = 274;
|
||||
const token_number_type undef_token_ = 2;
|
||||
|
||||
if (static_cast<int>(t) <= yyeof_)
|
||||
@@ -804,7 +812,8 @@ namespace isc { namespace eval {
|
||||
case 15: // "constant string"
|
||||
case 16: // "integer"
|
||||
case 17: // "constant hexstring"
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
case 19: // TOKEN
|
||||
value.copy< std::string > (other.value);
|
||||
break;
|
||||
|
||||
@@ -828,7 +837,8 @@ namespace isc { namespace eval {
|
||||
case 15: // "constant string"
|
||||
case 16: // "integer"
|
||||
case 17: // "constant hexstring"
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
case 19: // TOKEN
|
||||
value.copy< std::string > (v);
|
||||
break;
|
||||
|
||||
@@ -883,7 +893,8 @@ namespace isc { namespace eval {
|
||||
case 15: // "constant string"
|
||||
case 16: // "integer"
|
||||
case 17: // "constant hexstring"
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
case 19: // TOKEN
|
||||
value.template destroy< std::string > ();
|
||||
break;
|
||||
|
||||
@@ -913,7 +924,8 @@ namespace isc { namespace eval {
|
||||
case 15: // "constant string"
|
||||
case 16: // "integer"
|
||||
case 17: // "constant hexstring"
|
||||
case 18: // TOKEN
|
||||
case 18: // "option name"
|
||||
case 19: // TOKEN
|
||||
value.move< std::string > (s.value);
|
||||
break;
|
||||
|
||||
@@ -973,7 +985,7 @@ namespace isc { namespace eval {
|
||||
yytoken_number_[] =
|
||||
{
|
||||
0, 256, 257, 258, 259, 260, 261, 262, 263, 264,
|
||||
265, 266, 267, 268, 269, 270, 271, 272, 273
|
||||
265, 266, 267, 268, 269, 270, 271, 272, 273, 274
|
||||
};
|
||||
return static_cast<token_type> (yytoken_number_[type]);
|
||||
}
|
||||
@@ -1074,6 +1086,12 @@ namespace isc { namespace eval {
|
||||
return symbol_type (token::TOKEN_HEXSTRING, v, l);
|
||||
}
|
||||
|
||||
EvalParser::symbol_type
|
||||
EvalParser::make_OPTION_NAME (const std::string& v, const location_type& l)
|
||||
{
|
||||
return symbol_type (token::TOKEN_OPTION_NAME, v, l);
|
||||
}
|
||||
|
||||
EvalParser::symbol_type
|
||||
EvalParser::make_TOKEN (const std::string& v, const location_type& l)
|
||||
{
|
||||
@@ -1083,7 +1101,7 @@ namespace isc { namespace eval {
|
||||
|
||||
#line 21 "parser.yy" // lalr1.cc:392
|
||||
} } // isc::eval
|
||||
#line 1087 "parser.h" // lalr1.cc:392
|
||||
#line 1105 "parser.h" // lalr1.cc:392
|
||||
|
||||
|
||||
|
||||
|
@@ -25,6 +25,7 @@
|
||||
#include <string>
|
||||
#include <eval/token.h>
|
||||
#include <eval/eval_context_decl.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
|
||||
using namespace isc::dhcp;
|
||||
@@ -39,6 +40,10 @@ using namespace isc::eval;
|
||||
{
|
||||
# include "eval_context.h"
|
||||
}
|
||||
// Option universe: DHCPv4 or DHCPv6. This is required to use correct option
|
||||
// definition set to map option names to codes.
|
||||
%parse-param { const Option::Universe& option_universe }
|
||||
|
||||
%define api.token.prefix {TOKEN_}
|
||||
%token
|
||||
END 0 "end of file"
|
||||
@@ -59,6 +64,7 @@ using namespace isc::eval;
|
||||
%token <std::string> STRING "constant string"
|
||||
%token <std::string> INTEGER "integer"
|
||||
%token <std::string> HEXSTRING "constant hexstring"
|
||||
%token <std::string> OPTION_NAME "option name"
|
||||
%token <std::string> TOKEN
|
||||
|
||||
%printer { yyoutput << $$; } <*>;
|
||||
@@ -130,6 +136,32 @@ string_expr : STRING
|
||||
TokenPtr opt(new TokenOption(numeric_code, TokenOption::HEXADECIMAL));
|
||||
ctx.expression.push_back(opt);
|
||||
}
|
||||
| OPTION "[" OPTION_NAME "]" DOT TEXT
|
||||
{
|
||||
try {
|
||||
// This may result in exception if the specified
|
||||
// name is unknown.
|
||||
TokenPtr opt(new TokenOption($3, option_universe,
|
||||
TokenOption::TEXTUAL));
|
||||
ctx.expression.push_back(opt);
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
ctx.error(@3, ex.what());
|
||||
}
|
||||
}
|
||||
| OPTION "[" OPTION_NAME "]" DOT HEX
|
||||
{
|
||||
try {
|
||||
// This may result in exception if the specified
|
||||
// name is unknown.
|
||||
TokenPtr opt(new TokenOption($3, option_universe,
|
||||
TokenOption::HEXADECIMAL));
|
||||
ctx.expression.push_back(opt);
|
||||
|
||||
} catch (const std::exception& ex) {
|
||||
ctx.error(@3, ex.what());
|
||||
}
|
||||
}
|
||||
| SUBSTRING "(" string_expr "," start_expr "," length_expr ")"
|
||||
{
|
||||
TokenPtr sub(new TokenSubstring());
|
||||
|
@@ -16,6 +16,7 @@
|
||||
#include <eval/token.h>
|
||||
#include <eval/eval_context.h>
|
||||
#include <eval/token.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/pkt4.h>
|
||||
|
||||
#include <boost/shared_ptr.hpp>
|
||||
@@ -94,7 +95,7 @@ public:
|
||||
/// @brief checks if the given expression raises the expected message
|
||||
/// when it is parsed.
|
||||
void checkError(const string& expr, const string& msg) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
parsed_ = false;
|
||||
try {
|
||||
parsed_ = eval.parseString(expr);
|
||||
@@ -115,15 +116,15 @@ public:
|
||||
// Test the parsing of a basic expression
|
||||
TEST_F(EvalContextTest, basic) {
|
||||
|
||||
EvalContext tmp;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ = tmp.parseString("option[123].text == 'MSFT'"));
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].text == 'MSFT'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
}
|
||||
|
||||
// Test the parsing of a string terminal
|
||||
TEST_F(EvalContextTest, string) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("'foo' == 'bar'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
@@ -140,7 +141,7 @@ TEST_F(EvalContextTest, string) {
|
||||
// Test the parsing of a basic expression using integers
|
||||
TEST_F(EvalContextTest, integer) {
|
||||
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ =
|
||||
eval.parseString("substring(option[123].text, 0, 2) == '42'"));
|
||||
@@ -149,7 +150,7 @@ TEST_F(EvalContextTest, integer) {
|
||||
|
||||
// Test the parsing of a hexstring terminal
|
||||
TEST_F(EvalContextTest, hexstring) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("0x666f6f == 'foo'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
@@ -164,7 +165,7 @@ TEST_F(EvalContextTest, hexstring) {
|
||||
// Test the parsing of a hexstring terminal with an odd number of
|
||||
// hexadecimal digits
|
||||
TEST_F(EvalContextTest, oddHexstring) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("0X7 == 'foo'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
@@ -178,7 +179,7 @@ TEST_F(EvalContextTest, oddHexstring) {
|
||||
|
||||
// Test the parsing of an equal expression
|
||||
TEST_F(EvalContextTest, equal) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("'foo' == 'bar'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
@@ -196,7 +197,7 @@ TEST_F(EvalContextTest, equal) {
|
||||
|
||||
// Test the parsing of an option terminal
|
||||
TEST_F(EvalContextTest, option) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].text == 'foo'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
@@ -204,9 +205,31 @@ TEST_F(EvalContextTest, option) {
|
||||
checkTokenOption(eval.expression.at(0), 123);
|
||||
}
|
||||
|
||||
// Test parsing of an option identified by name.
|
||||
TEST_F(EvalContextTest, optionWithName) {
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
// Option 'host-name' is a standard DHCPv4 option defined in the libdhcp++.
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("option[host-name].text == 'foo'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
ASSERT_EQ(3, eval.expression.size());
|
||||
checkTokenOption(eval.expression.at(0), 12);
|
||||
}
|
||||
|
||||
// Test checking that whitespace can surround option name.
|
||||
TEST_F(EvalContextTest, optionWithNameAndWhitespace) {
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
// Option 'host-name' is a standard DHCPv4 option defined in the libdhcp++.
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("option[ host-name ].text == 'foo'"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
ASSERT_EQ(3, eval.expression.size());
|
||||
checkTokenOption(eval.expression.at(0), 12);
|
||||
}
|
||||
|
||||
// Test parsing of an option represented as hexadecimal string.
|
||||
TEST_F(EvalContextTest, optionHex) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ = eval.parseString("option[123].hex == 0x666F6F"));
|
||||
EXPECT_TRUE(parsed_);
|
||||
@@ -216,7 +239,7 @@ TEST_F(EvalContextTest, optionHex) {
|
||||
|
||||
// Test the parsing of a substring expression
|
||||
TEST_F(EvalContextTest, substring) {
|
||||
EvalContext eval;
|
||||
EvalContext eval(Option::V4);
|
||||
|
||||
EXPECT_NO_THROW(parsed_ =
|
||||
eval.parseString("substring('foobar',2,all) == 'obar'"));
|
||||
@@ -288,14 +311,12 @@ TEST_F(EvalContextTest, parseErrors) {
|
||||
checkError("option(10) == 'ab'",
|
||||
"<string>:1.7: syntax error, "
|
||||
"unexpected (, expecting [");
|
||||
checkError("option['ab'].text == 'foo'",
|
||||
"<string>:1.8-11: syntax error, "
|
||||
"unexpected constant string, "
|
||||
"expecting integer");
|
||||
checkError("option[ab].text == 'foo'",
|
||||
"<string>:1.8-9: option 'ab' is not defined");
|
||||
checkError("option[0xa].text == 'ab'",
|
||||
"<string>:1.8-10: syntax error, "
|
||||
"unexpected constant hexstring, "
|
||||
"expecting integer");
|
||||
"expecting integer or option name");
|
||||
checkError("substring('foobar') == 'f'",
|
||||
"<string>:1.19: syntax error, "
|
||||
"unexpected ), expecting \",\"");
|
||||
|
@@ -217,7 +217,7 @@ TEST_F(EvaluateTest, optionHex) {
|
||||
|
||||
ASSERT_NO_THROW(toption.reset(new TokenOption(100, TokenOption::HEXADECIMAL)));
|
||||
e_.push_back(toption);
|
||||
ASSERT_NO_THROW(tstring.reset(new TokenString("0x68756E6472656434")));
|
||||
ASSERT_NO_THROW(tstring.reset(new TokenString("hundred4")));
|
||||
e_.push_back(tstring);
|
||||
ASSERT_NO_THROW(tequal.reset(new TokenEqual()));
|
||||
e_.push_back(tequal);
|
||||
|
@@ -14,6 +14,9 @@
|
||||
|
||||
#include <config.h>
|
||||
#include <eval/token.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcp/pkt4.h>
|
||||
#include <dhcp/pkt6.h>
|
||||
#include <dhcp/dhcp4.h>
|
||||
@@ -52,6 +55,13 @@ public:
|
||||
pkt6_->addOption(option_str6_);
|
||||
}
|
||||
|
||||
/// @brief Destructor.
|
||||
///
|
||||
/// Removes any option definitions registered in runtime.
|
||||
virtual ~TokenTest() {
|
||||
LibDHCP::clearRuntimeOptionDefs();
|
||||
}
|
||||
|
||||
TokenPtr t_; ///< Just a convenience pointer
|
||||
|
||||
ValueStack values_; ///< evaluated values will be stored here
|
||||
@@ -62,6 +72,23 @@ public:
|
||||
OptionPtr option_str4_; ///< A string option for DHCPv4
|
||||
OptionPtr option_str6_; ///< A string option for DHCPv6
|
||||
|
||||
/// @brief Create definitions of DHCPv4 options used by unit tests.
|
||||
void createOptionDefinitions4() {
|
||||
OptionDefSpaceContainer defs;
|
||||
OptionDefinitionPtr opt_def4(new OptionDefinition("name-hundred4",
|
||||
100, "string"));
|
||||
defs.addItem(opt_def4, "dhcp4");
|
||||
LibDHCP::setRuntimeOptionDefs(defs);
|
||||
}
|
||||
|
||||
/// @brief Create definitions of DHCPv6 options used by unit tests.
|
||||
void createOptionDefinitions6() {
|
||||
OptionDefSpaceContainer defs;
|
||||
OptionDefinitionPtr opt_def6(new OptionDefinition("name-hundred6",
|
||||
100, "string"));
|
||||
defs.addItem(opt_def6, "dhcp6");
|
||||
LibDHCP::setRuntimeOptionDefs(defs);
|
||||
}
|
||||
|
||||
/// @brief Verify that the substring eval works properly
|
||||
///
|
||||
@@ -274,6 +301,28 @@ TEST_F(TokenTest, optionString4) {
|
||||
EXPECT_EQ("hundred4", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option identified by name is
|
||||
// able to extract this option from an IPv4 packet and properly store the
|
||||
// option's value.
|
||||
TEST_F(TokenTest, optionWithNameString4) {
|
||||
// Create definition of option 100 to provide a mapping between option
|
||||
// code and option name.
|
||||
ASSERT_NO_THROW(createOptionDefinitions4());
|
||||
|
||||
// Create token for option referenced by name. The constructor should
|
||||
// map the option name to its code.
|
||||
TokenPtr token;
|
||||
ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred4", Option::V4,
|
||||
TokenOption::TEXTUAL)));
|
||||
|
||||
// Evaluate option in the packet.
|
||||
ASSERT_NO_THROW(token->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// Then the content of the option.
|
||||
EXPECT_EQ("hundred4", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing option value is able to extract
|
||||
// the option from an IPv4 packet and properly store its value in a
|
||||
// hexadecimal format.
|
||||
@@ -300,7 +349,29 @@ TEST_F(TokenTest, optionHexString4) {
|
||||
values_.pop();
|
||||
|
||||
// Then the content of the option 100.
|
||||
EXPECT_EQ("0x68756E6472656434", values_.top());
|
||||
EXPECT_EQ("hundred4", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option identified by name is
|
||||
// able to extract this option from an IPv4 packet and properly store its
|
||||
// value in the hexadecimal format.
|
||||
TEST_F(TokenTest, optionWithNameHexString4) {
|
||||
// Create definition of option 100 to provide a mapping between option
|
||||
// code and option name.
|
||||
ASSERT_NO_THROW(createOptionDefinitions4());
|
||||
|
||||
// Create token for option referenced by name. The constructor should
|
||||
// map the option name to its code.
|
||||
TokenPtr token;
|
||||
ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred4", Option::V4,
|
||||
TokenOption::HEXADECIMAL)));
|
||||
|
||||
// Evaluate option in the packet.
|
||||
ASSERT_NO_THROW(token->evaluate(*pkt4_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// Then the content of the option.
|
||||
EXPECT_EQ("hundred4", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option value is able to extract
|
||||
@@ -331,6 +402,29 @@ TEST_F(TokenTest, optionString6) {
|
||||
EXPECT_EQ("hundred6", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option identified by name is
|
||||
// able to extract this option from an IPv6 packet and properly store the
|
||||
// option's value.
|
||||
TEST_F(TokenTest, optionWithNameString6) {
|
||||
// Create definition of option 100 to provide a mapping between option
|
||||
// code and option name.
|
||||
ASSERT_NO_THROW(createOptionDefinitions6());
|
||||
|
||||
// Create token for option referenced by name. The constructor should
|
||||
// map the option name to its code.
|
||||
TokenPtr token;
|
||||
ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred6", Option::V6,
|
||||
TokenOption::TEXTUAL)));
|
||||
|
||||
// Evaluate option in the packet.
|
||||
ASSERT_NO_THROW(token->evaluate(*pkt6_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// Then the content of the option.
|
||||
EXPECT_EQ("hundred6", values_.top());
|
||||
}
|
||||
|
||||
|
||||
// This test checks if a token representing an option value is able to extract
|
||||
// the option from an IPv6 packet and properly store its value in hexadecimal
|
||||
// format.
|
||||
@@ -357,7 +451,29 @@ TEST_F(TokenTest, optionHexString6) {
|
||||
values_.pop();
|
||||
|
||||
// Then the content of the option 100.
|
||||
EXPECT_EQ("0x68756E6472656436", values_.top());
|
||||
EXPECT_EQ("hundred6", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an option identified by name is
|
||||
// able to extract this option from an IPv6 packet and properly store its
|
||||
// value in the hexadecimal format.
|
||||
TEST_F(TokenTest, optionWithNameHexString6) {
|
||||
// Create definition of option 100 to provide a mapping between option
|
||||
// code and option name.
|
||||
ASSERT_NO_THROW(createOptionDefinitions6());
|
||||
|
||||
// Create token for option referenced by name. The constructor should
|
||||
// map the option name to its code.
|
||||
TokenPtr token;
|
||||
ASSERT_NO_THROW(token.reset(new TokenOption("name-hundred6", Option::V6,
|
||||
TokenOption::HEXADECIMAL)));
|
||||
|
||||
// Evaluate option in the packet.
|
||||
ASSERT_NO_THROW(token->evaluate(*pkt6_, values_));
|
||||
ASSERT_EQ(1, values_.size());
|
||||
|
||||
// Then the content of the option.
|
||||
EXPECT_EQ("hundred6", values_.top());
|
||||
}
|
||||
|
||||
// This test checks if a token representing an == operator is able to
|
||||
|
@@ -14,6 +14,8 @@
|
||||
|
||||
#include <eval/token.h>
|
||||
#include <eval/eval_log.h>
|
||||
#include <dhcp/option_definition.h>
|
||||
#include <dhcp/libdhcp++.h>
|
||||
#include <util/encode/hex.h>
|
||||
#include <boost/lexical_cast.hpp>
|
||||
#include <cstring>
|
||||
@@ -62,16 +64,42 @@ TokenHexString::evaluate(const Pkt& /*pkt*/, ValueStack& values) {
|
||||
values.push(value_);
|
||||
}
|
||||
|
||||
TokenOption::TokenOption(const std::string& option_name,
|
||||
const Option::Universe& option_universe,
|
||||
const RepresentationType& rep_type)
|
||||
: option_code_(0), representation_type_(rep_type) {
|
||||
OptionDefinitionPtr option_def = LibDHCP::getOptionDef(option_universe,
|
||||
option_name);
|
||||
if (!option_def) {
|
||||
const std::string global_space =
|
||||
(option_universe == Option::V4) ? "dhcp4" : "dhcp6";
|
||||
option_def = LibDHCP::getRuntimeOptionDef(global_space, option_name);
|
||||
}
|
||||
|
||||
if (!option_def) {
|
||||
isc_throw(BadValue, "option '" << option_name << "' is not defined");
|
||||
}
|
||||
|
||||
option_code_ = option_def->getCode();
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
TokenOption::evaluate(const Pkt& pkt, ValueStack& values) {
|
||||
OptionPtr opt = pkt.getOption(option_code_);
|
||||
std::string opt_str;
|
||||
if (opt) {
|
||||
values.push(representation_type_ == TEXTUAL ? opt->toString()
|
||||
: opt->toHexString());
|
||||
} else {
|
||||
// Option not found, push empty string
|
||||
values.push("");
|
||||
if (representation_type_ == TEXTUAL) {
|
||||
opt_str = opt->toString();
|
||||
} else {
|
||||
std::vector<uint8_t> binary = opt->toBinary();
|
||||
opt_str.assign(binary.begin(), binary.end());
|
||||
}
|
||||
}
|
||||
|
||||
// Push value of the option or empty string if there was no such option
|
||||
// in the packet.
|
||||
values.push(opt_str);
|
||||
}
|
||||
|
||||
void
|
||||
|
@@ -16,8 +16,10 @@
|
||||
#define TOKEN_H
|
||||
|
||||
#include <exceptions/exceptions.h>
|
||||
#include <dhcp/option.h>
|
||||
#include <dhcp/pkt.h>
|
||||
#include <stack>
|
||||
#include <string>
|
||||
|
||||
namespace isc {
|
||||
namespace dhcp {
|
||||
@@ -161,16 +163,24 @@ public:
|
||||
};
|
||||
|
||||
/// @brief Constructor that takes an option code as a parameter
|
||||
/// @param option_code code of the option
|
||||
///
|
||||
/// Note: There is no constructor that takes option_name, as it would
|
||||
/// introduce complex dependency of the libkea-eval on libdhcpsrv.
|
||||
///
|
||||
/// @param option_code code of the option to be represented.
|
||||
/// @param option_code Code of the option to be represented.
|
||||
/// @param rep_type Token representation type.
|
||||
TokenOption(const uint16_t option_code, const RepresentationType& rep_type)
|
||||
: option_code_(option_code), representation_type_(rep_type) {}
|
||||
|
||||
/// @brief Constructor that takes option name as a parameter.
|
||||
///
|
||||
/// This constructor will throw exception if there is no definition using
|
||||
/// specified option name in libdhcp++.
|
||||
///
|
||||
/// @param option_name Name of the option to be represented.
|
||||
/// @param option_universe Option universe: DHCPv4 or DHCPv6.
|
||||
/// @param rep_type Token representation type.
|
||||
TokenOption(const std::string& option_name,
|
||||
const Option::Universe& option_universe,
|
||||
const RepresentationType& rep_type);
|
||||
|
||||
/// @brief Evaluates the values of the option
|
||||
///
|
||||
/// This token represents a value of the option, so this method attempts
|
||||
|
@@ -21,6 +21,7 @@ libkea_util_la_SOURCES += pointer_util.h
|
||||
libkea_util_la_SOURCES += process_spawn.h process_spawn.cc
|
||||
libkea_util_la_SOURCES += range_utilities.h
|
||||
libkea_util_la_SOURCES += signal_set.cc signal_set.h
|
||||
libkea_util_la_SOURCES += staged_value.h
|
||||
libkea_util_la_SOURCES += stopwatch.cc stopwatch.h
|
||||
libkea_util_la_SOURCES += stopwatch_impl.cc stopwatch_impl.h
|
||||
libkea_util_la_SOURCES += versioned_csv_file.h versioned_csv_file.cc
|
||||
|
126
src/lib/util/staged_value.h
Normal file
126
src/lib/util/staged_value.h
Normal file
@@ -0,0 +1,126 @@
|
||||
// Copyright (C) 2015 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
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#ifndef STAGED_VALUE_H
|
||||
#define STAGED_VALUE_H
|
||||
|
||||
#include <boost/noncopyable.hpp>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
|
||||
namespace isc {
|
||||
namespace util {
|
||||
|
||||
/// @brief This class implements set/commit mechanism for a single object.
|
||||
///
|
||||
/// In some cases it is desired to set value for an object while keeping
|
||||
/// ability to revert to an original value under certain conditions.
|
||||
/// This is often desired for objects holding some part of application's
|
||||
/// configuration. Configuration is usually a multi-step process and
|
||||
/// may fail on almost any stage. If this happens, the last good
|
||||
/// configuration should be used. This implies that some of the state
|
||||
/// of some of the objects needs to be reverted.
|
||||
///
|
||||
/// This class implements a mechanism for setting and committing a value.
|
||||
/// Until the new value has been committed it is possible to revert to
|
||||
/// an original value.
|
||||
///
|
||||
/// @tparam ValueType Type of the value represented by this class.
|
||||
template<typename ValueType>
|
||||
class StagedValue : public boost::noncopyable {
|
||||
public:
|
||||
|
||||
/// @brief Constructor.
|
||||
///
|
||||
/// Initializes the default value.
|
||||
StagedValue()
|
||||
: staging_(new ValueType()), current_(new ValueType()),
|
||||
modified_(false) {
|
||||
}
|
||||
|
||||
/// @brief Retrieves current value.
|
||||
///
|
||||
/// If the value hasn't been modified since last commit, reset or
|
||||
/// revert operation, a committed value is returned. If the value
|
||||
/// has been modified, the modified value is returned.
|
||||
const ValueType& getValue() const {
|
||||
return (modified_ ? *staging_ : *current_);
|
||||
}
|
||||
|
||||
/// @brief Sets new value.
|
||||
///
|
||||
/// @param new_value New value to be assigned.
|
||||
void setValue(const ValueType& new_value) {
|
||||
*staging_ = new_value;
|
||||
modified_ = true;
|
||||
}
|
||||
|
||||
/// @brief Commits a value.
|
||||
void commit() {
|
||||
// Only apply changes if any modifications made.
|
||||
if (modified_) {
|
||||
current_ = staging_;
|
||||
}
|
||||
revert();
|
||||
}
|
||||
|
||||
/// @brief Resets value to defaults.
|
||||
void reset() {
|
||||
revert();
|
||||
current_.reset(new ValueType());
|
||||
}
|
||||
|
||||
/// @brief Reverts any modifications since last commit.
|
||||
void revert() {
|
||||
staging_.reset(new ValueType());
|
||||
modified_ = false;
|
||||
}
|
||||
|
||||
/// @brief Assignment operator.
|
||||
///
|
||||
/// @param value New value to be assigned.
|
||||
/// @return Reference to this.
|
||||
StagedValue& operator=(const ValueType& value) {
|
||||
setValue(value);
|
||||
return (*this);
|
||||
}
|
||||
|
||||
/// @brief Conversion operator to value type.
|
||||
///
|
||||
/// @return Reference to value represented by this object.
|
||||
operator const ValueType&() const {
|
||||
return (getValue());
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
/// @brief Pointer to staging value.
|
||||
///
|
||||
/// This value holds any modifications made.
|
||||
boost::shared_ptr<ValueType> staging_;
|
||||
|
||||
/// @brief Pointer to committed value.
|
||||
///
|
||||
/// This value holds last committed changes.
|
||||
boost::shared_ptr<ValueType> current_;
|
||||
|
||||
/// @brief Boolean flag which indicates if any modifications have been
|
||||
/// applied since last commit.
|
||||
bool modified_;
|
||||
|
||||
};
|
||||
|
||||
} // namespace isc::util
|
||||
} // namespace isc
|
||||
|
||||
#endif // STAGED_VALUE_H
|
@@ -45,6 +45,7 @@ run_unittests_SOURCES += process_spawn_unittest.cc
|
||||
run_unittests_SOURCES += qid_gen_unittest.cc
|
||||
run_unittests_SOURCES += random_number_generator_unittest.cc
|
||||
run_unittests_SOURCES += socketsession_unittest.cc
|
||||
run_unittests_SOURCES += staged_value_unittest.cc
|
||||
run_unittests_SOURCES += strutil_unittest.cc
|
||||
run_unittests_SOURCES += time_utilities_unittest.cc
|
||||
run_unittests_SOURCES += range_utilities_unittest.cc
|
||||
|
114
src/lib/util/tests/staged_value_unittest.cc
Normal file
114
src/lib/util/tests/staged_value_unittest.cc
Normal file
@@ -0,0 +1,114 @@
|
||||
// Copyright (C) 2015 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
|
||||
// copyright notice and this permission notice appear in all copies.
|
||||
//
|
||||
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
|
||||
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
|
||||
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
|
||||
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
|
||||
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
|
||||
// PERFORMANCE OF THIS SOFTWARE.
|
||||
|
||||
#include <config.h>
|
||||
#include <util/staged_value.h>
|
||||
#include <boost/shared_ptr.hpp>
|
||||
#include <gtest/gtest.h>
|
||||
|
||||
namespace {
|
||||
|
||||
using namespace isc::util;
|
||||
|
||||
// This test verifies that the value can be assigned and committed.
|
||||
TEST(StagedValueTest, assignAndCommit) {
|
||||
// Initally the value should be set to a default
|
||||
StagedValue<int> value;
|
||||
ASSERT_EQ(0, value.getValue());
|
||||
|
||||
// Set the new value without committing it and make sure it
|
||||
// can be retrieved.
|
||||
value.setValue(4);
|
||||
ASSERT_EQ(4, value.getValue());
|
||||
|
||||
// Commit the value and make sure it still can be retrieved.
|
||||
value.commit();
|
||||
ASSERT_EQ(4, value.getValue());
|
||||
|
||||
// Set new value and retrieve it.
|
||||
value.setValue(10);
|
||||
ASSERT_EQ(10, value.getValue());
|
||||
|
||||
// Do it again and commit it.
|
||||
value.setValue(20);
|
||||
ASSERT_EQ(20, value.getValue());
|
||||
value.commit();
|
||||
EXPECT_EQ(20, value.getValue());
|
||||
}
|
||||
|
||||
// This test verifies that the value can be reverted if it hasn't been
|
||||
// committed.
|
||||
TEST(StagedValueTest, revert) {
|
||||
// Set the value and commit.
|
||||
StagedValue<int> value;
|
||||
value.setValue(123);
|
||||
value.commit();
|
||||
|
||||
// Set new value and do not commit.
|
||||
value.setValue(500);
|
||||
// The new value should be the one returned.
|
||||
ASSERT_EQ(500, value.getValue());
|
||||
// But, reverting gets us back to original value.
|
||||
value.revert();
|
||||
EXPECT_EQ(123, value.getValue());
|
||||
// Reverting again doesn't have any effect.
|
||||
value.revert();
|
||||
EXPECT_EQ(123, value.getValue());
|
||||
}
|
||||
|
||||
// This test verifies that the value can be restored to an original one.
|
||||
TEST(StagedValueTest, reset) {
|
||||
// Set the new value and commit.
|
||||
StagedValue<int> value;
|
||||
value.setValue(123);
|
||||
value.commit();
|
||||
|
||||
// Override the value but do not commit.
|
||||
value.setValue(500);
|
||||
|
||||
// Resetting should take us back to default value.
|
||||
value.reset();
|
||||
EXPECT_EQ(0, value.getValue());
|
||||
value.revert();
|
||||
EXPECT_EQ(0, value.getValue());
|
||||
}
|
||||
|
||||
// This test verifies that second commit doesn't modify a value.
|
||||
TEST(StagedValueTest, commit) {
|
||||
// Set the value and commit.
|
||||
StagedValue<int> value;
|
||||
value.setValue(123);
|
||||
value.commit();
|
||||
|
||||
// Second commit should have no effect.
|
||||
value.commit();
|
||||
EXPECT_EQ(123, value.getValue());
|
||||
}
|
||||
|
||||
// This test checks that type conversion operator works correctly.
|
||||
TEST(StagedValueTest, conversionOperator) {
|
||||
StagedValue<int> value;
|
||||
value.setValue(244);
|
||||
EXPECT_EQ(244, value);
|
||||
}
|
||||
|
||||
// This test checks that the assignment operator works correctly.
|
||||
TEST(StagedValueTest, assignmentOperator) {
|
||||
StagedValue<int> value;
|
||||
value = 111;
|
||||
EXPECT_EQ(111, value);
|
||||
}
|
||||
|
||||
|
||||
} // end of anonymous namespace
|
Reference in New Issue
Block a user