libb10_dhcp___la_SOURCES += option6_addrlst.cc option6_addrlst.h
libb10_dhcp___la_SOURCES += option4_addrlst.cc option4_addrlst.h
libb10_dhcp___la_SOURCES += option6_int.h
+libb10_dhcp___la_SOURCES += option6_int_array.h
libb10_dhcp___la_SOURCES += dhcp6.h dhcp4.h
libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#ifndef OPTION_INT6_H_
-#define OPTION_INT6_H_
+#ifndef OPTION6_INT_H_
+#define OPTION6_INT_H_
#include <stdint.h>
#include <limits>
private:
- T value_;
+ T value_; ///< Value cabveyed by the option.
};
} // isc::dhcp namespace
} // isc namespace
-#endif /* OPTION_IA_H_ */
+#endif /* OPTION6_INT_H_ */
--- /dev/null
+// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
+//
+// Permission to use, copy, modify, and/or distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
+// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
+// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
+// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
+// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
+// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
+// PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef OPTION6_INT_ARRAY_H_
+#define OPTION6_INT_ARRAY_H_
+
+#include <stdint.h>
+#include <limits>
+#include <util/io_utilities.h>
+#include "dhcp/libdhcp++.h"
+#include "dhcp/option.h"
+#include "dhcp/option_data_types.h"
+
+namespace isc {
+namespace dhcp {
+
+/// This template class represents DHCPv6 option with 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.
+///
+/// @param T data field type (see above).
+template<typename T>
+class Option6IntArray: public Option {
+
+public:
+
+ typedef std::vector<T> ValuesCollection;
+
+ /// @brief Constructor.
+ ///
+ /// @param type option type.
+ /// @param value option value.
+ Option6IntArray(uint16_t type, const ValuesCollection& values)
+ : Option(Option::V6, type), values_(values) {
+ if (!OptionDataTypes<T>::valid) {
+ isc_throw(dhcp::InvalidDataType, "non-numeric type");
+ }
+ }
+
+ /// @brief Constructor.
+ ///
+ /// This constructor creates option from a buffer. This construtor
+ /// may throw exception if \ref unpack function throws during buffer
+ /// parsing.
+ ///
+ /// @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).
+ ///
+ /// @todo mention here what it throws.
+ Option6IntArray(uint16_t type, OptionBufferConstIter begin,
+ OptionBufferConstIter end)
+ : Option(Option::V6, type) {
+ if (!OptionDataTypes<T>::valid) {
+ isc_throw(dhcp::InvalidDataType, "non-numeric type");
+ }
+ unpack(begin, end);
+ }
+
+ /// 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)
+ ///
+ /// @throw isc::BadValue if invalid option type has been provided.
+ void pack(isc::util::OutputBuffer& buf) {
+ buf.writeUint16(type_);
+ buf.writeUint16(len() - OPTION6_HDR_LEN);
+ for (int i = 0; i < values_.size(); ++i) {
+ switch (OptionDataTypes<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-numeric type");
+ }
+ }
+ }
+
+ /// @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)
+ virtual void unpack(OptionBufferConstIter begin, OptionBufferConstIter end) {
+ if (distance(begin, end) % sizeof(T) != 0) {
+ isc_throw(OutOfRange, "Option " << type_ << " truncated");
+ }
+ values_.clear();
+ while (begin != end) {
+ switch (OptionDataTypes<T>::len) {
+ case 1:
+ values_.push_back(*begin);
+ break;
+ case 2:
+ values_.push_back(isc::util::readUint16(&(*begin)));
+ break;
+ case 4:
+ values_.push_back(isc::util::readUint32(&(*begin)));
+ break;
+ default:
+ isc_throw(dhcp::InvalidDataType, "non-numeric type");
+ }
+ begin += sizeof(T);
+ }
+
+ LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
+ }
+
+ /// @brief Returns collection of values.
+ ///
+ /// @return collection of values.
+ const ValuesCollection& getValues() const { return 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() {
+ uint16_t length = OPTION6_HDR_LEN + values_.size() * sizeof(T);
+ // length of all suboptions
+ for (Option::OptionCollection::iterator it = options_.begin();
+ it != options_.end();
+ ++it) {
+ length += (*it).second->len();
+ }
+ return (length);
+ }
+
+private:
+
+ ValuesCollection values_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif /* OPTION6_INT_ARRAY_H_ */
#ifndef OPTION_DATA_TYPES_H_
#define OPTION_DATA_TYPES_H_
+#include <stdint.h>
#include <exceptions/exceptions.h>
namespace isc {
#include "dhcp/option6_ia.h"
#include "dhcp/option6_iaaddr.h"
#include "dhcp/option6_int.h"
+#include "dhcp/option6_int_array.h"
using namespace std;
using namespace isc::util;
#ifndef OPTION_DEFINITION_H_
#define OPTION_DEFINITION_H_
+#include "dhcp/option_data_types.h"
#include "dhcp/option6_int.h"
+#include "dhcp/option6_int_array.h"
#include "dhcp/option.h"
namespace isc {
///
/// @param u universe (V6 or V4).
/// @param type option type.
- /// @param buf option buffer (must be empty).
+ /// @param buf option buffer.
/// @param T type of the data field (must be one of the uintX_t or intX_t).
template<typename T>
static OptionPtr factoryInteger(Option::Universe, uint16_t type, const OptionBuffer& buf) {
isc_throw(isc::OutOfRange, "provided option buffer is too large, expected: "
<< sizeof(T) << " bytes");
}
- OptionPtr option(new Option6Int<T>(type, buf.begin(), buf.begin() + buf.size()));
+ OptionPtr option(new Option6Int<T>(type, buf.begin(), buf.end()));
+ return (option);
+ }
+
+ /// @brief Factory function to create option with array of integer values.
+ ///
+ /// @param u universe (V6 or V4).
+ /// @param type option type.
+ /// @param buf option buffer.
+ /// @param T type of the data field (must be one of the uintX_t or intX_t).
+ template<typename T>
+ static OptionPtr factoryIntegerArray(Option::Universe, uint16_t type, const OptionBuffer& buf) {
+ if (buf.size() == 0) {
+ isc_throw(isc::OutOfRange, "option buffer length must be greater than zero");
+ } else if (buf.size() % OptionDataTypes<T>::len != 0) {
+ isc_throw(isc::OutOfRange, "option buffer length must be multiple of "
+ << OptionDataTypes<T>::len << " bytes");
+ }
+ OptionPtr option(new Option6IntArray<T>(type, buf.begin(), buf.end()));
return (option);
}
#include "dhcp/option6_ia.h"
#include "dhcp/option6_iaaddr.h"
#include "dhcp/option6_int.h"
+#include "dhcp/option6_int_array.h"
#include "dhcp/option_definition.h"
using namespace std;
EXPECT_EQ(0x04050607, option_cast_v6->getValid());
}
-TEST_F(OptionDefinitionTest, factoryIntegerNegative) {
+TEST_F(OptionDefinitionTest, factoryIntegerInvalidType) {
EXPECT_THROW(
OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, OptionBuffer(1)),
isc::dhcp::InvalidDataType
// @todo Add more cases for DHCPv4
}
+TEST_F(OptionDefinitionTest, factoryInteger16Array) {
+ Option::Factory* f = OptionDefinition::factoryIntegerArray<uint16_t>;
+ OptionPtr option_v6;
+ // Provided buffer size must be greater than zero. Check if we
+ // get exception if we provide zero-length buffer.
+ EXPECT_THROW(
+ option_v6 = f(Option::V6, 79, OptionBuffer()),
+ isc::OutOfRange
+ );
+ // Buffer length must be multiple of data type size.
+ EXPECT_THROW(
+ option_v6 = f(Option::V6, 79, OptionBuffer(5)),
+ isc::OutOfRange
+ );
+ // Positive scenario, initiate the buffer with length being
+ // multiple of uint16_t size.
+ // buffer elements will be: 0x112233.
+ OptionBuffer buf(6);
+ for (int i = 0; i < 6; ++i) {
+ buf[i] = i / 2;
+ }
+ // Constructor should succeed because buffer has correct size.
+ EXPECT_NO_THROW(
+ option_v6 = f(Option::V6, 79, buf);
+ );
+ boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
+ boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+ // Get the values from the initiated options and validate.
+ Option6IntArray<uint16_t>::ValuesCollection values =
+ option_cast_v6->getValues();
+ for (int i = 0; i < values.size(); ++i) {
+ // Expected value is calculated using on the same pattern
+ // as the one we used to initiate buffer:
+ // for i=0, expected = 0x00, for i = 1, expected == 0x11 etc.
+ uint16_t expected = (i << 8) | i;
+ EXPECT_EQ(expected, values[i]);
+ }
+}
+
+TEST_F(OptionDefinitionTest, factoryInteger32Array) {
+ Option::Factory* f = OptionDefinition::factoryIntegerArray<uint32_t>;
+ const uint16_t opt_code = 80;
+ OptionPtr option_v6;
+ // Provided buffer size must be greater than zero. Check if we
+ // get exception if we provide zero-length buffer.
+ EXPECT_THROW(
+ option_v6 = f(Option::V6, opt_code, OptionBuffer()),
+ isc::OutOfRange
+ );
+ // Buffer length must be multiple of data type size.
+ EXPECT_THROW(
+ option_v6 = f(Option::V6, opt_code, OptionBuffer(5)),
+ isc::OutOfRange
+ );
+ // Positive scenario, initiate the buffer with length being
+ // multiple of uint16_t size.
+ // buffer elements will be: 0x111122223333.
+ OptionBuffer buf(12);
+ for (int i = 0; i < buf.size(); ++i) {
+ buf[i] = i / 4;
+ }
+ // Constructor should succeed because buffer has correct size.
+ EXPECT_NO_THROW(
+ option_v6 = f(Option::V6, opt_code, buf);
+ );
+ boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
+ boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+ // Get the values from the initiated options and validate.
+ Option6IntArray<uint32_t>::ValuesCollection values =
+ option_cast_v6->getValues();
+ for (int i = 0; i < values.size(); ++i) {
+ // Expected value is calculated using on the same pattern
+ // as the one we used to initiate buffer:
+ // for i=0, expected = 0x0000, for i = 1, expected == 0x1111 etc.
+ uint32_t expected = 0x01010101 * i;
+ EXPECT_EQ(expected, values[i]);
+ }
+}
+
+
} // anonymous namespace