Commit 31c8d5e0 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[2304] Added Option6IntArray option type and unit tests.

parent 273e195e
......@@ -28,6 +28,7 @@ libb10_dhcp___la_SOURCES += option6_iaaddr.cc option6_iaaddr.h
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
......
......@@ -12,8 +12,8 @@
// 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>
......@@ -144,10 +144,10 @@ public:
private:
T value_;
T value_; ///< Value cabveyed by the option.
};
} // isc::dhcp namespace
} // isc namespace
#endif /* OPTION_IA_H_ */
#endif /* OPTION6_INT_H_ */
// 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_ */
......@@ -15,6 +15,7 @@
#ifndef OPTION_DATA_TYPES_H_
#define OPTION_DATA_TYPES_H_
#include <stdint.h>
#include <exceptions/exceptions.h>
namespace isc {
......
......@@ -18,6 +18,7 @@
#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;
......
......@@ -15,7 +15,9 @@
#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 {
......@@ -258,7 +260,7 @@ public:
///
/// @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) {
......@@ -266,7 +268,25 @@ public:
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);
}
......
......@@ -29,6 +29,7 @@
#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;
......@@ -319,7 +320,7 @@ TEST_F(OptionDefinitionTest, factoryIAAddr6) {
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
......@@ -408,4 +409,84 @@ TEST_F(OptionDefinitionTest, factoryInteger32) {
// @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
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment