"(" << value->getPosition() << ").");
}
if (check > std::numeric_limits<uint32_t>::max()) {
- isc_throw(BadValue, "Value " << value->str() << "is too large"
- << " for unsigned 32-bit integer "
+ isc_throw(BadValue, "Value " << value->str() << " is too large"
+ " for unsigned 32-bit integer "
"(" << value->getPosition() << ").");
}
if (check < 0) {
- isc_throw(BadValue, "Value " << value->str() << "is negative."
+ isc_throw(BadValue, "Value " << value->str() << " is negative."
<< " Only 0 or larger are allowed for unsigned 32-bit integer "
"(" << value->getPosition() << ").");
}
}
// Try to create the option instance.
- createOption();
+ createOption(option_data_entries);
}
void
}
void
-OptionDataParser::createOption() {
+OptionDataParser::createOption(ConstElementPtr option_data) {
+ // Check if mandatory parameters are specified.
+ uint32_t code;
+ std::string name;
+ std::string data;
+ try {
+ code = uint32_values_->getParam("code");
+ name = string_values_->getParam("name");
+ data = string_values_->getParam("data");
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError,
+ ex.what() << "(" << option_data->getPosition() << ")");
+ }
+ // Check parameters having default values.
+ std::string space = string_values_->getOptionalParam("space",
+ global_context_->universe_ == Option::V4 ? "dhcp4" : "dhcp6");
+ bool csv_format = boolean_values_->getOptionalParam("csv-format", false);
+
// Option code is held in the uint32_t storage but is supposed to
// be uint16_t value. We need to check that value in the configuration
// does not exceed range of uint8_t for DHCPv4, uint16_t for DHCPv6 and
// is not zero.
- uint32_t option_code = uint32_values_->getParam("code");
- if (option_code == 0) {
+ if (code == 0) {
isc_throw(DhcpConfigError, "option code must not be zero "
"(" << uint32_values_->getPosition("code") << ")");
} else if (global_context_->universe_ == Option::V4 &&
- option_code > std::numeric_limits<uint8_t>::max()) {
- isc_throw(DhcpConfigError, "invalid option code '" << option_code
+ code > std::numeric_limits<uint8_t>::max()) {
+ isc_throw(DhcpConfigError, "invalid option code '" << code
<< "', it must not exceed '"
<< static_cast<int>(std::numeric_limits<uint8_t>::max())
<< "' (" << uint32_values_->getPosition("code") << ")");
} else if (global_context_->universe_ == Option::V6 &&
- option_code > std::numeric_limits<uint16_t>::max()) {
- isc_throw(DhcpConfigError, "invalid option code '" << option_code
+ code > std::numeric_limits<uint16_t>::max()) {
+ isc_throw(DhcpConfigError, "invalid option code '" << code
<< "', it must not exceed '"
<< std::numeric_limits<uint16_t>::max()
<< "' (" << uint32_values_->getPosition("code") << ")");
}
- // Check that the option name has been specified, is non-empty and does not
- // contain spaces
- std::string option_name = string_values_->getParam("name");
- if (option_name.empty()) {
+ // Check that the option name is non-empty and does not contain spaces
+ if (name.empty()) {
isc_throw(DhcpConfigError, "name of the option with code '"
- << option_code << "' is empty ("
+ << code << "' is empty ("
<< string_values_->getPosition("name") << ")");
- } else if (option_name.find(" ") != std::string::npos) {
- isc_throw(DhcpConfigError, "invalid option name '" << option_name
+ } else if (name.find(" ") != std::string::npos) {
+ isc_throw(DhcpConfigError, "invalid option name '" << name
<< "', space character is not allowed ("
<< string_values_->getPosition("name") << ")");
}
- std::string option_space = string_values_->getParam("space");
- if (!OptionSpace::validateName(option_space)) {
+ if (!OptionSpace::validateName(space)) {
isc_throw(DhcpConfigError, "invalid option space name '"
- << option_space << "' specified for option '"
- << option_name << "', code '" << option_code
+ << space << "' specified for option '"
+ << name << "', code '" << code
<< "' (" << string_values_->getPosition("space") << ")");
}
- const bool csv_format = boolean_values_->getParam("csv-format");
-
// Find the Option Definition for the option by its option code.
// findOptionDefinition will throw if not found, no need to test.
// Find the definition for the option by its code. This function
// configuration.
OptionDefinitionPtr def;
try {
- def = findServerSpaceOptionDefinition(option_space, option_code);
+ def = findServerSpaceOptionDefinition(space, code);
} catch (const std::exception& ex) {
isc_throw(DhcpConfigError, ex.what()
// options. They are expected to be in the global storage
// already.
OptionDefContainerPtr defs =
- global_context_->option_defs_->getItems(option_space);
+ global_context_->option_defs_->getItems(space);
// The getItems() should never return the NULL pointer. If there are
// no option definitions for the particular option space a pointer
// to an empty container should be returned.
assert(defs);
const OptionDefContainerTypeIndex& idx = defs->get<1>();
- OptionDefContainerTypeRange range = idx.equal_range(option_code);
+ OptionDefContainerTypeRange range = idx.equal_range(code);
if (std::distance(range.first, range.second) > 0) {
def = *range.first;
}
// specified as hex
if (!def && csv_format) {
isc_throw(DhcpConfigError, "definition for the option '"
- << option_space << "." << option_name
- << "' having code '" << option_code
+ << space << "." << name
+ << "' having code '" << code
<< "' does not exist ("
<< string_values_->getPosition("name") << ")");
}
}
- // Get option data from the configuration database ('data' field).
- std::string option_data = string_values_->getParam("data");
-
// Transform string of hexadecimal digits into binary format.
std::vector<uint8_t> binary;
std::vector<std::string> data_tokens;
// separated values then we need to split this string into
// individual values - each value will be used to initialize
// one data field of an option.
- data_tokens = isc::util::str::tokens(option_data, ",");
+ data_tokens = isc::util::str::tokens(data, ",");
} else {
// Otherwise, the option data is specified as a string of
// hexadecimal digits that we have to turn into binary format.
// The decodeHex function expects that the string contains an
// even number of digits. If we don't meet this requirement,
// we have to insert a leading 0.
- if (!option_data.empty() && option_data.length() % 2) {
- option_data = option_data.insert(0, "0");
+ if (!data.empty() && data.length() % 2) {
+ data = data.insert(0, "0");
}
- util::encode::decodeHex(option_data, binary);
+ util::encode::decodeHex(data, binary);
} catch (...) {
isc_throw(DhcpConfigError, "option data is not a valid"
- << " string of hexadecimal digits: " << option_data
+ << " string of hexadecimal digits: " << data
<< " (" << string_values_->getPosition("data") << ")");
}
}
if (csv_format) {
isc_throw(DhcpConfigError, "the CSV option data format can be"
" used to specify values for an option that has a"
- " definition. The option with code " << option_code
+ " definition. The option with code " << code
<< " does not have a definition ("
<< boolean_values_->getPosition("csv-format") << ")");
}
// definition does not exist for a particular option code. For now it is
// ok to create generic option if definition does not exist.
OptionPtr option(new Option(global_context_->universe_,
- static_cast<uint16_t>(option_code), binary));
+ static_cast<uint16_t>(code), binary));
// The created option is stored in option_descriptor_ class member
// until the commit stage when it is inserted into the main storage.
// If an option with the same code exists in main storage already the
// to reference options and definitions using their names
// and/or option codes so keeping the option name in the
// definition of option value makes sense.
- if (def->getName() != option_name) {
+ if (def->getName() != name) {
isc_throw(DhcpConfigError, "specified option name '"
- << option_name << "' does not match the "
- << "option definition: '" << option_space
+ << name << "' does not match the "
+ << "option definition: '" << space
<< "." << def->getName() << "' ("
<< string_values_->getPosition("name") << ")");
}
try {
OptionPtr option = csv_format ?
def->optionFactory(global_context_->universe_,
- option_code, data_tokens) :
+ code, data_tokens) :
def->optionFactory(global_context_->universe_,
- option_code, binary);
+ code, binary);
Subnet::OptionDescriptor desc(option, false);
option_descriptor_.option = option;
option_descriptor_.persistent = false;
} catch (const isc::Exception& ex) {
isc_throw(DhcpConfigError, "option data does not match"
- << " option definition (space: " << option_space
- << ", code: " << option_code << "): "
+ << " option definition (space: " << space
+ << ", code: " << code << "): "
<< ex.what() << " ("
<< string_values_->getPosition("data") << ")");
}
}
// All went good, so we can set the option space name.
- option_space_ = option_space;
+ option_space_ = space;
}
// **************************** OptionDataListParser *************************
// ******************************** OptionDefParser ****************************
OptionDefParser::OptionDefParser(const std::string&,
- OptionDefStoragePtr storage)
- : storage_(storage), boolean_values_(new BooleanStorage()),
- string_values_(new StringStorage()), uint32_values_(new Uint32Storage()) {
+ OptionDefStoragePtr storage,
+ ParserContextPtr global_context)
+ : storage_(storage),
+ boolean_values_(new BooleanStorage()),
+ string_values_(new StringStorage()),
+ uint32_values_(new Uint32Storage()),
+ global_context_(global_context) {
if (!storage_) {
isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
<< "options storage may not be NULL");
void
OptionDefParser::build(ConstElementPtr option_def) {
// Parse the elements that make up the option definition.
- BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
+ BOOST_FOREACH(ConfigPair param, option_def->mapValue()) {
std::string entry(param.first);
ParserPtr parser;
if (entry == "name" || entry == "type" || entry == "record-types"
parser->build(param.second);
parser->commit();
}
-
- // Create an instance of option definition. It may throw an exception,
- // which we have to handle here by appending a position of the element.
- try {
- createOptionDef();
- } catch (isc::dhcp::MalformedOptionDefinition& ex) {
- // Have to catch an exception to append the position of the option
- // definition to the error string.
- isc_throw(DhcpConfigError,
- ex.what() << " (" << option_def->getPosition() << ")");
- }
+ // Create an instance of option definition.
+ createOptionDef(option_def);
// Get all items we collected so far for the particular option space.
OptionDefContainerPtr defs = storage_->getItems(option_space_name_);
}
void
-OptionDefParser::createOptionDef() {
- // Get the option space name and validate it.
- std::string space = string_values_->getParam("space");
+OptionDefParser::createOptionDef(ConstElementPtr option_def_element) {
+ // Check if mandatory parameters have been specified.
+ std::string name = string_values_->getParam("name");
+ uint32_t code = uint32_values_->getParam("code");
+ std::string type = string_values_->getParam("type");
+ try {
+ name = string_values_->getParam("name");
+ code = uint32_values_->getParam("code");
+ type = string_values_->getParam("type");
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, ex.what() << " ("
+ << option_def_element->getPosition() << ")");
+ }
+
+ bool array_type = boolean_values_->getOptionalParam("array", false);
+ std::string record_types =
+ string_values_->getOptionalParam("record-types", "");
+ std::string space = string_values_->getOptionalParam("space",
+ global_context_->universe_ == Option::V4 ? "dhcp4" : "dhcp6");
+ std::string encapsulates =
+ string_values_->getOptionalParam("encapsulate", "");
+
if (!OptionSpace::validateName(space)) {
isc_throw(DhcpConfigError, "invalid option space name '"
<< space << "' ("
<< string_values_->getPosition("space") << ")");
}
- // Get other parameters that are needed to create the
- // option definition.
- std::string name = string_values_->getParam("name");
- uint32_t code = uint32_values_->getParam("code");
- std::string type = string_values_->getParam("type");
- bool array_type = boolean_values_->getParam("array");
- std::string encapsulates = string_values_->getParam("encapsulate");
-
// Create option definition.
OptionDefinitionPtr def;
// We need to check if user has set encapsulated option space
isc_throw(DhcpConfigError, "option '" << space << "."
<< "name" << "', comprising an array of data"
<< " fields may not encapsulate any option space ("
- << string_values_->getPosition("encapsulate") << ")");
+ << option_def_element->getPosition() << ")");
} else if (encapsulates == space) {
isc_throw(DhcpConfigError, "option must not encapsulate"
<< " an option space it belongs to: '"
<< space << "." << name << "' is set to"
<< " encapsulate '" << space << "' ("
- << string_values_->getPosition("encapsulate") << ")");
+ << option_def_element->getPosition() << ")");
} else {
def.reset(new OptionDefinition(name, code, type,
}
- // The record-types field may carry a list of comma separated names
- // of data types that form a record.
- std::string record_types = string_values_->getParam("record-types");
-
// Split the list of record types into tokens.
std::vector<std::string> record_tokens =
isc::util::str::tokens(record_types, ",");
}
}
- // Check the option definition parameters are valid. If this fails, the
- // isc::dhcp::MalformedOptionDefinition exception will be thrown. We let
- // this exception to be thrown here so as the calling method can distiguish
- // between the errors which have been already handled here (position has
- // been appended) and those that have to be handled on the upper level.
- def->validate();
+ // Validate the definition.
+ try {
+ def->validate();
+ } catch (const std::exception& ex) {
+ isc_throw(DhcpConfigError, ex.what()
+ << " (" << option_def_element->getPosition() << ")");
+ }
// Option definition has been created successfully.
option_space_name_ = space;
}
// ******************************** OptionDefListParser ************************
-OptionDefListParser::OptionDefListParser(const std::string&,
- OptionDefStoragePtr storage) :storage_(storage) {
+OptionDefListParser::
+OptionDefListParser(const std::string&, OptionDefStoragePtr storage,
+ ParserContextPtr global_context)
+ : storage_(storage),
+ global_context_(global_context) {
if (!storage_) {
isc_throw(isc::dhcp::DhcpConfigError, "parser logic error:"
<< "storage may not be NULL");
BOOST_FOREACH(ConstElementPtr option_def, option_def_list->listValue()) {
boost::shared_ptr<OptionDefParser>
- parser(new OptionDefParser("single-option-def", storage_));
+ parser(new OptionDefParser("single-option-def", storage_,
+ global_context_));
parser->build(option_def);
parser->commit();
}