BIND 10 master, updated. 50a73567e8067fdbe4405b7ece5b08948ef87f98 [master] Merge branch 'trac2526'
BIND 10 source code commits
bind10-changes at lists.isc.org
Mon Dec 17 15:26:53 UTC 2012
The branch, master has been updated
via 50a73567e8067fdbe4405b7ece5b08948ef87f98 (commit)
via 030ab7aacd96bf18bc1748cd30fecb9b4f60b890 (commit)
via da3bcafa328abd1bd6125f89a3091196954ef55d (commit)
via 0ebb7cd975d578f3dea516b790e502fdd65cb683 (commit)
via 3759773a821827277aa2c8d457dd6fe63f1daf75 (commit)
via 1ee4d989baee8e0fe013aa0c1e63f4e6a429d114 (commit)
via 9e655bc3d628a2ada61d9d8f7518d655b0f84e7f (commit)
via 21da96d4bcb34a2289e5b16eead8ce181d8eb61c (commit)
via 7985a4bd28b3fb77fc1245ff1e0fe39350a46db2 (commit)
via 4b79e1c508a01dbf6b1ae92f31e6256840b80207 (commit)
via 92e23241bb54197ec11ed79691bf678cd042de6d (commit)
via f54d04b85937244a7c9cb00dc388387c1819eaa6 (commit)
via 26f89e5cc91ec20cb7607e81b82ec7087d40de2f (commit)
via 351dbdab0925b72ddaad6f95b9008426ceb834ee (commit)
via cc557baebc622a96b3f0813bde163f0397964a57 (commit)
via e000302572bb2ea1e407218e6d5484cd4bc54f25 (commit)
from 01496b7eff80566dd62b4d308ac8c932a16ed13e (commit)
Those revisions listed above that are new to this repository have
not appeared on any other notification email; so we list those
revisions in full, below.
- Log -----------------------------------------------------------------
commit 50a73567e8067fdbe4405b7ece5b08948ef87f98
Merge: 01496b7 030ab7a
Author: Marcin Siodelski <marcin at isc.org>
Date: Mon Dec 17 15:35:20 2012 +0100
[master] Merge branch 'trac2526'
Conflicts:
src/lib/dhcp/pkt4.cc
src/lib/dhcp/std_option_defs.h
-----------------------------------------------------------------------
Summary of changes:
src/bin/dhcp6/dhcp6_srv.cc | 6 +-
src/bin/dhcp6/tests/dhcp6_srv_unittest.cc | 6 +-
src/lib/dhcp/Makefile.am | 4 +-
src/lib/dhcp/libdhcp++.cc | 113 ++++-
src/lib/dhcp/libdhcp++.h | 8 +-
src/lib/dhcp/option.cc | 43 +-
src/lib/dhcp/option.h | 16 +
src/lib/dhcp/option_data_types.h | 2 +-
src/lib/dhcp/option_definition.cc | 12 +-
src/lib/dhcp/option_definition.h | 37 +-
src/lib/dhcp/{option6_int.h => option_int.h} | 29 +-
.../{option6_int_array.h => option_int_array.h} | 40 +-
src/lib/dhcp/pkt4.cc | 6 +-
src/lib/dhcp/std_option_defs.h | 209 +++++++--
src/lib/dhcp/tests/Makefile.am | 4 +-
src/lib/dhcp/tests/libdhcp++_unittest.cc | 490 ++++++++++++++++----
src/lib/dhcp/tests/option_definition_unittest.cc | 64 +--
...ay_unittest.cc => option_int_array_unittest.cc} | 207 ++++++---
...ion6_int_unittest.cc => option_int_unittest.cc} | 309 ++++++++----
src/lib/dhcp/tests/pkt4_unittest.cc | 36 +-
20 files changed, 1212 insertions(+), 429 deletions(-)
rename src/lib/dhcp/{option6_int.h => option_int.h} (89%)
rename src/lib/dhcp/{option6_int_array.h => option_int_array.h} (88%)
rename src/lib/dhcp/tests/{option6_int_array_unittest.cc => option_int_array_unittest.cc} (67%)
rename src/lib/dhcp/tests/{option6_int_unittest.cc => option_int_unittest.cc} (50%)
-----------------------------------------------------------------------
diff --git a/src/bin/dhcp6/dhcp6_srv.cc b/src/bin/dhcp6/dhcp6_srv.cc
index 2482833..a50be03 100644
--- a/src/bin/dhcp6/dhcp6_srv.cc
+++ b/src/bin/dhcp6/dhcp6_srv.cc
@@ -23,8 +23,8 @@
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
#include <dhcp/option_custom.h>
+#include <dhcp/option_int_array.h>
#include <dhcp/pkt6.h>
#include <dhcp6/dhcp6_log.h>
#include <dhcp6/dhcp6_srv.h>
@@ -331,8 +331,8 @@ void Dhcpv6Srv::appendRequestedOptions(const Pkt6Ptr& question, Pkt6Ptr& answer)
// Client requests some options using ORO option. Try to
// get this option from client's message.
- boost::shared_ptr<Option6IntArray<uint16_t> > option_oro =
- boost::dynamic_pointer_cast<Option6IntArray<uint16_t> >(question->getOption(D6O_ORO));
+ boost::shared_ptr<OptionIntArray<uint16_t> > option_oro =
+ boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >(question->getOption(D6O_ORO));
// Option ORO not found. Don't do anything then.
if (!option_oro) {
return;
diff --git a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
index de0dc28..040db35 100644
--- a/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
+++ b/src/bin/dhcp6/tests/dhcp6_srv_unittest.cc
@@ -23,7 +23,7 @@
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
+#include <dhcp/option_int_array.h>
#include <dhcp6/config_parser.h>
#include <dhcp6/dhcp6_srv.h>
#include <dhcpsrv/cfgmgr.h>
@@ -381,8 +381,8 @@ TEST_F(Dhcpv6SrvTest, advertiseOptions) {
// Let's now request option with code 1000.
// We expect that server will include this option in its reply.
- boost::shared_ptr<Option6IntArray<uint16_t> >
- option_oro(new Option6IntArray<uint16_t>(D6O_ORO));
+ boost::shared_ptr<OptionIntArray<uint16_t> >
+ option_oro(new OptionIntArray<uint16_t>(Option::V6, D6O_ORO));
// Create vector with two option codes.
std::vector<uint16_t> codes(2);
codes[0] = 1000;
diff --git a/src/lib/dhcp/Makefile.am b/src/lib/dhcp/Makefile.am
index f41ce53..571f11d 100644
--- a/src/lib/dhcp/Makefile.am
+++ b/src/lib/dhcp/Makefile.am
@@ -28,8 +28,8 @@ libb10_dhcp___la_SOURCES += option6_ia.cc option6_ia.h
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 += option_int.h
+libb10_dhcp___la_SOURCES += option_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
diff --git a/src/lib/dhcp/libdhcp++.cc b/src/lib/dhcp/libdhcp++.cc
index 2773d09..b19ed21 100644
--- a/src/lib/dhcp/libdhcp++.cc
+++ b/src/lib/dhcp/libdhcp++.cc
@@ -20,8 +20,8 @@
#include <dhcp/option.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
#include <dhcp/option_definition.h>
+#include <dhcp/option_int_array.h>
#include <dhcp/std_option_defs.h>
#include <exceptions/exceptions.h>
#include <util/buffer.h>
@@ -49,10 +49,12 @@ const OptionDefContainer&
LibDHCP::getOptionDefs(const Option::Universe u) {
switch (u) {
case Option::V4:
- initStdOptionDefs4();
+ if (v4option_defs_.empty()) {
+ initStdOptionDefs4();
+ }
return (v4option_defs_);
case Option::V6:
- if (v6option_defs_.size() == 0) {
+ if (v6option_defs_.empty()) {
initStdOptionDefs6();
}
return (v6option_defs_);
@@ -100,31 +102,35 @@ LibDHCP::optionFactory(Option::Universe u,
size_t LibDHCP::unpackOptions6(const OptionBuffer& buf,
isc::dhcp::Option::OptionCollection& options) {
size_t offset = 0;
- size_t end = buf.size();
-
- while (offset +4 <= end) {
- uint16_t opt_type = buf[offset] * 256 + buf[offset + 1];
+ size_t length = buf.size();
+
+ // Get the list of stdandard option definitions.
+ const OptionDefContainer& option_defs = LibDHCP::getOptionDefs(Option::V6);
+ // Get the search index #1. It allows to search for option definitions
+ // using option code.
+ const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
+
+ // The buffer being read comprises a set of options, each starting with
+ // a two-byte type code and a two-byte length field.
+ while (offset + 4 <= length) {
+ uint16_t opt_type = isc::util::readUint16(&buf[offset]);
offset += 2;
- uint16_t opt_len = buf[offset] * 256 + buf[offset + 1];
+ uint16_t opt_len = isc::util::readUint16(&buf[offset]);
offset += 2;
- if (offset + opt_len > end) {
+ if (offset + opt_len > length) {
// @todo: consider throwing exception here.
return (offset);
}
- // Get the list of stdandard option definitions.
- OptionDefContainer option_defs = LibDHCP::getOptionDefs(Option::V6);
- // Get the search index #1. It allows to search for option definitions
- // using option code.
- const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
- // Get all options with the particular option code. Note that option code
- // is non-unique within this container however at this point we expect
- // to get one option definition with the particular code. If more are
- // returned we report an error.
+ // Get all definitions with the particular option code. Note that option
+ // code is non-unique within this container however at this point we
+ // expect to get one option definition with the particular code. If more
+ // are returned we report an error.
const OptionDefContainerTypeRange& range = idx.equal_range(opt_type);
// Get the number of returned option definitions for the option code.
size_t num_defs = distance(range.first, range.second);
+
OptionPtr opt;
if (num_defs > 1) {
// Multiple options of the same code are not supported right now!
@@ -162,7 +168,14 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
isc::dhcp::Option::OptionCollection& options) {
size_t offset = 0;
- // 2 byte - header of DHCPv4 option
+ // Get the list of stdandard option definitions.
+ const OptionDefContainer& option_defs = LibDHCP::getOptionDefs(Option::V4);
+ // Get the search index #1. It allows to search for option definitions
+ // using option code.
+ const OptionDefContainerTypeIndex& idx = option_defs.get<1>();
+
+ // The buffer being read comprises a set of options, each starting with
+ // a one-byte type code and a one-byte length field.
while (offset + 1 <= buf.size()) {
uint8_t opt_type = buf[offset++];
@@ -176,8 +189,10 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
continue;
if (offset + 1 >= buf.size()) {
+ // opt_type must be cast to integer so as it is not treated as
+ // unsigned char value (a number is presented in error message).
isc_throw(OutOfRange, "Attempt to parse truncated option "
- << opt_type);
+ << static_cast<int>(opt_type));
}
uint8_t opt_len = buf[offset++];
@@ -187,12 +202,35 @@ size_t LibDHCP::unpackOptions4(const OptionBuffer& buf,
<< "-byte long buffer.");
}
+ // Get all definitions with the particular option code. Note that option code
+ // is non-unique within this container however at this point we expect
+ // to get one option definition with the particular code. If more are
+ // returned we report an error.
+ const OptionDefContainerTypeRange& range = idx.equal_range(opt_type);
+ // Get the number of returned option definitions for the option code.
+ size_t num_defs = distance(range.first, range.second);
+
OptionPtr opt;
- switch(opt_type) {
- default:
+ if (num_defs > 1) {
+ // Multiple options of the same code are not supported right now!
+ isc_throw(isc::Unexpected, "Internal error: multiple option definitions"
+ " for option type " << static_cast<int>(opt_type)
+ << " returned. Currently it is not supported to initialize"
+ << " multiple option definitions for the same option code."
+ << " This will be supported once support for option spaces"
+ << " is implemented");
+ } else if (num_defs == 0) {
opt = OptionPtr(new Option(Option::V4, opt_type,
- buf.begin()+offset,
- buf.begin()+offset+opt_len));
+ buf.begin() + offset,
+ buf.begin() + offset + opt_len));
+ } else {
+ // The option definition has been found. Use it to create
+ // the option instance from the provided buffer chunk.
+ const OptionDefinitionPtr& def = *(range.first);
+ assert(def);
+ opt = def->optionFactory(Option::V4, opt_type,
+ buf.begin() + offset,
+ buf.begin() + offset + opt_len);
}
options.insert(std::make_pair(opt_type, opt));
@@ -259,7 +297,32 @@ void LibDHCP::OptionFactoryRegister(Option::Universe u,
void
LibDHCP::initStdOptionDefs4() {
- isc_throw(isc::NotImplemented, "initStdOptionDefs4 is not implemented");
+ v4option_defs_.clear();
+
+ // Now let's add all option definitions.
+ for (int i = 0; i < OPTION_DEF_PARAMS_SIZE4; ++i) {
+ OptionDefinitionPtr definition(new OptionDefinition(OPTION_DEF_PARAMS4[i].name,
+ OPTION_DEF_PARAMS4[i].code,
+ OPTION_DEF_PARAMS4[i].type,
+ OPTION_DEF_PARAMS4[i].array));
+
+ for (int rec = 0; rec < OPTION_DEF_PARAMS4[i].records_size; ++rec) {
+ definition->addRecordField(OPTION_DEF_PARAMS4[i].records[rec]);
+ }
+
+ // Sanity check if the option is valid.
+ try {
+ definition->validate();
+ } catch (const Exception& ex) {
+ // This is unlikely event that validation fails and may
+ // be only caused by programming error. To guarantee the
+ // data consistency we clear all option definitions that
+ // have been added so far and pass the exception forward.
+ v4option_defs_.clear();
+ throw;
+ }
+ v4option_defs_.push_back(definition);
+ }
}
void
diff --git a/src/lib/dhcp/libdhcp++.h b/src/lib/dhcp/libdhcp++.h
index e855070..c325aa5 100644
--- a/src/lib/dhcp/libdhcp++.h
+++ b/src/lib/dhcp/libdhcp++.h
@@ -138,9 +138,9 @@ private:
/// The method creates option definitions for all DHCPv4 options.
/// Currently this function is not implemented.
///
- /// @todo implemend this function.
- ///
- /// @throw isc::NotImplemeneted
+ /// @throw std::bad alloc if system went out of memory.
+ /// @throw MalformedOptionDefinition if any of the definitions
+ /// are incorrect. This is programming error.
static void initStdOptionDefs4();
/// Initialize standard DHCPv6 option definitions.
@@ -149,7 +149,7 @@ private:
///
/// @throw std::bad_alloc if system went out of memory.
/// @throw MalformedOptionDefinition if any of the definitions
- /// is incorect. This is a programming error.
+ /// is incorrect. This is a programming error.
static void initStdOptionDefs6();
/// pointers to factories that produce DHCPv6 options
diff --git a/src/lib/dhcp/option.cc b/src/lib/dhcp/option.cc
index 2a53f0f..dbdac0c 100644
--- a/src/lib/dhcp/option.cc
+++ b/src/lib/dhcp/option.cc
@@ -100,22 +100,14 @@ void Option::pack(isc::util::OutputBuffer& buf) {
void
Option::pack4(isc::util::OutputBuffer& buf) {
if (universe_ == V4) {
- if (len() > 255) {
- isc_throw(OutOfRange, "DHCPv4 Option " << type_ << " is too big. "
- << "At most 255 bytes are supported.");
- /// TODO Larger options can be stored as separate instances
- /// of DHCPv4 options. Clients MUST concatenate them.
- /// Fortunately, there are no such large options used today.
- }
-
- buf.writeUint8(type_);
- buf.writeUint8(len() - getHeaderLen());
+ // Write a header.
+ packHeader(buf);
+ // Write data.
if (!data_.empty()) {
buf.writeData(&data_[0], data_.size());
}
-
+ // Write sub-options.
packOptions(buf);
-
} else {
isc_throw(BadValue, "Invalid universe type " << universe_);
}
@@ -125,12 +117,13 @@ Option::pack4(isc::util::OutputBuffer& buf) {
void Option::pack6(isc::util::OutputBuffer& buf) {
if (universe_ == V6) {
- buf.writeUint16(type_);
- buf.writeUint16(len() - getHeaderLen());
+ // Write a header.
+ packHeader(buf);
+ // Write data.
if (!data_.empty()) {
buf.writeData(&data_[0], data_.size());
}
-
+ // Write sub-options.
packOptions(buf);
} else {
isc_throw(BadValue, "Invalid universe type " << universe_);
@@ -139,6 +132,26 @@ void Option::pack6(isc::util::OutputBuffer& buf) {
}
void
+Option::packHeader(isc::util::OutputBuffer& buf) {
+ if (universe_ == V4) {
+ if (len() > 255) {
+ isc_throw(OutOfRange, "DHCPv4 Option " << type_ << " is too big. "
+ << "At most 255 bytes are supported.");
+ /// TODO Larger options can be stored as separate instances
+ /// of DHCPv4 options. Clients MUST concatenate them.
+ /// Fortunately, there are no such large options used today.
+ }
+
+ buf.writeUint8(type_);
+ buf.writeUint8(len() - getHeaderLen());
+
+ } else {
+ buf.writeUint16(type_);
+ buf.writeUint16(len() - getHeaderLen());
+ }
+}
+
+void
Option::packOptions(isc::util::OutputBuffer& buf) {
switch (universe_) {
case V4:
diff --git a/src/lib/dhcp/option.h b/src/lib/dhcp/option.h
index 3c7799f..e4105cc 100644
--- a/src/lib/dhcp/option.h
+++ b/src/lib/dhcp/option.h
@@ -325,6 +325,22 @@ protected:
/// @throw BadValue Universe is not V6.
virtual void pack6(isc::util::OutputBuffer& buf);
+ /// @brief Store option's header in a buffer.
+ ///
+ /// This method writes option's header into a buffer in the
+ /// on-wire format. The universe set for the particular option
+ /// is used to determine whether option code and length are
+ /// stored as 2-byte (for DHCPv6) or single-byte (for DHCPv4)
+ /// values. For DHCPv4 options, this method checks if the
+ /// length does not exceed 255 bytes and throws exception if
+ /// it does.
+ /// This method is used by derived classes to pack option's
+ /// header into a buffer. This method should not be called
+ /// directly by other classes.
+ ///
+ /// @param [out] buf output buffer.
+ void packHeader(isc::util::OutputBuffer& buf);
+
/// @brief Store sub options in a buffer.
///
/// This method stores all sub-options defined for a particular
diff --git a/src/lib/dhcp/option6_int.h b/src/lib/dhcp/option6_int.h
deleted file mode 100644
index d61509b..0000000
--- a/src/lib/dhcp/option6_int.h
+++ /dev/null
@@ -1,189 +0,0 @@
-// 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_H
-#define OPTION6_INT_H
-
-#include <dhcp/libdhcp++.h>
-#include <dhcp/option.h>
-#include <dhcp/option_data_types.h>
-#include <util/io_utilities.h>
-
-#include <stdint.h>
-
-namespace isc {
-namespace dhcp {
-
-/// This template class represents DHCPv6 option with single value.
-/// This value is of integer type and 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 Option6Int: public Option {
-
-public:
- /// @brief Constructor.
- ///
- /// @param type option type.
- /// @param value option value.
- ///
- /// @throw isc::dhcp::InvalidDataType if data field type provided
- /// as template parameter is not a supported integer type.
- Option6Int(uint16_t type, T value)
- : Option(Option::V6, type), value_(value) {
- if (!OptionDataTypeTraits<T>::integer_type) {
- isc_throw(dhcp::InvalidDataType, "non-integer 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).
- ///
- /// @throw isc::OutOfRange if provided buffer is shorter than data size.
- /// @throw isc::dhcp::InvalidDataType if data field type provided
- /// as template parameter is not a supported integer type.
- Option6Int(uint16_t type, OptionBufferConstIter begin,
- OptionBufferConstIter end)
- : Option(Option::V6, type) {
- if (!OptionDataTypeTraits<T>::integer_type) {
- isc_throw(dhcp::InvalidDataType, "non-integer 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::dhcp::InvalidDataType if size of a data field 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.
- void pack(isc::util::OutputBuffer& buf) {
- buf.writeUint16(type_);
- buf.writeUint16(len() - OPTION6_HDR_LEN);
- // 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(value_);
- break;
- case 2:
- buf.writeUint16(value_);
- break;
- case 4:
- buf.writeUint32(value_);
- break;
- default:
- isc_throw(dhcp::InvalidDataType, "non-integer type");
- }
- packOptions(buf);
- }
-
- /// @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::OutOfRange if provided buffer is shorter than data size.
- /// @throw isc::dhcp::InvalidDataType if size of a data field 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) < sizeof(T)) {
- isc_throw(OutOfRange, "Option " << getType() << " truncated");
- }
- // @todo consider what to do if buffer is longer than data type.
-
- // 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:
- value_ = *begin;
- break;
- case 2:
- value_ = isc::util::readUint16(&(*begin));
- break;
- case 4:
- value_ = isc::util::readUint32(&(*begin));
- 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;
- unpackOptions(OptionBuffer(begin, end));
- }
-
- /// @brief Set option value.
- ///
- /// @param value new option value.
- void setValue(T value) { value_ = value; }
-
- /// @brief Return option value.
- ///
- /// @return option value.
- T getValue() const { return value_; }
-
- /// @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 + sizeof(T);
- // length of all suboptions
- for (Option::OptionCollection::iterator it = options_.begin();
- it != options_.end();
- ++it) {
- length += (*it).second->len();
- }
- return (length);
- }
-
-private:
-
- T value_; ///< Value conveyed by the option.
-};
-
-} // isc::dhcp namespace
-} // isc namespace
-
-#endif // OPTION6_INT_H
diff --git a/src/lib/dhcp/option6_int_array.h b/src/lib/dhcp/option6_int_array.h
deleted file mode 100644
index 3b64213..0000000
--- a/src/lib/dhcp/option6_int_array.h
+++ /dev/null
@@ -1,228 +0,0 @@
-// 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 <dhcp/libdhcp++.h>
-#include <dhcp/option.h>
-#include <dhcp/option_data_types.h>
-#include <util/io_utilities.h>
-
-#include <stdint.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.
-///
-/// @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.
-///
-/// @param T data field type (see above).
-template<typename T>
-class Option6IntArray: public Option {
-
-public:
-
- /// @brief Constructor.
- ///
- /// Creates option with empty values vector.
- ///
- /// @param type option type.
- ///
- /// @throw isc::dhcp::InvalidDataType if data field type provided
- /// as template parameter is not a supported integer type.
- Option6IntArray(uint16_t type)
- : Option(Option::V6, type),
- values_(0) {
- if (!OptionDataTypeTraits<T>::integer_type) {
- isc_throw(dhcp::InvalidDataType, "non-integer type");
- }
- }
-
- /// @brief Constructor.
- ///
- /// @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.
- Option6IntArray(uint16_t type, const OptionBuffer& buf)
- : Option(Option::V6, 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 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).
- ///
- /// @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.
- Option6IntArray(uint16_t type, OptionBufferConstIter begin,
- OptionBufferConstIter end)
- : Option(Option::V6, type) {
- if (!OptionDataTypeTraits<T>::integer_type) {
- isc_throw(dhcp::InvalidDataType, "non-integer 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::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.
- void pack(isc::util::OutputBuffer& buf) {
- buf.writeUint16(type_);
- buf.writeUint16(len() - OPTION6_HDR_LEN);
- for (int 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, "option " << 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)));
- break;
- case 4:
- values_.push_back(isc::util::readUint32(&(*begin)));
- 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() {
- 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:
-
- std::vector<T> values_;
-};
-
-} // isc::dhcp namespace
-} // isc namespace
-
-#endif // OPTION6_INT_ARRAY_H
diff --git a/src/lib/dhcp/option_data_types.h b/src/lib/dhcp/option_data_types.h
index ff5789d..e53fa6e 100644
--- a/src/lib/dhcp/option_data_types.h
+++ b/src/lib/dhcp/option_data_types.h
@@ -70,7 +70,7 @@ enum OptionDataType {
/// @brief Trait class for data types supported in DHCP option definitions.
///
/// This is useful to check whether the type specified as template parameter
-/// is supported by classes like Option6Int, Option6IntArray and some template
+/// is supported by classes like OptionInt, OptionIntArray and some template
/// factory functions in OptionDefinition class.
template<typename T>
struct OptionDataTypeTraits {
diff --git a/src/lib/dhcp/option_definition.cc b/src/lib/dhcp/option_definition.cc
index 2248bd7..260d3e5 100644
--- a/src/lib/dhcp/option_definition.cc
+++ b/src/lib/dhcp/option_definition.cc
@@ -17,10 +17,10 @@
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
-#include <dhcp/option6_int_array.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_definition.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
#include <util/encode/hex.h>
using namespace std;
@@ -97,19 +97,19 @@ OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
factoryInteger<int8_t>(u, type, begin, end));
case OPT_UINT16_TYPE:
- return (array_type_ ? factoryIntegerArray<uint16_t>(type, begin, end) :
+ return (array_type_ ? factoryIntegerArray<uint16_t>(u, type, begin, end) :
factoryInteger<uint16_t>(u, type, begin, end));
case OPT_INT16_TYPE:
- return (array_type_ ? factoryIntegerArray<uint16_t>(type, begin, end) :
+ return (array_type_ ? factoryIntegerArray<uint16_t>(u, type, begin, end) :
factoryInteger<int16_t>(u, type, begin, end));
case OPT_UINT32_TYPE:
- return (array_type_ ? factoryIntegerArray<uint32_t>(type, begin, end) :
+ return (array_type_ ? factoryIntegerArray<uint32_t>(u, type, begin, end) :
factoryInteger<uint32_t>(u, type, begin, end));
case OPT_INT32_TYPE:
- return (array_type_ ? factoryIntegerArray<uint32_t>(type, begin, end) :
+ return (array_type_ ? factoryIntegerArray<uint32_t>(u, type, begin, end) :
factoryInteger<int32_t>(u, type, begin, end));
case OPT_IPV4_ADDRESS_TYPE:
diff --git a/src/lib/dhcp/option_definition.h b/src/lib/dhcp/option_definition.h
index ca40428..9f6bef2 100644
--- a/src/lib/dhcp/option_definition.h
+++ b/src/lib/dhcp/option_definition.h
@@ -48,25 +48,25 @@ class OptionDefinition;
/// @brief Pointer to option definition object.
typedef boost::shared_ptr<OptionDefinition> OptionDefinitionPtr;
-/// @brief Forward declaration to Option6Int.
+/// @brief Forward declaration to OptionInt.
///
-/// This forward declaration is needed to access Option6Int class
-/// without having to include option6_int.h header. This is because
-/// this header includes libdhcp++.h and this causes circular
-/// inclusion between libdhcp++.h, option_definition.h and
+/// 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
/// option6_int.h.
template<typename T>
-class Option6Int;
+class OptionInt;
-/// @brief Forward declaration to Option6IntArray.
+/// @brief Forward declaration to OptionIntArray.
///
-/// This forward declaration is needed to access Option6IntArray class
-/// without having to include option6_int_array.h header. This is because
-/// this header includes libdhcp++.h and this causes circular
-/// inclusion between libdhcp++.h, option_definition.h and
-/// option6_int_array.h.
+/// 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.
template<typename T>
-class Option6IntArray;
+class OptionIntArray;
/// @brief Base class representing a DHCP option definition.
///
@@ -344,6 +344,7 @@ public:
/// @brief Factory function to create option with integer value.
///
+ /// @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.
@@ -351,15 +352,16 @@ public:
///
/// @throw isc::OutOfRange if provided option buffer length is invalid.
template<typename T>
- static OptionPtr factoryInteger(Option::Universe, uint16_t type,
+ static OptionPtr factoryInteger(Option::Universe u, uint16_t type,
OptionBufferConstIter begin,
OptionBufferConstIter end) {
- OptionPtr option(new Option6Int<T>(type, begin, end));
+ OptionPtr option(new OptionInt<T>(u, type, begin, end));
return (option);
}
/// @brief Factory function to create option with array of integer values.
///
+ /// @param 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.
@@ -367,10 +369,11 @@ public:
///
/// @throw isc::OutOfRange if provided option buffer length is invalid.
template<typename T>
- static OptionPtr factoryIntegerArray(uint16_t type,
+ static OptionPtr factoryIntegerArray(Option::Universe u,
+ uint16_t type,
OptionBufferConstIter begin,
OptionBufferConstIter end) {
- OptionPtr option(new Option6IntArray<T>(type, begin, end));
+ OptionPtr option(new OptionIntArray<T>(u, type, begin, end));
return (option);
}
diff --git a/src/lib/dhcp/option_int.h b/src/lib/dhcp/option_int.h
new file mode 100644
index 0000000..ebb1641
--- /dev/null
+++ b/src/lib/dhcp/option_int.h
@@ -0,0 +1,194 @@
+// 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 OPTION_INT_H
+#define OPTION_INT_H
+
+#include <dhcp/libdhcp++.h>
+#include <dhcp/option.h>
+#include <dhcp/option_data_types.h>
+#include <util/io_utilities.h>
+
+#include <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// This template class represents DHCP option with single value.
+/// This value is of integer type and 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 OptionInt: public Option {
+
+public:
+ /// @brief Constructor.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @param type option type.
+ /// @param value option value.
+ ///
+ /// @throw isc::dhcp::InvalidDataType if data field type provided
+ /// as template parameter is not a supported integer type.
+ OptionInt(Option::Universe u, uint16_t type, T value)
+ : Option(u, type), value_(value) {
+ if (!OptionDataTypeTraits<T>::integer_type) {
+ isc_throw(dhcp::InvalidDataType, "non-integer type");
+ }
+ }
+
+ /// @brief Constructor.
+ ///
+ /// This constructor creates option from a buffer. This construtor
+ /// 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 shorter than data size.
+ /// @throw isc::dhcp::InvalidDataType if data field type provided
+ /// as template parameter is not a supported integer type.
+ OptionInt(Option::Universe u, 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);
+ }
+
+ /// 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::dhcp::InvalidDataType if size of a data field 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.
+ void pack(isc::util::OutputBuffer& buf) {
+ // Pack option header.
+ packHeader(buf);
+ // 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(value_);
+ break;
+ case 2:
+ buf.writeUint16(value_);
+ break;
+ case 4:
+ buf.writeUint32(value_);
+ break;
+ default:
+ isc_throw(dhcp::InvalidDataType, "non-integer type");
+ }
+ packOptions(buf);
+ }
+
+ /// @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::OutOfRange if provided buffer is shorter than data size.
+ /// @throw isc::dhcp::InvalidDataType if size of a data field 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) < sizeof(T)) {
+ isc_throw(OutOfRange, "Option " << getType() << " truncated");
+ }
+ // @todo consider what to do if buffer is longer than data type.
+
+ // 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:
+ value_ = *begin;
+ break;
+ case 2:
+ value_ = isc::util::readUint16(&(*begin));
+ break;
+ case 4:
+ value_ = isc::util::readUint32(&(*begin));
+ 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;
+ unpackOptions(OptionBuffer(begin, end));
+ }
+
+ /// @brief Set option value.
+ ///
+ /// @param value new option value.
+ void setValue(T value) { value_ = value; }
+
+ /// @brief Return option value.
+ ///
+ /// @return option value.
+ T getValue() const { return value_; }
+
+ /// @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() {
+ // Calculate the length of the header.
+ uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
+ // The data length is equal to size of T.
+ length += sizeof(T);;
+ // length of all suboptions
+ for (Option::OptionCollection::iterator it = options_.begin();
+ it != options_.end();
+ ++it) {
+ length += (*it).second->len();
+ }
+ return (length);
+ }
+
+private:
+
+ T value_; ///< Value conveyed by the option.
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif // OPTION_INT_H
diff --git a/src/lib/dhcp/option_int_array.h b/src/lib/dhcp/option_int_array.h
new file mode 100644
index 0000000..5004152
--- /dev/null
+++ b/src/lib/dhcp/option_int_array.h
@@ -0,0 +1,234 @@
+// 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 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 <stdint.h>
+
+namespace isc {
+namespace dhcp {
+
+/// 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.
+///
+/// @param T data field type (see above).
+template<typename T>
+class OptionIntArray: public Option {
+
+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 construtor
+ /// 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);
+ }
+
+ /// 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::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.
+ void pack(isc::util::OutputBuffer& buf) {
+ // Pack option header.
+ packHeader(buf);
+ // Pack option data.
+ for (int 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, "option " << 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)));
+ break;
+ case 4:
+ values_.push_back(isc::util::readUint32(&(*begin)));
+ 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() {
+ uint16_t length = (getUniverse() == Option::V4) ? OPTION4_HDR_LEN : OPTION6_HDR_LEN;
+ length += 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:
+
+ std::vector<T> values_;
+};
+
+} // isc::dhcp namespace
+} // isc namespace
+
+#endif // OPTION_INT_ARRAY_H
diff --git a/src/lib/dhcp/pkt4.cc b/src/lib/dhcp/pkt4.cc
index 15c885c..15c8f4e 100644
--- a/src/lib/dhcp/pkt4.cc
+++ b/src/lib/dhcp/pkt4.cc
@@ -15,6 +15,7 @@
#include <asiolink/io_address.h>
#include <dhcp/dhcp4.h>
#include <dhcp/libdhcp++.h>
+#include <dhcp/option_int.h>
#include <dhcp/pkt4.h>
#include <exceptions/exceptions.h>
@@ -188,9 +189,10 @@ Pkt4::unpack() {
}
void Pkt4::check() {
- boost::shared_ptr<Option> typeOpt = getOption(DHO_DHCP_MESSAGE_TYPE);
+ boost::shared_ptr<OptionInt<uint8_t> > typeOpt =
+ boost::dynamic_pointer_cast<OptionInt<uint8_t> >(getOption(DHO_DHCP_MESSAGE_TYPE));
if (typeOpt) {
- uint8_t msg_type = typeOpt->getUint8();
+ uint8_t msg_type = typeOpt->getValue();
if (msg_type > DHCPLEASEACTIVE) {
isc_throw(BadValue, "Invalid DHCP message type received: "
<< msg_type);
diff --git a/src/lib/dhcp/std_option_defs.h b/src/lib/dhcp/std_option_defs.h
index d66dcf8..048be6a 100644
--- a/src/lib/dhcp/std_option_defs.h
+++ b/src/lib/dhcp/std_option_defs.h
@@ -25,7 +25,7 @@ namespace {
/// @param name name of the array being declared.
/// @param types data types of fields that belong to the record.
#ifndef RECORD_DECL
-#define RECORD_DECL(name, types...) static OptionDataType name[] = { types }
+#define RECORD_DECL(name, types...) const OptionDataType name[] = { types }
#endif
/// @brief A pair of values: one pointing to the array holding types of
@@ -44,41 +44,186 @@ using namespace isc::dhcp;
/// @brief Parameters being used to make up an option definition.
struct OptionDefParams {
- const char* name; // option name
- uint16_t code; // option code
- OptionDataType type; // data type
- bool array; // is array
- OptionDataType* records; // record fields
- size_t records_size; // number of fields in a record
+ const char* name; // option name
+ uint16_t code; // option code
+ OptionDataType type; // data type
+ bool array; // is array
+ const OptionDataType* records; // record fields
+ size_t records_size; // number of fields in a record
};
+// fqdn option record fields.
+//
+// Note that the flags field indicates the type of domain
+// name encoding. There is a choice between deprecated
+// ASCII encoding and compressed encoding described in
+// RFC 1035, section 3.1. The latter could be handled
+// by OPT_FQDN_TYPE but we can't use it here because
+// clients may request ASCII encoding.
+RECORD_DECL(FQDN_RECORDS, OPT_UINT8_TYPE, OPT_UINT8_TYPE, OPT_STRING_TYPE);
+
+/// @brief Definitions of standard DHCPv4 options.
+const OptionDefParams OPTION_DEF_PARAMS4[] = {
+ { "subnet-mask", DHO_SUBNET_MASK, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+ { "time-offset", DHO_TIME_OFFSET, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "routers", DHO_ROUTERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "time-servers", DHO_TIME_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "name-servers", DHO_NAME_SERVERS, OPT_IPV4_ADDRESS_TYPE,
+ false },
+ { "domain-name-servers", DHO_DOMAIN_NAME_SERVERS,
+ OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "log-servers", DHO_LOG_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "cookie-servers", DHO_COOKIE_SERVERS, OPT_IPV4_ADDRESS_TYPE,
+ true },
+ { "lpr-servers", DHO_LPR_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "impress-servers", DHO_IMPRESS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "resource-location-servers", DHO_RESOURCE_LOCATION_SERVERS,
+ OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "host-name", DHO_HOST_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+ { "boot-size", DHO_BOOT_SIZE, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+ { "merit-dump", DHO_MERIT_DUMP, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+ { "domain-name", DHO_DOMAIN_NAME, OPT_FQDN_TYPE, false, NO_RECORD_DEF },
+ { "swap-server", DHO_SWAP_SERVER, OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+ { "root-path", DHO_ROOT_PATH, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+ { "extensions-path", DHO_EXTENSIONS_PATH, OPT_STRING_TYPE,
+ false },
+ { "ip-forwarding", DHO_IP_FORWARDING, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "non-local-source-routing", DHO_NON_LOCAL_SOURCE_ROUTING,
+ OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "policy-filter", DHO_POLICY_FILTER, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "max-dgram-reassembly", DHO_MAX_DGRAM_REASSEMBLY,
+ OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+ { "default-ip-ttl", DHO_DEFAULT_IP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+ { "path-mtu-aging-timeout", DHO_PATH_MTU_AGING_TIMEOUT,
+ OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "path-mtu-plateau-table", DHO_PATH_MTU_PLATEAU_TABLE,
+ OPT_UINT16_TYPE, true, NO_RECORD_DEF },
+ { "interface-mtu", DHO_INTERFACE_MTU, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+ { "all-subnets-local", DHO_ALL_SUBNETS_LOCAL,
+ OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "broadcast-address", DHO_BROADCAST_ADDRESS,
+ OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+ { "perform-mask-discovery", DHO_PERFORM_MASK_DISCOVERY,
+ OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "mask-supplier", DHO_MASK_SUPPLIER, OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "router-discovery", DHO_ROUTER_DISCOVERY,
+ OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "router-solicitation-address", DHO_ROUTER_SOLICITATION_ADDRESS,
+ OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+ { "static-routes", DHO_STATIC_ROUTES,
+ OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "trailer-encapsulation", DHO_TRAILER_ENCAPSULATION,
+ OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "arp-cache-timeout", DHO_ARP_CACHE_TIMEOUT,
+ OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "ieee802-3-encapsulation", DHO_IEEE802_3_ENCAPSULATION,
+ OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "default-tcp-ttl", DHO_DEFAULT_TCP_TTL, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+ { "tcp-keepalive-internal", DHO_TCP_KEEPALIVE_INTERVAL,
+ OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "tcp-keepalive-garbage", DHO_TCP_KEEPALIVE_GARBAGE,
+ OPT_BOOLEAN_TYPE, false, NO_RECORD_DEF },
+ { "nis-domain", DHO_NIS_DOMAIN, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+ { "nis-servers", DHO_NIS_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "ntp-servers", DHO_NTP_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "vendor-encapsulated-options", DHO_VENDOR_ENCAPSULATED_OPTIONS,
+ OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "netbios-name-servers", DHO_NETBIOS_NAME_SERVERS,
+ OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "netbios-dd-server", DHO_NETBIOS_DD_SERVER,
+ OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "netbios-node-type", DHO_NETBIOS_NODE_TYPE,
+ OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+ { "netbios-scope", DHO_NETBIOS_SCOPE, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+ { "font-servers", DHO_FONT_SERVERS, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "x-display-manager", DHO_X_DISPLAY_MANAGER,
+ OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "dhcp-requested-address", DHO_DHCP_REQUESTED_ADDRESS,
+ OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-lease-time", DHO_DHCP_LEASE_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-option-overload", DHO_DHCP_OPTION_OVERLOAD,
+ OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-message-type", DHO_DHCP_MESSAGE_TYPE, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-server-identifier", DHO_DHCP_SERVER_IDENTIFIER,
+ OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-parameter-request-list", DHO_DHCP_PARAMETER_REQUEST_LIST,
+ OPT_UINT8_TYPE, true, NO_RECORD_DEF },
+ { "dhcp-message", DHO_DHCP_MESSAGE, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-max-message-size", DHO_DHCP_MAX_MESSAGE_SIZE,
+ OPT_UINT16_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-renewal-time", DHO_DHCP_RENEWAL_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-rebinding-time", DHO_DHCP_REBINDING_TIME,
+ OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "vendor-class-identifier", DHO_VENDOR_CLASS_IDENTIFIER,
+ OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "dhcp-client-identifier", DHO_DHCP_CLIENT_IDENTIFIER,
+ OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "nwip-domain-name", DHO_NWIP_DOMAIN_NAME, OPT_STRING_TYPE, false, NO_RECORD_DEF },
+ { "nwip-suboptions", DHO_NWIP_SUBOPTIONS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "user-class", DHO_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "fqdn", DHO_FQDN, OPT_RECORD_TYPE, false, RECORD_DEF(FQDN_RECORDS) },
+ { "dhcp-agent-options", DHO_DHCP_AGENT_OPTIONS,
+ OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ // Unfortunatelly the AUTHENTICATE option contains a 64-bit
+ // data field called 'replay-detection' that can't be added
+ // as a record field to a custom option. Also, there is no
+ // dedicated option class to handle it so we simply return
+ // binary option type for now.
+ // @todo implement a class to handle AUTH option.
+ { "authenticate", DHO_AUTHENTICATE, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "client-last-transaction-time", DHO_CLIENT_LAST_TRANSACTION_TIME,
+ OPT_UINT32_TYPE, false, NO_RECORD_DEF },
+ { "associated-ip", DHO_ASSOCIATED_IP, OPT_IPV4_ADDRESS_TYPE, true, NO_RECORD_DEF },
+ { "subnet-selection", DHO_SUBNET_SELECTION,
+ OPT_IPV4_ADDRESS_TYPE, false, NO_RECORD_DEF },
+ // The following options need a special encoding of data
+ // being carried by them. Therefore, there is no way they can
+ // be handled by OptionCustom. We may need to implement
+ // dedicated classes to handle them. Until that happens
+ // let's treat them as 'binary' options.
+ { "domain-search", DHO_DOMAIN_SEARCH, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "vivco-suboptions", DHO_VIVCO_SUBOPTIONS,
+ OPT_BINARY_TYPE, false, NO_RECORD_DEF },
+ { "vivso-suboptions", DHO_VIVSO_SUBOPTIONS, OPT_BINARY_TYPE,
+ false }
+
+ // @todo add definitions for all remaning options.
+};
+
+/// Number of option definitions defined.
+const int OPTION_DEF_PARAMS_SIZE4 =
+ sizeof(OPTION_DEF_PARAMS4) / sizeof(OPTION_DEF_PARAMS4[0]);
+
+
+/// Start Definition of DHCPv6 options
+
// client-fqdn
-RECORD_DECL(clientFqdnRecords, OPT_UINT8_TYPE, OPT_FQDN_TYPE);
+RECORD_DECL(CLIENT_FQDN_RECORDS, OPT_UINT8_TYPE, OPT_FQDN_TYPE);
// geoconf-civic
-RECORD_DECL(geoconfCivicRecords, OPT_UINT8_TYPE, OPT_UINT16_TYPE,
+RECORD_DECL(GEOCONF_CIVIC_RECORDS, OPT_UINT8_TYPE, OPT_UINT16_TYPE,
OPT_BINARY_TYPE);
// iaddr
-RECORD_DECL(iaaddrRecords, OPT_IPV6_ADDRESS_TYPE, OPT_UINT32_TYPE,
+RECORD_DECL(IAADDR_RECORDS, OPT_IPV6_ADDRESS_TYPE, OPT_UINT32_TYPE,
OPT_UINT32_TYPE);
// ia-na
-RECORD_DECL(ianaRecords, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
+RECORD_DECL(IA_NA_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
// ia-pd
-RECORD_DECL(iapdRecords, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
+RECORD_DECL(IA_PD_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE, OPT_UINT32_TYPE);
// ia-prefix
-RECORD_DECL(iaPrefixRecords, OPT_UINT32_TYPE, OPT_UINT32_TYPE,
+RECORD_DECL(IA_PREFIX_RECORDS, OPT_UINT32_TYPE, OPT_UINT32_TYPE,
OPT_UINT8_TYPE, OPT_BINARY_TYPE);
// lq-query
-RECORD_DECL(lqQueryRecords, OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE);
+RECORD_DECL(LQ_QUERY_RECORDS, OPT_UINT8_TYPE, OPT_IPV6_ADDRESS_TYPE);
// lq-relay-data
-RECORD_DECL(lqRelayData, OPT_IPV6_ADDRESS_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(LQ_RELAY_DATA_RECORDS, OPT_IPV6_ADDRESS_TYPE, OPT_BINARY_TYPE);
// remote-id
-RECORD_DECL(remoteIdRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(REMOTE_ID_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
// status-code
-RECORD_DECL(statusCodeRecords, OPT_UINT16_TYPE, OPT_STRING_TYPE);
+RECORD_DECL(STATUS_CODE_RECORDS, OPT_UINT16_TYPE, OPT_STRING_TYPE);
// vendor-class
-RECORD_DECL(vendorClassRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(VENDOR_CLASS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
// vendor-opts
-RECORD_DECL(vendorOptsRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
+RECORD_DECL(VENDOR_OPTS_RECORDS, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
/// Standard DHCPv6 option definitions.
///
@@ -90,12 +235,12 @@ RECORD_DECL(vendorOptsRecords, OPT_UINT32_TYPE, OPT_BINARY_TYPE);
/// This however does not work on Solaris (GCC) which issues a
/// warning about lack of initializers for some struct members
/// causing build to fail.
-static const OptionDefParams OPTION_DEF_PARAMS6[] = {
+const OptionDefParams OPTION_DEF_PARAMS6[] = {
{ "clientid", D6O_CLIENTID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
{ "serverid", D6O_SERVERID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
- { "ia-na", D6O_IA_NA, OPT_RECORD_TYPE, false, RECORD_DEF(ianaRecords) },
+ { "ia-na", D6O_IA_NA, OPT_RECORD_TYPE, false, RECORD_DEF(IA_NA_RECORDS) },
{ "ia-ta", D6O_IA_TA, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
- { "iaaddr", D6O_IAADDR, OPT_RECORD_TYPE, false, RECORD_DEF(iaaddrRecords) },
+ { "iaaddr", D6O_IAADDR, OPT_RECORD_TYPE, false, RECORD_DEF(IAADDR_RECORDS) },
{ "oro", D6O_ORO, OPT_UINT16_TYPE, true, NO_RECORD_DEF },
{ "preference", D6O_PREFERENCE, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
{ "elapsed-time", D6O_ELAPSED_TIME, OPT_UINT16_TYPE, false, NO_RECORD_DEF },
@@ -109,13 +254,13 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
{ "auth", D6O_AUTH, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
{ "unicast", D6O_UNICAST, OPT_IPV6_ADDRESS_TYPE, false, NO_RECORD_DEF },
{ "status-code", D6O_STATUS_CODE, OPT_RECORD_TYPE, false,
- RECORD_DEF(statusCodeRecords) },
+ RECORD_DEF(STATUS_CODE_RECORDS) },
{ "rapid-commit", D6O_RAPID_COMMIT, OPT_EMPTY_TYPE, false, NO_RECORD_DEF },
{ "user-class", D6O_USER_CLASS, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
{ "vendor-class", D6O_VENDOR_CLASS, OPT_RECORD_TYPE, false,
- RECORD_DEF(vendorClassRecords) },
+ RECORD_DEF(VENDOR_CLASS_RECORDS) },
{ "vendor-opts", D6O_VENDOR_OPTS, OPT_RECORD_TYPE, false,
- RECORD_DEF(vendorOptsRecords) },
+ RECORD_DEF(VENDOR_OPTS_RECORDS) },
{ "interface-id", D6O_INTERFACE_ID, OPT_BINARY_TYPE, false, NO_RECORD_DEF },
{ "reconf-msg", D6O_RECONF_MSG, OPT_UINT8_TYPE, false, NO_RECORD_DEF },
{ "reconf-accept", D6O_RECONF_ACCEPT, OPT_EMPTY_TYPE, false,
@@ -127,9 +272,9 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
{ "dns-servers", D6O_NAME_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
NO_RECORD_DEF },
{ "domain-search", D6O_DOMAIN_SEARCH, OPT_FQDN_TYPE, true, NO_RECORD_DEF },
- { "ia-pd", D6O_IA_PD, OPT_RECORD_TYPE, false, RECORD_DEF(iapdRecords) },
+ { "ia-pd", D6O_IA_PD, OPT_RECORD_TYPE, false, RECORD_DEF(IA_PD_RECORDS) },
{ "iaprefix", D6O_IAPREFIX, OPT_RECORD_TYPE, false,
- RECORD_DEF(iaPrefixRecords) },
+ RECORD_DEF(IA_PREFIX_RECORDS) },
{ "nis-servers", D6O_NIS_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
NO_RECORD_DEF },
{ "nisp-servers", D6O_NISP_SERVERS, OPT_IPV6_ADDRESS_TYPE, true,
@@ -147,13 +292,13 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
{ "bcmcs-server-addr", D6O_BCMCS_SERVER_A, OPT_IPV6_ADDRESS_TYPE, true,
NO_RECORD_DEF },
{ "geoconf-civic", D6O_GEOCONF_CIVIC, OPT_RECORD_TYPE, false,
- RECORD_DEF(geoconfCivicRecords) },
+ RECORD_DEF(GEOCONF_CIVIC_RECORDS) },
{ "remote-id", D6O_REMOTE_ID, OPT_RECORD_TYPE, false,
- RECORD_DEF(remoteIdRecords) },
+ RECORD_DEF(REMOTE_ID_RECORDS) },
{ "subscriber-id", D6O_SUBSCRIBER_ID, OPT_BINARY_TYPE, false,
NO_RECORD_DEF },
{ "client-fqdn", D6O_CLIENT_FQDN, OPT_RECORD_TYPE, false,
- RECORD_DEF(clientFqdnRecords) },
+ RECORD_DEF(CLIENT_FQDN_RECORDS) },
{ "pana-agent", D6O_PANA_AGENT, OPT_IPV6_ADDRESS_TYPE, true,
NO_RECORD_DEF },
{ "new-posix-timezone", D6O_NEW_POSIX_TIMEZONE, OPT_STRING_TYPE, false,
@@ -162,11 +307,11 @@ static const OptionDefParams OPTION_DEF_PARAMS6[] = {
NO_RECORD_DEF },
{ "ero", D6O_ERO, OPT_UINT16_TYPE, true, NO_RECORD_DEF },
{ "lq-query", D6O_LQ_QUERY, OPT_RECORD_TYPE, false,
- RECORD_DEF(lqQueryRecords) },
+ RECORD_DEF(LQ_QUERY_RECORDS) },
{ "client-data", D6O_CLIENT_DATA, OPT_EMPTY_TYPE, false, NO_RECORD_DEF },
{ "clt-time", D6O_CLT_TIME, OPT_UINT32_TYPE, false, NO_RECORD_DEF },
{ "lq-relay-data", D6O_LQ_RELAY_DATA, OPT_RECORD_TYPE, false,
- RECORD_DEF(lqRelayData) },
+ RECORD_DEF(LQ_RELAY_DATA_RECORDS) },
{ "lq-client-link", D6O_LQ_CLIENT_LINK, OPT_IPV6_ADDRESS_TYPE, true,
NO_RECORD_DEF }
diff --git a/src/lib/dhcp/tests/Makefile.am b/src/lib/dhcp/tests/Makefile.am
index 5799d58..4d177d1 100644
--- a/src/lib/dhcp/tests/Makefile.am
+++ b/src/lib/dhcp/tests/Makefile.am
@@ -33,8 +33,8 @@ libdhcp___unittests_SOURCES += option4_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option6_addrlst_unittest.cc
libdhcp___unittests_SOURCES += option6_ia_unittest.cc
libdhcp___unittests_SOURCES += option6_iaaddr_unittest.cc
-libdhcp___unittests_SOURCES += option6_int_array_unittest.cc
-libdhcp___unittests_SOURCES += option6_int_unittest.cc
+libdhcp___unittests_SOURCES += option_int_unittest.cc
+libdhcp___unittests_SOURCES += option_int_array_unittest.cc
libdhcp___unittests_SOURCES += option_data_types_unittest.cc
libdhcp___unittests_SOURCES += option_definition_unittest.cc
libdhcp___unittests_SOURCES += option_custom_unittest.cc
diff --git a/src/lib/dhcp/tests/libdhcp++_unittest.cc b/src/lib/dhcp/tests/libdhcp++_unittest.cc
index 8ead521..e44ef58 100644
--- a/src/lib/dhcp/tests/libdhcp++_unittest.cc
+++ b/src/lib/dhcp/tests/libdhcp++_unittest.cc
@@ -17,12 +17,13 @@
#include <dhcp/dhcp4.h>
#include <dhcp/dhcp6.h>
#include <dhcp/libdhcp++.h>
+#include <dhcp/option4_addrlst.h>
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
-#include <dhcp/option6_int_array.h>
#include <dhcp/option_custom.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
#include <util/buffer.h>
#include <gtest/gtest.h>
@@ -55,23 +56,69 @@ public:
return OptionPtr(option);
}
- /// @brief Test option option definition.
+ /// @brief Test DHCPv4 option definition.
///
/// This function tests if option definition for standard
/// option has been initialized correctly.
///
/// @param code option code.
- /// @param bug buffer to be used to create option instance.
+ /// @param begin iterator pointing a begining of a buffer to
+ /// be used to create option instance.
+ /// @param end iterator pointing an end of a buffer to be
+ /// used to create option instance.
+ /// @param expected_type type of the option created by the
+ /// factory function returned by the option definition.
+ static void testStdOptionDefs4(const uint16_t code,
+ const OptionBufferConstIter begin,
+ const OptionBufferConstIter end,
+ const std::type_info& expected_type) {
+ // Use V4 universe.
+ testStdOptionDefs(Option::V4, code, begin, end, expected_type);
+ }
+
+ /// @brief Test DHCPv6 option definition.
+ ///
+ /// This function tests if option definition for standard
+ /// option has been initialized correctly.
+ ///
+ /// @param code option code.
+ /// @param begin iterator pointing a begining of a buffer to
+ /// be used to create option instance.
+ /// @param end iterator pointing an end of a buffer to be
+ /// used to create option instance.
/// @param expected_type type of the option created by the
/// factory function returned by the option definition.
static void testStdOptionDefs6(const uint16_t code,
- const OptionBuffer& buf,
- const std::type_info& expected_type) {
+ const OptionBufferConstIter begin,
+ const OptionBufferConstIter end,
+ const std::type_info& expected_type) {
+ // Use V6 universe.
+ testStdOptionDefs(Option::V6, code, begin, end, expected_type);
+ }
+private:
+
+ /// @brief Test DHCPv4 or DHCPv6 option definition.
+ ///
+ /// This function tests if option definition for standard
+ /// option has been initialized correctly.
+ ///
+ /// @param code option code.
+ /// @param begin iterator pointing a begining of a buffer to
+ /// be used to create option instance.
+ /// @param end iterator pointing an end of a buffer to be
+ /// used to create option instance.
+ /// @param expected_type type of the option created by the
+ /// factory function returned by the option definition.
+ static void testStdOptionDefs(const Option::Universe u,
+ const uint16_t code,
+ const OptionBufferConstIter begin,
+ const OptionBufferConstIter end,
+ const std::type_info& expected_type) {
// Get all option definitions, we will use them to extract
// the definition for a particular option code.
// We don't have to initialize option definitions here because they
// are initialized in the class's constructor.
- OptionDefContainer options = LibDHCP::getOptionDefs(Option::V6);
+ OptionDefContainer options = LibDHCP::getOptionDefs(u);
// Get the container index #1. This one allows for searching
// option definitions using option code.
const OptionDefContainerTypeIndex& idx = options.get<1>();
@@ -79,20 +126,25 @@ public:
// For standard options we expect that the range returned
// will contain single option as their codes are unique.
OptionDefContainerTypeRange range = idx.equal_range(code);
- ASSERT_EQ(1, std::distance(range.first, range.second));
+ ASSERT_EQ(1, std::distance(range.first, range.second))
+ << "Standard option definition for the code " << code
+ << " has not been found.";
// If we have single option definition returned, the
// first iterator holds it.
OptionDefinitionPtr def = *(range.first);
// It should not happen that option definition is NULL but
// let's make sure (test should take things like that into
// account).
- ASSERT_TRUE(def);
+ ASSERT_TRUE(def) << "Option definition for the code "
+ << code << " is NULL.";
// Check that option definition is valid.
- ASSERT_NO_THROW(def->validate());
+ ASSERT_NO_THROW(def->validate())
+ << "Option definition for the option code " << code
+ << " is invalid";
OptionPtr option;
// Create the option.
- ASSERT_NO_THROW(option = def->optionFactory(Option::V6, code, buf))
- << "Option creation failed to option code " << code;
+ ASSERT_NO_THROW(option = def->optionFactory(u, code, begin, end))
+ << "Option creation failed for option code " << code;
// Make sure it is not NULL.
ASSERT_TRUE(option);
// And the actual object type is the one that we expect.
@@ -103,7 +155,8 @@ public:
}
};
-static const uint8_t packed[] = {
+// The DHCPv6 options in the wire format, used by multiple tests.
+const uint8_t v6packed[] = {
0, 1, 0, 5, 100, 101, 102, 103, 104, // CLIENT_ID (9 bytes)
0, 2, 0, 3, 105, 106, 107, // SERVER_ID (7 bytes)
0, 14, 0, 0, // RAPID_COMMIT (0 bytes)
@@ -207,8 +260,8 @@ TEST_F(LibDhcpTest, packOptions6) {
OutputBuffer assembled(512);
EXPECT_NO_THROW(LibDHCP::packOptions6(assembled, opts));
- EXPECT_EQ(sizeof(packed), assembled.getLength());
- EXPECT_EQ(0, memcmp(assembled.getData(), packed, sizeof(packed)));
+ EXPECT_EQ(sizeof(v6packed), assembled.getLength());
+ EXPECT_EQ(0, memcmp(assembled.getData(), v6packed, sizeof(v6packed)));
}
TEST_F(LibDhcpTest, unpackOptions6) {
@@ -220,10 +273,10 @@ TEST_F(LibDhcpTest, unpackOptions6) {
isc::dhcp::Option::OptionCollection options; // list of options
OptionBuffer buf(512);
- memcpy(&buf[0], packed, sizeof(packed));
+ memcpy(&buf[0], v6packed, sizeof(v6packed));
EXPECT_NO_THROW ({
- LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin() + sizeof(packed)),
+ LibDHCP::unpackOptions6(OptionBuffer(buf.begin(), buf.begin() + sizeof(v6packed)),
options);
});
@@ -234,14 +287,14 @@ TEST_F(LibDhcpTest, unpackOptions6) {
EXPECT_EQ(1, x->second->getType()); // this should be option 1
ASSERT_EQ(9, x->second->len()); // it should be of length 9
ASSERT_EQ(5, x->second->getData().size());
- EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed + 4, 5)); // data len=5
+ EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 4, 5)); // data len=5
x = options.find(2);
ASSERT_FALSE(x == options.end()); // option 2 should exist
EXPECT_EQ(2, x->second->getType()); // this should be option 2
ASSERT_EQ(7, x->second->len()); // it should be of length 7
ASSERT_EQ(3, x->second->getData().size());
- EXPECT_EQ(0, memcmp(&x->second->getData()[0], packed + 13, 3)); // data len=3
+ EXPECT_EQ(0, memcmp(&x->second->getData()[0], v6packed + 13, 3)); // data len=3
x = options.find(14);
ASSERT_FALSE(x == options.end()); // option 14 should exist
@@ -254,11 +307,11 @@ TEST_F(LibDhcpTest, unpackOptions6) {
EXPECT_EQ(6, x->second->getType()); // this should be option 6
ASSERT_EQ(8, x->second->len()); // it should be of length 8
// Option with code 6 is the OPTION_ORO. This option is
- // represented by the Option6IntArray<uint16_t> class which
+ // represented by the OptionIntArray<uint16_t> class which
// comprises the set of uint16_t values. We need to cast the
// returned pointer to this type to get values stored in it.
- boost::shared_ptr<Option6IntArray<uint16_t> > opt_oro =
- boost::dynamic_pointer_cast<Option6IntArray<uint16_t> >(x->second);
+ boost::shared_ptr<OptionIntArray<uint16_t> > opt_oro =
+ boost::dynamic_pointer_cast<OptionIntArray<uint16_t> >(x->second);
// This value will be NULL if cast was unsuccessful. This is the case
// when returned option has different type than expected.
ASSERT_TRUE(opt_oro);
@@ -280,8 +333,8 @@ TEST_F(LibDhcpTest, unpackOptions6) {
// Option with code 8 is OPTION_ELAPSED_TIME. This option is
// represented by Option6Int<uint16_t> value that holds single
// uint16_t value.
- boost::shared_ptr<Option6Int<uint16_t> > opt_elapsed_time =
- boost::dynamic_pointer_cast<Option6Int<uint16_t> >(x->second);
+ boost::shared_ptr<OptionInt<uint16_t> > opt_elapsed_time =
+ boost::dynamic_pointer_cast<OptionInt<uint16_t> >(x->second);
// This value will be NULL if cast was unsuccessful. This is the case
// when returned option has different type than expected.
ASSERT_TRUE(opt_elapsed_time);
@@ -301,13 +354,17 @@ TEST_F(LibDhcpTest, unpackOptions6) {
EXPECT_TRUE(x == options.end()); // option 32000 not found */
}
-
+/// V4 Options being used to test pack/unpack operations.
+/// These are variable length options only so as there
+/// is no restriction on the data length being carried by them.
+/// For simplicity, we assign data of the length 3 for each
+/// of them.
static uint8_t v4Opts[] = {
- 12, 3, 0, 1, 2,
- 13, 3, 10, 11, 12,
- 14, 3, 20, 21, 22,
- 254, 3, 30, 31, 32,
- 128, 3, 40, 41, 42
+ 12, 3, 0, 1, 2, // Hostname
+ 60, 3, 10, 11, 12, // Class Id
+ 14, 3, 20, 21, 22, // Merit Dump File
+ 254, 3, 30, 31, 32, // Reserved
+ 128, 3, 40, 41, 42 // Vendor specific
};
TEST_F(LibDhcpTest, packOptions4) {
@@ -321,7 +378,7 @@ TEST_F(LibDhcpTest, packOptions4) {
}
OptionPtr opt1(new Option(Option::V4, 12, payload[0]));
- OptionPtr opt2(new Option(Option::V4, 13, payload[1]));
+ OptionPtr opt2(new Option(Option::V4, 60, payload[1]));
OptionPtr opt3(new Option(Option::V4, 14, payload[2]));
OptionPtr opt4(new Option(Option::V4,254, payload[3]));
OptionPtr opt5(new Option(Option::V4,128, payload[4]));
@@ -344,11 +401,11 @@ TEST_F(LibDhcpTest, packOptions4) {
TEST_F(LibDhcpTest, unpackOptions4) {
- vector<uint8_t> packed(v4Opts, v4Opts + sizeof(v4Opts));
+ vector<uint8_t> v4packed(v4Opts, v4Opts + sizeof(v4Opts));
isc::dhcp::Option::OptionCollection options; // list of options
ASSERT_NO_THROW(
- LibDHCP::unpackOptions4(packed, options);
+ LibDHCP::unpackOptions4(v4packed, options);
);
isc::dhcp::Option::OptionCollection::const_iterator x = options.find(12);
@@ -358,9 +415,9 @@ TEST_F(LibDhcpTest, unpackOptions4) {
EXPECT_EQ(5, x->second->len()); // total option length 5
EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4Opts+2, 3)); // data len=3
- x = options.find(13);
- ASSERT_FALSE(x == options.end()); // option 1 should exist
- EXPECT_EQ(13, x->second->getType()); // this should be option 13
+ x = options.find(60);
+ ASSERT_FALSE(x == options.end()); // option 2 should exist
+ EXPECT_EQ(60, x->second->getType()); // this should be option 60
ASSERT_EQ(3, x->second->getData().size()); // it should be of length 3
EXPECT_EQ(5, x->second->len()); // total option length 5
EXPECT_EQ(0, memcmp(&x->second->getData()[0], v4Opts+7, 3)); // data len=3
@@ -396,6 +453,235 @@ TEST_F(LibDhcpTest, unpackOptions4) {
EXPECT_TRUE(x == options.end()); // option 2 not found
}
+TEST_F(LibDhcpTest, stdOptionDefs4) {
+
+ // Create a buffer that holds dummy option data.
+ // It will be used to create most of the options.
+ std::vector<uint8_t> buf(48, 1);
+ OptionBufferConstIter begin = buf.begin();
+ OptionBufferConstIter end = buf.begin();
+
+ LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_MASK, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_TIME_OFFSET, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_ROUTERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_TIME_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NAME_SERVERS, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_LOG_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_COOKIE_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_LPR_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_IMPRESS_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_RESOURCE_LOCATION_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_HOST_NAME, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_BOOT_SIZE, begin, begin + 2,
+ typeid(OptionInt<uint16_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_MERIT_DUMP, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_NAME, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_SWAP_SERVER, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_ROOT_PATH, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_EXTENSIONS_PATH, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_IP_FORWARDING, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NON_LOCAL_SOURCE_ROUTING, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_POLICY_FILTER, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_MAX_DGRAM_REASSEMBLY, begin, begin + 2,
+ typeid(OptionInt<uint16_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_IP_TTL, begin, begin + 1,
+ typeid(OptionInt<uint8_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_AGING_TIMEOUT, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_PATH_MTU_PLATEAU_TABLE, begin, begin + 10,
+ typeid(OptionIntArray<uint16_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_INTERFACE_MTU, begin, begin + 2,
+ typeid(OptionInt<uint16_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_ALL_SUBNETS_LOCAL, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_BROADCAST_ADDRESS, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_PERFORM_MASK_DISCOVERY, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_MASK_SUPPLIER, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_DISCOVERY, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_ROUTER_SOLICITATION_ADDRESS, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_STATIC_ROUTES, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_TRAILER_ENCAPSULATION, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_ARP_CACHE_TIMEOUT, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_IEEE802_3_ENCAPSULATION, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DEFAULT_TCP_TTL, begin, begin + 1,
+ typeid(OptionInt<uint8_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_INTERVAL, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_TCP_KEEPALIVE_GARBAGE, begin, begin + 1,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NIS_DOMAIN, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NIS_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NTP_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_ENCAPSULATED_OPTIONS, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NAME_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_DD_SERVER, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_NODE_TYPE, begin, begin + 1,
+ typeid(OptionInt<uint8_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NETBIOS_SCOPE, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_FONT_SERVERS, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_X_DISPLAY_MANAGER, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REQUESTED_ADDRESS, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_LEASE_TIME, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_OPTION_OVERLOAD, begin, begin + 1,
+ typeid(OptionInt<uint8_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE_TYPE, begin, begin + 1,
+ typeid(OptionInt<uint8_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_SERVER_IDENTIFIER, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_PARAMETER_REQUEST_LIST, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MESSAGE, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_MAX_MESSAGE_SIZE, begin, begin + 2,
+ typeid(OptionInt<uint16_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_RENEWAL_TIME, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_REBINDING_TIME, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_VENDOR_CLASS_IDENTIFIER, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_CLIENT_IDENTIFIER, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NWIP_DOMAIN_NAME, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_NWIP_SUBOPTIONS, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_USER_CLASS, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_FQDN, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DHCP_AGENT_OPTIONS, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_AUTHENTICATE, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_CLIENT_LAST_TRANSACTION_TIME,
+ begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_ASSOCIATED_IP, begin, end,
+ typeid(Option4AddrLst));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_SUBNET_SELECTION, begin, end,
+ typeid(OptionCustom));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_DOMAIN_SEARCH, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_VIVCO_SUBOPTIONS, begin, end,
+ typeid(Option));
+
+ LibDhcpTest::testStdOptionDefs4(DHO_VIVSO_SUBOPTIONS, begin, end,
+ typeid(Option));
+}
+
// Test that definitions of standard options have been initialized
// correctly.
// @todo Only limited number of option definitions are now created
@@ -406,6 +692,8 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
// Create a buffer that holds dummy option data.
// It will be used to create most of the options.
std::vector<uint8_t> buf(48, 1);
+ OptionBufferConstIter begin = buf.begin();
+ OptionBufferConstIter end = buf.end();
// Prepare buffer holding an array of FQDNs.
const char data[] = {
@@ -428,122 +716,144 @@ TEST_F(LibDhcpTest, stdOptionDefs6) {
fqdn_buf.end());
// The actual test starts here for all supported option codes.
- LibDhcpTest::testStdOptionDefs6(D6O_CLIENTID, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_CLIENTID, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_SERVERID, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_SERVERID, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_IA_NA, buf, typeid(Option6IA));
+ LibDhcpTest::testStdOptionDefs6(D6O_IA_NA, begin, end,
+ typeid(Option6IA));
- LibDhcpTest::testStdOptionDefs6(D6O_IA_TA, buf,
- typeid(Option6Int<uint32_t>));
+ LibDhcpTest::testStdOptionDefs6(D6O_IA_TA, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_IAADDR, buf, typeid(Option6IAAddr));
+ LibDhcpTest::testStdOptionDefs6(D6O_IAADDR, begin, end,
+ typeid(Option6IAAddr));
- LibDhcpTest::testStdOptionDefs6(D6O_ORO, buf,
- typeid(Option6IntArray<uint16_t>));
+ LibDhcpTest::testStdOptionDefs6(D6O_ORO, begin, end,
+ typeid(OptionIntArray<uint16_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_PREFERENCE, buf,
- typeid(Option6Int<uint8_t>));
+ LibDhcpTest::testStdOptionDefs6(D6O_PREFERENCE, begin, begin + 1,
+ typeid(OptionInt<uint8_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_ELAPSED_TIME, buf,
- typeid(Option6Int<uint16_t>));
+ LibDhcpTest::testStdOptionDefs6(D6O_ELAPSED_TIME, begin, begin + 2,
+ typeid(OptionInt<uint16_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_RELAY_MSG, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_RELAY_MSG, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_STATUS_CODE, buf, typeid(OptionCustom));
+ LibDhcpTest::testStdOptionDefs6(D6O_STATUS_CODE, begin, end,
+ typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_RAPID_COMMIT, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_RAPID_COMMIT, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_USER_CLASS, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_USER_CLASS, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_CLASS, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_CLASS, begin, end,
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_OPTS, buf, typeid(OptionCustom));
+ LibDhcpTest::testStdOptionDefs6(D6O_VENDOR_OPTS, begin, end,
+ typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_INTERFACE_ID, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_INTERFACE_ID, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_RECONF_MSG, buf,
- typeid(Option6Int<uint8_t>));
+ LibDhcpTest::testStdOptionDefs6(D6O_RECONF_MSG, begin, begin + 1,
+ typeid(OptionInt<uint8_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_RECONF_ACCEPT, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_RECONF_ACCEPT, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_DNS, fqdn_buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_DNS, fqdn_buf.begin(),
+ fqdn_buf.end(),
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_ADDR, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_SIP_SERVERS_ADDR, begin, end,
typeid(Option6AddrLst));
- LibDhcpTest::testStdOptionDefs6(D6O_NAME_SERVERS, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_NAME_SERVERS, begin, end,
typeid(Option6AddrLst));
- LibDhcpTest::testStdOptionDefs6(D6O_DOMAIN_SEARCH, fqdn_buf,
- typeid(OptionCustom));
+ LibDhcpTest::testStdOptionDefs6(D6O_DOMAIN_SEARCH, fqdn_buf.begin(),
+ fqdn_buf.end(), typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_IA_PD, buf, typeid(Option6IA));
+ LibDhcpTest::testStdOptionDefs6(D6O_IA_PD, begin, end,
+ typeid(Option6IA));
- LibDhcpTest::testStdOptionDefs6(D6O_IAPREFIX, buf, typeid(OptionCustom));
+ LibDhcpTest::testStdOptionDefs6(D6O_IAPREFIX, begin, end,
+ typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_NIS_SERVERS, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_NIS_SERVERS, begin, end,
typeid(Option6AddrLst));
- LibDhcpTest::testStdOptionDefs6(D6O_NISP_SERVERS, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_NISP_SERVERS, begin, end,
typeid(Option6AddrLst));
- LibDhcpTest::testStdOptionDefs6(D6O_NIS_DOMAIN_NAME, fqdn_buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_NIS_DOMAIN_NAME, fqdn_buf.begin(),
+ fqdn_buf.end(),
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_NISP_DOMAIN_NAME, fqdn_buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_NISP_DOMAIN_NAME, fqdn_buf.begin(),
+ fqdn_buf.end(),
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_SNTP_SERVERS, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_SNTP_SERVERS, begin, end,
typeid(Option6AddrLst));
LibDhcpTest::testStdOptionDefs6(D6O_INFORMATION_REFRESH_TIME,
- buf, typeid(Option6Int<uint32_t>));
+ begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_D, fqdn_buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_D, fqdn_buf.begin(),
+ fqdn_buf.end(),
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_A, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_BCMCS_SERVER_A, begin, end,
typeid(Option6AddrLst));
- LibDhcpTest::testStdOptionDefs6(D6O_GEOCONF_CIVIC, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_GEOCONF_CIVIC, begin, end,
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_REMOTE_ID, buf, typeid(OptionCustom));
+ LibDhcpTest::testStdOptionDefs6(D6O_REMOTE_ID, begin, end,
+ typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_SUBSCRIBER_ID, buf,typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_SUBSCRIBER_ID, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_FQDN, client_fqdn_buf,
- typeid(OptionCustom));
+ LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_FQDN, client_fqdn_buf.begin(),
+ client_fqdn_buf.end(), typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
typeid(Option6AddrLst));
- LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_PANA_AGENT, begin, end,
typeid(Option6AddrLst));
- LibDhcpTest::testStdOptionDefs6(D6O_NEW_POSIX_TIMEZONE, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_NEW_POSIX_TIMEZONE, begin, end,
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_NEW_TZDB_TIMEZONE, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_NEW_TZDB_TIMEZONE, begin, end,
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_ERO, buf,
- typeid(Option6IntArray<uint16_t>));
+ LibDhcpTest::testStdOptionDefs6(D6O_ERO, begin, end,
+ typeid(OptionIntArray<uint16_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_LQ_QUERY, buf, typeid(OptionCustom));
+ LibDhcpTest::testStdOptionDefs6(D6O_LQ_QUERY, begin, end,
+ typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_DATA, buf, typeid(Option));
+ LibDhcpTest::testStdOptionDefs6(D6O_CLIENT_DATA, begin, end,
+ typeid(Option));
- LibDhcpTest::testStdOptionDefs6(D6O_CLT_TIME, buf,
- typeid(Option6Int<uint32_t>));
+ LibDhcpTest::testStdOptionDefs6(D6O_CLT_TIME, begin, begin + 4,
+ typeid(OptionInt<uint32_t>));
- LibDhcpTest::testStdOptionDefs6(D6O_LQ_RELAY_DATA, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_LQ_RELAY_DATA, begin, end,
typeid(OptionCustom));
- LibDhcpTest::testStdOptionDefs6(D6O_LQ_CLIENT_LINK, buf,
+ LibDhcpTest::testStdOptionDefs6(D6O_LQ_CLIENT_LINK, begin, end,
typeid(Option6AddrLst));
}
diff --git a/src/lib/dhcp/tests/option6_int_array_unittest.cc b/src/lib/dhcp/tests/option6_int_array_unittest.cc
deleted file mode 100644
index 3a8640a..0000000
--- a/src/lib/dhcp/tests/option6_int_array_unittest.cc
+++ /dev/null
@@ -1,421 +0,0 @@
-// 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.
-
-#include <config.h>
-
-#include <dhcp/dhcp6.h>
-#include <dhcp/option.h>
-#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int_array.h>
-#include <util/buffer.h>
-
-#include <boost/pointer_cast.hpp>
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::dhcp;
-using namespace isc::asiolink;
-using namespace isc::util;
-
-namespace {
-
-/// @brief Option6IntArray test class.
-class Option6IntArrayTest : public ::testing::Test {
-public:
- /// @brief Constructor.
- ///
- /// Initializes the option buffer with some data.
- Option6IntArrayTest(): buf_(255), out_buf_(255) {
- for (int i = 0; i < 255; i++) {
- buf_[i] = 255 - i;
- }
- }
-
- /// @brief Test parsing buffer into array of int8_t or uint8_t values.
- ///
- /// @warning this function does not perform type check. Make
- /// sure that only int8_t or uint8_t type is used.
- ///
- /// @tparam T int8_t or uint8_t.
- template<typename T>
- void bufferToIntTest8() {
- // Create option that conveys array of multiple uint8_t or int8_t values.
- // In fact there is no need to use this template class for array
- // of uint8_t values because Option class is sufficient - it
- // returns the buffer which is actually the array of uint8_t.
- // However, since we allow using uint8_t types with this template
- // class we have to test it here.
- boost::shared_ptr<Option6IntArray<T> > opt;
- const int opt_len = 10;
- const uint16_t opt_code = 80;
-
- // Constructor throws exception if provided buffer is empty.
- EXPECT_THROW(
- Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
- isc::OutOfRange
- );
-
- // Provided buffer is not empty so it should not throw exception.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<
- Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
- buf_.begin() + opt_len))
- );
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- // Option should return the collection of int8_t or uint8_t values that
- // we can match with the buffer we used to create the option.
- std::vector<T> values = opt->getValues();
- // We need to copy values from the buffer to apply sign if signed
- // type is used.
- std::vector<T> reference_values;
- for (int i = 0; i < opt_len; ++i) {
- // Values have been read from the buffer in network
- // byte order. We put them back in the same order here.
- reference_values.push_back(static_cast<T>(buf_[i]));
- }
-
- // Compare the values against the reference buffer.
- ASSERT_EQ(opt_len, values.size());
- EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.begin()
- + opt_len, values.begin()));
-
- // test for pack()
- opt->pack(out_buf_);
-
- // Data length is 10 bytes.
- EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(opt_code, opt->getType());
- // The total length is 10 bytes for data and 4 bytes for header.
- ASSERT_EQ(14, out_buf_.getLength());
-
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint16());
- // if option length is correct
- EXPECT_EQ(10, out.readUint16());
- // if data is correct
- std::vector<uint8_t> out_data;
- ASSERT_NO_THROW(out.readVector(out_data, opt_len));
- ASSERT_EQ(opt_len, out_data.size());
- EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
- }
-
- /// @brief Test parsing buffer into array of int16_t or uint16_t values.
- ///
- /// @warning this function does not perform type check. Make
- /// sure that only int16_t or uint16_t type is used.
- ///
- /// @tparam T int16_t or uint16_t.
- template<typename T>
- void bufferToIntTest16() {
- // Create option that conveys array of multiple uint16_t or int16_t values.
- boost::shared_ptr<Option6IntArray<T> > opt;
- const int opt_len = 20;
- const uint16_t opt_code = 81;
-
- // Constructor throws exception if provided buffer is empty.
- EXPECT_THROW(
- Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
- isc::OutOfRange
- );
-
- // Constructor throws exception if provided buffer's length is not
- // multiple of 2-bytes.
- EXPECT_THROW(
- Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 5),
- isc::OutOfRange
- );
-
- // Now the buffer length is correct.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<
- Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
- buf_.begin() + opt_len))
- );
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- // Option should return vector of uint16_t values which should be
- // constructed from the buffer we provided.
- std::vector<T> values = opt->getValues();
- ASSERT_EQ(opt_len, values.size() * sizeof(T));
- // Create reference values from the buffer so as we can
- // simply compare two vectors.
- std::vector<T> reference_values;
- for (int i = 0; i < opt_len; i += 2) {
- reference_values.push_back((buf_[i] << 8) |
- buf_[i + 1]);
- }
- EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
- values.begin()));
-
- // Test for pack()
- opt->pack(out_buf_);
-
- // Data length is 20 bytes.
- EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(opt_code, opt->getType());
- // The total length is 20 bytes for data and 4 bytes for header.
- ASSERT_EQ(24, out_buf_.getLength());
-
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint16());
- // if option length is correct
- EXPECT_EQ(20, out.readUint16());
- // if data is correct
- std::vector<uint8_t> out_data;
- ASSERT_NO_THROW(out.readVector(out_data, opt_len));
- ASSERT_EQ(opt_len, out_data.size());
- EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
- }
-
- /// @brief Test parsing buffer into array of int32_t or uint32_t values.
- ///
- /// @warning this function does not perform type check. Make
- /// sure that only int32_t or uint32_t type is used.
- ///
- /// @tparam T int32_t or uint32_t.
- template<typename T>
- void bufferToIntTest32() {
- // Create option that conveys array of multiple uint16_t values.
- boost::shared_ptr<Option6IntArray<T> > opt;
- const int opt_len = 40;
- const uint16_t opt_code = 82;
-
- // Constructor throws exception if provided buffer is empty.
- EXPECT_THROW(
- Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin()),
- isc::OutOfRange
- );
-
- // Constructor throws exception if provided buffer's length is not
- // multiple of 4-bytes.
- EXPECT_THROW(
- Option6IntArray<T>(opt_code, buf_.begin(), buf_.begin() + 9),
- isc::OutOfRange
- );
-
- // Now the buffer length is correct.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<
- Option6IntArray<T> >(new Option6IntArray<T>(opt_code, buf_.begin(),
- buf_.begin() + opt_len))
- );
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- // Option should return vector of uint32_t values which should be
- // constructed from the buffer we provided.
- std::vector<T> values = opt->getValues();
- ASSERT_EQ(opt_len, values.size() * sizeof(T));
- // Create reference values from the buffer so as we can
- // simply compare two vectors.
- std::vector<T> reference_values;
- for (int i = 0; i < opt_len; i += 4) {
- reference_values.push_back((buf_[i] << 24) |
- (buf_[i + 1] << 16 & 0x00FF0000) |
- (buf_[i + 2] << 8 & 0xFF00) |
- (buf_[i + 3] & 0xFF));
- }
- EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
- values.begin()));
-
- // Test for pack()
- opt->pack(out_buf_);
-
- // Data length is 40 bytes.
- EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(opt_code, opt->getType());
- // The total length is 40 bytes for data and 4 bytes for header.
- ASSERT_EQ(44, out_buf_.getLength());
-
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(opt_code, out.readUint16());
- // if option length is correct
- EXPECT_EQ(40, out.readUint16());
- // if data is correct
- std::vector<uint8_t> out_data;
- ASSERT_NO_THROW(out.readVector(out_data, opt_len));
- ASSERT_EQ(opt_len, out_data.size());
- EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
- }
-
-
- OptionBuffer buf_; ///< Option buffer
- OutputBuffer out_buf_; ///< Output buffer
-};
-
-/// @todo: below, there is a bunch of tests for options that
-/// convey unsigned values. We should maybe extend these tests for
-/// signed types too.
-
-TEST_F(Option6IntArrayTest, useInvalidType) {
- const uint16_t opt_code = 80;
- EXPECT_THROW(
- boost::scoped_ptr<
- Option6IntArray<bool> >(new Option6IntArray<bool>(opt_code, OptionBuffer(5))),
- InvalidDataType
- );
-
- EXPECT_THROW(
- boost::scoped_ptr<
- Option6IntArray<int64_t> >(new Option6IntArray<int64_t>(opt_code,
- OptionBuffer(10))),
- InvalidDataType
- );
-
-}
-
-TEST_F(Option6IntArrayTest, bufferToUint8) {
- bufferToIntTest8<uint8_t>();
-}
-
-TEST_F(Option6IntArrayTest, bufferToInt8) {
- bufferToIntTest8<int8_t>();
-}
-
-TEST_F(Option6IntArrayTest, bufferToUint16) {
- bufferToIntTest16<uint16_t>();
-}
-
-TEST_F(Option6IntArrayTest, bufferToInt16) {
- bufferToIntTest16<int16_t>();
-}
-
-TEST_F(Option6IntArrayTest, bufferToUint32) {
- bufferToIntTest32<uint32_t>();
-}
-
-TEST_F(Option6IntArrayTest, bufferToInt32) {
- bufferToIntTest32<int32_t>();
-}
-
-TEST_F(Option6IntArrayTest, setValuesUint8) {
- const uint16_t opt_code = 100;
- // Create option with empty vector of values.
- boost::shared_ptr<Option6IntArray<uint8_t> > opt(new Option6IntArray<uint8_t>(opt_code));
- // Initialize vector with some data and pass to the option.
- std::vector<uint8_t> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<uint8_t>::max() - i);
- }
- opt->setValues(values);
-
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<uint8_t> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
-}
-
-TEST_F(Option6IntArrayTest, setValuesInt8) {
- const uint16_t opt_code = 100;
- // Create option with empty vector of values.
- boost::shared_ptr<Option6IntArray<int8_t> > opt(new Option6IntArray<int8_t>(opt_code));
- // Initialize vector with some data and pass to the option.
- std::vector<int8_t> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<int8_t>::min() + i);
- }
- opt->setValues(values);
-
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<int8_t> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
-}
-
-TEST_F(Option6IntArrayTest, setValuesUint16) {
- const uint16_t opt_code = 101;
- // Create option with empty vector of values.
- boost::shared_ptr<Option6IntArray<uint16_t> > opt(new Option6IntArray<uint16_t>(opt_code));
- // Initialize vector with some data and pass to the option.
- std::vector<uint16_t> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<uint16_t>::max() - i);
- }
- opt->setValues(values);
-
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<uint16_t> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
-}
-
-TEST_F(Option6IntArrayTest, setValuesInt16) {
- const uint16_t opt_code = 101;
- // Create option with empty vector of values.
- boost::shared_ptr<Option6IntArray<int16_t> > opt(new Option6IntArray<int16_t>(opt_code));
- // Initialize vector with some data and pass to the option.
- std::vector<int16_t> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<int16_t>::min() + i);
- }
- opt->setValues(values);
-
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<int16_t> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
-}
-
-TEST_F(Option6IntArrayTest, setValuesUint32) {
- const uint32_t opt_code = 101;
- // Create option with empty vector of values.
- boost::shared_ptr<Option6IntArray<uint32_t> > opt(new Option6IntArray<uint32_t>(opt_code));
- // Initialize vector with some data and pass to the option.
- std::vector<uint32_t> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<uint32_t>::max() - i);
- }
- opt->setValues(values);
-
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<uint32_t> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
-}
-
-TEST_F(Option6IntArrayTest, setValuesInt32) {
- const uint32_t opt_code = 101;
- // Create option with empty vector of values.
- boost::shared_ptr<Option6IntArray<int32_t> > opt(new Option6IntArray<int32_t>(opt_code));
- // Initialize vector with some data and pass to the option.
- std::vector<int32_t> values;
- for (int i = 0; i < 10; ++i) {
- values.push_back(numeric_limits<int32_t>::min() + i);
- }
- opt->setValues(values);
-
- // Check if universe, option type and data was set correctly.
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(opt_code, opt->getType());
- std::vector<int32_t> returned_values = opt->getValues();
- EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
-}
-
-
-} // anonymous namespace
diff --git a/src/lib/dhcp/tests/option6_int_unittest.cc b/src/lib/dhcp/tests/option6_int_unittest.cc
deleted file mode 100644
index c9eac9c..0000000
--- a/src/lib/dhcp/tests/option6_int_unittest.cc
+++ /dev/null
@@ -1,414 +0,0 @@
-// 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.
-
-#include <config.h>
-
-#include <dhcp/dhcp6.h>
-#include <dhcp/option.h>
-#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
-#include <util/buffer.h>
-
-#include <boost/pointer_cast.hpp>
-#include <gtest/gtest.h>
-
-using namespace std;
-using namespace isc;
-using namespace isc::dhcp;
-using namespace isc::asiolink;
-using namespace isc::util;
-
-namespace {
-
-/// @brief Option6Int test class.
-class Option6IntTest : public ::testing::Test {
-public:
- /// @brief Constructor.
- ///
- /// Initializes the option buffer with some data.
- Option6IntTest(): buf_(255), out_buf_(255) {
- for (int i = 0; i < 255; i++) {
- buf_[i] = 255 - i;
- }
- }
-
- /// @brief Basic test for int8 and uint8 types.
- ///
- /// @note this function does not perform type check. Make
- /// sure that only int8_t or uint8_t type is used.
- ///
- /// @tparam T int8_t or uint8_t.
- template<typename T>
- void basicTest8() {
- // Create option that conveys single 8 bit integer value.
- boost::shared_ptr<Option6Int<T> > opt;
- // Initialize buffer with this value.
- buf_[0] = 0xa1;
- // Constructor may throw in case provided buffer is too short.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_PREFERENCE,
- buf_.begin(),
- buf_.end()))
- );
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_PREFERENCE, opt->getType());
- // Option should return the same value that we initialized the first
- // byte of the buffer with.
- EXPECT_EQ(static_cast<T>(0xa1), opt->getValue());
-
- // test for pack()
- opt->pack(out_buf_);
-
- // Data length is 1 byte.
- EXPECT_EQ(1, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(D6O_PREFERENCE, opt->getType());
- // The total length is 1 byte for data and 4 bytes for header.
- EXPECT_EQ(5, out_buf_.getLength());
-
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(D6O_PREFERENCE, out.readUint16());
- // if option length is correct
- EXPECT_EQ(1, out.readUint16());
- // if data is correct
- EXPECT_EQ(0xa1, out.readUint8() );
- }
-
- /// @brief Basic test for int16 and uint16 types.
- ///
- /// @note this function does not perform type check. Make
- /// sure that only int16_t or uint16_t type is used.
- ///
- /// @tparam T int16_t or uint16_t.
- template<typename T>
- void basicTest16() {
- // Create option that conveys single 16-bit integer value.
- boost::shared_ptr<Option6Int<T> > opt;
- // Initialize buffer with uint16_t value.
- buf_[0] = 0xa1;
- buf_[1] = 0xa2;
- // Constructor may throw in case provided buffer is too short.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_ELAPSED_TIME,
- buf_.begin(),
- buf_.end()))
- );
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
- // Option should return the value equal to the contents of first
- // and second byte of the buffer.
- EXPECT_EQ(static_cast<T>(0xa1a2), opt->getValue());
-
- // Test for pack()
- opt->pack(out_buf_);
-
- // Data length is 2 bytes.
- EXPECT_EQ(2, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
- // The total length is 2 byte for data and 4 bytes for header.
- EXPECT_EQ(6, out_buf_.getLength());
-
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(D6O_ELAPSED_TIME, out.readUint16());
- // if option length is correct
- EXPECT_EQ(2, out.readUint16());
- // if data is correct
- EXPECT_EQ(0xa1a2, out.readUint16() );
- }
-
- /// @brief Basic test for int32 and uint32 types.
- ///
- /// @note this function does not perform type check. Make
- /// sure that only int32_t or uint32_t type is used.
- ///
- /// @tparam T int32_t or uint32_t.
- template<typename T>
- void basicTest32() {
- // Create option that conveys single 32-bit integer value.
- boost::shared_ptr<Option6Int<T> > opt;
- // Initialize buffer with 32-bit integer value.
- buf_[0] = 0xa1;
- buf_[1] = 0xa2;
- buf_[2] = 0xa3;
- buf_[3] = 0xa4;
- // Constructor may throw in case provided buffer is too short.
- ASSERT_NO_THROW(
- opt = boost::shared_ptr<Option6Int<T> >(new Option6Int<T>(D6O_CLT_TIME,
- buf_.begin(),
- buf_.end()))
- );
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_CLT_TIME, opt->getType());
- // Option should return the value equal to the value made of
- // first 4 bytes of the buffer.
- EXPECT_EQ(static_cast<T>(0xa1a2a3a4), opt->getValue());
-
- // Test for pack()
- opt->pack(out_buf_);
-
- // Data length is 4 bytes.
- EXPECT_EQ(4, opt->len() - opt->getHeaderLen());
- EXPECT_EQ(D6O_CLT_TIME, opt->getType());
- // The total length is 4 bytes for data and 4 bytes for header.
- EXPECT_EQ(8, out_buf_.getLength());
-
- // Check if pack worked properly:
- InputBuffer out(out_buf_.getData(), out_buf_.getLength());
- // if option type is correct
- EXPECT_EQ(D6O_CLT_TIME, out.readUint16());
- // if option length is correct
- EXPECT_EQ(4, out.readUint16());
- // if data is correct
- EXPECT_EQ(0xa1a2a3a4, out.readUint32());
- }
-
- OptionBuffer buf_; ///< Option buffer
- OutputBuffer out_buf_; ///< Output buffer
-};
-
-/// @todo: below, there is a bunch of tests for options that
-/// convey unsigned value. We should maybe extend these tests for
-/// signed types too.
-
-TEST_F(Option6IntTest, useInvalidType) {
- EXPECT_THROW(
- boost::scoped_ptr<Option6Int<bool> >(new Option6Int<bool>(D6O_ELAPSED_TIME, 10)),
- InvalidDataType
- );
-
- EXPECT_THROW(
- boost::scoped_ptr<Option6Int<int64_t> >(new Option6Int<int64_t>(D6O_ELAPSED_TIME, 10)),
- InvalidDataType
- );
-
-}
-
-TEST_F(Option6IntTest, basicUint8) {
- basicTest8<uint8_t>();
-}
-
-TEST_F(Option6IntTest, basicUint16) {
- basicTest16<uint16_t>();
-}
-
-TEST_F(Option6IntTest, basicUint32) {
- basicTest32<uint32_t>();
-}
-
-TEST_F(Option6IntTest, basicInt8) {
- basicTest8<int8_t>();
-}
-
-TEST_F(Option6IntTest, basicInt16) {
- basicTest16<int16_t>();
-}
-
-TEST_F(Option6IntTest, basicInt32) {
- basicTest32<int32_t>();
-}
-
-TEST_F(Option6IntTest, setValueUint8) {
- boost::shared_ptr<Option6Int<uint8_t> > opt(new Option6Int<uint8_t>(D6O_PREFERENCE, 123));
- // Check if constructor intitialized the option value correctly.
- EXPECT_EQ(123, opt->getValue());
- // Override the value.
- opt->setValue(111);
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_PREFERENCE, opt->getType());
- // Check if the value has been overriden.
- EXPECT_EQ(111, opt->getValue());
-}
-
-TEST_F(Option6IntTest, setValueInt8) {
- boost::shared_ptr<Option6Int<int8_t> > opt(new Option6Int<int8_t>(D6O_PREFERENCE, -123));
- // Check if constructor intitialized the option value correctly.
- EXPECT_EQ(-123, opt->getValue());
- // Override the value.
- opt->setValue(-111);
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_PREFERENCE, opt->getType());
- // Check if the value has been overriden.
- EXPECT_EQ(-111, opt->getValue());
-}
-
-
-TEST_F(Option6IntTest, setValueUint16) {
- boost::shared_ptr<Option6Int<uint16_t> > opt(new Option6Int<uint16_t>(D6O_ELAPSED_TIME, 123));
- // Check if constructor intitialized the option value correctly.
- EXPECT_EQ(123, opt->getValue());
- // Override the value.
- opt->setValue(0x0102);
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
- // Check if the value has been overriden.
- EXPECT_EQ(0x0102, opt->getValue());
-}
-
-TEST_F(Option6IntTest, setValueInt16) {
- boost::shared_ptr<Option6Int<int16_t> > opt(new Option6Int<int16_t>(D6O_ELAPSED_TIME, -16500));
- // Check if constructor intitialized the option value correctly.
- EXPECT_EQ(-16500, opt->getValue());
- // Override the value.
- opt->setValue(-20100);
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
- // Check if the value has been overriden.
- EXPECT_EQ(-20100, opt->getValue());
-}
-
-TEST_F(Option6IntTest, setValueUint32) {
- boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(D6O_CLT_TIME, 123));
- // Check if constructor intitialized the option value correctly.
- EXPECT_EQ(123, opt->getValue());
- // Override the value.
- opt->setValue(0x01020304);
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_CLT_TIME, opt->getType());
- // Check if the value has been overriden.
- EXPECT_EQ(0x01020304, opt->getValue());
-}
-
-TEST_F(Option6IntTest, setValueint32) {
- boost::shared_ptr<Option6Int<int32_t> > opt(new Option6Int<int32_t>(D6O_CLT_TIME, -120100));
- // Check if constructor intitialized the option value correctly.
- EXPECT_EQ(-120100, opt->getValue());
- // Override the value.
- opt->setValue(-125000);
-
- EXPECT_EQ(Option::V6, opt->getUniverse());
- EXPECT_EQ(D6O_CLT_TIME, opt->getType());
- // Check if the value has been overriden.
- EXPECT_EQ(-125000, opt->getValue());
-}
-
-TEST_F(Option6IntTest, packSuboptions) {
- // option code is really uint16_t, but using uint8_t
- // for easier conversion to uint8_t array.
- uint8_t opt_code = 80;
-
- boost::shared_ptr<Option6Int<uint32_t> > opt(new Option6Int<uint32_t>(opt_code, 0x01020304));
- OptionPtr sub1(new Option(Option::V6, 0xcafe));
-
- boost::shared_ptr<Option6IAAddr> addr1(
- new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 0x5000, 0x7000));
-
- opt->addOption(sub1);
- opt->addOption(addr1);
-
- ASSERT_EQ(28, addr1->len());
- ASSERT_EQ(4, sub1->len());
- ASSERT_EQ(40, opt->len());
-
- uint8_t expected[] = {
- 0, opt_code, // type
- 0, 36, // length
- 0x01, 0x02, 0x03, 0x04, // uint32_t value
-
- // iaaddr suboption
- D6O_IAADDR / 256, D6O_IAADDR % 256, // type
- 0, 24, // len
- 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
- 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
- 0, 0, 0x50, 0, // preferred-lifetime
- 0, 0, 0x70, 0, // valid-lifetime
-
- // suboption
- 0xca, 0xfe, // type
- 0, 0 // len
- };
-
- // Create on-wire format of option and suboptions.
- opt->pack(out_buf_);
- // Compare the on-wire data with the reference buffer.
- ASSERT_EQ(40, out_buf_.getLength());
- EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, 40));
-}
-
-
-TEST_F(Option6IntTest, unpackSuboptions) {
- // option code is really uint16_t, but using uint8_t
- // for easier conversion to uint8_t array.
- const uint8_t opt_code = 80;
- // Prepare reference data.
- uint8_t expected[] = {
- 0, opt_code, // type
- 0, 34, // length
- 0x01, 0x02, // uint16_t value
-
- // iaaddr suboption
- D6O_IAADDR / 256, D6O_IAADDR % 256, // type
- 0, 24, // len
- 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
- 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
- 0, 0, 0x50, 0, // preferred-lifetime
- 0, 0, 0x70, 0, // valid-lifetime
-
- // suboption
- 0xca, 0xfe, // type
- 0, 0 // len
- };
- ASSERT_EQ(38, sizeof(expected));
-
- memcpy(&buf_[0], expected, sizeof(expected));
-
- boost::shared_ptr<Option6Int<uint16_t> > opt;
- EXPECT_NO_THROW(
- opt = boost::shared_ptr<
- Option6Int<uint16_t> >(new Option6Int<uint16_t>(opt_code, buf_.begin() + 4,
- buf_.begin() + sizeof(expected)));
- );
- ASSERT_TRUE(opt);
-
- EXPECT_EQ(opt_code, opt->getType());
- EXPECT_EQ(0x0102, opt->getValue());
-
- // Checks for address option
- OptionPtr subopt = opt->getOption(D6O_IAADDR);
- ASSERT_TRUE(subopt);
- boost::shared_ptr<Option6IAAddr> addr(boost::dynamic_pointer_cast<Option6IAAddr>(subopt));
- ASSERT_TRUE(addr);
-
- EXPECT_EQ(D6O_IAADDR, addr->getType());
- EXPECT_EQ(28, addr->len());
- EXPECT_EQ(0x5000, addr->getPreferred());
- EXPECT_EQ(0x7000, addr->getValid());
- EXPECT_EQ("2001:db8:1234:5678::abcd", addr->getAddress().toText());
-
- // Checks for dummy option
- subopt = opt->getOption(0xcafe);
- ASSERT_TRUE(subopt); // should be non-NULL
-
- EXPECT_EQ(0xcafe, subopt->getType());
- EXPECT_EQ(4, subopt->len());
- // There should be no data at all
- EXPECT_EQ(0, subopt->getData().size());
-
- // Try to get non-existent option.
- subopt = opt->getOption(1);
- // Expecting NULL which means that option does not exist.
- ASSERT_FALSE(subopt);
-}
-
-} // anonymous namespace
diff --git a/src/lib/dhcp/tests/option_definition_unittest.cc b/src/lib/dhcp/tests/option_definition_unittest.cc
index 91b822c..c88df83 100644
--- a/src/lib/dhcp/tests/option_definition_unittest.cc
+++ b/src/lib/dhcp/tests/option_definition_unittest.cc
@@ -21,10 +21,10 @@
#include <dhcp/option6_addrlst.h>
#include <dhcp/option6_ia.h>
#include <dhcp/option6_iaaddr.h>
-#include <dhcp/option6_int.h>
-#include <dhcp/option6_int_array.h>
#include <dhcp/option_custom.h>
#include <dhcp/option_definition.h>
+#include <dhcp/option_int.h>
+#include <dhcp/option_int_array.h>
#include <exceptions/exceptions.h>
#include <boost/pointer_cast.hpp>
@@ -578,10 +578,10 @@ TEST_F(OptionDefinitionTest, uint8) {
ASSERT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, OptionBuffer(1, 1));
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint8_t>));
// Validate the value.
- boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
+ boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
EXPECT_EQ(1, option_cast_v6->getValue());
// Try to provide zero-length buffer. Expect exception.
@@ -606,10 +606,10 @@ TEST_F(OptionDefinitionTest, uint8Tokenized) {
ASSERT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, D6O_PREFERENCE, values);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint8_t>));
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint8_t>));
// Validate the value.
- boost::shared_ptr<Option6Int<uint8_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6Int<uint8_t> >(option_v6);
+ boost::shared_ptr<OptionInt<uint8_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionInt<uint8_t> >(option_v6);
EXPECT_EQ(123, option_cast_v6->getValue());
// @todo Add more cases for DHCPv4
@@ -629,10 +629,10 @@ TEST_F(OptionDefinitionTest, uint16) {
ASSERT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, buf);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint16_t>));
// Validate the value.
- boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
+ boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
EXPECT_EQ(0x0102, option_cast_v6->getValue());
// Try to provide zero-length buffer. Expect exception.
@@ -658,10 +658,10 @@ TEST_F(OptionDefinitionTest, uint16Tokenized) {
ASSERT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, D6O_ELAPSED_TIME, values);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint16_t>));
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint16_t>));
// Validate the value.
- boost::shared_ptr<Option6Int<uint16_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6Int<uint16_t> >(option_v6);
+ boost::shared_ptr<OptionInt<uint16_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionInt<uint16_t> >(option_v6);
EXPECT_EQ(1234, option_cast_v6->getValue());
// @todo Add more cases for DHCPv4
@@ -683,10 +683,10 @@ TEST_F(OptionDefinitionTest, uint32) {
ASSERT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, buf);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint32_t>));
// Validate the value.
- boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
+ boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
EXPECT_EQ(0x01020304, option_cast_v6->getValue());
// Try to provide too short buffer. Expect exception.
@@ -711,10 +711,10 @@ TEST_F(OptionDefinitionTest, uint32Tokenized) {
ASSERT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, D6O_CLT_TIME, values);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6Int<uint32_t>));
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionInt<uint32_t>));
// Validate the value.
- boost::shared_ptr<Option6Int<uint32_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6Int<uint32_t> >(option_v6);
+ boost::shared_ptr<OptionInt<uint32_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionInt<uint32_t> >(option_v6);
EXPECT_EQ(123456, option_cast_v6->getValue());
// @todo Add more cases for DHCPv4
@@ -740,9 +740,9 @@ TEST_F(OptionDefinitionTest, uint16Array) {
EXPECT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
- boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint16_t>));
+ boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
// Get the values from the initiated options and validate.
std::vector<uint16_t> values = option_cast_v6->getValues();
for (int i = 0; i < values.size(); ++i) {
@@ -782,9 +782,9 @@ TEST_F(OptionDefinitionTest, uint16ArrayTokenized) {
EXPECT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint16_t>));
- boost::shared_ptr<Option6IntArray<uint16_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6IntArray<uint16_t> >(option_v6);
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint16_t>));
+ boost::shared_ptr<OptionIntArray<uint16_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionIntArray<uint16_t> >(option_v6);
// Get the values from the initiated options and validate.
std::vector<uint16_t> values = option_cast_v6->getValues();
EXPECT_EQ(12345, values[0]);
@@ -813,9 +813,9 @@ TEST_F(OptionDefinitionTest, uint32Array) {
EXPECT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, opt_code, buf);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
- boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint32_t>));
+ boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
// Get the values from the initiated options and validate.
std::vector<uint32_t> values = option_cast_v6->getValues();
for (int i = 0; i < values.size(); ++i) {
@@ -858,9 +858,9 @@ TEST_F(OptionDefinitionTest, uint32ArrayTokenized) {
EXPECT_NO_THROW(
option_v6 = opt_def.optionFactory(Option::V6, opt_code, str_values);
);
- ASSERT_TRUE(typeid(*option_v6) == typeid(Option6IntArray<uint32_t>));
- boost::shared_ptr<Option6IntArray<uint32_t> > option_cast_v6 =
- boost::static_pointer_cast<Option6IntArray<uint32_t> >(option_v6);
+ ASSERT_TRUE(typeid(*option_v6) == typeid(OptionIntArray<uint32_t>));
+ boost::shared_ptr<OptionIntArray<uint32_t> > option_cast_v6 =
+ boost::static_pointer_cast<OptionIntArray<uint32_t> >(option_v6);
// Get the values from the initiated options and validate.
std::vector<uint32_t> values = option_cast_v6->getValues();
EXPECT_EQ(123456, values[0]);
diff --git a/src/lib/dhcp/tests/option_int_array_unittest.cc b/src/lib/dhcp/tests/option_int_array_unittest.cc
new file mode 100644
index 0000000..1aeb584
--- /dev/null
+++ b/src/lib/dhcp/tests/option_int_array_unittest.cc
@@ -0,0 +1,488 @@
+// 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.
+
+#include <config.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option_int_array.h>
+#include <util/buffer.h>
+
+#include <boost/pointer_cast.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace {
+
+/// @brief OptionIntArray test class.
+class OptionIntArrayTest : public ::testing::Test {
+public:
+ /// @brief Constructor.
+ ///
+ /// Initializes the option buffer with some data.
+ OptionIntArrayTest(): buf_(255), out_buf_(255) {
+ for (int i = 0; i < 255; i++) {
+ buf_[i] = 255 - i;
+ }
+ }
+
+ /// @brief Test parsing buffer into array of int8_t or uint8_t values.
+ ///
+ /// @warning this function does not perform type check. Make
+ /// sure that only int8_t or uint8_t type is used.
+ ///
+ /// @param u universe (v4 or V6).
+ /// @tparam T int8_t or uint8_t.
+ template<typename T>
+ void bufferToIntTest8(const Option::Universe u) {
+ // Create option that conveys array of multiple uint8_t or int8_t values.
+ // In fact there is no need to use this template class for array
+ // of uint8_t values because Option class is sufficient - it
+ // returns the buffer which is actually the array of uint8_t.
+ // However, since we allow using uint8_t types with this template
+ // class we have to test it here.
+ boost::shared_ptr<OptionIntArray<T> > opt;
+ const int opt_len = 10;
+ const uint16_t opt_code = 80;
+
+ // Constructor throws exception if provided buffer is empty.
+ EXPECT_THROW(
+ OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
+ isc::OutOfRange
+ );
+
+ // Provided buffer is not empty so it should not throw exception.
+ ASSERT_NO_THROW(
+ opt = boost::shared_ptr<
+ OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
+ buf_.begin() + opt_len))
+ );
+
+ EXPECT_EQ(u, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ // Option should return the collection of int8_t or uint8_t values that
+ // we can match with the buffer we used to create the option.
+ std::vector<T> values = opt->getValues();
+ // We need to copy values from the buffer to apply sign if signed
+ // type is used.
+ std::vector<T> reference_values;
+ for (int i = 0; i < opt_len; ++i) {
+ // Values have been read from the buffer in network
+ // byte order. We put them back in the same order here.
+ reference_values.push_back(static_cast<T>(buf_[i]));
+ }
+
+ // Compare the values against the reference buffer.
+ ASSERT_EQ(opt_len, values.size());
+ EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.begin()
+ + opt_len, values.begin()));
+
+ // test for pack()
+ opt->pack(out_buf_);
+
+ // Data length is 10 bytes.
+ EXPECT_EQ(10, opt->len() - opt->getHeaderLen());
+ EXPECT_EQ(opt_code, opt->getType());
+
+ // Check if pack worked properly:
+ InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+
+ if (u == Option::V4) {
+ // The total length is 10 bytes for data and 2 bytes for a header.
+ ASSERT_EQ(12, out_buf_.getLength());
+ // if option type is correct
+ EXPECT_EQ(opt_code, out.readUint8());
+ // if option length is correct
+ EXPECT_EQ(10, out.readUint8());
+ } else {
+ // The total length is 10 bytes for data and 4 bytes for a header.
+ ASSERT_EQ(14, out_buf_.getLength());
+ // if option type is correct
+ EXPECT_EQ(opt_code, out.readUint16());
+ // if option length is correct
+ EXPECT_EQ(10, out.readUint16());
+ }
+
+ // if data is correct
+ std::vector<uint8_t> out_data;
+ ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+ ASSERT_EQ(opt_len, out_data.size());
+ EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+ }
+
+ /// @brief Test parsing buffer into array of int16_t or uint16_t values.
+ ///
+ /// @warning this function does not perform type check. Make
+ /// sure that only int16_t or uint16_t type is used.
+ ///
+ /// @param u universe (V4 or V6).
+ /// @tparam T int16_t or uint16_t.
+ template<typename T>
+ void bufferToIntTest16(const Option::Universe u) {
+ // Create option that conveys array of multiple uint16_t or int16_t values.
+ boost::shared_ptr<OptionIntArray<T> > opt;
+ const int opt_len = 20;
+ const uint16_t opt_code = 81;
+
+ // Constructor throws exception if provided buffer is empty.
+ EXPECT_THROW(
+ OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
+ isc::OutOfRange
+ );
+
+ // Constructor throws exception if provided buffer's length is not
+ // multiple of 2-bytes.
+ EXPECT_THROW(
+ OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 5),
+ isc::OutOfRange
+ );
+
+ // Now the buffer length is correct.
+ ASSERT_NO_THROW(
+ opt = boost::shared_ptr<
+ OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
+ buf_.begin() + opt_len))
+ );
+
+ EXPECT_EQ(u, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ // Option should return vector of uint16_t values which should be
+ // constructed from the buffer we provided.
+ std::vector<T> values = opt->getValues();
+ ASSERT_EQ(opt_len, values.size() * sizeof(T));
+ // Create reference values from the buffer so as we can
+ // simply compare two vectors.
+ std::vector<T> reference_values;
+ for (int i = 0; i < opt_len; i += 2) {
+ reference_values.push_back((buf_[i] << 8) |
+ buf_[i + 1]);
+ }
+ EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
+ values.begin()));
+
+ // Test for pack()
+ opt->pack(out_buf_);
+
+ // Data length is 20 bytes.
+ EXPECT_EQ(20, opt->len() - opt->getHeaderLen());
+ EXPECT_EQ(opt_code, opt->getType());
+
+ // Check if pack worked properly:
+ InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+
+ if (u == Option::V4) {
+ // The total length is 20 bytes for data and 2 bytes for a header.
+ ASSERT_EQ(22, out_buf_.getLength());
+ // if option type is correct
+ EXPECT_EQ(opt_code, out.readUint8());
+ // if option length is correct
+ EXPECT_EQ(20, out.readUint8());
+ } else {
+ // The total length is 20 bytes for data and 4 bytes for a header.
+ ASSERT_EQ(24, out_buf_.getLength());
+ // if option type is correct
+ EXPECT_EQ(opt_code, out.readUint16());
+ // if option length is correct
+ EXPECT_EQ(20, out.readUint16());
+ }
+ // if data is correct
+ std::vector<uint8_t> out_data;
+ ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+ ASSERT_EQ(opt_len, out_data.size());
+ EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+ }
+
+ /// @brief Test parsing buffer into array of int32_t or uint32_t values.
+ ///
+ /// @warning this function does not perform type check. Make
+ /// sure that only int32_t or uint32_t type is used.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @tparam T int32_t or uint32_t.
+ template<typename T>
+ void bufferToIntTest32(const Option::Universe u) {
+ // Create option that conveys array of multiple uint16_t values.
+ boost::shared_ptr<OptionIntArray<T> > opt;
+ const int opt_len = 40;
+ const uint16_t opt_code = 82;
+
+ // Constructor throws exception if provided buffer is empty.
+ EXPECT_THROW(
+ OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin()),
+ isc::OutOfRange
+ );
+
+ // Constructor throws exception if provided buffer's length is not
+ // multiple of 4-bytes.
+ EXPECT_THROW(
+ OptionIntArray<T>(u, opt_code, buf_.begin(), buf_.begin() + 9),
+ isc::OutOfRange
+ );
+
+ // Now the buffer length is correct.
+ ASSERT_NO_THROW(
+ opt = boost::shared_ptr<
+ OptionIntArray<T> >(new OptionIntArray<T>(u, opt_code, buf_.begin(),
+ buf_.begin() + opt_len))
+ );
+
+ EXPECT_EQ(u, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ // Option should return vector of uint32_t values which should be
+ // constructed from the buffer we provided.
+ std::vector<T> values = opt->getValues();
+ ASSERT_EQ(opt_len, values.size() * sizeof(T));
+ // Create reference values from the buffer so as we can
+ // simply compare two vectors.
+ std::vector<T> reference_values;
+ for (int i = 0; i < opt_len; i += 4) {
+ reference_values.push_back((buf_[i] << 24) |
+ (buf_[i + 1] << 16 & 0x00FF0000) |
+ (buf_[i + 2] << 8 & 0xFF00) |
+ (buf_[i + 3] & 0xFF));
+ }
+ EXPECT_TRUE(std::equal(reference_values.begin(), reference_values.end(),
+ values.begin()));
+
+ // Test for pack()
+ opt->pack(out_buf_);
+
+ // Data length is 40 bytes.
+ EXPECT_EQ(40, opt->len() - opt->getHeaderLen());
+ EXPECT_EQ(opt_code, opt->getType());
+
+ // Check if pack worked properly:
+ InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+
+ if (u == Option::V4) {
+ // The total length is 40 bytes for data and 2 bytes for a header.
+ ASSERT_EQ(42, out_buf_.getLength());
+ // if option type is correct
+ EXPECT_EQ(opt_code, out.readUint8());
+ // if option length is correct
+ EXPECT_EQ(40, out.readUint8());
+ } else {
+ // The total length is 40 bytes for data and 4 bytes for a header.
+ ASSERT_EQ(44, out_buf_.getLength());
+ // if option type is correct
+ EXPECT_EQ(opt_code, out.readUint16());
+ // if option length is correct
+ EXPECT_EQ(40, out.readUint16());
+ }
+
+ // if data is correct
+ std::vector<uint8_t> out_data;
+ ASSERT_NO_THROW(out.readVector(out_data, opt_len));
+ ASSERT_EQ(opt_len, out_data.size());
+ EXPECT_TRUE(std::equal(buf_.begin(), buf_.begin() + opt_len, out_data.begin()));;
+ }
+
+
+ OptionBuffer buf_; ///< Option buffer
+ OutputBuffer out_buf_; ///< Output buffer
+};
+
+/// @todo: below, there is a bunch of tests for options that
+/// convey unsigned values. We should maybe extend these tests for
+/// signed types too.
+
+TEST_F(OptionIntArrayTest, useInvalidType) {
+ const uint16_t opt_code = 80;
+ EXPECT_THROW(
+ boost::scoped_ptr<
+ OptionIntArray<bool> >(new OptionIntArray<bool>(Option::V6, opt_code,
+ OptionBuffer(5))),
+ InvalidDataType
+ );
+
+ EXPECT_THROW(
+ boost::scoped_ptr<
+ OptionIntArray<int64_t> >(new OptionIntArray<int64_t>(Option::V6,
+ opt_code,
+ OptionBuffer(10))),
+ InvalidDataType
+ );
+
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint8V4) {
+ bufferToIntTest8<uint8_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint8V6) {
+ bufferToIntTest8<uint8_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt8V4) {
+ bufferToIntTest8<int8_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt8V6) {
+ bufferToIntTest8<int8_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint16V4) {
+ bufferToIntTest16<uint16_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint16V6) {
+ bufferToIntTest16<uint16_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt16V4) {
+ bufferToIntTest16<int16_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt16V6) {
+ bufferToIntTest16<int16_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint32V4) {
+ bufferToIntTest32<uint32_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToUint32V6) {
+ bufferToIntTest32<uint32_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt32V4) {
+ bufferToIntTest32<int32_t>(Option::V4);
+}
+
+TEST_F(OptionIntArrayTest, bufferToInt32V6) {
+ bufferToIntTest32<int32_t>(Option::V6);
+}
+
+TEST_F(OptionIntArrayTest, setValuesUint8) {
+ const uint16_t opt_code = 100;
+ // Create option with empty vector of values.
+ boost::shared_ptr<OptionIntArray<uint8_t> >
+ opt(new OptionIntArray<uint8_t>(Option::V6, opt_code));
+ // Initialize vector with some data and pass to the option.
+ std::vector<uint8_t> values;
+ for (int i = 0; i < 10; ++i) {
+ values.push_back(numeric_limits<uint8_t>::max() - i);
+ }
+ opt->setValues(values);
+
+ // Check if universe, option type and data was set correctly.
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ std::vector<uint8_t> returned_values = opt->getValues();
+ EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(OptionIntArrayTest, setValuesInt8) {
+ const uint16_t opt_code = 100;
+ // Create option with empty vector of values.
+ boost::shared_ptr<OptionIntArray<int8_t> >
+ opt(new OptionIntArray<int8_t>(Option::V6, opt_code));
+ // Initialize vector with some data and pass to the option.
+ std::vector<int8_t> values;
+ for (int i = 0; i < 10; ++i) {
+ values.push_back(numeric_limits<int8_t>::min() + i);
+ }
+ opt->setValues(values);
+
+ // Check if universe, option type and data was set correctly.
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ std::vector<int8_t> returned_values = opt->getValues();
+ EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(OptionIntArrayTest, setValuesUint16) {
+ const uint16_t opt_code = 101;
+ // Create option with empty vector of values.
+ boost::shared_ptr<OptionIntArray<uint16_t> >
+ opt(new OptionIntArray<uint16_t>(Option::V6, opt_code));
+ // Initialize vector with some data and pass to the option.
+ std::vector<uint16_t> values;
+ for (int i = 0; i < 10; ++i) {
+ values.push_back(numeric_limits<uint16_t>::max() - i);
+ }
+ opt->setValues(values);
+
+ // Check if universe, option type and data was set correctly.
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ std::vector<uint16_t> returned_values = opt->getValues();
+ EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(OptionIntArrayTest, setValuesInt16) {
+ const uint16_t opt_code = 101;
+ // Create option with empty vector of values.
+ boost::shared_ptr<OptionIntArray<int16_t> >
+ opt(new OptionIntArray<int16_t>(Option::V6, opt_code));
+ // Initialize vector with some data and pass to the option.
+ std::vector<int16_t> values;
+ for (int i = 0; i < 10; ++i) {
+ values.push_back(numeric_limits<int16_t>::min() + i);
+ }
+ opt->setValues(values);
+
+ // Check if universe, option type and data was set correctly.
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ std::vector<int16_t> returned_values = opt->getValues();
+ EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(OptionIntArrayTest, setValuesUint32) {
+ const uint32_t opt_code = 101;
+ // Create option with empty vector of values.
+ boost::shared_ptr<OptionIntArray<uint32_t> >
+ opt(new OptionIntArray<uint32_t>(Option::V6, opt_code));
+ // Initialize vector with some data and pass to the option.
+ std::vector<uint32_t> values;
+ for (int i = 0; i < 10; ++i) {
+ values.push_back(numeric_limits<uint32_t>::max() - i);
+ }
+ opt->setValues(values);
+
+ // Check if universe, option type and data was set correctly.
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ std::vector<uint32_t> returned_values = opt->getValues();
+ EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+TEST_F(OptionIntArrayTest, setValuesInt32) {
+ const uint32_t opt_code = 101;
+ // Create option with empty vector of values.
+ boost::shared_ptr<OptionIntArray<int32_t> >
+ opt(new OptionIntArray<int32_t>(Option::V6, opt_code));
+ // Initialize vector with some data and pass to the option.
+ std::vector<int32_t> values;
+ for (int i = 0; i < 10; ++i) {
+ values.push_back(numeric_limits<int32_t>::min() + i);
+ }
+ opt->setValues(values);
+
+ // Check if universe, option type and data was set correctly.
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(opt_code, opt->getType());
+ std::vector<int32_t> returned_values = opt->getValues();
+ EXPECT_TRUE(std::equal(values.begin(), values.end(), returned_values.begin()));
+}
+
+
+} // anonymous namespace
diff --git a/src/lib/dhcp/tests/option_int_unittest.cc b/src/lib/dhcp/tests/option_int_unittest.cc
new file mode 100644
index 0000000..81ebcf0
--- /dev/null
+++ b/src/lib/dhcp/tests/option_int_unittest.cc
@@ -0,0 +1,563 @@
+// 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.
+
+#include <config.h>
+
+#include <dhcp/dhcp6.h>
+#include <dhcp/option.h>
+#include <dhcp/option6_iaaddr.h>
+#include <dhcp/option_int.h>
+#include <util/buffer.h>
+
+#include <boost/pointer_cast.hpp>
+#include <gtest/gtest.h>
+
+using namespace std;
+using namespace isc;
+using namespace isc::dhcp;
+using namespace isc::asiolink;
+using namespace isc::util;
+
+namespace {
+
+/// Option code being used in many test cases.
+const uint16_t TEST_OPT_CODE = 232;
+
+/// @brief OptionInt test class.
+class OptionIntTest : public ::testing::Test {
+public:
+ /// @brief Constructor.
+ ///
+ /// Initializes the option buffer with some data.
+ OptionIntTest(): buf_(255), out_buf_(255) {
+ for (int i = 0; i < 255; i++) {
+ buf_[i] = 255 - i;
+ }
+ }
+
+ /// @brief Basic test for int8 and uint8 types.
+ ///
+ /// @note this function does not perform type check. Make
+ /// sure that only int8_t or uint8_t type is used.
+ ///
+ /// @param u universe (V4 or V6).
+ /// @tparam T int8_t or uint8_t.
+ template<typename T>
+ void basicTest8(const Option::Universe u) {
+ // Create option that conveys single 8 bit integer value.
+ boost::shared_ptr<OptionInt<T> > opt;
+ // Initialize buffer with this value.
+ buf_[0] = 0xa1;
+ // Constructor may throw in case provided buffer is too short.
+ ASSERT_NO_THROW(
+ opt = boost::shared_ptr<OptionInt<T> >(new OptionInt<T>(u,
+ TEST_OPT_CODE,
+ buf_.begin(),
+ buf_.begin() + 1))
+ );
+
+ EXPECT_EQ(u, opt->getUniverse());
+ EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+ // Option should return the same value that we initialized the first
+ // byte of the buffer with.
+ EXPECT_EQ(static_cast<T>(0xa1), opt->getValue());
+
+ // test for pack()
+ opt->pack(out_buf_);
+
+ // Data length is 1 byte.
+ EXPECT_EQ(1, opt->len() - opt->getHeaderLen());
+ EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+ // The total length is 1 byte for data and 2 bytes or 4 bytes
+ // for option code and option length.
+ if (u == Option::V4) {
+ EXPECT_EQ(3, out_buf_.getLength());
+ } else {
+ EXPECT_EQ(5, out_buf_.getLength());
+ }
+
+ // Check if pack worked properly:
+ InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+ if (u == Option::V4) {
+ // if option type is correct
+ EXPECT_EQ(TEST_OPT_CODE, out.readUint8());
+ // if option length is correct
+ EXPECT_EQ(1, out.readUint8());
+ } else {
+ // if option type is correct
+ EXPECT_EQ(TEST_OPT_CODE, out.readUint16());
+ // if option length is correct
+ EXPECT_EQ(1, out.readUint16());
+ }
+ // if data is correct
+ EXPECT_EQ(0xa1, out.readUint8() );
+ }
+
+ /// @brief Basic test for int16 and uint16 types.
+ ///
+ /// @note this function does not perform type check. Make
+ /// sure that only int16_t or uint16_t type is used.
+ ///
+ /// @param u universe (V4 or V6)
+ /// @tparam T int16_t or uint16_t.
+ template<typename T>
+ void basicTest16(const Option::Universe u) {
+ // Create option that conveys single 16-bit integer value.
+ boost::shared_ptr<OptionInt<T> > opt;
+ // Initialize buffer with uint16_t value.
+ buf_[0] = 0xa1;
+ buf_[1] = 0xa2;
+ // Constructor may throw in case provided buffer is too short.
+ ASSERT_NO_THROW(
+ opt = boost::shared_ptr<OptionInt<T> >(new OptionInt<T>(u,
+ TEST_OPT_CODE,
+ buf_.begin(),
+ buf_.begin() + 2))
+ );
+
+ EXPECT_EQ(u, opt->getUniverse());
+ EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+ // Option should return the value equal to the contents of first
+ // and second byte of the buffer.
+ EXPECT_EQ(static_cast<T>(0xa1a2), opt->getValue());
+
+ // Test for pack()
+ opt->pack(out_buf_);
+
+ // Data length is 2 bytes.
+ EXPECT_EQ(2, opt->len() - opt->getHeaderLen());
+ EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+ // The total length is 2 bytes for data and 2 or 4 bytes for aheader.
+ if (u == Option::V4) {
+ EXPECT_EQ(4, out_buf_.getLength());
+ } else {
+ EXPECT_EQ(6, out_buf_.getLength());
+ }
+
+ // Check if pack worked properly:
+ InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+ if (u == Option::V4) {
+ // if option type is correct
+ EXPECT_EQ(TEST_OPT_CODE, out.readUint8());
+ // if option length is correct
+ EXPECT_EQ(2, out.readUint8());
+ } else {
+ // if option type is correct
+ EXPECT_EQ(TEST_OPT_CODE, out.readUint16());
+ // if option length is correct
+ EXPECT_EQ(2, out.readUint16());
+ }
+ // if data is correct
+ EXPECT_EQ(0xa1a2, out.readUint16() );
+ }
+
+ /// @brief Basic test for int32 and uint32 types.
+ ///
+ /// @note this function does not perform type check. Make
+ /// sure that only int32_t or uint32_t type is used.
+ ///
+ /// @param u universe (V4 or V6).
+ /// @tparam T int32_t or uint32_t.
+ template<typename T>
+ void basicTest32(const Option::Universe u) {
+ // Create option that conveys single 32-bit integer value.
+ boost::shared_ptr<OptionInt<T> > opt;
+ // Initialize buffer with 32-bit integer value.
+ buf_[0] = 0xa1;
+ buf_[1] = 0xa2;
+ buf_[2] = 0xa3;
+ buf_[3] = 0xa4;
+ // Constructor may throw in case provided buffer is too short.
+ ASSERT_NO_THROW(
+ opt = boost::shared_ptr<OptionInt<T> >(new OptionInt<T>(u,
+ TEST_OPT_CODE,
+ buf_.begin(),
+ buf_.begin() + 4))
+ );
+
+ EXPECT_EQ(u, opt->getUniverse());
+ EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+ // Option should return the value equal to the value made of
+ // first 4 bytes of the buffer.
+ EXPECT_EQ(static_cast<T>(0xa1a2a3a4), opt->getValue());
+
+ // Test for pack()
+ opt->pack(out_buf_);
+
+ // Data length is 4 bytes.
+ EXPECT_EQ(4, opt->len() - opt->getHeaderLen());
+ EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+ // The total length is 4 bytes for data and 2 or 4 bytes for a header.
+ if (u == Option::V4) {
+ EXPECT_EQ(6, out_buf_.getLength());
+ } else {
+ EXPECT_EQ(8, out_buf_.getLength());
+ }
+
+ // Check if pack worked properly:
+ InputBuffer out(out_buf_.getData(), out_buf_.getLength());
+ if (u == Option::V4) {
+ // if option type is correct
+ EXPECT_EQ(TEST_OPT_CODE, out.readUint8());
+ // if option length is correct
+ EXPECT_EQ(4, out.readUint8());
+ } else {
+ // if option type is correct
+ EXPECT_EQ(TEST_OPT_CODE, out.readUint16());
+ // if option length is correct
+ EXPECT_EQ(4, out.readUint16());
+ }
+ // if data is correct
+ EXPECT_EQ(0xa1a2a3a4, out.readUint32());
+ }
+
+ OptionBuffer buf_; ///< Option buffer
+ OutputBuffer out_buf_; ///< Output buffer
+};
+
+/// @todo: below, there is a bunch of tests for options that
+/// convey unsigned value. We should maybe extend these tests for
+/// signed types too.
+
+TEST_F(OptionIntTest, useInvalidType) {
+ EXPECT_THROW(
+ boost::scoped_ptr<OptionInt<bool> >(new OptionInt<bool>(Option::V6,
+ D6O_ELAPSED_TIME, 10)),
+ InvalidDataType
+ );
+
+ EXPECT_THROW(
+ boost::scoped_ptr<OptionInt<int64_t> >(new OptionInt<int64_t>(Option::V6,
+ D6O_ELAPSED_TIME, 10)),
+ InvalidDataType
+ );
+
+}
+
+TEST_F(OptionIntTest, basicUint8V4) {
+ basicTest8<uint8_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicUint8V6) {
+ basicTest8<uint8_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, basicUint16V4) {
+ basicTest16<uint16_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicUint16V6) {
+ basicTest16<uint16_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, basicUint32V4) {
+ basicTest32<uint32_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicUint32V6) {
+ basicTest32<uint32_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, basicInt8V4) {
+ basicTest8<int8_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicInt8V6) {
+ basicTest8<int8_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, basicInt16V4) {
+ basicTest16<int16_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicInt16V6) {
+ basicTest16<int16_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, basicInt32V4) {
+ basicTest32<int32_t>(Option::V4);
+}
+
+TEST_F(OptionIntTest, basicInt32V6) {
+ basicTest32<int32_t>(Option::V6);
+}
+
+TEST_F(OptionIntTest, setValueUint8) {
+ boost::shared_ptr<OptionInt<uint8_t> > opt(new OptionInt<uint8_t>(Option::V6,
+ D6O_PREFERENCE, 123));
+ // Check if constructor intitialized the option value correctly.
+ EXPECT_EQ(123, opt->getValue());
+ // Override the value.
+ opt->setValue(111);
+
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+ // Check if the value has been overriden.
+ EXPECT_EQ(111, opt->getValue());
+}
+
+TEST_F(OptionIntTest, setValueInt8) {
+ boost::shared_ptr<OptionInt<int8_t> > opt(new OptionInt<int8_t>(Option::V6,
+ D6O_PREFERENCE, -123));
+ // Check if constructor intitialized the option value correctly.
+ EXPECT_EQ(-123, opt->getValue());
+ // Override the value.
+ opt->setValue(-111);
+
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(D6O_PREFERENCE, opt->getType());
+ // Check if the value has been overriden.
+ EXPECT_EQ(-111, opt->getValue());
+}
+
+
+TEST_F(OptionIntTest, setValueUint16) {
+ boost::shared_ptr<OptionInt<uint16_t> > opt(new OptionInt<uint16_t>(Option::V6,
+ D6O_ELAPSED_TIME, 123));
+ // Check if constructor intitialized the option value correctly.
+ EXPECT_EQ(123, opt->getValue());
+ // Override the value.
+ opt->setValue(0x0102);
+
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+ // Check if the value has been overriden.
+ EXPECT_EQ(0x0102, opt->getValue());
+}
+
+TEST_F(OptionIntTest, setValueInt16) {
+ boost::shared_ptr<OptionInt<int16_t> > opt(new OptionInt<int16_t>(Option::V6,
+ D6O_ELAPSED_TIME, -16500));
+ // Check if constructor intitialized the option value correctly.
+ EXPECT_EQ(-16500, opt->getValue());
+ // Override the value.
+ opt->setValue(-20100);
+
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(D6O_ELAPSED_TIME, opt->getType());
+ // Check if the value has been overriden.
+ EXPECT_EQ(-20100, opt->getValue());
+}
+
+TEST_F(OptionIntTest, setValueUint32) {
+ boost::shared_ptr<OptionInt<uint32_t> > opt(new OptionInt<uint32_t>(Option::V6,
+ D6O_CLT_TIME, 123));
+ // Check if constructor intitialized the option value correctly.
+ EXPECT_EQ(123, opt->getValue());
+ // Override the value.
+ opt->setValue(0x01020304);
+
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+ // Check if the value has been overriden.
+ EXPECT_EQ(0x01020304, opt->getValue());
+}
+
+TEST_F(OptionIntTest, setValueInt32) {
+ boost::shared_ptr<OptionInt<int32_t> > opt(new OptionInt<int32_t>(Option::V6,
+ D6O_CLT_TIME, -120100));
+ // Check if constructor intitialized the option value correctly.
+ EXPECT_EQ(-120100, opt->getValue());
+ // Override the value.
+ opt->setValue(-125000);
+
+ EXPECT_EQ(Option::V6, opt->getUniverse());
+ EXPECT_EQ(D6O_CLT_TIME, opt->getType());
+ // Check if the value has been overriden.
+ EXPECT_EQ(-125000, opt->getValue());
+}
+
+TEST_F(OptionIntTest, packSuboptions4) {
+ boost::shared_ptr<OptionInt<uint16_t> > opt(new OptionInt<uint16_t>(Option::V4,
+ TEST_OPT_CODE,
+ 0x0102));
+ // Add sub option with some 4 bytes of data (each byte set to 1)
+ OptionPtr sub1(new Option(Option::V4, TEST_OPT_CODE + 1, OptionBuffer(4, 1)));
+ // Add sub option with some 5 bytes of data (each byte set to 2)
+ OptionPtr sub2(new Option(Option::V4, TEST_OPT_CODE + 2, OptionBuffer(5, 2)));
+
+ // Add suboptions.
+ opt->addOption(sub1);
+ opt->addOption(sub2);
+
+ // Prepare reference data: option + suoptions in wire format.
+ uint8_t expected[] = {
+ TEST_OPT_CODE, 15, // option header
+ 0x01, 0x02, // data, uint16_t value = 0x0102
+ TEST_OPT_CODE + 1, 0x04, 0x01, 0x01, 0x01, 0x01, // sub1
+ TEST_OPT_CODE + 2, 0x05, 0x02, 0x02, 0x02, 0x02, 0x02 // sub2
+ };
+
+ // Create on-wire format of option and suboptions.
+ opt->pack(out_buf_);
+ // Compare the on-wire data with the reference buffer.
+ ASSERT_EQ(sizeof(expected), out_buf_.getLength());
+ EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, sizeof(expected)));
+}
+
+TEST_F(OptionIntTest, packSuboptions6) {
+ // option code is really uint16_t, but using uint8_t
+ // for easier conversion to uint8_t array.
+ uint8_t opt_code = 80;
+
+ boost::shared_ptr<OptionInt<uint32_t> > opt(new OptionInt<uint32_t>(Option::V6,
+ opt_code, 0x01020304));
+ OptionPtr sub1(new Option(Option::V6, 0xcafe));
+
+ boost::shared_ptr<Option6IAAddr> addr1(
+ new Option6IAAddr(D6O_IAADDR, IOAddress("2001:db8:1234:5678::abcd"), 0x5000, 0x7000));
+
+ opt->addOption(sub1);
+ opt->addOption(addr1);
+
+ ASSERT_EQ(28, addr1->len());
+ ASSERT_EQ(4, sub1->len());
+ ASSERT_EQ(40, opt->len());
+
+ uint8_t expected[] = {
+ 0, opt_code, // type
+ 0, 36, // length
+ 0x01, 0x02, 0x03, 0x04, // uint32_t value
+
+ // iaaddr suboption
+ D6O_IAADDR / 256, D6O_IAADDR % 256, // type
+ 0, 24, // len
+ 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+ 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+ 0, 0, 0x50, 0, // preferred-lifetime
+ 0, 0, 0x70, 0, // valid-lifetime
+
+ // suboption
+ 0xca, 0xfe, // type
+ 0, 0 // len
+ };
+
+ // Create on-wire format of option and suboptions.
+ opt->pack(out_buf_);
+ // Compare the on-wire data with the reference buffer.
+ ASSERT_EQ(40, out_buf_.getLength());
+ EXPECT_EQ(0, memcmp(out_buf_.getData(), expected, 40));
+}
+
+TEST_F(OptionIntTest, unpackSuboptions4) {
+ // Prepare reference data.
+ const uint8_t expected[] = {
+ TEST_OPT_CODE, 0x0A, // option code and length
+ 0x01, 0x02, 0x03, 0x04, // data, uint32_t value = 0x01020304
+ TEST_OPT_CODE + 1, 0x4, 0x01, 0x01, 0x01, 0x01 // suboption
+ };
+ // Make sure that the buffer size is sufficient to copy the
+ // elements from the array.
+ ASSERT_GE(buf_.size(), sizeof(expected));
+ // Copy the data to a vector so as we can pass it to the
+ // OptionInt's constructor.
+ memcpy(&buf_[0], expected, sizeof(expected));
+
+ // Create an option.
+ boost::shared_ptr<OptionInt<uint32_t> > opt;
+ EXPECT_NO_THROW(
+ opt = boost::shared_ptr<
+ OptionInt<uint32_t> >(new OptionInt<uint32_t>(Option::V4, TEST_OPT_CODE,
+ buf_.begin() + 2,
+ buf_.begin() + sizeof(expected)));
+ );
+ ASSERT_TRUE(opt);
+
+ // Verify that it has expected type and data.
+ EXPECT_EQ(TEST_OPT_CODE, opt->getType());
+ EXPECT_EQ(0x01020304, opt->getValue());
+
+ // Expect that there is the sub option with the particular
+ // option code added.
+ OptionPtr subopt = opt->getOption(TEST_OPT_CODE + 1);
+ ASSERT_TRUE(subopt);
+ // Check that this option has correct universe and code.
+ EXPECT_EQ(Option::V4, subopt->getUniverse());
+ EXPECT_EQ(TEST_OPT_CODE + 1, subopt->getType());
+ // Check the sub option's data.
+ OptionBuffer subopt_buf = subopt->getData();
+ ASSERT_EQ(4, subopt_buf.size());
+ // The data in the input buffer starts at offset 8.
+ EXPECT_TRUE(std::equal(subopt_buf.begin(), subopt_buf.end(), buf_.begin() + 8));
+}
+
+TEST_F(OptionIntTest, unpackSuboptions6) {
+ // option code is really uint16_t, but using uint8_t
+ // for easier conversion to uint8_t array.
+ const uint8_t opt_code = 80;
+ // Prepare reference data.
+ uint8_t expected[] = {
+ 0, opt_code, // type
+ 0, 34, // length
+ 0x01, 0x02, // uint16_t value
+
+ // iaaddr suboption
+ D6O_IAADDR / 256, D6O_IAADDR % 256, // type
+ 0, 24, // len
+ 0x20, 0x01, 0xd, 0xb8, 0x12,0x34, 0x56, 0x78,
+ 0, 0, 0, 0, 0, 0, 0xab, 0xcd, // IP address
+ 0, 0, 0x50, 0, // preferred-lifetime
+ 0, 0, 0x70, 0, // valid-lifetime
+
+ // suboption
+ 0xca, 0xfe, // type
+ 0, 0 // len
+ };
+ ASSERT_EQ(38, sizeof(expected));
+
+ // Make sure that the buffer's size is sufficient to
+ // copy the elements from the array.
+ ASSERT_GE(buf_.size(), sizeof(expected));
+ memcpy(&buf_[0], expected, sizeof(expected));
+
+ boost::shared_ptr<OptionInt<uint16_t> > opt;
+ EXPECT_NO_THROW(
+ opt = boost::shared_ptr<
+ OptionInt<uint16_t> >(new OptionInt<uint16_t>(Option::V6, opt_code,
+ buf_.begin() + 4,
+ buf_.begin() + sizeof(expected)));
+ );
+ ASSERT_TRUE(opt);
+
+ EXPECT_EQ(opt_code, opt->getType());
+ EXPECT_EQ(0x0102, opt->getValue());
+
+ // Checks for address option
+ OptionPtr subopt = opt->getOption(D6O_IAADDR);
+ ASSERT_TRUE(subopt);
+ boost::shared_ptr<Option6IAAddr> addr(boost::dynamic_pointer_cast<Option6IAAddr>(subopt));
+ ASSERT_TRUE(addr);
+
+ EXPECT_EQ(D6O_IAADDR, addr->getType());
+ EXPECT_EQ(28, addr->len());
+ EXPECT_EQ(0x5000, addr->getPreferred());
+ EXPECT_EQ(0x7000, addr->getValid());
+ EXPECT_EQ("2001:db8:1234:5678::abcd", addr->getAddress().toText());
+
+ // Checks for dummy option
+ subopt = opt->getOption(0xcafe);
+ ASSERT_TRUE(subopt); // should be non-NULL
+
+ EXPECT_EQ(0xcafe, subopt->getType());
+ EXPECT_EQ(4, subopt->len());
+ // There should be no data at all
+ EXPECT_EQ(0, subopt->getData().size());
+
+ // Try to get non-existent option.
+ subopt = opt->getOption(1);
+ // Expecting NULL which means that option does not exist.
+ ASSERT_FALSE(subopt);
+}
+
+} // anonymous namespace
diff --git a/src/lib/dhcp/tests/pkt4_unittest.cc b/src/lib/dhcp/tests/pkt4_unittest.cc
index 2ef982a..bd848ff 100644
--- a/src/lib/dhcp/tests/pkt4_unittest.cc
+++ b/src/lib/dhcp/tests/pkt4_unittest.cc
@@ -462,13 +462,17 @@ TEST(Pkt4Test, file) {
EXPECT_THROW(pkt4.setFile(NULL, 0), InvalidParameter);
}
+/// V4 Options being used for pack/unpack testing.
+/// For test simplicity, all selected options have
+/// variable length data so as there are no restrictions
+/// on a length of their data.
static uint8_t v4Opts[] = {
- 12, 3, 0, 1, 2,
- 13, 3, 10, 11, 12,
- 14, 3, 20, 21, 22,
- 53, 1, 1, // DHCP_MESSAGE_TYPE (required to not throw exception during unpack)
- 128, 3, 30, 31, 32,
- 254, 3, 40, 41, 42,
+ 12, 3, 0, 1, 2, // Hostname
+ 14, 3, 10, 11, 12, // Merit Dump File
+ 53, 1, 1, // Message Type (required to not throw exception during unpack)
+ 60, 3, 20, 21, 22, // Class Id
+ 128, 3, 30, 31, 32, // Vendor specific
+ 254, 3, 40, 41, 42, // Reserved
};
TEST(Pkt4Test, options) {
@@ -482,9 +486,9 @@ TEST(Pkt4Test, options) {
}
boost::shared_ptr<Option> opt1(new Option(Option::V4, 12, payload[0]));
- boost::shared_ptr<Option> opt2(new Option(Option::V4, 13, payload[1]));
- boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[2]));
+ boost::shared_ptr<Option> opt3(new Option(Option::V4, 14, payload[1]));
boost::shared_ptr<Option> optMsgType(new Option(Option::V4, DHO_DHCP_MESSAGE_TYPE));
+ boost::shared_ptr<Option> opt2(new Option(Option::V4, 60, payload[2]));
boost::shared_ptr<Option> opt5(new Option(Option::V4,128, payload[3]));
boost::shared_ptr<Option> opt4(new Option(Option::V4,254, payload[4]));
optMsgType->setUint8(static_cast<uint8_t>(DHCPDISCOVER));
@@ -497,7 +501,7 @@ TEST(Pkt4Test, options) {
pkt->addOption(optMsgType);
EXPECT_TRUE(pkt->getOption(12));
- EXPECT_TRUE(pkt->getOption(13));
+ EXPECT_TRUE(pkt->getOption(60));
EXPECT_TRUE(pkt->getOption(14));
EXPECT_TRUE(pkt->getOption(128));
EXPECT_TRUE(pkt->getOption(254));
@@ -554,7 +558,7 @@ TEST(Pkt4Test, unpackOptions) {
);
EXPECT_TRUE(pkt->getOption(12));
- EXPECT_TRUE(pkt->getOption(13));
+ EXPECT_TRUE(pkt->getOption(60));
EXPECT_TRUE(pkt->getOption(14));
EXPECT_TRUE(pkt->getOption(128));
EXPECT_TRUE(pkt->getOption(254));
@@ -566,19 +570,19 @@ TEST(Pkt4Test, unpackOptions) {
EXPECT_EQ(5, x->len()); // total option length 5
EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+2, 3)); // data len=3
- x = pkt->getOption(13);
+ x = pkt->getOption(14);
ASSERT_TRUE(x); // option 13 should exist
- EXPECT_EQ(13, x->getType()); // this should be option 13
+ EXPECT_EQ(14, x->getType()); // this should be option 13
ASSERT_EQ(3, x->getData().size()); // it should be of length 3
EXPECT_EQ(5, x->len()); // total option length 5
EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+7, 3)); // data len=3
- x = pkt->getOption(14);
- ASSERT_TRUE(x); // option 14 should exist
- EXPECT_EQ(14, x->getType()); // this should be option 14
+ x = pkt->getOption(60);
+ ASSERT_TRUE(x); // option 60 should exist
+ EXPECT_EQ(60, x->getType()); // this should be option 60
ASSERT_EQ(3, x->getData().size()); // it should be of length 3
EXPECT_EQ(5, x->len()); // total option length 5
- EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+12, 3)); // data len=3
+ EXPECT_EQ(0, memcmp(&x->getData()[0], v4Opts+15, 3)); // data len=3
x = pkt->getOption(128);
ASSERT_TRUE(x); // option 3 should exist
More information about the bind10-changes
mailing list