diff options
Diffstat (limited to 'src/lib/dhcp/option_int_array.h')
-rw-r--r-- | src/lib/dhcp/option_int_array.h | 295 |
1 files changed, 295 insertions, 0 deletions
diff --git a/src/lib/dhcp/option_int_array.h b/src/lib/dhcp/option_int_array.h new file mode 100644 index 0000000..70803d7 --- /dev/null +++ b/src/lib/dhcp/option_int_array.h @@ -0,0 +1,295 @@ +// Copyright (C) 2012-2022 Internet Systems Consortium, Inc. ("ISC") +// +// 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/. + +#ifndef OPTION_INT_ARRAY_H +#define OPTION_INT_ARRAY_H + +#include <dhcp/libdhcp++.h> +#include <dhcp/option.h> +#include <dhcp/option_data_types.h> +#include <util/io_utilities.h> +#include <boost/shared_ptr.hpp> +#include <sstream> +#include <stdint.h> + +namespace isc { +namespace dhcp { + +/// Forward declaration of OptionIntArray. +template<typename T> +class OptionIntArray; + +/// @defgroup option_int_array_defs Typedefs for OptionIntArray class. +/// +/// @brief Classes that represent options comprising array of integers. +/// +/// @{ +typedef OptionIntArray<uint8_t> OptionUint8Array; +typedef boost::shared_ptr<OptionUint8Array> OptionUint8ArrayPtr; +typedef OptionIntArray<uint16_t> OptionUint16Array; +typedef boost::shared_ptr<OptionUint16Array> OptionUint16ArrayPtr; +typedef OptionIntArray<uint32_t> OptionUint32Array; +typedef boost::shared_ptr<OptionUint32Array> OptionUint32ArrayPtr; +/// @} + +/// This template class represents DHCP (v4 or v6) option with an +/// array of integer values. The type of the elements in the array +/// can be any of the following: +/// - uint8_t, +/// - uint16_t, +/// - uint32_t, +/// - int8_t, +/// - int16_t, +/// - int32_t. +/// +/// @warning Since this option may convey variable number of integer +/// values, sub-options are should not be added in this option as +/// there is no way to distinguish them from other data. The API will +/// allow addition of sub-options but they will be ignored during +/// packing and unpacking option data. +/// +/// @tparam T data field type (see above). +template<typename T> +class OptionIntArray : public Option { +private: + + /// @brief Pointer to the option type for the specified T. + typedef boost::shared_ptr<OptionIntArray<T> > OptionIntArrayTypePtr; + +public: + + /// @brief Constructor. + /// + /// Creates option with empty values vector. + /// + /// @param u universe (V4 or V6). + /// @param type option type. + /// + /// @throw isc::dhcp::InvalidDataType if data field type provided + /// as template parameter is not a supported integer type. + OptionIntArray(const Option::Universe u, const uint16_t type) + : Option(u, type), + values_(0) { + if (!OptionDataTypeTraits<T>::integer_type) { + isc_throw(dhcp::InvalidDataType, "non-integer type"); + } + } + + /// @brief Constructor. + /// + /// @param u universe (V4 or V6). + /// @param type option type. + /// @param buf buffer with option data (must not be empty). + /// + /// @throw isc::OutOfRange if provided buffer is empty or its length + /// is not multiple of size of the data type in bytes. + /// @throw isc::dhcp::InvalidDataType if data field type provided + /// as template parameter is not a supported integer type. + OptionIntArray(const Option::Universe u, const uint16_t type, + const OptionBuffer& buf) + : Option(u, type) { + if (!OptionDataTypeTraits<T>::integer_type) { + isc_throw(dhcp::InvalidDataType, "non-integer type"); + } + unpack(buf.begin(), buf.end()); + } + + /// @brief Constructor. + /// + /// This constructor creates option from a buffer. This constructor + /// may throw exception if \ref unpack function throws during buffer + /// parsing. + /// + /// @param u universe (V4 or V6). + /// @param type option type. + /// @param begin iterator to first byte of option data. + /// @param end iterator to end of option data (first byte after option end). + /// + /// @throw isc::OutOfRange if provided buffer is empty or its length + /// is not multiple of size of the data type in bytes. + /// @throw isc::dhcp::InvalidDataType if data field type provided + /// as template parameter is not a supported integer type. + OptionIntArray(const Option::Universe u, const uint16_t type, + OptionBufferConstIter begin, OptionBufferConstIter end) + : Option(u, type) { + if (!OptionDataTypeTraits<T>::integer_type) { + isc_throw(dhcp::InvalidDataType, "non-integer type"); + } + unpack(begin, end); + } + + /// @brief Copies this option and returns a pointer to the copy. + virtual OptionPtr clone() const { + return (cloneInternal<OptionIntArray<T> >()); + } + + /// @brief Adds a new value to the array. + /// + /// @param value a value being added. + void addValue(const T value) { + values_.push_back(value); + } + + /// Writes option in wire-format to buf, returns pointer to first unused + /// byte after stored option. + /// + /// @param [out] buf buffer (option will be stored here) + /// @param check if set to false, allows options larger than 255 for v4 + /// + /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not + /// equal to 1, 2 or 4 bytes. The data type is not checked in this function + /// because it is checked in a constructor. + virtual void pack(isc::util::OutputBuffer& buf, bool check = true) const { + // Pack option header. + packHeader(buf, check); + // Pack option data. + for (size_t i = 0; i < values_.size(); ++i) { + // Depending on the data type length we use different utility functions + // writeUint16 or writeUint32 which write the data in the network byte + // order to the provided buffer. The same functions can be safely used + // for either unsigned or signed integers so there is not need to create + // special cases for intX_t types. + switch (OptionDataTypeTraits<T>::len) { + case 1: + buf.writeUint8(values_[i]); + break; + case 2: + buf.writeUint16(values_[i]); + break; + case 4: + buf.writeUint32(values_[i]); + break; + default: + isc_throw(dhcp::InvalidDataType, "non-integer type"); + } + } + // We don't pack sub-options here because we have array-type option. + // We don't allow sub-options in array-type options as there is no + // way to distinguish them from the data fields on option reception. + } + + /// @brief Parses received buffer + /// + /// Parses received buffer and returns offset to the first unused byte after + /// parsed option. + /// + /// @param begin iterator to first byte of option data + /// @param end iterator to end of option data (first byte after option end) + /// + /// @throw isc::dhcp::InvalidDataType if size of a data fields type is not + /// equal to 1, 2 or 4 bytes. The data type is not checked in this function + /// because it is checked in a constructor. + virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) { + if (distance(begin, end) == 0) { + isc_throw(OutOfRange, "option " << getType() << " empty"); + } + if (distance(begin, end) % sizeof(T) != 0) { + isc_throw(OutOfRange, "OptionIntArray " << getType() << " truncated"); + } + // @todo consider what to do if buffer is longer than data type. + + values_.clear(); + while (begin != end) { + // Depending on the data type length we use different utility functions + // readUint16 or readUint32 which read the data laid in the network byte + // order from the provided buffer. The same functions can be safely used + // for either unsigned or signed integers so there is not need to create + // special cases for intX_t types. + int data_size_len = OptionDataTypeTraits<T>::len; + switch (data_size_len) { + case 1: + values_.push_back(*begin); + break; + case 2: + values_.push_back(isc::util::readUint16(&(*begin), + std::distance(begin, end))); + break; + case 4: + values_.push_back(isc::util::readUint32(&(*begin), + std::distance(begin, end))); + break; + default: + isc_throw(dhcp::InvalidDataType, "non-integer type"); + } + // Use local variable to set a new value for this iterator. + // When using OptionDataTypeTraits<T>::len directly some versions + // of clang complain about unresolved reference to + // OptionDataTypeTraits structure during linking. + begin += data_size_len; + } + // We do not unpack sub-options here because we have array-type option. + // Such option have variable number of data fields, thus there is no + // way to assess where sub-options start. + } + + /// @brief Return collection of option values. + /// + /// @return collection of values. + const std::vector<T>& getValues() const { return (values_); } + + /// @brief Set option values. + /// + /// @param values collection of values to be set for option. + void setValues(const std::vector<T>& values) { values_ = values; } + + /// @brief returns complete length of option + /// + /// Returns length of this option, including option header and suboptions + /// + /// @return length of this option + virtual uint16_t len() const { + uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN; + length += values_.size() * sizeof(T); + // length of all suboptions + for (OptionCollection::const_iterator it = options_.begin(); + it != options_.end(); + ++it) { + length += (*it).second->len(); + } + return (length); + } + + /// @brief Returns textual representation of the option. + /// + /// @param indent Number of space characters to be inserted before + /// the text. + /// + /// @return textual representation of the option. + virtual std::string toText(int indent = 0) const { + std::stringstream output; + output << headerToText(indent) << ":"; + + std::string data_type = OptionDataTypeUtil::getDataTypeName(OptionDataTypeTraits<T>::type); + for (typename std::vector<T>::const_iterator value = values_.begin(); + value != values_.end(); ++value) { + output << " "; + + // For 1 byte long data types we need to cast to the integer + // because they are usually implemented as "char" types, in + // which case the character rather than number would be printed. + if (OptionDataTypeTraits<T>::len == 1) { + output << static_cast<int>(*value); + + } else { + output << *value; + } + + // Append data type. + output << "(" << data_type << ")"; + } + + return (output.str()); + } + +private: + + std::vector<T> values_; +}; + +} // isc::dhcp namespace +} // isc namespace + +#endif // OPTION_INT_ARRAY_H |