2015-12-16 14:45:33 +01:00
|
|
|
// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
|
2012-11-26 12:09:17 +01:00
|
|
|
//
|
2015-12-15 21:37:34 +01:00
|
|
|
// 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/.
|
2012-11-26 12:09:17 +01:00
|
|
|
|
|
|
|
#ifndef OPTION_CUSTOM_H
|
|
|
|
#define OPTION_CUSTOM_H
|
|
|
|
|
|
|
|
#include <dhcp/option.h>
|
|
|
|
#include <dhcp/option_definition.h>
|
|
|
|
#include <util/io_utilities.h>
|
|
|
|
|
|
|
|
namespace isc {
|
|
|
|
namespace dhcp {
|
|
|
|
|
|
|
|
/// @brief Option with defined data fields represented as buffers that can
|
|
|
|
/// be accessed using data field index.
|
|
|
|
///
|
|
|
|
/// This class represents an option which has defined structure: data fields
|
|
|
|
/// of specific types and order. Those fields can be accessed using indexes,
|
|
|
|
/// where index 0 represents first data field within an option. The last
|
|
|
|
/// field can be accessed using index equal to 'number of fields' - 1.
|
|
|
|
/// Internally, the option data is stored as a collection of OptionBuffer
|
|
|
|
/// objects, each representing data for a particular data field. This data
|
|
|
|
/// can be converted to the actual data type using methods implemented
|
|
|
|
/// within this class. This class is used to represent those options that
|
|
|
|
/// can't be represented by any other specialized class (this excludes the
|
|
|
|
/// Option class which is generic and can be used to represent any option).
|
|
|
|
class OptionCustom : public Option {
|
|
|
|
public:
|
|
|
|
|
2012-11-30 17:32:12 +01:00
|
|
|
/// @brief Constructor, used for options to be sent.
|
|
|
|
///
|
|
|
|
/// This constructor creates an instance of an option with default
|
|
|
|
/// data set for all data fields. The option buffers are allocated
|
|
|
|
/// according to data size being stored in particular data fields.
|
|
|
|
/// For variable size data empty buffers are created.
|
|
|
|
///
|
|
|
|
/// @param def option definition.
|
|
|
|
/// @param u specifies universe (V4 or V6)
|
|
|
|
OptionCustom(const OptionDefinition& def, Universe u);
|
|
|
|
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @brief Constructor, used for options to be sent.
|
|
|
|
///
|
2012-11-28 17:04:26 +01:00
|
|
|
/// This constructor creates an instance of an option from the whole
|
|
|
|
/// supplied buffer. This constructor is mainly used to create an
|
|
|
|
/// instances of options to be stored in outgoing DHCP packets.
|
|
|
|
/// The buffer used to create the instance of an option can be
|
|
|
|
/// created from the option data specified in server's configuration.
|
|
|
|
///
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @param def option definition.
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @param u specifies universe (V4 or V6).
|
|
|
|
/// @param data content of the option.
|
2012-11-27 11:48:06 +01:00
|
|
|
///
|
|
|
|
/// @throw OutOfRange if option buffer is truncated.
|
|
|
|
///
|
|
|
|
/// @todo list all exceptions thrown by ctor.
|
2012-11-26 12:09:17 +01:00
|
|
|
OptionCustom(const OptionDefinition& def, Universe u, const OptionBuffer& data);
|
|
|
|
|
|
|
|
/// @brief Constructor, used for received options.
|
|
|
|
///
|
2012-11-28 17:04:26 +01:00
|
|
|
/// This constructor creates an instance an option from the portion
|
|
|
|
/// of the buffer specified by iterators. This is mainly useful when
|
|
|
|
/// parsing received packets. Such packets are represented by a single
|
|
|
|
/// buffer holding option data and all sub options. Methods that are
|
|
|
|
/// parsing a packet, supply relevant portions of the packet buffer
|
|
|
|
/// to this constructor to create option instances out of it.
|
|
|
|
///
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @param def option definition.
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @param u specifies universe (V4 or V6).
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @param first iterator to the first element that should be copied.
|
|
|
|
/// @param last iterator to the next element after the last one
|
|
|
|
/// to be copied.
|
2012-11-27 11:48:06 +01:00
|
|
|
///
|
|
|
|
/// @throw OutOfRange if option buffer is truncated.
|
|
|
|
///
|
|
|
|
/// @todo list all exceptions thrown by ctor.
|
2012-11-26 12:09:17 +01:00
|
|
|
OptionCustom(const OptionDefinition& def, Universe u,
|
|
|
|
OptionBufferConstIter first, OptionBufferConstIter last);
|
|
|
|
|
2012-12-03 13:10:22 +01:00
|
|
|
/// @brief Create new buffer and set its value as an IP address.
|
|
|
|
///
|
|
|
|
/// @param address IPv4 or IPv6 address to be written to
|
|
|
|
/// a buffer being created.
|
|
|
|
void addArrayDataField(const asiolink::IOAddress& address);
|
|
|
|
|
2012-12-03 13:26:14 +01:00
|
|
|
/// @brief Create new buffer and store boolean value in it.
|
|
|
|
///
|
|
|
|
/// @param value value to be stored in the created buffer.
|
|
|
|
void addArrayDataField(const bool value);
|
|
|
|
|
2012-12-03 14:05:10 +01:00
|
|
|
/// @brief Create new buffer and store integer value in it.
|
|
|
|
///
|
|
|
|
/// @param value value to be stored in the created buffer.
|
|
|
|
/// @tparam T integer type of the value being stored.
|
|
|
|
template<typename T>
|
|
|
|
void addArrayDataField(const T value) {
|
|
|
|
checkArrayType();
|
|
|
|
OptionDataType data_type = definition_.getType();
|
|
|
|
if (OptionDataTypeTraits<T>::type != data_type) {
|
|
|
|
isc_throw(isc::dhcp::InvalidDataType,
|
|
|
|
"specified data type " << data_type << " does not"
|
|
|
|
" match the data type in an option definition");
|
|
|
|
}
|
|
|
|
|
|
|
|
OptionBuffer buf;
|
|
|
|
OptionDataTypeUtil::writeInt<T>(value, buf);
|
|
|
|
buffers_.push_back(buf);
|
|
|
|
}
|
|
|
|
|
2012-11-27 14:32:34 +01:00
|
|
|
/// @brief Return a number of the data fields.
|
|
|
|
///
|
|
|
|
/// @return number of data fields held by the option.
|
|
|
|
uint32_t getDataFieldsNum() const { return (buffers_.size()); }
|
|
|
|
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @brief Read a buffer as IP address.
|
|
|
|
///
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
2012-11-28 17:04:26 +01:00
|
|
|
/// @return IP address read from a buffer.
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
2012-11-30 17:32:12 +01:00
|
|
|
asiolink::IOAddress readAddress(const uint32_t index = 0) const;
|
|
|
|
|
|
|
|
/// @brief Write an IP address into a buffer.
|
|
|
|
///
|
|
|
|
/// @param address IP address being written.
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
|
|
|
/// @throw isc::dhcp::BadDataTypeCast if IP address is invalid.
|
|
|
|
void writeAddress(const asiolink::IOAddress& address,
|
|
|
|
const uint32_t index = 0);
|
2012-11-26 12:09:17 +01:00
|
|
|
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @brief Read a buffer as binary data.
|
|
|
|
///
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
|
|
|
/// @return read buffer holding binary data.
|
2012-11-30 17:32:12 +01:00
|
|
|
const OptionBuffer& readBinary(const uint32_t index = 0) const;
|
2012-11-27 11:06:29 +01:00
|
|
|
|
2012-11-30 18:06:26 +01:00
|
|
|
/// @brief Write binary data into a buffer.
|
|
|
|
///
|
|
|
|
/// @param buf buffer holding binary data to be written.
|
|
|
|
/// @param index buffer index.
|
|
|
|
void writeBinary(const OptionBuffer& buf, const uint32_t index = 0);
|
2012-11-27 11:06:29 +01:00
|
|
|
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @brief Read a buffer as boolean value.
|
|
|
|
///
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
|
|
|
/// @return read boolean value.
|
2012-11-30 17:32:12 +01:00
|
|
|
bool readBoolean(const uint32_t index = 0) const;
|
|
|
|
|
|
|
|
/// @brief Write a boolean value into a buffer.
|
|
|
|
///
|
|
|
|
/// @param value boolean value to be written.
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
|
|
|
void writeBoolean(const bool value, const uint32_t index = 0);
|
2012-11-26 12:09:17 +01:00
|
|
|
|
2012-11-29 19:40:32 +01:00
|
|
|
/// @brief Read a buffer as FQDN.
|
|
|
|
///
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if buffer index is out of range.
|
|
|
|
/// @throw isc::dhcp::BadDataTypeCast if a buffer being read
|
|
|
|
/// does not hold a valid FQDN.
|
|
|
|
/// @return string representation if FQDN.
|
2012-11-30 17:32:12 +01:00
|
|
|
std::string readFqdn(const uint32_t index = 0) const;
|
2012-11-29 19:40:32 +01:00
|
|
|
|
2012-12-03 10:45:32 +01:00
|
|
|
/// @brief Write an FQDN into a buffer.
|
|
|
|
///
|
|
|
|
/// @param fqdn text representation of FQDN.
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
|
|
|
void writeFqdn(const std::string& fqdn, const uint32_t index = 0);
|
2012-11-26 12:09:17 +01:00
|
|
|
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @brief Read a buffer as integer value.
|
|
|
|
///
|
|
|
|
/// @param index buffer index.
|
2012-11-27 13:43:54 +01:00
|
|
|
/// @tparam integer type of a value being returned.
|
2012-11-27 11:48:06 +01:00
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
2012-11-30 17:32:12 +01:00
|
|
|
/// @throw isc::dhcp::InvalidDataType if T is invalid.
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @return read integer value.
|
2012-11-26 12:09:17 +01:00
|
|
|
template<typename T>
|
2012-11-30 17:32:12 +01:00
|
|
|
T readInteger(const uint32_t index = 0) const {
|
2012-12-06 16:39:04 +01:00
|
|
|
// Check that the index is not out of range.
|
2012-11-26 12:09:17 +01:00
|
|
|
checkIndex(index);
|
2012-11-30 17:32:12 +01:00
|
|
|
// Check that T points to a valid integer type and this type
|
|
|
|
// is consistent with an option definition.
|
|
|
|
checkDataType<T>(index);
|
2012-11-27 11:48:06 +01:00
|
|
|
// When we created the buffer we have checked that it has a
|
2013-03-08 10:32:43 -06:00
|
|
|
// valid size so this condition here should be always fulfilled.
|
2012-11-26 12:09:17 +01:00
|
|
|
assert(buffers_[index].size() == OptionDataTypeTraits<T>::len);
|
2012-11-27 11:48:06 +01:00
|
|
|
// Read an integer value.
|
2012-11-26 15:53:20 +01:00
|
|
|
return (OptionDataTypeUtil::readInt<T>(buffers_[index]));
|
2012-11-26 12:09:17 +01:00
|
|
|
}
|
|
|
|
|
2012-11-30 17:32:12 +01:00
|
|
|
/// @brief Write an integer value into a buffer.
|
|
|
|
///
|
|
|
|
/// @param value integer value to be written.
|
|
|
|
/// @param index buffer index.
|
|
|
|
/// @tparam T integer type of a value being written.
|
|
|
|
///
|
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
|
|
|
/// @throw isc::dhcp::InvalidDataType if T is invalid.
|
|
|
|
template<typename T>
|
|
|
|
void writeInteger(const T value, const uint32_t index = 0) {
|
|
|
|
// Check that the index is not out of range.
|
|
|
|
checkIndex(index);
|
|
|
|
// Check that T points to a valid integer type and this type
|
|
|
|
// is consistent with an option definition.
|
|
|
|
checkDataType<T>(index);
|
|
|
|
// Get some temporary buffer.
|
|
|
|
OptionBuffer buf;
|
|
|
|
// Try to write to the buffer.
|
|
|
|
OptionDataTypeUtil::writeInt<T>(value, buf);
|
|
|
|
// If successful, replace the old buffer with new one.
|
|
|
|
std::swap(buffers_[index], buf);
|
|
|
|
}
|
|
|
|
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @brief Read a buffer as string value.
|
|
|
|
///
|
|
|
|
/// @param index buffer index.
|
|
|
|
///
|
2012-11-28 17:04:26 +01:00
|
|
|
/// @return string value read from buffer.
|
2012-11-27 11:48:06 +01:00
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
2012-11-30 17:32:12 +01:00
|
|
|
std::string readString(const uint32_t index = 0) const;
|
|
|
|
|
|
|
|
/// @brief Write a string value into a buffer.
|
|
|
|
///
|
|
|
|
/// @param text the string value to be written.
|
2012-12-13 11:38:21 +00:00
|
|
|
/// @param index buffer index.
|
2012-11-30 17:32:12 +01:00
|
|
|
void writeString(const std::string& text,
|
|
|
|
const uint32_t index = 0);
|
2012-11-26 12:09:17 +01:00
|
|
|
|
2013-01-21 13:28:33 +01:00
|
|
|
/// @brief Writes DHCP option in a wire format to a buffer.
|
|
|
|
///
|
|
|
|
/// @param buf output buffer (option will be stored there).
|
|
|
|
virtual void pack(isc::util::OutputBuffer& buf);
|
|
|
|
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @brief Parses received buffer.
|
|
|
|
///
|
|
|
|
/// @param begin iterator to first byte of option data
|
|
|
|
/// @param end iterator to end of option data (first byte after option end)
|
|
|
|
virtual void unpack(OptionBufferConstIter begin,
|
|
|
|
OptionBufferConstIter end);
|
|
|
|
|
2012-11-28 13:03:44 +00:00
|
|
|
/// @brief Returns string representation of the option.
|
2012-11-26 12:09:17 +01:00
|
|
|
///
|
|
|
|
/// @param indent number of spaces before printed text.
|
|
|
|
///
|
|
|
|
/// @return string with text representation.
|
|
|
|
virtual std::string toText(int indent = 0);
|
|
|
|
|
2012-11-28 13:03:44 +00:00
|
|
|
/// @brief Returns length of the complete option (data length +
|
|
|
|
/// DHCPv4/DHCPv6 option header)
|
2012-11-26 12:09:17 +01:00
|
|
|
///
|
|
|
|
/// @return length of the option
|
|
|
|
virtual uint16_t len();
|
|
|
|
|
|
|
|
/// @brief Sets content of this option from buffer.
|
|
|
|
///
|
|
|
|
/// Option will be resized to length of buffer.
|
|
|
|
///
|
2013-03-06 08:41:51 -06:00
|
|
|
/// @param first iterator pointing to beginning of buffer to copy.
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @param last iterator pointing to end of buffer to copy.
|
2013-05-17 14:36:45 +02:00
|
|
|
void initialize(const OptionBufferConstIter first,
|
|
|
|
const OptionBufferConstIter last);
|
2012-11-26 12:09:17 +01:00
|
|
|
|
|
|
|
private:
|
|
|
|
|
2012-12-03 13:10:22 +01:00
|
|
|
/// @brief Verify that the option comprises an array of values.
|
2012-11-26 12:09:17 +01:00
|
|
|
///
|
2012-12-03 13:10:22 +01:00
|
|
|
/// This helper function is used by createArrayEntry functions
|
|
|
|
/// and throws an exception if the particular option is not
|
|
|
|
/// an array.
|
2012-11-28 13:03:44 +00:00
|
|
|
///
|
2012-12-03 13:10:22 +01:00
|
|
|
/// @throw isc::InvalidOperation if option is not an array.
|
2012-12-03 14:05:10 +01:00
|
|
|
inline void checkArrayType() const {
|
|
|
|
if (!definition_.getArrayType()) {
|
|
|
|
isc_throw(InvalidOperation, "failed to add new array entry to an"
|
|
|
|
<< " option. The option is not an array.");
|
|
|
|
}
|
|
|
|
}
|
2012-11-26 12:09:17 +01:00
|
|
|
|
2012-11-30 17:32:12 +01:00
|
|
|
/// @brief Verify that the integer type is consistent with option
|
|
|
|
/// field type.
|
|
|
|
///
|
|
|
|
/// This convenience function checks that the data type specified as T
|
|
|
|
/// is consistent with a type of a data field identified by index.
|
|
|
|
///
|
|
|
|
/// @param index data field index.
|
|
|
|
/// @tparam data type to be validated.
|
|
|
|
///
|
|
|
|
/// @throw isc::dhcp::InvalidDataType if the type is invalid.
|
|
|
|
template<typename T>
|
2013-06-13 10:51:19 +02:00
|
|
|
// cppcheck-suppress unusedPrivateFunction
|
2012-11-30 17:32:12 +01:00
|
|
|
void checkDataType(const uint32_t index) const;
|
2012-12-03 13:10:22 +01:00
|
|
|
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @brief Check if data field index is valid.
|
|
|
|
///
|
2012-11-28 13:03:44 +00:00
|
|
|
/// @param index Data field index to check.
|
|
|
|
///
|
2012-11-26 12:09:17 +01:00
|
|
|
/// @throw isc::OutOfRange if index is out of range.
|
|
|
|
void checkIndex(const uint32_t index) const;
|
|
|
|
|
2012-11-30 17:32:12 +01:00
|
|
|
/// @brief Create a collection of non initialized buffers.
|
2012-11-26 12:09:17 +01:00
|
|
|
void createBuffers();
|
|
|
|
|
2012-11-30 17:32:12 +01:00
|
|
|
/// @brief Create collection of buffers representing data field values.
|
|
|
|
///
|
|
|
|
/// @param data_buf a buffer to be parsed.
|
|
|
|
void createBuffers(const OptionBuffer& data_buf);
|
|
|
|
|
2012-11-28 10:02:18 +01:00
|
|
|
/// @brief Return a text representation of a data field.
|
|
|
|
///
|
|
|
|
/// @param data_type data type of a field.
|
|
|
|
/// @param index data field buffer index within a custom option.
|
|
|
|
///
|
|
|
|
/// @return text representation of a data field.
|
|
|
|
std::string dataFieldToText(const OptionDataType data_type,
|
|
|
|
const uint32_t index) const;
|
|
|
|
|
2013-05-17 14:36:45 +02:00
|
|
|
/// Make this function private as we don't want it to be invoked
|
|
|
|
/// on OptionCustom object. We rather want that initialize to
|
|
|
|
/// be called instead.
|
|
|
|
using Option::setData;
|
|
|
|
|
2012-11-27 11:48:06 +01:00
|
|
|
/// Option definition used to create an option.
|
2012-11-26 12:09:17 +01:00
|
|
|
OptionDefinition definition_;
|
|
|
|
|
2012-11-27 11:48:06 +01:00
|
|
|
/// The collection of buffers holding data for option fields.
|
|
|
|
/// The order of buffers corresponds to the order of option
|
|
|
|
/// fields.
|
2012-11-26 12:09:17 +01:00
|
|
|
std::vector<OptionBuffer> buffers_;
|
|
|
|
};
|
|
|
|
|
2013-01-15 15:33:55 +01:00
|
|
|
/// A pointer to the OptionCustom object.
|
|
|
|
typedef boost::shared_ptr<OptionCustom> OptionCustomPtr;
|
|
|
|
|
2014-05-10 12:23:34 +02:00
|
|
|
template<typename T>
|
|
|
|
void
|
|
|
|
OptionCustom::checkDataType(const uint32_t index) const {
|
|
|
|
// Check that the requested return type is a supported integer.
|
|
|
|
if (!OptionDataTypeTraits<T>::integer_type) {
|
|
|
|
isc_throw(isc::dhcp::InvalidDataType, "specified data type"
|
|
|
|
" is not a supported integer type.");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get the option definition type.
|
|
|
|
OptionDataType data_type = definition_.getType();
|
|
|
|
if (data_type == OPT_RECORD_TYPE) {
|
|
|
|
const OptionDefinition::RecordFieldsCollection& record_fields =
|
|
|
|
definition_.getRecordFields();
|
|
|
|
// When we initialized buffers we have already checked that
|
|
|
|
// the number of these buffers is equal to number of option
|
|
|
|
// fields in the record so the condition below should be met.
|
|
|
|
assert(index < record_fields.size());
|
|
|
|
// Get the data type to be returned.
|
|
|
|
data_type = record_fields[index];
|
|
|
|
}
|
|
|
|
|
|
|
|
if (OptionDataTypeTraits<T>::type != data_type) {
|
|
|
|
isc_throw(isc::dhcp::InvalidDataType,
|
|
|
|
"specified data type " << data_type << " does not"
|
|
|
|
" match the data type in an option definition for field"
|
|
|
|
" index " << index);
|
|
|
|
}
|
|
|
|
}
|
2012-11-26 12:09:17 +01:00
|
|
|
} // namespace isc::dhcp
|
|
|
|
} // namespace isc
|
|
|
|
|
|
|
|
#endif // OPTION_CUSTOM_H
|