Bug Summary

File:usr/include/boost/algorithm/string/detail/classification.hpp
Warning:line 141, column 17
Potential memory leak

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-redhat-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name option_definition.cc -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fcoverage-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/src/lib/dhcp -resource-dir /usr/lib64/clang/16 -D HAVE_CONFIG_H -I . -I ../../.. -I ../../../src/lib -I ../../../src/lib -D OS_LINUX -I ../../.. -I ../../.. -D PIC -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/x86_64-redhat-linux -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../include/c++/13/backward -internal-isystem /usr/lib64/clang/16/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-redhat-linux/13/../../../../x86_64-redhat-linux/include -internal-externc-isystem /include -internal-externc-isystem /usr/include -O0 -Wwrite-strings -Wno-sign-compare -Wno-missing-field-initializers -std=c++20 -fdeprecated-macro -fdebug-compilation-dir=/home/fedora/workspace/kea-dev/clang-static-analyzer/src/lib/dhcp -ferror-limit 19 -stack-protector 2 -fgnuc-version=4.2.1 -fno-implicit-modules -fcxx-exceptions -fexceptions -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /home/fedora/workspace/kea-dev/clang-static-analyzer/report/2024-05-17-164749-18469-1 -x c++ option_definition.cc

option_definition.cc

1// Copyright (C) 2012-2024 Internet Systems Consortium, Inc. ("ISC")
2//
3// This Source Code Form is subject to the terms of the Mozilla Public
4// License, v. 2.0. If a copy of the MPL was not distributed with this
5// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6
7#include <config.h>
8
9#include <dhcp/dhcp4.h>
10#include <dhcp/dhcp6.h>
11#include <dhcp/option4_addrlst.h>
12#include <dhcp/option4_client_fqdn.h>
13#include <dhcp/option4_dnr.h>
14#include <dhcp/option6_addrlst.h>
15#include <dhcp/option6_client_fqdn.h>
16#include <dhcp/option6_dnr.h>
17#include <dhcp/option6_ia.h>
18#include <dhcp/option6_iaaddr.h>
19#include <dhcp/option6_iaprefix.h>
20#include <dhcp/option6_pdexclude.h>
21#include <dhcp/option6_status_code.h>
22#include <dhcp/option_custom.h>
23#include <dhcp/option_definition.h>
24#include <dhcp/option_int.h>
25#include <dhcp/option_int_array.h>
26#include <dhcp/option_opaque_data_tuples.h>
27#include <dhcp/option_classless_static_route.h>
28#include <dhcp/option_string.h>
29#include <dhcp/option_vendor.h>
30#include <dhcp/option_vendor_class.h>
31#include <util/encode/encode.h>
32#include <dns/labelsequence.h>
33#include <dns/name.h>
34#include <util/str.h>
35#include <boost/algorithm/string/classification.hpp>
36#include <boost/algorithm/string/predicate.hpp>
37#include <boost/algorithm/string/replace.hpp>
38#include <boost/dynamic_bitset.hpp>
39#include <boost/make_shared.hpp>
40#include <sstream>
41
42using namespace std;
43using namespace isc::util;
44
45namespace isc {
46namespace dhcp {
47
48OptionDefinition::OptionDefinition(const std::string& name,
49 const uint16_t code,
50 const std::string& space,
51 const std::string& type,
52 const bool array_type /* = false */)
53 : name_(name),
54 code_(code),
55 type_(OPT_UNKNOWN_TYPE),
56 array_type_(array_type),
57 encapsulated_space_(""),
58 record_fields_(),
59 user_context_(),
60 option_space_name_(space) {
61 // Data type is held as enum value by this class.
62 // Use the provided option type string to get the
63 // corresponding enum value.
64 type_ = OptionDataTypeUtil::getDataType(type);
65}
66
67OptionDefinition::OptionDefinition(const std::string& name,
68 const uint16_t code,
69 const std::string& space,
70 const OptionDataType type,
71 const bool array_type /* = false */)
72 : name_(name),
73 code_(code),
74 type_(type),
75 array_type_(array_type),
76 encapsulated_space_(""),
77 option_space_name_(space){
78}
79
80OptionDefinition::OptionDefinition(const std::string& name,
81 const uint16_t code,
82 const std::string& space,
83 const std::string& type,
84 const char* encapsulated_space)
85 : name_(name),
86 code_(code),
87 // Data type is held as enum value by this class.
88 // Use the provided option type string to get the
89 // corresponding enum value.
90 type_(OptionDataTypeUtil::getDataType(type)),
91 array_type_(false),
92 encapsulated_space_(encapsulated_space),
93 record_fields_(),
94 user_context_(),
95 option_space_name_(space) {
96}
97
98OptionDefinition::OptionDefinition(const std::string& name,
99 const uint16_t code,
100 const std::string& space,
101 const OptionDataType type,
102 const char* encapsulated_space)
103 : name_(name),
104 code_(code),
105 type_(type),
106 array_type_(false),
107 encapsulated_space_(encapsulated_space),
108 record_fields_(),
109 user_context_(),
110 option_space_name_(space) {
111}
112
113OptionDefinitionPtr
114OptionDefinition::create(const std::string& name,
115 const uint16_t code,
116 const std::string& space,
117 const std::string& type,
118 const bool array_type) {
119 return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
120}
121
122OptionDefinitionPtr
123OptionDefinition::create(const std::string& name,
124 const uint16_t code,
125 const std::string& space,
126 const OptionDataType type,
127 const bool array_type) {
128 return (boost::make_shared<OptionDefinition>(name, code, space, type, array_type));
129}
130
131OptionDefinitionPtr
132OptionDefinition::create(const std::string& name,
133 const uint16_t code,
134 const std::string& space,
135 const std::string& type,
136 const char* encapsulated_space) {
137 return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
138}
139
140OptionDefinitionPtr
141OptionDefinition::create(const std::string& name,
142 const uint16_t code,
143 const std::string& space,
144 const OptionDataType type,
145 const char* encapsulated_space) {
146 return (boost::make_shared<OptionDefinition>(name, code, space, type, encapsulated_space));
147}
148
149bool
150OptionDefinition::equals(const OptionDefinition& other) const {
151 return (name_ == other.name_ &&
152 code_ == other.code_ &&
153 type_ == other.type_ &&
154 array_type_ == other.array_type_ &&
155 encapsulated_space_ == other.encapsulated_space_ &&
156 record_fields_ == other.record_fields_ &&
157 option_space_name_ == other.option_space_name_);
158}
159
160void
161OptionDefinition::addRecordField(const std::string& data_type_name) {
162 OptionDataType data_type = OptionDataTypeUtil::getDataType(data_type_name);
163 addRecordField(data_type);
164}
165
166void
167OptionDefinition::addRecordField(const OptionDataType data_type) {
168 if (type_ != OPT_RECORD_TYPE) {
169 isc_throw(isc::InvalidOperation,do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '"
<< OptionDataTypeUtil::getDataTypeName(type_) <<
"' to add data fields to the record"; throw isc::InvalidOperation
("option_definition.cc", 172, oss__.str().c_str()); } while (
1)
170 "'record' option type must be used instead of '"do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '"
<< OptionDataTypeUtil::getDataTypeName(type_) <<
"' to add data fields to the record"; throw isc::InvalidOperation
("option_definition.cc", 172, oss__.str().c_str()); } while (
1)
171 << OptionDataTypeUtil::getDataTypeName(type_)do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '"
<< OptionDataTypeUtil::getDataTypeName(type_) <<
"' to add data fields to the record"; throw isc::InvalidOperation
("option_definition.cc", 172, oss__.str().c_str()); } while (
1)
172 << "' to add data fields to the record")do { std::ostringstream oss__; oss__ << "'record' option type must be used instead of '"
<< OptionDataTypeUtil::getDataTypeName(type_) <<
"' to add data fields to the record"; throw isc::InvalidOperation
("option_definition.cc", 172, oss__.str().c_str()); } while (
1)
;
173 }
174 if (data_type >= OPT_RECORD_TYPE ||
175 data_type == OPT_ANY_ADDRESS_TYPE ||
176 data_type == OPT_EMPTY_TYPE) {
177 isc_throw(isc::BadValue,do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '"
<< OptionDataTypeUtil::getDataTypeName(data_type) <<
"' to the record."; throw isc::BadValue("option_definition.cc"
, 180, oss__.str().c_str()); } while (1)
178 "attempted to add invalid data type '"do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '"
<< OptionDataTypeUtil::getDataTypeName(data_type) <<
"' to the record."; throw isc::BadValue("option_definition.cc"
, 180, oss__.str().c_str()); } while (1)
179 << OptionDataTypeUtil::getDataTypeName(data_type)do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '"
<< OptionDataTypeUtil::getDataTypeName(data_type) <<
"' to the record."; throw isc::BadValue("option_definition.cc"
, 180, oss__.str().c_str()); } while (1)
180 << "' to the record.")do { std::ostringstream oss__; oss__ << "attempted to add invalid data type '"
<< OptionDataTypeUtil::getDataTypeName(data_type) <<
"' to the record."; throw isc::BadValue("option_definition.cc"
, 180, oss__.str().c_str()); } while (1)
;
181 }
182 record_fields_.push_back(data_type);
183}
184
185OptionPtr
186OptionDefinition::optionFactory(Option::Universe u,
187 uint16_t type,
188 OptionBufferConstIter begin,
189 OptionBufferConstIter end,
190 bool convenient_notation) const {
191
192 try {
193 // Some of the options are represented by the specialized classes derived
194 // from Option class (e.g. IA_NA, IAADDR). Although, they can be also
195 // represented by the generic classes, we want the object of the specialized
196 // type to be returned. Therefore, we first check that if we are dealing
197 // with such an option. If the instance is returned we just exit at this
198 // point. If not, we will search for a generic option type to return.
199 OptionPtr option = factorySpecialFormatOption(u, begin, end, convenient_notation);
200 if (option) {
201 return (option);
202 }
203
204 switch (type_) {
205 case OPT_EMPTY_TYPE:
206 if (getEncapsulatedSpace().empty()) {
207 return (factoryEmpty(u, type));
208 } else {
209 return (OptionPtr(new OptionCustom(*this, u, begin, end)));
210 }
211
212 case OPT_BINARY_TYPE:
213 // If this is Internal type, and it wasn't handled by factorySpecialFormatOption() before,
214 // let's treat it like normal Binary type.
215 case OPT_INTERNAL_TYPE:
216 return (factoryGeneric(u, type, begin, end));
217
218 case OPT_UINT8_TYPE:
219 return (array_type_ ?
220 factoryIntegerArray<uint8_t>(u, type, begin, end) :
221 factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(),
222 begin, end));
223
224 case OPT_INT8_TYPE:
225 return (array_type_ ?
226 factoryIntegerArray<int8_t>(u, type, begin, end) :
227 factoryInteger<int8_t>(u, type, getEncapsulatedSpace(),
228 begin, end));
229
230 case OPT_UINT16_TYPE:
231 return (array_type_ ?
232 factoryIntegerArray<uint16_t>(u, type, begin, end) :
233 factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(),
234 begin, end));
235
236 case OPT_INT16_TYPE:
237 return (array_type_ ?
238 factoryIntegerArray<uint16_t>(u, type, begin, end) :
239 factoryInteger<int16_t>(u, type, getEncapsulatedSpace(),
240 begin, end));
241
242 case OPT_UINT32_TYPE:
243 return (array_type_ ?
244 factoryIntegerArray<uint32_t>(u, type, begin, end) :
245 factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(),
246 begin, end));
247
248 case OPT_INT32_TYPE:
249 return (array_type_ ?
250 factoryIntegerArray<uint32_t>(u, type, begin, end) :
251 factoryInteger<int32_t>(u, type, getEncapsulatedSpace(),
252 begin, end));
253
254 case OPT_IPV4_ADDRESS_TYPE:
255 // If definition specifies that an option is an array
256 // of IPv4 addresses we return an instance of specialized
257 // class (OptionAddrLst4). For non-array types there is no
258 // specialized class yet implemented so we drop through
259 // to return an instance of OptionCustom.
260 if (array_type_) {
261 return (factoryAddrList4(type, begin, end));
262 }
263 break;
264
265 case OPT_IPV6_ADDRESS_TYPE:
266 // Handle array type only here (see comments for
267 // OPT_IPV4_ADDRESS_TYPE case).
268 if (array_type_) {
269 return (factoryAddrList6(type, begin, end));
270 }
271 break;
272
273 case OPT_STRING_TYPE:
274 return (OptionPtr(new OptionString(u, type, begin, end)));
275
276 case OPT_TUPLE_TYPE:
277 // Handle array type only here (see comments for
278 // OPT_IPV4_ADDRESS_TYPE case).
279 if (array_type_) {
280 return (factoryOpaqueDataTuples(u, type, begin, end));
281 }
282 break;
283
284 default:
285 // Do nothing. We will return generic option a few lines down.
286 ;
287 }
288 return (OptionPtr(new OptionCustom(*this, u, begin, end)));
289 } catch (const SkipThisOptionError&) {
290 // We need to throw this one as is.
291 throw;
292 } catch (const SkipRemainingOptionsError&) {
293 // We need to throw this one as is.
294 throw;
295 } catch (const Exception& ex) {
296 isc_throw(InvalidOptionValue, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
InvalidOptionValue("option_definition.cc", 296, oss__.str().
c_str()); } while (1)
;
297 }
298}
299
300OptionPtr
301OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
302 const OptionBuffer& buf) const {
303 return (optionFactory(u, type, buf.begin(), buf.end()));
304}
305
306OptionPtr
307OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
308 const std::vector<std::string>& values) const {
309 OptionBuffer buf;
310 if (!array_type_ && type_ != OPT_RECORD_TYPE) {
311 if (values.empty()) {
312 if (type_ != OPT_EMPTY_TYPE) {
313 isc_throw(InvalidOptionValue, "no option value specified")do { std::ostringstream oss__; oss__ << "no option value specified"
; throw InvalidOptionValue("option_definition.cc", 313, oss__
.str().c_str()); } while (1)
;
314 }
315 } else if (type_ == OPT_INTERNAL_TYPE) {
316 // If an Option of type Internal is configured using csv-format=true, it means it is
317 // convenient notation option config that needs special parsing. Let's treat it like
318 // String type. optionFactory() will be called with convenient_notation flag set to
319 // true, so that the factory will have a chance to handle it in a special way.
320
321 // At this stage any escape backslash chars were lost during last call of
322 // isc::util::str::tokens() inside of
323 // OptionDataParser::createOption(ConstElementPtr option_data), so we must
324 // restore them. Some INTERNAL options may use escaped delimiters, e.g. DNR options.
325 // Values are concatenated back to comma separated format and will be written to
326 // the OptionBuffer as one String type option.
327 std::ostringstream stream;
328 bool first = true;
329 for (auto val : values) {
330 boost::algorithm::replace_all(val, ",", "\\,");
331 if (first) {
332 first = false;
333 } else {
334 stream << ",";
335 }
336
337 stream << val;
338 }
339
340 writeToBuffer(u, stream.str(), OPT_STRING_TYPE, buf);
341 } else {
342 writeToBuffer(u, util::str::trim(values[0]), type_, buf);
343 }
344 } else if (array_type_ && type_ != OPT_RECORD_TYPE) {
345 for (size_t i = 0; i < values.size(); ++i) {
346 writeToBuffer(u, util::str::trim(values[i]), type_, buf);
347 }
348 } else if (type_ == OPT_RECORD_TYPE) {
349 const RecordFieldsCollection& records = getRecordFields();
350 if (records.size() > values.size()) {
351 isc_throw(InvalidOptionValue, "number of data fields for the option"do { std::ostringstream oss__; oss__ << "number of data fields for the option"
<< " type '" << getCode() << "' is greater than number"
<< " of values provided."; throw InvalidOptionValue("option_definition.cc"
, 353, oss__.str().c_str()); } while (1)
352 << " type '" << getCode() << "' is greater than number"do { std::ostringstream oss__; oss__ << "number of data fields for the option"
<< " type '" << getCode() << "' is greater than number"
<< " of values provided."; throw InvalidOptionValue("option_definition.cc"
, 353, oss__.str().c_str()); } while (1)
353 << " of values provided.")do { std::ostringstream oss__; oss__ << "number of data fields for the option"
<< " type '" << getCode() << "' is greater than number"
<< " of values provided."; throw InvalidOptionValue("option_definition.cc"
, 353, oss__.str().c_str()); } while (1)
;
354 }
355 for (size_t i = 0; i < records.size(); ++i) {
356 writeToBuffer(u, util::str::trim(values[i]), records[i], buf);
357 }
358 if (array_type_ && (values.size() > records.size())) {
359 for (size_t i = records.size(); i < values.size(); ++i) {
360 writeToBuffer(u, util::str::trim(values[i]),
361 records.back(), buf);
362 }
363 }
364 }
365 return (optionFactory(u, type, buf.begin(), buf.end(), (type_ == OPT_INTERNAL_TYPE)));
366}
367
368void
369OptionDefinition::validate() const {
370
371 using namespace boost::algorithm;
372
373 std::ostringstream err_str;
374
375 // Allowed characters in the option name are: lower or
376 // upper case letters, digits, underscores and hyphens.
377 // Empty option spaces are not allowed.
378 if (!all(name_, boost::is_from_range('a', 'z') ||
1
Calling 'operator||<boost::algorithm::detail::pred_orF<boost::algorithm::detail::pred_orF<boost::algorithm::detail::is_from_rangeF<char>, boost::algorithm::detail::is_from_rangeF<char>>, boost::algorithm::detail::is_classifiedF>, boost::algorithm::detail::is_any_ofF<char>>'
379 boost::is_from_range('A', 'Z') ||
380 boost::is_digit() ||
381 boost::is_any_of(std::string("-_"))) ||
382 name_.empty() ||
383 // Hyphens and underscores are not allowed at the beginning
384 // and at the end of the option name.
385 all(find_head(name_, 1), boost::is_any_of(std::string("-_"))) ||
386 all(find_tail(name_, 1), boost::is_any_of(std::string("-_")))) {
387 err_str << "invalid option name '" << name_ << "'";
388
389 } else if (!OptionSpace::validateName(option_space_name_)) {
390 err_str << "invalid option space name: '"
391 << option_space_name_ << "'";
392
393 } else if (!encapsulated_space_.empty() &&
394 !OptionSpace::validateName(encapsulated_space_)) {
395 err_str << "invalid encapsulated option space name: '"
396 << encapsulated_space_ << "'";
397
398 } else if (type_ >= OPT_UNKNOWN_TYPE) {
399 // Option definition must be of a known type.
400 err_str << "option type " << type_ << " not supported.";
401
402 } else if (type_ == OPT_RECORD_TYPE) {
403 // At least two data fields should be added to the record. Otherwise
404 // non-record option definition could be used.
405 if (getRecordFields().size() < 2) {
406 err_str << "invalid number of data fields: "
407 << getRecordFields().size()
408 << " specified for the option of type 'record'. Expected at"
409 << " least 2 fields.";
410
411 } else {
412 // If the number of fields is valid we have to check if their order
413 // is valid too. We check that string or binary data fields are not
414 // laid before other fields. But we allow that they are laid at the
415 // end of an option.
416 const RecordFieldsCollection& fields = getRecordFields();
417 for (RecordFieldsConstIter it = fields.begin();
418 it != fields.end(); ++it) {
419 if (*it == OPT_STRING_TYPE &&
420 it < fields.end() - 1) {
421 err_str << "string data field can't be laid before data"
422 << " fields of other types.";
423 break;
424 }
425 if (*it == OPT_BINARY_TYPE &&
426 it < fields.end() - 1) {
427 err_str << "binary data field can't be laid before data"
428 << " fields of other types.";
429 break;
430 }
431 // Empty type is not allowed within a record.
432 if (*it == OPT_EMPTY_TYPE) {
433 err_str << "empty data type can't be stored as a field in"
434 << " an option record.";
435 break;
436 }
437 // Internal type is not allowed within a record.
438 if (*it == OPT_INTERNAL_TYPE) {
439 err_str << "internal data type can't be stored as a field in"
440 << " an option record.";
441 break;
442 }
443 }
444 // If the array flag is set the last field is an array.
445 if (err_str.str().empty() && array_type_) {
446 const OptionDataType& last_type = fields.back();
447 if (last_type == OPT_STRING_TYPE) {
448 err_str
449 << "array of strings is not a valid option definition.";
450 } else if (last_type == OPT_BINARY_TYPE) {
451 err_str << "array of binary values is not a valid option "
452 "definition.";
453 }
454 // Empty type was already checked.
455 }
456 }
457
458 } else if (array_type_) {
459 if (type_ == OPT_STRING_TYPE) {
460 // Array of strings is not allowed because there is no way
461 // to determine the size of a particular string and thus there
462 // it no way to tell when other data fields begin.
463 err_str << "array of strings is not a valid option definition.";
464 } else if (type_ == OPT_BINARY_TYPE) {
465 err_str << "array of binary values is not"
466 << " a valid option definition.";
467
468 } else if (type_ == OPT_EMPTY_TYPE) {
469 err_str << "array of empty value is not"
470 << " a valid option definition.";
471
472 } else if (type_ == OPT_INTERNAL_TYPE) {
473 err_str << "array of internal type value is not"
474 << " a valid option definition.";
475
476 }
477 }
478
479 // Non-empty error string means that we have hit the error. We throw
480 // exception and include error string.
481 if (!err_str.str().empty()) {
482 isc_throw(MalformedOptionDefinition, err_str.str())do { std::ostringstream oss__; oss__ << err_str.str(); throw
MalformedOptionDefinition("option_definition.cc", 482, oss__
.str().c_str()); } while (1)
;
483 }
484}
485
486bool
487OptionDefinition::haveCompressedFqdnListFormat() const {
488 return (haveType(OPT_FQDN_TYPE) && getArrayType());
489}
490
491bool
492OptionDefinition::convertToBool(const std::string& value_str) const {
493 // Case-insensitive check that the input is one of: "true" or "false".
494 if (boost::iequals(value_str, "true")) {
495 return (true);
496
497 } else if (boost::iequals(value_str, "false")) {
498 return (false);
499
500 }
501
502 // The input string is neither "true" nor "false", so let's check
503 // if it is not an integer wrapped in a string.
504 int result;
505 try {
506 result = boost::lexical_cast<int>(value_str);
507
508 } catch (const boost::bad_lexical_cast&) {
509 isc_throw(BadDataTypeCast, "unable to covert the value '"do { std::ostringstream oss__; oss__ << "unable to covert the value '"
<< value_str << "' to boolean data type"; throw BadDataTypeCast
("option_definition.cc", 510, oss__.str().c_str()); } while (
1)
510 << value_str << "' to boolean data type")do { std::ostringstream oss__; oss__ << "unable to covert the value '"
<< value_str << "' to boolean data type"; throw BadDataTypeCast
("option_definition.cc", 510, oss__.str().c_str()); } while (
1)
;
511 }
512 // The boolean value is encoded in DHCP option as 0 or 1. Therefore,
513 // we only allow a user to specify those values for options which
514 // have boolean fields.
515 if (result != 1 && result != 0) {
516 isc_throw(BadDataTypeCast, "unable to convert '" << value_strdo { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to boolean data type"; throw BadDataTypeCast
("option_definition.cc", 517, oss__.str().c_str()); } while (
1)
517 << "' to boolean data type")do { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to boolean data type"; throw BadDataTypeCast
("option_definition.cc", 517, oss__.str().c_str()); } while (
1)
;
518 }
519 return (static_cast<bool>(result));
520}
521
522template<typename T>
523T
524OptionDefinition::lexicalCastWithRangeCheck(const std::string& value_str)
525 const {
526 // The lexical cast should be attempted when converting to an integer
527 // value only.
528 if (!OptionDataTypeTraits<T>::integer_type) {
529 isc_throw(BadDataTypeCast,do { std::ostringstream oss__; oss__ << "must not convert '"
<< value_str << "' to non-integer data type"; throw
BadDataTypeCast("option_definition.cc", 531, oss__.str().c_str
()); } while (1)
530 "must not convert '" << value_strdo { std::ostringstream oss__; oss__ << "must not convert '"
<< value_str << "' to non-integer data type"; throw
BadDataTypeCast("option_definition.cc", 531, oss__.str().c_str
()); } while (1)
531 << "' to non-integer data type")do { std::ostringstream oss__; oss__ << "must not convert '"
<< value_str << "' to non-integer data type"; throw
BadDataTypeCast("option_definition.cc", 531, oss__.str().c_str
()); } while (1)
;
532 }
533
534 // We use the 64-bit value here because it has wider range than
535 // any other type we use here and it allows to detect out of
536 // bounds conditions e.g. negative value specified for uintX_t
537 // data type. Obviously if the value exceeds the limits of int64
538 // this function will not handle that properly.
539 int64_t result = 0;
540 try {
541 result = boost::lexical_cast<int64_t>(value_str);
542
543 } catch (const boost::bad_lexical_cast&) {
544 // boost::lexical_cast does not handle hexadecimal
545 // but stringstream does so do it the hard way.
546 std::stringstream ss;
547 ss << std::hex << value_str;
548 ss >> result;
549 if (ss.fail() || !ss.eof()) {
550 isc_throw(BadDataTypeCast, "unable to convert the value '"do { std::ostringstream oss__; oss__ << "unable to convert the value '"
<< value_str << "' to integer data type"; throw BadDataTypeCast
("option_definition.cc", 551, oss__.str().c_str()); } while (
1)
551 << value_str << "' to integer data type")do { std::ostringstream oss__; oss__ << "unable to convert the value '"
<< value_str << "' to integer data type"; throw BadDataTypeCast
("option_definition.cc", 551, oss__.str().c_str()); } while (
1)
;
552 }
553 }
554 // Perform range checks.
555 if (OptionDataTypeTraits<T>::integer_type) {
556 if (result > numeric_limits<T>::max() ||
557 result < numeric_limits<T>::min()) {
558 isc_throw(BadDataTypeCast, "unable to convert '"do { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to numeric type. This value is "
"expected to be in the range of " << +numeric_limits<
T>::min() << ".." << +numeric_limits<T>::
max(); throw BadDataTypeCast("option_definition.cc", 562, oss__
.str().c_str()); } while (1)
559 << value_str << "' to numeric type. This value is "do { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to numeric type. This value is "
"expected to be in the range of " << +numeric_limits<
T>::min() << ".." << +numeric_limits<T>::
max(); throw BadDataTypeCast("option_definition.cc", 562, oss__
.str().c_str()); } while (1)
560 "expected to be in the range of "do { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to numeric type. This value is "
"expected to be in the range of " << +numeric_limits<
T>::min() << ".." << +numeric_limits<T>::
max(); throw BadDataTypeCast("option_definition.cc", 562, oss__
.str().c_str()); } while (1)
561 << +numeric_limits<T>::min() << ".."do { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to numeric type. This value is "
"expected to be in the range of " << +numeric_limits<
T>::min() << ".." << +numeric_limits<T>::
max(); throw BadDataTypeCast("option_definition.cc", 562, oss__
.str().c_str()); } while (1)
562 << +numeric_limits<T>::max())do { std::ostringstream oss__; oss__ << "unable to convert '"
<< value_str << "' to numeric type. This value is "
"expected to be in the range of " << +numeric_limits<
T>::min() << ".." << +numeric_limits<T>::
max(); throw BadDataTypeCast("option_definition.cc", 562, oss__
.str().c_str()); } while (1)
;
563 }
564 }
565 return (static_cast<T>(result));
566}
567
568void
569OptionDefinition::writeToBuffer(Option::Universe u,
570 const std::string& value,
571 const OptionDataType type,
572 OptionBuffer& buf) const {
573 // We are going to write value given by value argument to the buffer.
574 // The actual type of the value is given by second argument. Check
575 // this argument to determine how to write this value to the buffer.
576 switch (type) {
577 case OPT_BINARY_TYPE:
578 OptionDataTypeUtil::writeBinary(value, buf);
579 return;
580 case OPT_BOOLEAN_TYPE:
581 // We encode the true value as 1 and false as 0 on 8 bits.
582 // That way we actually waste 7 bits but it seems to be the
583 // simpler way to encode boolean.
584 // @todo Consider if any other encode methods can be used.
585 OptionDataTypeUtil::writeBool(convertToBool(value), buf);
586 return;
587 case OPT_INT8_TYPE:
588 OptionDataTypeUtil::writeInt<uint8_t>
589 (lexicalCastWithRangeCheck<int8_t>(value),
590 buf);
591 return;
592 case OPT_INT16_TYPE:
593 OptionDataTypeUtil::writeInt<uint16_t>
594 (lexicalCastWithRangeCheck<int16_t>(value),
595 buf);
596 return;
597 case OPT_INT32_TYPE:
598 OptionDataTypeUtil::writeInt<uint32_t>
599 (lexicalCastWithRangeCheck<int32_t>(value),
600 buf);
601 return;
602 case OPT_UINT8_TYPE:
603 OptionDataTypeUtil::writeInt<uint8_t>
604 (lexicalCastWithRangeCheck<uint8_t>(value),
605 buf);
606 return;
607 case OPT_UINT16_TYPE:
608 OptionDataTypeUtil::writeInt<uint16_t>
609 (lexicalCastWithRangeCheck<uint16_t>(value),
610 buf);
611 return;
612 case OPT_UINT32_TYPE:
613 OptionDataTypeUtil::writeInt<uint32_t>
614 (lexicalCastWithRangeCheck<uint32_t>(value),
615 buf);
616 return;
617 case OPT_IPV4_ADDRESS_TYPE:
618 case OPT_IPV6_ADDRESS_TYPE:
619 {
620 asiolink::IOAddress address(value);
621 if (!address.isV4() && !address.isV6()) {
622 isc_throw(BadDataTypeCast, "provided address "do { std::ostringstream oss__; oss__ << "provided address "
<< address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("option_definition.cc", 624, oss__.str
().c_str()); } while (1)
623 << addressdo { std::ostringstream oss__; oss__ << "provided address "
<< address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("option_definition.cc", 624, oss__.str
().c_str()); } while (1)
624 << " is not a valid IPv4 or IPv6 address.")do { std::ostringstream oss__; oss__ << "provided address "
<< address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("option_definition.cc", 624, oss__.str
().c_str()); } while (1)
;
625 }
626 OptionDataTypeUtil::writeAddress(address, buf);
627 return;
628 }
629 case OPT_IPV6_PREFIX_TYPE:
630 {
631 std::string txt = value;
632
633 // first let's remove any whitespaces
634 boost::erase_all(txt, " "); // space
635 boost::erase_all(txt, "\t"); // tabulation
636
637 // Is this prefix/len notation?
638 size_t pos = txt.find("/");
639
640 if (pos == string::npos) {
641 isc_throw(BadDataTypeCast, "provided address/prefix "do { std::ostringstream oss__; oss__ << "provided address/prefix "
<< value << " is not valid."; throw BadDataTypeCast
("option_definition.cc", 643, oss__.str().c_str()); } while (
1)
642 << valuedo { std::ostringstream oss__; oss__ << "provided address/prefix "
<< value << " is not valid."; throw BadDataTypeCast
("option_definition.cc", 643, oss__.str().c_str()); } while (
1)
643 << " is not valid.")do { std::ostringstream oss__; oss__ << "provided address/prefix "
<< value << " is not valid."; throw BadDataTypeCast
("option_definition.cc", 643, oss__.str().c_str()); } while (
1)
;
644 }
645
646 std::string txt_address = txt.substr(0, pos);
647 isc::asiolink::IOAddress address = isc::asiolink::IOAddress(txt_address);
648 if (!address.isV6()) {
649 isc_throw(BadDataTypeCast, "provided address "do { std::ostringstream oss__; oss__ << "provided address "
<< txt_address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("option_definition.cc", 651, oss__.str
().c_str()); } while (1)
650 << txt_addressdo { std::ostringstream oss__; oss__ << "provided address "
<< txt_address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("option_definition.cc", 651, oss__.str
().c_str()); } while (1)
651 << " is not a valid IPv4 or IPv6 address.")do { std::ostringstream oss__; oss__ << "provided address "
<< txt_address << " is not a valid IPv4 or IPv6 address."
; throw BadDataTypeCast("option_definition.cc", 651, oss__.str
().c_str()); } while (1)
;
652 }
653
654 std::string txt_prefix = txt.substr(pos + 1);
655 uint8_t len = 0;
656 try {
657 // start with the first character after /
658 len = lexicalCastWithRangeCheck<uint8_t>(txt_prefix);
659 } catch (...) {
660 isc_throw(BadDataTypeCast, "provided prefix "do { std::ostringstream oss__; oss__ << "provided prefix "
<< txt_prefix << " is not valid."; throw BadDataTypeCast
("option_definition.cc", 662, oss__.str().c_str()); } while (
1)
661 << txt_prefixdo { std::ostringstream oss__; oss__ << "provided prefix "
<< txt_prefix << " is not valid."; throw BadDataTypeCast
("option_definition.cc", 662, oss__.str().c_str()); } while (
1)
662 << " is not valid.")do { std::ostringstream oss__; oss__ << "provided prefix "
<< txt_prefix << " is not valid."; throw BadDataTypeCast
("option_definition.cc", 662, oss__.str().c_str()); } while (
1)
;
663 }
664
665 // Write a prefix.
666 OptionDataTypeUtil::writePrefix(PrefixLen(len), address, buf);
667
668 return;
669 }
670 case OPT_PSID_TYPE:
671 {
672 std::string txt = value;
673
674 // first let's remove any whitespaces
675 boost::erase_all(txt, " "); // space
676 boost::erase_all(txt, "\t"); // tabulation
677
678 // Is this prefix/len notation?
679 size_t pos = txt.find("/");
680
681 if (pos == string::npos) {
682 isc_throw(BadDataTypeCast, "provided PSID value "do { std::ostringstream oss__; oss__ << "provided PSID value "
<< value << " is not valid"; throw BadDataTypeCast
("option_definition.cc", 683, oss__.str().c_str()); } while (
1)
683 << value << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID value "
<< value << " is not valid"; throw BadDataTypeCast
("option_definition.cc", 683, oss__.str().c_str()); } while (
1)
;
684 }
685
686 const std::string txt_psid = txt.substr(0, pos);
687 const std::string txt_psid_len = txt.substr(pos + 1);
688
689 uint16_t psid = 0;
690 uint8_t psid_len = 0;
691
692 try {
693 psid = lexicalCastWithRangeCheck<uint16_t>(txt_psid);
694 } catch (...) {
695 isc_throw(BadDataTypeCast, "provided PSID "do { std::ostringstream oss__; oss__ << "provided PSID "
<< txt_psid << " is not valid"; throw BadDataTypeCast
("option_definition.cc", 696, oss__.str().c_str()); } while (
1)
696 << txt_psid << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID "
<< txt_psid << " is not valid"; throw BadDataTypeCast
("option_definition.cc", 696, oss__.str().c_str()); } while (
1)
;
697 }
698
699 try {
700 psid_len = lexicalCastWithRangeCheck<uint8_t>(txt_psid_len);
701 } catch (...) {
702 isc_throw(BadDataTypeCast, "provided PSID length "do { std::ostringstream oss__; oss__ << "provided PSID length "
<< txt_psid_len << " is not valid"; throw BadDataTypeCast
("option_definition.cc", 703, oss__.str().c_str()); } while (
1)
703 << txt_psid_len << " is not valid")do { std::ostringstream oss__; oss__ << "provided PSID length "
<< txt_psid_len << " is not valid"; throw BadDataTypeCast
("option_definition.cc", 703, oss__.str().c_str()); } while (
1)
;
704 }
705
706 OptionDataTypeUtil::writePsid(PSIDLen(psid_len), PSID(psid), buf);
707 return;
708 }
709 case OPT_STRING_TYPE:
710 OptionDataTypeUtil::writeString(value, buf);
711 return;
712 case OPT_FQDN_TYPE:
713 OptionDataTypeUtil::writeFqdn(value, buf);
714 return;
715 case OPT_TUPLE_TYPE:
716 {
717 // In case of V4_SZTP_REDIRECT option #143, bootstrap-server-list is formatted
718 // as a list of tuples "uri-length;URI" where uri-length is coded on 2 octets,
719 // which is not typical for V4 Universe.
720 OpaqueDataTuple::LengthFieldType lft = getCode() == DHO_V4_SZTP_REDIRECT
721 ? OpaqueDataTuple::LENGTH_2_BYTES
722 : OptionDataTypeUtil::getTupleLenFieldType(u);
723 OptionDataTypeUtil::writeTuple(value, lft, buf);
724 return;
725 }
726 default:
727 // We hit this point because invalid option data type has been specified
728 // This may be the case because 'empty' or 'record' data type has been
729 // specified. We don't throw exception here because it will be thrown
730 // at the exit point from this function.
731 ;
732 }
733 isc_throw(isc::BadValue, "attempt to write invalid option data field type"do { std::ostringstream oss__; oss__ << "attempt to write invalid option data field type"
" into the option buffer: " << type; throw isc::BadValue
("option_definition.cc", 734, oss__.str().c_str()); } while (
1)
734 " into the option buffer: " << type)do { std::ostringstream oss__; oss__ << "attempt to write invalid option data field type"
" into the option buffer: " << type; throw isc::BadValue
("option_definition.cc", 734, oss__.str().c_str()); } while (
1)
;
735
736}
737
738OptionPtr
739OptionDefinition::factoryAddrList4(uint16_t type,
740 OptionBufferConstIter begin,
741 OptionBufferConstIter end) {
742 boost::shared_ptr<Option4AddrLst> option(new Option4AddrLst(type, begin,
743 end));
744 return (option);
745}
746
747OptionPtr
748OptionDefinition::factoryAddrList6(uint16_t type,
749 OptionBufferConstIter begin,
750 OptionBufferConstIter end) {
751 boost::shared_ptr<Option6AddrLst> option(new Option6AddrLst(type, begin,
752 end));
753 return (option);
754}
755
756
757OptionPtr
758OptionDefinition::factoryEmpty(Option::Universe u, uint16_t type) {
759 OptionPtr option(new Option(u, type));
760 return (option);
761}
762
763OptionPtr
764OptionDefinition::factoryGeneric(Option::Universe u, uint16_t type,
765 OptionBufferConstIter begin,
766 OptionBufferConstIter end) {
767 OptionPtr option(new Option(u, type, begin, end));
768 return (option);
769}
770
771OptionPtr
772OptionDefinition::factoryIA6(uint16_t type,
773 OptionBufferConstIter begin,
774 OptionBufferConstIter end) {
775 if (std::distance(begin, end) < Option6IA::OPTION6_IA_LEN) {
776 isc_throw(isc::OutOfRange, "input option buffer has invalid size,"do { std::ostringstream oss__; oss__ << "input option buffer has invalid size,"
<< " expected at least " << Option6IA::OPTION6_IA_LEN
<< " bytes"; throw isc::OutOfRange("option_definition.cc"
, 778, oss__.str().c_str()); } while (1)
777 << " expected at least " << Option6IA::OPTION6_IA_LENdo { std::ostringstream oss__; oss__ << "input option buffer has invalid size,"
<< " expected at least " << Option6IA::OPTION6_IA_LEN
<< " bytes"; throw isc::OutOfRange("option_definition.cc"
, 778, oss__.str().c_str()); } while (1)
778 << " bytes")do { std::ostringstream oss__; oss__ << "input option buffer has invalid size,"
<< " expected at least " << Option6IA::OPTION6_IA_LEN
<< " bytes"; throw isc::OutOfRange("option_definition.cc"
, 778, oss__.str().c_str()); } while (1)
;
779 }
780 boost::shared_ptr<Option6IA> option(new Option6IA(type, begin, end));
781 return (option);
782}
783
784OptionPtr
785OptionDefinition::factoryIAAddr6(uint16_t type,
786 OptionBufferConstIter begin,
787 OptionBufferConstIter end) {
788 if (std::distance(begin, end) < Option6IAAddr::OPTION6_IAADDR_LEN) {
789 isc_throw(isc::OutOfRange,do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least "
<< Option6IAAddr::OPTION6_IAADDR_LEN << " bytes"
; throw isc::OutOfRange("option_definition.cc", 791, oss__.str
().c_str()); } while (1)
790 "input option buffer has invalid size, expected at least "do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least "
<< Option6IAAddr::OPTION6_IAADDR_LEN << " bytes"
; throw isc::OutOfRange("option_definition.cc", 791, oss__.str
().c_str()); } while (1)
791 << Option6IAAddr::OPTION6_IAADDR_LEN << " bytes")do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least "
<< Option6IAAddr::OPTION6_IAADDR_LEN << " bytes"
; throw isc::OutOfRange("option_definition.cc", 791, oss__.str
().c_str()); } while (1)
;
792 }
793 boost::shared_ptr<Option6IAAddr> option(new Option6IAAddr(type, begin,
794 end));
795 return (option);
796}
797
798OptionPtr
799OptionDefinition::factoryIAPrefix6(uint16_t type,
800 OptionBufferConstIter begin,
801 OptionBufferConstIter end) {
802 if (std::distance(begin, end) < Option6IAPrefix::OPTION6_IAPREFIX_LEN) {
803 isc_throw(isc::OutOfRange,do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least "
<< Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes"
; throw isc::OutOfRange("option_definition.cc", 805, oss__.str
().c_str()); } while (1)
804 "input option buffer has invalid size, expected at least "do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least "
<< Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes"
; throw isc::OutOfRange("option_definition.cc", 805, oss__.str
().c_str()); } while (1)
805 << Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes")do { std::ostringstream oss__; oss__ << "input option buffer has invalid size, expected at least "
<< Option6IAPrefix::OPTION6_IAPREFIX_LEN << " bytes"
; throw isc::OutOfRange("option_definition.cc", 805, oss__.str
().c_str()); } while (1)
;
806 }
807 boost::shared_ptr<Option6IAPrefix> option(new Option6IAPrefix(type, begin,
808 end));
809 return (option);
810}
811
812OptionPtr
813OptionDefinition::factoryOpaqueDataTuples(Option::Universe u,
814 uint16_t type,
815 OptionBufferConstIter begin,
816 OptionBufferConstIter end) {
817 boost::shared_ptr<OptionOpaqueDataTuples>
818 option(new OptionOpaqueDataTuples(u, type, begin, end));
819
820 return (option);
821}
822
823OptionPtr
824OptionDefinition::factoryOpaqueDataTuples(Option::Universe u,
825 uint16_t type,
826 OptionBufferConstIter begin,
827 OptionBufferConstIter end,
828 OpaqueDataTuple::LengthFieldType length_field_type) {
829 boost::shared_ptr<OptionOpaqueDataTuples>
830 option(new OptionOpaqueDataTuples(u, type, begin, end, length_field_type));
831
832 return (option);
833}
834
835OptionPtr
836OptionDefinition::factoryFqdnList(Option::Universe u,
837 OptionBufferConstIter begin,
838 OptionBufferConstIter end) const {
839
840 const std::vector<uint8_t> data(begin, end);
841 if (data.empty()) {
842 isc_throw(InvalidOptionValue, "FQDN list option has invalid length of 0")do { std::ostringstream oss__; oss__ << "FQDN list option has invalid length of 0"
; throw InvalidOptionValue("option_definition.cc", 842, oss__
.str().c_str()); } while (1)
;
843 }
844 InputBuffer in_buf(static_cast<const void*>(&data[0]), data.size());
845 std::vector<uint8_t> out_buf;
846 out_buf.reserve(data.size());
847 while (in_buf.getPosition() < in_buf.getLength()) {
848 // Reuse readFqdn and writeFqdn code but on the whole buffer
849 // so the DNS name code handles compression for us.
850 try {
851 isc::dns::Name name(in_buf);
852 isc::dns::LabelSequence labels(name);
853 if (labels.getDataLength() > 0) {
854 size_t read_len = 0;
855 const uint8_t* label = labels.getData(&read_len);
856 out_buf.insert(out_buf.end(), label, label + read_len);
857 }
858 } catch (const isc::Exception& ex) {
859 isc_throw(InvalidOptionValue, ex.what())do { std::ostringstream oss__; oss__ << ex.what(); throw
InvalidOptionValue("option_definition.cc", 859, oss__.str().
c_str()); } while (1)
;
860 }
861 }
862 return OptionPtr(new OptionCustom(*this, u,
863 out_buf.begin(), out_buf.end()));
864}
865
866OptionPtr
867OptionDefinition::factorySpecialFormatOption(Option::Universe u,
868 OptionBufferConstIter begin,
869 OptionBufferConstIter end,
870 bool convenient_notation) const {
871 if ((u == Option::V6) && haveSpace(DHCP6_OPTION_SPACE"dhcp6")) {
872 switch (getCode()) {
873 case D6O_IA_NA:
874 case D6O_IA_PD:
875 // Record of 3 uint32, no array.
876 return (factoryIA6(getCode(), begin, end));
877
878 case D6O_IAADDR:
879 // Record of an IPv6 address followed by 2 uint32, no array.
880 return (factoryIAAddr6(getCode(), begin, end));
881
882 case D6O_IAPREFIX:
883 // Record of 2 uint32, one uint8 and an IPv6 address, no array.
884 return (factoryIAPrefix6(getCode(), begin, end));
885
886 case D6O_CLIENT_FQDN:
887 // Record of one uint8 and one FQDN, no array.
888 return (OptionPtr(new Option6ClientFqdn(begin, end)));
889
890 case D6O_VENDOR_OPTS:
891 // Type uint32.
892 // Vendor-Specific Information (option code 17).
893 return (OptionPtr(new OptionVendor(Option::V6, begin, end)));
894
895 case D6O_VENDOR_CLASS:
896 // Record of one uint32 and one string.
897 // Vendor Class (option code 16).
898 return (OptionPtr(new OptionVendorClass(Option::V6, begin, end)));
899
900 case D6O_STATUS_CODE:
901 // Record of one uint16 and one string.
902 // Status Code (option code 13).
903 return (OptionPtr(new Option6StatusCode(begin, end)));
904
905 case D6O_BOOTFILE_PARAM:
906 // Array of tuples.
907 // Bootfile params (option code 60).
908 return (factoryOpaqueDataTuples(Option::V6, getCode(), begin, end));
909
910 case D6O_PD_EXCLUDE:
911 // Type IPv6 prefix.
912 // Prefix Exclude (option code 67),
913 return (OptionPtr(new Option6PDExclude(begin, end)));
914
915 case D6O_V6_DNR:
916 return (OptionPtr(new Option6Dnr(begin, end, convenient_notation)));
917
918 default:
919 break;
920 }
921 } else if ((u == Option::V4) && haveSpace(DHCP4_OPTION_SPACE"dhcp4")) {
922 switch (getCode()) {
923 case DHO_SERVICE_SCOPE:
924 // Record of a boolean and a string.
925 return (OptionPtr(new Option4SlpServiceScope(begin, end)));
926
927 case DHO_FQDN:
928 // Record of 3 uint8 and a FQDN, no array.
929 return (OptionPtr(new Option4ClientFqdn(begin, end)));
930
931 case DHO_CLASSLESS_STATIC_ROUTE:
932 return (OptionPtr(new OptionClasslessStaticRoute(begin, end, convenient_notation)));
933
934 case DHO_VIVCO_SUBOPTIONS:
935 // Record of uint32 followed by binary.
936 // V-I Vendor Class (option code 124).
937 return (OptionPtr(new OptionVendorClass(Option::V4, begin, end)));
938
939 case DHO_VIVSO_SUBOPTIONS:
940 // Type uint32.
941 // Vendor-Specific Information (option code 125).
942 return (OptionPtr(new OptionVendor(Option::V4, begin, end)));
943
944 case DHO_V4_SZTP_REDIRECT:
945 // Array of tuples.
946 // DHCPv4 SZTP Redirect Option (option code 143).
947 return (factoryOpaqueDataTuples(Option::V4, getCode(), begin, end, OpaqueDataTuple::LENGTH_2_BYTES));
948
949 case DHO_V4_DNR:
950 return (OptionPtr(new Option4Dnr(begin, end, convenient_notation)));
951
952 default:
953 break;
954 }
955 }
956 if ((u == Option::V4) && haveCompressedFqdnListFormat()) {
957 return (factoryFqdnList(Option::V4, begin, end));
958 }
959 return (OptionPtr());
960}
961
962} // end of isc::dhcp namespace
963} // end of isc namespace

/usr/include/boost/algorithm/string/classification.hpp

1// Boost string_algo library classification.hpp header file ---------------------------//
2
3// Copyright Pavol Droba 2002-2003.
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8
9// See http://www.boost.org/ for updates, documentation, and revision history.
10
11#ifndef BOOST_STRING_CLASSIFICATION_HPP
12#define BOOST_STRING_CLASSIFICATION_HPP
13
14#include <algorithm>
15#include <locale>
16#include <boost/range/value_type.hpp>
17#include <boost/range/as_literal.hpp>
18#include <boost/algorithm/string/detail/classification.hpp>
19#include <boost/algorithm/string/predicate_facade.hpp>
20
21
22/*! \file
23 Classification predicates are included in the library to give
24 some more convenience when using algorithms like \c trim() and \c all().
25 They wrap functionality of STL classification functions ( e.g. \c std::isspace() )
26 into generic functors.
27*/
28
29namespace boost {
30 namespace algorithm {
31
32// classification functor generator -------------------------------------//
33
34 //! is_classified predicate
35 /*!
36 Construct the \c is_classified predicate. This predicate holds if the input is
37 of specified \c std::ctype category.
38
39 \param Type A \c std::ctype category
40 \param Loc A locale used for classification
41 \return An instance of the \c is_classified predicate
42 */
43 inline detail::is_classifiedF
44 is_classified(std::ctype_base::mask Type, const std::locale& Loc=std::locale())
45 {
46 return detail::is_classifiedF(Type, Loc);
47 }
48
49 //! is_space predicate
50 /*!
51 Construct the \c is_classified predicate for the \c ctype_base::space category.
52
53 \param Loc A locale used for classification
54 \return An instance of the \c is_classified predicate
55 */
56 inline detail::is_classifiedF
57 is_space(const std::locale& Loc=std::locale())
58 {
59 return detail::is_classifiedF(std::ctype_base::space, Loc);
60 }
61
62 //! is_alnum predicate
63 /*!
64 Construct the \c is_classified predicate for the \c ctype_base::alnum category.
65
66 \param Loc A locale used for classification
67 \return An instance of the \c is_classified predicate
68 */
69 inline detail::is_classifiedF
70 is_alnum(const std::locale& Loc=std::locale())
71 {
72 return detail::is_classifiedF(std::ctype_base::alnum, Loc);
73 }
74
75 //! is_alpha predicate
76 /*!
77 Construct the \c is_classified predicate for the \c ctype_base::alpha category.
78
79 \param Loc A locale used for classification
80 \return An instance of the \c is_classified predicate
81 */
82 inline detail::is_classifiedF
83 is_alpha(const std::locale& Loc=std::locale())
84 {
85 return detail::is_classifiedF(std::ctype_base::alpha, Loc);
86 }
87
88 //! is_cntrl predicate
89 /*!
90 Construct the \c is_classified predicate for the \c ctype_base::cntrl category.
91
92 \param Loc A locale used for classification
93 \return An instance of the \c is_classified predicate
94 */
95 inline detail::is_classifiedF
96 is_cntrl(const std::locale& Loc=std::locale())
97 {
98 return detail::is_classifiedF(std::ctype_base::cntrl, Loc);
99 }
100
101 //! is_digit predicate
102 /*!
103 Construct the \c is_classified predicate for the \c ctype_base::digit category.
104
105 \param Loc A locale used for classification
106 \return An instance of the \c is_classified predicate
107 */
108 inline detail::is_classifiedF
109 is_digit(const std::locale& Loc=std::locale())
110 {
111 return detail::is_classifiedF(std::ctype_base::digit, Loc);
112 }
113
114 //! is_graph predicate
115 /*!
116 Construct the \c is_classified predicate for the \c ctype_base::graph category.
117
118 \param Loc A locale used for classification
119 \return An instance of the \c is_classified predicate
120 */
121 inline detail::is_classifiedF
122 is_graph(const std::locale& Loc=std::locale())
123 {
124 return detail::is_classifiedF(std::ctype_base::graph, Loc);
125 }
126
127 //! is_lower predicate
128 /*!
129 Construct the \c is_classified predicate for the \c ctype_base::lower category.
130
131 \param Loc A locale used for classification
132 \return An instance of \c is_classified predicate
133 */
134 inline detail::is_classifiedF
135 is_lower(const std::locale& Loc=std::locale())
136 {
137 return detail::is_classifiedF(std::ctype_base::lower, Loc);
138 }
139
140 //! is_print predicate
141 /*!
142 Construct the \c is_classified predicate for the \c ctype_base::print category.
143
144 \param Loc A locale used for classification
145 \return An instance of the \c is_classified predicate
146 */
147 inline detail::is_classifiedF
148 is_print(const std::locale& Loc=std::locale())
149 {
150 return detail::is_classifiedF(std::ctype_base::print, Loc);
151 }
152
153 //! is_punct predicate
154 /*!
155 Construct the \c is_classified predicate for the \c ctype_base::punct category.
156
157 \param Loc A locale used for classification
158 \return An instance of the \c is_classified predicate
159 */
160 inline detail::is_classifiedF
161 is_punct(const std::locale& Loc=std::locale())
162 {
163 return detail::is_classifiedF(std::ctype_base::punct, Loc);
164 }
165
166 //! is_upper predicate
167 /*!
168 Construct the \c is_classified predicate for the \c ctype_base::upper category.
169
170 \param Loc A locale used for classification
171 \return An instance of the \c is_classified predicate
172 */
173 inline detail::is_classifiedF
174 is_upper(const std::locale& Loc=std::locale())
175 {
176 return detail::is_classifiedF(std::ctype_base::upper, Loc);
177 }
178
179 //! is_xdigit predicate
180 /*!
181 Construct the \c is_classified predicate for the \c ctype_base::xdigit category.
182
183 \param Loc A locale used for classification
184 \return An instance of the \c is_classified predicate
185 */
186 inline detail::is_classifiedF
187 is_xdigit(const std::locale& Loc=std::locale())
188 {
189 return detail::is_classifiedF(std::ctype_base::xdigit, Loc);
190 }
191
192 //! is_any_of predicate
193 /*!
194 Construct the \c is_any_of predicate. The predicate holds if the input
195 is included in the specified set of characters.
196
197 \param Set A set of characters to be recognized
198 \return An instance of the \c is_any_of predicate
199 */
200 template<typename RangeT>
201 inline detail::is_any_ofF<
202 BOOST_STRING_TYPENAMEtypename range_value<RangeT>::type>
203 is_any_of( const RangeT& Set )
204 {
205 iterator_range<BOOST_STRING_TYPENAMEtypename range_const_iterator<RangeT>::type> lit_set(boost::as_literal(Set));
206 return detail::is_any_ofF<BOOST_STRING_TYPENAMEtypename range_value<RangeT>::type>(lit_set);
207 }
208
209 //! is_from_range predicate
210 /*!
211 Construct the \c is_from_range predicate. The predicate holds if the input
212 is included in the specified range. (i.e. From <= Ch <= To )
213
214 \param From The start of the range
215 \param To The end of the range
216 \return An instance of the \c is_from_range predicate
217 */
218 template<typename CharT>
219 inline detail::is_from_rangeF<CharT> is_from_range(CharT From, CharT To)
220 {
221 return detail::is_from_rangeF<CharT>(From,To);
222 }
223
224 // predicate combinators ---------------------------------------------------//
225
226 //! predicate 'and' composition predicate
227 /*!
228 Construct the \c class_and predicate. This predicate can be used
229 to logically combine two classification predicates. \c class_and holds,
230 if both predicates return true.
231
232 \param Pred1 The first predicate
233 \param Pred2 The second predicate
234 \return An instance of the \c class_and predicate
235 */
236 template<typename Pred1T, typename Pred2T>
237 inline detail::pred_andF<Pred1T, Pred2T>
238 operator&&(
239 const predicate_facade<Pred1T>& Pred1,
240 const predicate_facade<Pred2T>& Pred2 )
241 {
242 // Doing the static_cast with the pointer instead of the reference
243 // is a workaround for some compilers which have problems with
244 // static_cast's of template references, i.e. CW8. /grafik/
245 return detail::pred_andF<Pred1T,Pred2T>(
246 *static_cast<const Pred1T*>(&Pred1),
247 *static_cast<const Pred2T*>(&Pred2) );
248 }
249
250 //! predicate 'or' composition predicate
251 /*!
252 Construct the \c class_or predicate. This predicate can be used
253 to logically combine two classification predicates. \c class_or holds,
254 if one of the predicates return true.
255
256 \param Pred1 The first predicate
257 \param Pred2 The second predicate
258 \return An instance of the \c class_or predicate
259 */
260 template<typename Pred1T, typename Pred2T>
261 inline detail::pred_orF<Pred1T, Pred2T>
262 operator||(
263 const predicate_facade<Pred1T>& Pred1,
264 const predicate_facade<Pred2T>& Pred2 )
265 {
266 // Doing the static_cast with the pointer instead of the reference
267 // is a workaround for some compilers which have problems with
268 // static_cast's of template references, i.e. CW8. /grafik/
269 return detail::pred_orF<Pred1T,Pred2T>(
270 *static_cast<const Pred1T*>(&Pred1),
271 *static_cast<const Pred2T*>(&Pred2));
2
Calling copy constructor for 'is_any_ofF<char>'
5
Returning from copy constructor for 'is_any_ofF<char>'
6
Calling '~is_any_ofF'
272 }
273
274 //! predicate negation operator
275 /*!
276 Construct the \c class_not predicate. This predicate represents a negation.
277 \c class_or holds if of the predicates return false.
278
279 \param Pred The predicate to be negated
280 \return An instance of the \c class_not predicate
281 */
282 template<typename PredT>
283 inline detail::pred_notF<PredT>
284 operator!( const predicate_facade<PredT>& Pred )
285 {
286 // Doing the static_cast with the pointer instead of the reference
287 // is a workaround for some compilers which have problems with
288 // static_cast's of template references, i.e. CW8. /grafik/
289 return detail::pred_notF<PredT>(*static_cast<const PredT*>(&Pred));
290 }
291
292 } // namespace algorithm
293
294 // pull names to the boost namespace
295 using algorithm::is_classified;
296 using algorithm::is_space;
297 using algorithm::is_alnum;
298 using algorithm::is_alpha;
299 using algorithm::is_cntrl;
300 using algorithm::is_digit;
301 using algorithm::is_graph;
302 using algorithm::is_lower;
303 using algorithm::is_upper;
304 using algorithm::is_print;
305 using algorithm::is_punct;
306 using algorithm::is_xdigit;
307 using algorithm::is_any_of;
308 using algorithm::is_from_range;
309
310} // namespace boost
311
312#endif // BOOST_STRING_PREDICATE_HPP

/usr/include/boost/algorithm/string/detail/classification.hpp

1// Boost string_algo library classification.hpp header file ---------------------------//
2
3// Copyright Pavol Droba 2002-2003.
4//
5// Distributed under the Boost Software License, Version 1.0.
6// (See accompanying file LICENSE_1_0.txt or copy at
7// http://www.boost.org/LICENSE_1_0.txt)
8
9// See http://www.boost.org/ for updates, documentation, and revision history.
10
11#ifndef BOOST_STRING_CLASSIFICATION_DETAIL_HPP
12#define BOOST_STRING_CLASSIFICATION_DETAIL_HPP
13
14#include <boost/algorithm/string/config.hpp>
15#include <algorithm>
16#include <cstring>
17#include <functional>
18#include <locale>
19
20#include <boost/range/begin.hpp>
21#include <boost/range/distance.hpp>
22#include <boost/range/end.hpp>
23
24#include <boost/algorithm/string/predicate_facade.hpp>
25#include <boost/type_traits/remove_const.hpp>
26
27namespace boost {
28 namespace algorithm {
29 namespace detail {
30
31// classification functors -----------------------------------------------//
32
33 // is_classified functor
34 struct is_classifiedF :
35 public predicate_facade<is_classifiedF>
36 {
37 // Boost.ResultOf support
38 typedef bool result_type;
39
40 // Constructor from a locale
41 is_classifiedF(std::ctype_base::mask Type, std::locale const & Loc = std::locale()) :
42 m_Type(Type), m_Locale(Loc) {}
43 // Operation
44 template<typename CharT>
45 bool operator()( CharT Ch ) const
46 {
47 return std::use_facet< std::ctype<CharT> >(m_Locale).is( m_Type, Ch );
48 }
49
50 #if defined(BOOST_BORLANDC) && (BOOST_BORLANDC >= 0x560) && (BOOST_BORLANDC <= 0x582) && !defined(_USE_OLD_RW_STL)
51 template<>
52 bool operator()( char const Ch ) const
53 {
54 return std::use_facet< std::ctype<char> >(m_Locale).is( m_Type, Ch );
55 }
56 #endif
57
58 private:
59 std::ctype_base::mask m_Type;
60 std::locale m_Locale;
61 };
62
63
64 // is_any_of functor
65 /*
66 returns true if the value is from the specified set
67 */
68 template<typename CharT>
69 struct is_any_ofF :
70 public predicate_facade<is_any_ofF<CharT> >
71 {
72 private:
73 // set cannot operate on const value-type
74 typedef typename ::boost::remove_const<CharT>::type set_value_type;
75
76 public:
77 // Boost.ResultOf support
78 typedef bool result_type;
79
80 // Constructor
81 template<typename RangeT>
82 is_any_ofF( const RangeT& Range ) : m_Size(0)
83 {
84 // Prepare storage
85 m_Storage.m_dynSet=0;
86
87 std::size_t Size=::boost::distance(Range);
88 m_Size=Size;
89 set_value_type* Storage=0;
90
91 if(use_fixed_storage(m_Size))
92 {
93 // Use fixed storage
94 Storage=&m_Storage.m_fixSet[0];
95 }
96 else
97 {
98 // Use dynamic storage
99 m_Storage.m_dynSet=new set_value_type[m_Size];
100 Storage=m_Storage.m_dynSet;
101 }
102
103 // Use fixed storage
104 ::std::copy(::boost::begin(Range), ::boost::end(Range), Storage);
105 ::std::sort(Storage, Storage+m_Size);
106 }
107
108 // Copy constructor
109 is_any_ofF(const is_any_ofF& Other) : m_Size(Other.m_Size)
110 {
111 // Prepare storage
112 m_Storage.m_dynSet=0;
113 const set_value_type* SrcStorage=0;
114 set_value_type* DestStorage=0;
115
116 if(use_fixed_storage(m_Size))
3
Taking false branch
117 {
118 // Use fixed storage
119 DestStorage=&m_Storage.m_fixSet[0];
120 SrcStorage=&Other.m_Storage.m_fixSet[0];
121 }
122 else
123 {
124 // Use dynamic storage
125 m_Storage.m_dynSet=new set_value_type[m_Size];
4
Memory is allocated
126 DestStorage=m_Storage.m_dynSet;
127 SrcStorage=Other.m_Storage.m_dynSet;
128 }
129
130 // Use fixed storage
131 ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size);
132 }
133
134 // Destructor
135 ~is_any_ofF()
136 {
137 if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0)
138 {
139 delete [] m_Storage.m_dynSet;
140 }
141 }
7
Potential memory leak
142
143 // Assignment
144 is_any_ofF& operator=(const is_any_ofF& Other)
145 {
146 // Handle self assignment
147 if(this==&Other) return *this;
148
149 // Prepare storage
150 const set_value_type* SrcStorage;
151 set_value_type* DestStorage;
152
153 if(use_fixed_storage(Other.m_Size))
154 {
155 // Use fixed storage
156 DestStorage=&m_Storage.m_fixSet[0];
157 SrcStorage=&Other.m_Storage.m_fixSet[0];
158
159 // Delete old storage if was present
160 if(!use_fixed_storage(m_Size) && m_Storage.m_dynSet!=0)
161 {
162 delete [] m_Storage.m_dynSet;
163 }
164
165 // Set new size
166 m_Size=Other.m_Size;
167 }
168 else
169 {
170 // Other uses dynamic storage
171 SrcStorage=Other.m_Storage.m_dynSet;
172
173 // Check what kind of storage are we using right now
174 if(use_fixed_storage(m_Size))
175 {
176 // Using fixed storage, allocate new
177 set_value_type* pTemp=new set_value_type[Other.m_Size];
178 DestStorage=pTemp;
179 m_Storage.m_dynSet=pTemp;
180 m_Size=Other.m_Size;
181 }
182 else
183 {
184 // Using dynamic storage, check if can reuse
185 if(m_Storage.m_dynSet!=0 && m_Size>=Other.m_Size && m_Size<Other.m_Size*2)
186 {
187 // Reuse the current storage
188 DestStorage=m_Storage.m_dynSet;
189 m_Size=Other.m_Size;
190 }
191 else
192 {
193 // Allocate the new one
194 set_value_type* pTemp=new set_value_type[Other.m_Size];
195 DestStorage=pTemp;
196
197 // Delete old storage if necessary
198 if(m_Storage.m_dynSet!=0)
199 {
200 delete [] m_Storage.m_dynSet;
201 }
202 // Store the new storage
203 m_Storage.m_dynSet=pTemp;
204 // Set new size
205 m_Size=Other.m_Size;
206 }
207 }
208 }
209
210 // Copy the data
211 ::std::memcpy(DestStorage, SrcStorage, sizeof(set_value_type)*m_Size);
212
213 return *this;
214 }
215
216 // Operation
217 template<typename Char2T>
218 bool operator()( Char2T Ch ) const
219 {
220 const set_value_type* Storage=
221 (use_fixed_storage(m_Size))
222 ? &m_Storage.m_fixSet[0]
223 : m_Storage.m_dynSet;
224
225 return ::std::binary_search(Storage, Storage+m_Size, Ch);
226 }
227 private:
228 // check if the size is eligible for fixed storage
229 static bool use_fixed_storage(std::size_t size)
230 {
231 return size<=sizeof(set_value_type*)*2;
232 }
233
234
235 private:
236 // storage
237 // The actual used storage is selected on the type
238 union
239 {
240 set_value_type* m_dynSet;
241 set_value_type m_fixSet[sizeof(set_value_type*)*2];
242 }
243 m_Storage;
244
245 // storage size
246 ::std::size_t m_Size;
247 };
248
249 // is_from_range functor
250 /*
251 returns true if the value is from the specified range.
252 (i.e. x>=From && x>=To)
253 */
254 template<typename CharT>
255 struct is_from_rangeF :
256 public predicate_facade< is_from_rangeF<CharT> >
257 {
258 // Boost.ResultOf support
259 typedef bool result_type;
260
261 // Constructor
262 is_from_rangeF( CharT From, CharT To ) : m_From(From), m_To(To) {}
263
264 // Operation
265 template<typename Char2T>
266 bool operator()( Char2T Ch ) const
267 {
268 return ( m_From <= Ch ) && ( Ch <= m_To );
269 }
270
271 private:
272 CharT m_From;
273 CharT m_To;
274 };
275
276 // class_and composition predicate
277 template<typename Pred1T, typename Pred2T>
278 struct pred_andF :
279 public predicate_facade< pred_andF<Pred1T,Pred2T> >
280 {
281 public:
282
283 // Boost.ResultOf support
284 typedef bool result_type;
285
286 // Constructor
287 pred_andF( Pred1T Pred1, Pred2T Pred2 ) :
288 m_Pred1(Pred1), m_Pred2(Pred2) {}
289
290 // Operation
291 template<typename CharT>
292 bool operator()( CharT Ch ) const
293 {
294 return m_Pred1(Ch) && m_Pred2(Ch);
295 }
296
297 private:
298 Pred1T m_Pred1;
299 Pred2T m_Pred2;
300 };
301
302 // class_or composition predicate
303 template<typename Pred1T, typename Pred2T>
304 struct pred_orF :
305 public predicate_facade< pred_orF<Pred1T,Pred2T> >
306 {
307 public:
308 // Boost.ResultOf support
309 typedef bool result_type;
310
311 // Constructor
312 pred_orF( Pred1T Pred1, Pred2T Pred2 ) :
313 m_Pred1(Pred1), m_Pred2(Pred2) {}
314
315 // Operation
316 template<typename CharT>
317 bool operator()( CharT Ch ) const
318 {
319 return m_Pred1(Ch) || m_Pred2(Ch);
320 }
321
322 private:
323 Pred1T m_Pred1;
324 Pred2T m_Pred2;
325 };
326
327 // class_not composition predicate
328 template< typename PredT >
329 struct pred_notF :
330 public predicate_facade< pred_notF<PredT> >
331 {
332 public:
333 // Boost.ResultOf support
334 typedef bool result_type;
335
336 // Constructor
337 pred_notF( PredT Pred ) : m_Pred(Pred) {}
338
339 // Operation
340 template<typename CharT>
341 bool operator()( CharT Ch ) const
342 {
343 return !m_Pred(Ch);
344 }
345
346 private:
347 PredT m_Pred;
348 };
349
350 } // namespace detail
351 } // namespace algorithm
352} // namespace boost
353
354
355#endif // BOOST_STRING_CLASSIFICATION_DETAIL_HPP