option_definition.h 32.2 KB
Newer Older
1
// Copyright (C) 2012-2017 Internet Systems Consortium, Inc. ("ISC")
2
//
3 4 5
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
6

7 8
#ifndef OPTION_DEFINITION_H
#define OPTION_DEFINITION_H
9

Marcin Siodelski's avatar
Marcin Siodelski committed
10
#include <dhcp/option.h>
11
#include <dhcp/option_data_types.h>
12
#include <dhcp/option_space_container.h>
13

14 15
#include <boost/multi_index/hashed_index.hpp>
#include <boost/multi_index/mem_fun.hpp>
16 17 18
#include <boost/multi_index/sequenced_index.hpp>
#include <boost/multi_index_container.hpp>
#include <boost/shared_ptr.hpp>
19
#include <map>
20
#include <string>
21 22 23 24

namespace isc {
namespace dhcp {

25 26 27 28 29 30 31 32
/// @brief Exception to be thrown when invalid option value has been
/// specified for a particular option definition.
class InvalidOptionValue : public Exception {
public:
    InvalidOptionValue(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

33 34 35 36 37 38 39
/// @brief Exception to be thrown when option definition is invalid.
class MalformedOptionDefinition : public Exception {
public:
    MalformedOptionDefinition(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

40 41 42 43 44 45 46 47
/// @brief Exception to be thrown when the particular option definition
/// duplicates existing option definition.
class DuplicateOptionDefinition : public Exception {
public:
    DuplicateOptionDefinition(const char* file, size_t line, const char* what) :
        isc::Exception(file, line, what) { };
};

48 49 50 51 52 53
/// @brief Forward declaration to OptionDefinition.
class OptionDefinition;

/// @brief Pointer to option definition object.
typedef boost::shared_ptr<OptionDefinition> OptionDefinitionPtr;

54
/// @brief Forward declaration to OptionInt.
55
///
56 57 58 59
/// This forward declaration is needed to access the OptionInt class without
/// having to include the option_int.h header file. It is required because
/// this header includes libdhcp++.h, and including option_int.h would cause
/// circular inclusion between libdhcp++.h, option_definition.h and
60 61
/// option6_int.h.
template<typename T>
62
class OptionInt;
63

64
/// @brief Forward declaration to OptionIntArray.
65
///
66 67 68 69 70
/// This forward declaration is needed to access the OptionIntArray class
/// without having to include the option_int_array.h header file. It is
/// required because this header includes libdhcp++.h, and including
/// option_int_array.h would cause circular inclusion between libdhcp++.h,
/// option_definition.h and option_int_array.h.
71
template<typename T>
72
class OptionIntArray;
73

74
/// @brief Base class representing a DHCP option definition.
75
///
76 77
/// This is a base class representing a DHCP option definition, which describes
/// the format of the option. In particular, it defines:
78 79 80 81 82
/// - option name,
/// - option code,
/// - data fields order and their types,
/// - sub options space that the particular option encapsulates.
///
83 84 85 86 87
/// The option type specifies the data type(s) which an option conveys.  If
/// this is a single value the option type points to the data type of the
/// value. For example, DHCPv6 option 8 comprises a two-byte option code, a
/// two-byte option length and two-byte field that carries a uint16 value
/// (RFC 3315 - http://ietf.org/rfc/rfc3315.txt).  In such a case, the option
88 89 90
/// type is defined as "uint16". Length and string tuples are a length
/// on one (DHCPv4) or two (DHCPv6) bytes followed by a string of
/// the given length.
91 92 93 94 95 96 97 98 99 100
///
/// When the option has a more complex structure, the option type may be
/// defined as "array", "record" or even "array of records".
///
/// Array types should be used when the option contains multiple contiguous
/// data values of the same type laid. For example, DHCPv6 option 6 includes
/// multiple fields holding uint16 codes of requested DHCPv6 options (RFC 3315).
/// Such an option can be represented with this class by setting the option
/// type to "uint16" and the array indicator (array_type) to true.  The number
/// of elements in the array is effectively unlimited (although it is actually
101
/// limited by the maximal DHCPv6 option length).
102 103 104
///
/// Should the option comprise data fields of different types, the "record"
/// option type is used. In such cases the data field types within the record
105
/// are specified using \ref OptionDefinition::addRecordField.
106
///
Andrei Pavel's avatar
Andrei Pavel committed
107
/// When the OptionDefinition object has been successfully created, it can be
108 109 110 111
/// queried to return the appropriate option factory function for the specified
/// specified option format. There are a number of "standard" factory functions
/// that cover well known (common) formats.  If the particular format does not
/// match any common format the generic factory function is returned.
112 113
///
/// The following data type strings are supported:
114
/// - "empty" (option does not contain data fields)
115 116 117 118 119 120 121
/// - "boolean"
/// - "int8"
/// - "int16"
/// - "int32"
/// - "uint8"
/// - "uint16"
/// - "uint32"
122
/// - "ipv4-address" (IPv4 Address)
123 124 125
/// - "ipv6-address" (IPv6 Address)
/// - "ipv6-prefix" (IPv6 variable length prefix)
/// - "psid" (PSID length / value)
126
/// - "string"
127
/// - "fqdn" (fully qualified name)
128
/// - "tuple" (length and string)
129
/// - "record" (set of data fields of different types)
130 131 132
///
/// @todo Extend the comment to describe "generic factories".
/// @todo Extend this class to use custom namespaces.
Marcin Siodelski's avatar
Marcin Siodelski committed
133
/// @todo Extend this class with more factory functions.
134 135 136 137
class OptionDefinition {
public:

    /// List of fields within the record.
138
    typedef std::vector<OptionDataType> RecordFieldsCollection;
139
    /// Const iterator for record data fields.
140
    typedef std::vector<OptionDataType>::const_iterator RecordFieldsConstIter;
141 142 143 144 145 146

    /// @brief Constructor.
    ///
    /// @param name option name.
    /// @param code option code.
    /// @param type option data type as string.
147
    /// @param array_type array indicator, if true it indicates that the
148
    /// option fields are the array.
149 150 151 152
    explicit OptionDefinition(const std::string& name,
                              const uint16_t code,
                              const std::string& type,
                              const bool array_type = false);
153 154 155 156 157 158

    /// @brief Constructor.
    ///
    /// @param name option name.
    /// @param code option code.
    /// @param type option data type.
159
    /// @param array_type array indicator, if true it indicates that the
160
    /// option fields are the array.
161 162 163 164 165 166 167 168 169
    explicit OptionDefinition(const std::string& name,
                              const uint16_t code,
                              const OptionDataType type,
                              const bool array_type = false);

    /// @brief Constructor.
    ///
    /// This constructor sets the name of the option space that is
    /// encapsulated by this option. The encapsulated option space
170
    /// identifies sub-options that are carried within this option.
171 172 173 174 175 176 177 178 179 180 181 182 183 184
    /// This constructor does not allow to set array indicator
    /// because options comprising an array of data fields must
    /// not be used with sub-options.
    ///
    /// @param name option name.
    /// @param code option code.
    /// @param type option data type given as string.
    /// @param encapsulated_space name of the option space being
    /// encapsulated by this option.
    explicit OptionDefinition(const std::string& name,
                              const uint16_t code,
                              const std::string& type,
                              const char* encapsulated_space);

185 186 187 188 189 190 191 192
    /// @brief Constructor.
    ///
    /// This constructor sets the name of the option space that is
    /// encapsulated by this option. The encapsulated option space
    /// identifies sub-options that are carried within this option.
    /// This constructor does not allow to set array indicator
    /// because options comprising an array of data fields must
    /// not be used with sub-options.
193
    ///
194 195 196 197 198 199 200 201 202 203
    /// @param name option name.
    /// @param code option code.
    /// @param type option data type.
    /// @param encapsulated_space name of the option space being
    /// encapsulated by this option.
    explicit OptionDefinition(const std::string& name,
                              const uint16_t code,
                              const OptionDataType type,
                              const char* encapsulated_space);

204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233

    /// @name Comparison functions and operators.
    ///
    //@{
    /// @brief Check if option definition is equal to other.
    ///
    /// @param other Option definition to compare to.
    ///
    /// @return true if two option definitions are equal, false otherwise.
    bool equals(const OptionDefinition& other) const;

    /// @brief Equality operator.
    ///
    /// @param other Option definition to compare to.
    ///
    /// @return true if two option definitions are equal, false otherwise.
    bool operator==(const OptionDefinition& other) const {
        return (equals(other));
    }

    /// @brief Inequality operator.
    ///
    /// @param other Option definition to compare to.
    ///
    /// @return true if option definitions are not equal, false otherwise.
    bool operator!=(const OptionDefinition& other) const {
        return (!equals(other));
    }
    //@}

234 235 236 237 238 239 240 241 242 243 244 245 246 247
    /// @brief Adds data field to the record.
    ///
    /// @param data_type_name name of the data type for the field.
    ///
    /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
    /// @throw isc::BadValue if specified invalid data type.
    void addRecordField(const std::string& data_type_name);

    /// @brief Adds data field to the record.
    ///
    /// @param data_type data type for the field.
    ///
    /// @throw isc::InvalidOperation if option type is not set to RECORD_TYPE.
    /// @throw isc::BadValue if specified invalid data type.
248
    void addRecordField(const OptionDataType data_type);
249 250 251

    /// @brief Return array type indicator.
    ///
252 253
    /// The method returns the bool value to indicate whether the option is a
    /// a single value or an array of values.
254 255 256 257 258 259 260 261 262
    ///
    /// @return true if option comprises an array of values.
    bool getArrayType() const { return (array_type_); }

    /// @brief Return option code.
    ///
    /// @return option code.
    uint16_t getCode() const { return (code_); }

263 264 265
    /// @brief Return name of the encapsulated option space.
    ///
    /// @return name of the encapsulated option space.
266
    std::string getEncapsulatedSpace() const {
267 268 269
        return (encapsulated_space_);
    }

270 271 272
    /// @brief Return option name.
    ///
    /// @return option name.
273
    std::string getName() const { return (name_); }
274 275 276 277

    /// @brief Return list of record fields.
    ///
    /// @return list of record fields.
278 279 280
    const RecordFieldsCollection& getRecordFields() const {
        return (record_fields_);
    }
281 282 283 284

    /// @brief Return option data type.
    ///
    /// @return option data type.
285
    OptionDataType getType() const { return (type_); };
286

Marcin Siodelski's avatar
Marcin Siodelski committed
287 288
    /// @brief Check if the option definition is valid.
    ///
289 290 291 292 293 294 295
    /// Note that it is a responsibility of the code that created
    /// the OptionDefinition object to validate that it is valid.
    /// This function will not be called internally anywhere in this
    /// class to verify that the option definition is valid. Using
    /// invalid option definition to create an instance of the
    /// DHCP option leads to undefined behavior.
    ///
296
    /// @throw MalformedOptionDefinition option definition is invalid.
Marcin Siodelski's avatar
Marcin Siodelski committed
297 298
    void validate() const;

299 300 301 302 303 304 305 306 307 308
    /// @brief Check if specified format is IA_NA option format.
    ///
    /// @return true if specified format is IA_NA option format.
    bool haveIA6Format() const;

    /// @brief Check if specified format is IAADDR option format.
    ///
    /// @return true if specified format is IAADDR option format.
    bool haveIAAddr6Format() const;

309 310 311 312 313
    /// @brief Check if specified format is IAPREFIX option format.
    ///
    /// @return true if specified format is IAPREFIX option format.
    bool haveIAPrefix6Format() const;

314 315 316 317 318 319
    /// @brief Check if specified format is OPTION_CLIENT_FQDN option format.
    ///
    /// @return true of specified format is OPTION_CLIENT_FQDN option format,
    /// false otherwise.
    bool haveClientFqdnFormat() const;

320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
    /// @brief Check if option has format of the DHCPv4 Client FQDN
    /// %Option.
    ///
    /// The encoding of the domain-name carried by the FQDN option is
    /// conditional and is specified in the flags field of the option.
    /// The domain-name can be encoded in the ASCII format or canonical
    /// wire format. The ASCII format is deprecated, therefore canonical
    /// format is selected for the FQDN option definition and this function
    /// returns true if the option definition comprises the domain-name
    /// field encoded in canonical format.
    ///
    /// @return true if option has the format of DHCPv4 Client FQDN
    /// %Option.
    bool haveFqdn4Format() const;

335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356
    /// @brief Check if the option has format of Vendor-Identifying Vendor
    /// Specific Options.
    ///
    /// @return Always true.
    /// @todo The Vendor-Identifying Vendor-Specific Option has a complex format
    /// which we do not support here. Therefore it is not really possible to
    /// check that the current definition is valid. We may need to add support
    /// for such option format or simply do not check the format for certain
    /// options, e.g. vendor options, IA_NA, IAADDR and always return objects
    /// of the certain type.
    bool haveVendor4Format() const;

    /// @brief Check if option has a format of the Vendor-Specific Information
    /// %Option.
    ///
    /// The Vendor-Specific Information %Option comprises 32-bit enterprise id
    /// and the suboptions.
    ///
    /// @return true if option definition conforms to the format of the
    /// Vendor-Specific Information %Option.
    bool haveVendor6Format() const;

357 358 359 360 361
    /// @brief Check if the option has format of DHCPv4 V-I Vendor Class option.
    ///
    /// @return true if the option has the format of DHCPv4 Vendor Class option.
    bool haveVendorClass4Format() const;

362 363 364 365 366
    /// @brief Check if the option has format of DHCPv6 Vendor Class option.
    ///
    /// @return true if option has the format of DHCPv6 Vendor Class option.
    bool haveVendorClass6Format() const;

367 368 369 370 371
    /// @brief Check if the option has format of DHCPv6 Status Code option.
    ///
    /// @return true if option has the format of DHCPv6 Status code option.
    bool haveStatusCodeFormat() const;

Shawn Routhier's avatar
Shawn Routhier committed
372 373 374 375 376
    /// @brief Check if the option has format of OpaqueDataTuples type options.
    ///
    /// @return true if option has the format of OpaqueDataTuples type options.
    bool haveOpaqueDataTuplesFormat() const;

377 378 379
    /// @brief Check if the option has format of CompressedFqdnList options.
    bool haveCompressedFqdnListFormat() const;

380 381 382 383 384 385
    /// @brief Option factory.
    ///
    /// This function creates an instance of DHCP option using
    /// provided chunk of buffer. This function may be used to
    /// create option which is to be sent in the outgoing packet.
    ///
386 387 388 389
    /// @warning calling this function on invalid option definition
    /// yields undefined behavior. Use \ref validate to test that
    /// the option definition is valid.
    ///
390
    /// @param u option universe (V4 or V6).
391 392 393 394 395
    /// @param type option type.
    /// @param begin beginning of the option buffer.
    /// @param end end of the option buffer.
    ///
    /// @return instance of the DHCP option.
396
    /// @throw InvalidOptionValue if data for the option is invalid.
397 398
    OptionPtr optionFactory(Option::Universe u, uint16_t type,
                            OptionBufferConstIter begin,
399
                            OptionBufferConstIter end) const;
400 401 402 403 404 405 406

    /// @brief Option factory.
    ///
    /// This function creates an instance of DHCP option using
    /// whole provided buffer. This function may be used to
    /// create option which is to be sent in the outgoing packet.
    ///
407 408 409 410
    /// @warning calling this function on invalid option definition
    /// yields undefined behavior. Use \ref validate to test that
    /// the option definition is valid.
    ///
411
    /// @param u option universe (V4 or V6).
412 413 414 415
    /// @param type option type.
    /// @param buf option buffer.
    ///
    /// @return instance of the DHCP option.
416
    /// @throw InvalidOptionValue if data for the option is invalid.
417
    OptionPtr optionFactory(Option::Universe u, uint16_t type,
418
                            const OptionBuffer& buf = OptionBuffer()) const;
419 420 421 422 423 424 425 426 427 428 429 430 431 432 433

    /// @brief Option factory.
    ///
    /// This function creates an instance of DHCP option using the vector
    /// of strings which carry data values for option data fields.
    /// The order of values in the vector corresponds to the order of data
    /// fields in the option. The supplied string values are cast to
    /// their actual data types which are determined based on the
    /// option definition. If cast fails due to type mismatch, an exception
    /// is thrown. This factory function can be used to create option
    /// instance when user specified option value in the <b>comma separated
    /// values</b> format in the configuration database. Provided string
    /// must be tokenized into the vector of string values and this vector
    /// can be supplied to this function.
    ///
434 435 436 437
    /// @warning calling this function on invalid option definition
    /// yields undefined behavior. Use \ref validate to test that
    /// the option definition is valid.
    ///
438
    /// @param u option universe (V4 or V6).
439 440 441 442
    /// @param type option type.
    /// @param values a vector of values to be used to set data for an option.
    ///
    /// @return instance of the DHCP option.
443
    /// @throw InvalidOptionValue if data for the option is invalid.
444 445
    OptionPtr optionFactory(Option::Universe u, uint16_t type,
                            const std::vector<std::string>& values) const;
446

447 448 449
    /// @brief Factory to create option with address list.
    ///
    /// @param type option type.
450 451 452 453
    /// @param begin iterator pointing to the beginning of the buffer
    /// with a list of IPv4 addresses.
    /// @param end iterator pointing to the end of the buffer with
    /// a list of IPv4 addresses.
Marcin Siodelski's avatar
Marcin Siodelski committed
454 455 456
    ///
    /// @throw isc::OutOfRange if length of the provided option buffer
    /// is not multiple of IPV4 address length.
457
    static OptionPtr factoryAddrList4(uint16_t type,
458 459
                                      OptionBufferConstIter begin,
                                      OptionBufferConstIter end);
460 461 462 463

    /// @brief Factory to create option with address list.
    ///
    /// @param type option type.
464 465 466 467
    /// @param begin iterator pointing to the beginning of the buffer
    /// with a list of IPv6 addresses.
    /// @param end iterator pointing to the end of the buffer with
    /// a list of IPv6 addresses.
Marcin Siodelski's avatar
Marcin Siodelski committed
468 469 470
    ///
    /// @throw isc::OutOfaRange if length of provided option buffer
    /// is not multiple of IPV6 address length.
471
    static OptionPtr factoryAddrList6(uint16_t type,
472 473
                                      OptionBufferConstIter begin,
                                      OptionBufferConstIter end);
474 475 476 477 478

    /// @brief Empty option factory.
    ///
    /// @param u universe (V6 or V4).
    /// @param type option type.
479
    static OptionPtr factoryEmpty(Option::Universe u, uint16_t type);
480

Marcin Siodelski's avatar
Marcin Siodelski committed
481
    /// @brief Factory to create generic option.
482 483 484
    ///
    /// @param u universe (V6 or V4).
    /// @param type option type.
485 486
    /// @param begin iterator pointing to the beginning of the buffer.
    /// @param end iterator pointing to the end of the buffer.
487
    static OptionPtr factoryGeneric(Option::Universe u, uint16_t type,
488 489
                                    OptionBufferConstIter begin,
                                    OptionBufferConstIter end);
490

491 492 493
    /// @brief Factory for IA-type of option.
    ///
    /// @param type option type.
494 495
    /// @param begin iterator pointing to the beginning of the buffer.
    /// @param end iterator pointing to the end of the buffer.
496 497 498
    ///
    /// @throw isc::OutOfRange if provided option buffer is too short or
    /// too long. Expected size is 12 bytes.
499
    static OptionPtr factoryIA6(uint16_t type,
500 501
                                OptionBufferConstIter begin,
                                OptionBufferConstIter end);
502 503 504 505

    /// @brief Factory for IAADDR-type of option.
    ///
    /// @param type option type.
506 507
    /// @param begin iterator pointing to the beginning of the buffer.
    /// @param end iterator pointing to the end of the buffer.
508 509 510
    ///
    /// @throw isc::OutOfRange if provided option buffer is too short or
    /// too long. Expected size is 24 bytes.
511
    static OptionPtr factoryIAAddr6(uint16_t type,
512 513
                                    OptionBufferConstIter begin,
                                    OptionBufferConstIter end);
514

515 516 517 518 519 520
    /// @brief Factory for IAPREFIX-type of option.
    ///
    /// @param type option type.
    /// @param begin iterator pointing to the beginning of the buffer.
    /// @param end iterator pointing to the end of the buffer.
    ///
Tomek Mrugalski's avatar
Tomek Mrugalski committed
521 522
    /// @throw isc::OutOfRange if provided option buffer is too short.
    /// Expected minimum size is 25 bytes.
523 524 525 526
    static OptionPtr factoryIAPrefix6(uint16_t type,
                                      OptionBufferConstIter begin,
                                      OptionBufferConstIter end);

527 528 529 530 531 532 533 534 535 536 537 538 539 540
    /// @brief Factory to create option with tuple list.
    ///
    /// @param u option universe (V4 or V6).
    /// @param begin iterator pointing to the beginning of the buffer
    /// with a list of tuples.
    /// @param end iterator pointing to the end of the buffer with
    /// a list of tuples.
    ///
    /// @return instance of the DHCP option.
    static OptionPtr factoryOpaqueDataTuples(Option::Universe u,
                                             uint16_t type,
                                             OptionBufferConstIter begin,
                                             OptionBufferConstIter end);

541 542
    /// @brief Factory function to create option with integer value.
    ///
543
    /// @param u universe (V4 or V6).
544
    /// @param type option type.
545 546 547
    /// @param encapsulated_space An option space being encapsulated by the
    /// options created by this factory function. The options which belong to
    /// encapsulated option space are sub options of this option.
548 549
    /// @param begin iterator pointing to the beginning of the buffer.
    /// @param end iterator pointing to the end of the buffer.
Marcin Siodelski's avatar
Marcin Siodelski committed
550 551 552
    /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
    ///
    /// @throw isc::OutOfRange if provided option buffer length is invalid.
553
    template<typename T>
554
    static OptionPtr factoryInteger(Option::Universe u, uint16_t type,
555
                                    const std::string& encapsulated_space,
556
                                    OptionBufferConstIter begin,
557
                                    OptionBufferConstIter end) {
558 559 560
        OptionPtr option(new OptionInt<T>(u, type, 0));
        option->setEncapsulatedSpace(encapsulated_space);
        option->unpack(begin, end);
561 562 563 564 565
        return (option);
    }

    /// @brief Factory function to create option with array of integer values.
    ///
566
    /// @param u universe (V4 or V6).
567
    /// @param type option type.
568 569
    /// @param begin iterator pointing to the beginning of the buffer.
    /// @param end iterator pointing to the end of the buffer.
Marcin Siodelski's avatar
Marcin Siodelski committed
570 571 572
    /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
    ///
    /// @throw isc::OutOfRange if provided option buffer length is invalid.
573
    template<typename T>
574 575
    static OptionPtr factoryIntegerArray(Option::Universe u,
                                         uint16_t type,
576 577
                                         OptionBufferConstIter begin,
                                         OptionBufferConstIter end) {
578
        OptionPtr option(new OptionIntArray<T>(u, type, begin, end));
579 580 581 582 583
        return (option);
    }

private:

584 585 586 587 588 589 590 591 592 593 594 595 596
    /// @brief Factory function to create option with a compressed FQDN list.
    ///
    /// @param u universe (V4 or V6).
    /// @param type option type.
    /// @param begin iterator pointing to the beginning of the buffer.
    /// @param end iterator pointing to the end of the buffer.
    ///
    /// @return instance of the DHCP option where FQDNs are uncompressed.
    /// @throw InvalidOptionValue if data for the option is invalid.
    OptionPtr factoryFqdnList(Option::Universe u,
                              OptionBufferConstIter begin,
                              OptionBufferConstIter end) const;

597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614
    /// @brief Creates an instance of an option having special format.
    ///
    /// The option with special formats are encapsulated by the dedicated
    /// classes derived from @c Option class. In particular these are:
    /// - IA_NA
    /// - IAADDR
    /// - FQDN
    /// - VIVSO.
    ///
    /// @param u A universe (V4 or V6).
    /// @param begin beginning of the option buffer.
    /// @param end end of the option buffer.
    ///
    /// @return An instance of the option having special format or NULL if
    /// such an option can't be created because an option with the given
    /// option code hasn't got the special format.
    OptionPtr factorySpecialFormatOption(Option::Universe u,
                                         OptionBufferConstIter begin,
615
                                         OptionBufferConstIter end) const;
616

617 618 619 620 621 622 623 624 625
    /// @brief Check if specified option format is a record with 3 fields
    /// where first one is custom, and two others are uint32.
    ///
    /// This is a helper function for functions that detect IA_NA and IAAddr
    /// option formats.
    ///
    /// @param first_type type of the first data field.
    ///
    /// @return true if actual option format matches expected format.
626
    bool haveIAx6Format(const OptionDataType first_type) const;
627

628 629 630
    /// @brief Check if specified type matches option definition type.
    ///
    /// @return true if specified type matches option definition type.
631
    inline bool haveType(const OptionDataType type) const {
632 633 634
        return (type == type_);
    }

635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
    /// @brief Converts a string value to a boolean value.
    ///
    /// This function converts the value represented as string to a boolean
    /// value. The following conversions are acceptable:
    /// - "true" => true
    /// - "false" => false
    /// - "1" => true
    /// - "0" => false
    /// The first two conversions are case insensitive, so as conversions from
    /// strings such as "TRUE", "trUE" etc. will be accepted. Note that the
    /// only acceptable integer values, carried as strings are: "0" and "1".
    /// For other values, e.g. "2", "3" etc. an exception will be thrown
    /// during conversion.
    ///
    /// @param value_str Input value.
    ///
    /// @return boolean representation of the string specified as the parameter.
    /// @throw isc::dhcp::BadDataTypeCast if failed to perform the conversion.
    bool convertToBool(const std::string& value_str) const;

655 656 657
    /// @brief Perform lexical cast of the value and validate its range.
    ///
    /// This function performs lexical cast of a string value to integer
658 659
    /// value and checks if the resulting value is within a range of a
    /// target type. The target type should be one of the supported
660
    /// integer types. Hexadecimal input is supported.
661 662
    ///
    /// @param value_str input value given as string.
663
    /// @tparam T target integer type for lexical cast.
664
    ///
665 666
    /// @return Integer value after conversion from the string.
    /// @throw isc::dhcp::BadDataTypeCast if conversion was not successful.
667 668 669 670 671 672 673 674 675 676 677 678 679
    template<typename T>
    T lexicalCastWithRangeCheck(const std::string& value_str) const;

    /// @brief Write the string value into the provided buffer.
    ///
    /// This method writes the given value to the specified buffer.
    /// The provided string value may represent data of different types.
    /// The actual data type is specified with the second argument.
    /// Based on a value of this argument, this function will first
    /// try to cast the string value to the particular data type and
    /// if it is successful it will store the data in the buffer
    /// in a binary format.
    ///
680
    /// @param u option universe (V4 or V6).
681 682 683 684 685
    /// @param value string representation of the value to be written.
    /// @param type the actual data type to be stored.
    /// @param [in, out] buf buffer where the value is to be stored.
    ///
    /// @throw BadDataTypeCast if data write was unsuccessful.
686 687
    void writeToBuffer(Option::Universe u, const std::string& value,
                       const OptionDataType type, OptionBuffer& buf) const;
688

689 690 691 692 693
    /// Option name.
    std::string name_;
    /// Option code.
    uint16_t code_;
    /// Option data type.
694
    OptionDataType type_;
695 696
    /// Indicates wheter option is a single value or array.
    bool array_type_;
697 698
    /// Name of the space being encapsulated by this option.
    std::string encapsulated_space_;
699 700 701 702 703
    /// Collection of data fields within the record.
    RecordFieldsCollection record_fields_;
};


704 705 706 707
/// @brief Multi index container for DHCP option definitions.
///
/// This container allows to search for DHCP option definition
/// using two indexes:
708
/// - sequenced: used to access elements in the order they have
709
/// been added to the container
710
/// - option code: used to search definitions of options
711
/// with a specified option code (aka option type).
712 713
/// Note that this container can hold multiple options with the
/// same code. For this reason, the latter index can be used to
714
/// obtain a range of options for a particular option code.
715
///
716 717 718 719 720 721 722 723 724 725 726 727 728 729 730
/// @todo: need an index to search options using option space name
/// once option spaces are implemented.
typedef boost::multi_index_container<
    // Container comprises elements of OptionDefinition type.
    OptionDefinitionPtr,
    // Here we start enumerating various indexes.
    boost::multi_index::indexed_by<
        // Sequenced index allows accessing elements in the same way
        // as elements in std::list. Sequenced is an index #0.
        boost::multi_index::sequenced<>,
        // Start definition of index #1.
        boost::multi_index::hashed_non_unique<
            // Use option type as the index key. The type is held
            // in OptionDefinition object so we have to call
            // OptionDefinition::getCode to retrieve this key
731 732 733
            // for each element. The option code is non-unique so
            // multiple elements with the same option code can
            // be returned by this index.
734 735 736 737 738
            boost::multi_index::const_mem_fun<
                OptionDefinition,
                uint16_t,
                &OptionDefinition::getCode
            >
739 740 741 742 743 744 745 746 747 748 749
        >,
        // Start definition of index #2
        boost::multi_index::hashed_non_unique<
            // Use option name as the index key. This value is
            // returned by the @c OptionDefinition::getName
            // method.
            boost::multi_index::const_mem_fun<
                OptionDefinition,
                std::string,
                &OptionDefinition::getName
            >
750 751 752 753
        >
    >
> OptionDefContainer;

754 755 756
/// Pointer to an option definition container.
typedef boost::shared_ptr<OptionDefContainer> OptionDefContainerPtr;

757 758 759
/// Container that holds option definitions for various option spaces.
typedef std::map<std::string, OptionDefContainerPtr> OptionDefContainers;

760
/// Container that holds various vendor option containers
761
typedef std::map<uint32_t, OptionDefContainerPtr> VendorOptionDefContainers;
762

763 764 765 766
/// Type of the index #1 - option type.
typedef OptionDefContainer::nth_index<1>::type OptionDefContainerTypeIndex;
/// Pair of iterators to represent the range of options definitions
///  having the same option type value. The first element in this pair
767
///  represents the beginning of the range, the second element
768 769 770 771
///  represents the end.
typedef std::pair<OptionDefContainerTypeIndex::const_iterator,
                  OptionDefContainerTypeIndex::const_iterator> OptionDefContainerTypeRange;

772 773 774 775 776 777 778 779 780
/// Type of the index #2 - option name.
typedef OptionDefContainer::nth_index<2>::type OptionDefContainerNameIndex;
/// Pair of iterators to represent the range of options definitions
/// having the same option name. The first element in this pair
/// represents the beginning of the range, the second element
/// represents the end.
typedef std::pair<OptionDefContainerNameIndex::const_iterator,
                  OptionDefContainerNameIndex::const_iterator> OptionDefContainerNameRange;

781 782 783 784
typedef OptionSpaceContainer<
    OptionDefContainer, OptionDefinitionPtr, std::string
> OptionDefSpaceContainer;

785

786 787 788
} // namespace isc::dhcp
} // namespace isc

789
#endif // OPTION_DEFINITION_H