32 #include <boost/algorithm/string/classification.hpp>
33 #include <boost/algorithm/string/predicate.hpp>
34 #include <boost/dynamic_bitset.hpp>
43 OptionDefinition::OptionDefinition(
const std::string& name,
45 const std::string& type,
46 const bool array_type )
50 array_type_(array_type),
51 encapsulated_space_(
""),
54 option_space_name_() {
64 const bool array_type )
68 array_type_(array_type),
69 encapsulated_space_(
"") {
74 const std::string& type,
75 const char* encapsulated_space)
83 encapsulated_space_(encapsulated_space),
86 option_space_name_() {
92 const char* encapsulated_space)
97 encapsulated_space_(encapsulated_space),
100 option_space_name_() {
105 return (name_ == other.name_ &&
106 code_ == other.code_ &&
107 type_ == other.type_ &&
108 array_type_ == other.array_type_ &&
109 encapsulated_space_ == other.encapsulated_space_ &&
110 record_fields_ == other.record_fields_ &&
111 option_space_name_ == other.option_space_name_);
124 " to add data fields to the record");
130 "attempted to add invalid data type to the record.");
132 record_fields_.push_back(data_type);
147 OptionPtr option = factorySpecialFormatOption(u, begin, end);
164 return (array_type_ ?
165 factoryIntegerArray<uint8_t>(u, type, begin, end) :
170 return (array_type_ ?
171 factoryIntegerArray<int8_t>(u, type, begin, end) :
176 return (array_type_ ?
177 factoryIntegerArray<uint16_t>(u, type, begin, end) :
182 return (array_type_ ?
183 factoryIntegerArray<uint16_t>(u, type, begin, end) :
188 return (array_type_ ?
189 factoryIntegerArray<uint32_t>(u, type, begin, end) :
194 return (array_type_ ?
195 factoryIntegerArray<uint32_t>(u, type, begin, end) :
250 const std::vector<std::string>& values)
const {
253 if (values.empty()) {
261 for (
size_t i = 0; i < values.size(); ++i) {
266 if (records.size() > values.size()) {
268 <<
" type '" <<
getCode() <<
"' is greater than number"
269 <<
" of values provided.");
271 for (
size_t i = 0; i < records.size(); ++i) {
274 if (array_type_ && (values.size() > records.size())) {
275 for (
size_t i = records.size(); i < values.size(); ++i) {
277 records.back(), buf);
287 using namespace boost::algorithm;
289 std::ostringstream err_str;
294 if (!all(
name_, boost::is_from_range(
'a',
'z') ||
295 boost::is_from_range(
'A',
'Z') ||
297 boost::is_any_of(std::string(
"-_"))) ||
301 all(find_head(
name_, 1), boost::is_any_of(std::string(
"-_"))) ||
302 all(find_tail(
name_, 1), boost::is_any_of(std::string(
"-_")))) {
303 err_str <<
"invalid option name '" <<
name_ <<
"'";
305 }
else if (!encapsulated_space_.empty() &&
307 err_str <<
"invalid encapsulated option space name: '"
308 << encapsulated_space_ <<
"'";
312 err_str <<
"option type " << type_ <<
" not supported.";
318 err_str <<
"invalid number of data fields: "
320 <<
" specified for the option of type 'record'. Expected at"
321 <<
" least 2 fields.";
330 it != fields.end(); ++it) {
332 it < fields.end() - 1) {
333 err_str <<
"string data field can't be laid before data"
334 <<
" fields of other types.";
338 it < fields.end() - 1) {
339 err_str <<
"binary data field can't be laid before data"
340 <<
" fields of other types.";
345 err_str <<
"empty data type can't be stored as a field in"
346 <<
" an option record.";
351 if (err_str.str().empty() && array_type_) {
354 err_str <<
"array of strings is not"
355 <<
"a valid option definition.";
357 err_str <<
"array of binary values is not"
358 <<
" a valid option definition.";
364 }
else if (array_type_) {
369 err_str <<
"array of strings is not a valid option definition.";
371 err_str <<
"array of binary values is not"
372 <<
" a valid option definition.";
375 err_str <<
"array of empty value is not"
376 <<
" a valid option definition.";
383 if (!err_str.str().empty()) {
389 OptionDefinition::haveIAx6Format(
OptionDataType first_type)
const {
392 record_fields_.size() == 3 &&
393 record_fields_[0] == first_type &&
418 record_fields_.size() == 4 &&
429 record_fields_.size() == 4 &&
440 (record_fields_.size() == 2) &&
458 (record_fields_.size() == 2) &&
466 (record_fields_.size() == 2) &&
474 (record_fields_.size() == 2) &&
482 (record_fields_.size() == 2) &&
498 OptionDefinition::convertToBool(
const std::string& value_str)
const {
500 if (boost::iequals(value_str,
"true")) {
503 }
else if (boost::iequals(value_str,
"false")) {
512 result = boost::lexical_cast<int>(value_str);
514 }
catch (
const boost::bad_lexical_cast&) {
515 isc_throw(BadDataTypeCast,
"unable to covert the value '"
516 << value_str <<
"' to boolean data type");
521 if (result != 1 && result != 0) {
522 isc_throw(BadDataTypeCast,
"unable to convert '" << value_str
523 <<
"' to boolean data type");
525 return (
static_cast<bool>(result));
530 OptionDefinition::lexicalCastWithRangeCheck(
const std::string& value_str)
536 "must not convert '" << value_str
537 <<
"' to non-integer data type");
547 result = boost::lexical_cast<int64_t>(value_str);
549 }
catch (
const boost::bad_lexical_cast&) {
552 std::stringstream ss;
553 ss << std::hex << value_str;
555 if (ss.fail() || !ss.eof()) {
556 isc_throw(BadDataTypeCast,
"unable to convert the value '"
557 << value_str <<
"' to integer data type");
562 if (result > numeric_limits<T>::max() ||
563 result < numeric_limits<T>::min()) {
564 isc_throw(BadDataTypeCast,
"unable to convert '"
565 << value_str <<
"' to numeric type. This value is "
566 " expected to be in the range of "
567 << numeric_limits<T>::min()
568 <<
".." << numeric_limits<T>::max());
571 return (
static_cast<T
>(result));
576 const std::string& value,
594 OptionDataTypeUtil::writeInt<uint8_t>
595 (lexicalCastWithRangeCheck<int8_t>(value),
599 OptionDataTypeUtil::writeInt<uint16_t>
600 (lexicalCastWithRangeCheck<int16_t>(value),
604 OptionDataTypeUtil::writeInt<uint32_t>
605 (lexicalCastWithRangeCheck<int32_t>(value),
609 OptionDataTypeUtil::writeInt<uint8_t>
610 (lexicalCastWithRangeCheck<uint8_t>(value),
614 OptionDataTypeUtil::writeInt<uint16_t>
615 (lexicalCastWithRangeCheck<uint16_t>(value),
619 OptionDataTypeUtil::writeInt<uint32_t>
620 (lexicalCastWithRangeCheck<uint32_t>(value),
626 asiolink::IOAddress address(value);
627 if (!address.isV4() && !address.isV6()) {
628 isc_throw(BadDataTypeCast,
"provided address "
630 <<
" is not a valid IPv4 or IPv6 address.");
637 std::string txt = value;
640 boost::erase_all(txt,
" ");
641 boost::erase_all(txt,
"\t");
644 size_t pos = txt.find(
"/");
646 if (pos == string::npos) {
647 isc_throw(BadDataTypeCast,
"provided address/prefix "
649 <<
" is not valid.");
652 std::string txt_address = txt.substr(0, pos);
654 if (!address.
isV6()) {
655 isc_throw(BadDataTypeCast,
"provided address "
657 <<
" is not a valid IPv4 or IPv6 address.");
660 std::string txt_prefix = txt.substr(pos + 1);
664 len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
666 isc_throw(BadDataTypeCast,
"provided prefix "
668 <<
" is not valid.");
678 std::string txt = value;
681 boost::erase_all(txt,
" ");
682 boost::erase_all(txt,
"\t");
685 size_t pos = txt.find(
"/");
687 if (pos == string::npos) {
688 isc_throw(BadDataTypeCast,
"provided PSID value "
689 << value <<
" is not valid");
692 const std::string txt_psid = txt.substr(0, pos);
693 const std::string txt_psid_len = txt.substr(pos + 1);
696 uint8_t psid_len = 0;
699 psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
701 isc_throw(BadDataTypeCast,
"provided PSID "
702 << txt_psid <<
" is not valid");
706 psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
708 isc_throw(BadDataTypeCast,
"provided PSID length "
709 << txt_psid_len <<
" is not valid");
736 " into the option buffer: " << type);
744 boost::shared_ptr<Option4AddrLst> option(
new Option4AddrLst(type, begin,
753 boost::shared_ptr<Option6AddrLst> option(
new Option6AddrLst(type, begin,
782 boost::shared_ptr<Option6IA> option(
new Option6IA(type, begin, end));
792 "input option buffer has invalid size, expected at least "
795 boost::shared_ptr<Option6IAAddr> option(
new Option6IAAddr(type, begin,
806 "input option buffer has invalid size, expected at least "
809 boost::shared_ptr<Option6IAPrefix> option(
new Option6IAPrefix(type, begin,
819 boost::shared_ptr<OptionOpaqueDataTuples>
830 const std::vector<uint8_t> data(begin, end);
834 InputBuffer in_buf(
static_cast<const void*
>(&data[0]), data.size());
835 std::vector<uint8_t> out_buf;
836 out_buf.reserve(data.size());
837 while (in_buf.getPosition() < in_buf.getLength()) {
843 if (labels.getDataLength() > 0) {
845 const uint8_t* label = labels.getData(&read_len);
846 out_buf.insert(out_buf.end(), label, label + read_len);
852 return OptionPtr(
new OptionCustom(*
this, u,
853 out_buf.begin(), out_buf.end()));
883 return (
OptionPtr(
new Option6ClientFqdn(begin, end)));
892 return (
OptionPtr(
new Option6StatusCode(begin, end)));
898 return (
OptionPtr(
new Option6PDExclude(begin, end)));
902 return (
OptionPtr(
new Option4SlpServiceScope(begin, end)));
904 return (
OptionPtr(
new Option4ClientFqdn(begin, end)));
906 return (factoryFqdnList(
Option::V4, begin, end));