#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>
#include <limits>
-#include <util/io_utilities.h>
-#include "dhcp/libdhcp++.h"
-#include "dhcp/option.h"
-#include "dhcp/option_data_types.h"
namespace isc {
namespace dhcp {
#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>
#include <limits>
-#include <util/io_utilities.h>
-#include "dhcp/libdhcp++.h"
-#include "dhcp/option.h"
-#include "dhcp/option_data_types.h"
namespace isc {
namespace dhcp {
/// @brief Set option values.
///
- /// @param collection of values to be set.
+ /// @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
#ifndef OPTION_DATA_TYPES_H_
#define OPTION_DATA_TYPES_H_
-#include <stdint.h>
#include <exceptions/exceptions.h>
+#include <stdint.h>
+
namespace isc {
namespace dhcp {
isc::Exception(file, line, what) { };
};
-/// @brief Numeric data types supported by DHCP option defintions.
+/// @brief Trait class for integer 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
+/// factory functions in OptionDefinition class.
template<typename T>
struct OptionDataTypes {
static const bool valid = false;
static const int len = 0;
};
+/// int8_t type is supported.
template<>
struct OptionDataTypes<int8_t> {
static const bool valid = true;
static const int len = 1;
};
+/// int16_t type is supported.
template<>
struct OptionDataTypes<int16_t> {
static const bool valid = true;
static const int len = 2;
};
+/// int32_t type is supported.
template<>
struct OptionDataTypes<int32_t> {
static const bool valid = true;
static const int len = 4;
};
+/// uint8_t type is supported.
template<>
struct OptionDataTypes<uint8_t> {
static const bool valid = true;
static const int len = 1;
};
+/// uint16_t type is supported.
template<>
struct OptionDataTypes<uint16_t> {
static const bool valid = true;
static const int len = 2;
};
+/// uint32_t type is supported.
template<>
struct OptionDataTypes<uint32_t> {
static const bool valid = true;
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
-#include "dhcp/dhcp6.h"
-#include "dhcp/option_definition.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/dhcp6.h>
+#include <dhcp/option_definition.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>
using namespace std;
using namespace isc::util;
Option::Factory*
OptionDefinition::getFactory() const {
+ // @todo This function must be extended to return more factory
+ // functions that create instances of more specialized options.
+ // This requires us to first implement those more specialized
+ // options that will be derived from Option class.
if (type_ == IPV6_ADDRESS_TYPE && array_type_) {
return (factoryAddrList6);
} else if (type_ == IPV4_ADDRESS_TYPE && array_type_) {
return (factoryInteger<uint32_t>);
}
}
+ // Factory generic returns instance of Option class. However, once we
+ // implement CustomOption class we may want to return factory function
+ // that will create instance of CustomOption rather than Option.
+ // CustomOption will allow to access particular data fields within the
+ // option rather than raw data buffer.
return (factoryGeneric);
}
void
OptionDefinition::validate() const {
+ // Option name must not be empty.
+ if (name_.empty()) {
+ isc_throw(isc::BadValue, "option name must not be empty");
+ }
+ // Option name must not contain spaces.
+ if (name_.find(" ") != string::npos) {
+ isc_throw(isc::BadValue, "option name must not contain spaces");
+ }
+ // Unsupported option types are not allowed.
if (type_ >= UNKNOWN_TYPE) {
isc_throw(isc::OutOfRange, "option type value " << type_
<< " is out of range");
#ifndef OPTION_DEFINITION_H_
#define OPTION_DEFINITION_H_
-#include "dhcp/option_data_types.h"
-#include "dhcp/option6_int.h"
-#include "dhcp/option6_int_array.h"
-#include "dhcp/option.h"
+#include <dhcp/option_data_types.h>
+#include <dhcp/option6_int.h>
+#include <dhcp/option6_int_array.h>
+#include <dhcp/option.h>
namespace isc {
namespace dhcp {
/// limited by the maximal DHCPv6 option length).
/// Should option comprise data fields of different types the "record"
/// option type is used. In such cases the data field types within the
-/// record are specified using \ref OptionDefinition::AddRecordField.
+/// record are specified using \ref OptionDefinition::addRecordField.
/// When OptionDefinition object has been sucessfully created it
/// can be queried to return the appropriate option factory function
/// for the specified option format. There is a number of "standard"
///
/// @todo Extend the comment to describe "generic factories".
/// @todo Extend this class to use custom namespaces.
+/// @todo Extend this class with more factory functions.
class OptionDefinition {
public:
private:
/// @brief Utility class for operations on DataTypes.
+ ///
+ /// This class is implemented as the singleton because the list of
+ /// supported data types is in this case loaded only once
+ /// into the memory and persists for all option definitions.
+ ///
+ /// @todo This class can be extended to return the string value
+ /// representing the data type from the enum value.
class DataTypeUtil {
public:
/// @return option data type.
DataType getType() const { return (type_); };
+ /// @brief Check if the option definition is valid.
+ ///
+ /// @throw isc::OutOfRange if invalid option type was specified.
+ /// @throw isc::BadValue if invalid option name was specified,
+ /// e.g. empty or containing spaces.
+ void validate() const;
+
/// @brief Check if specified format is IA_NA option format.
///
/// @return true if specified format is IA_NA option format.
/// @param u universe (must be V4).
/// @param type option type.
/// @param buf option buffer with a list of IPv4 addresses.
+ ///
+ /// @throw isc::OutOfRange if length of the provided option buffer
+ /// is not multiple of IPV4 address length.
static OptionPtr factoryAddrList4(Option::Universe u, uint16_t type,
const OptionBuffer& buf);
/// @param u universe (must be V6).
/// @param type option type.
/// @param buf option buffer with a list of IPv6 addresses.
+ ///
+ /// @throw isc::OutOfaRange if length of provided option buffer
+ /// is not multiple of IPV6 address length.
static OptionPtr factoryAddrList6(Option::Universe u, uint16_t type,
const OptionBuffer& buf);
static OptionPtr factoryEmpty(Option::Universe u, uint16_t type,
const OptionBuffer& buf);
- /// @brief Factory to create generic option..
+ /// @brief Factory to create generic option.
///
/// @param u universe (V6 or V4).
/// @param type option type.
/// @brief Factory function to create option with integer value.
///
- /// @param u universe (V6 or V4).
/// @param type option type.
/// @param buf option buffer.
- /// @param T type of the data field (must be one of the uintX_t or intX_t).
+ /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
+ ///
+ /// @throw isc::OutOfRange if provided option buffer length is invalid.
template<typename T>
static OptionPtr factoryInteger(Option::Universe, uint16_t type, const OptionBuffer& buf) {
if (buf.size() > sizeof(T)) {
/// @brief Factory function to create option with array of integer values.
///
- /// @param u universe (V6 or V4).
/// @param type option type.
/// @param buf option buffer.
- /// @param T type of the data field (must be one of the uintX_t or intX_t).
+ /// @tparam T type of the data field (must be one of the uintX_t or intX_t).
+ ///
+ /// @throw isc::OutOfRange if provided option buffer length is invalid.
template<typename T>
static OptionPtr factoryIntegerArray(Option::Universe, uint16_t type, const OptionBuffer& buf) {
if (buf.size() == 0) {
/// @param actual_universe actual universe value.
///
/// @throw isc::BadValue if expected universe and actual universe don't match.
- static inline void sanityCheckUniverse(const Option::Universe expected_universe,
- const Option::Universe actual_universe);
-
- /// @brief Check if the option definition is valid.
- ///
- /// @todo: list exceptions it throws.
- void validate() const;
+ static inline void sanityCheckUniverse(const Option::Universe expected_universe,
+ const Option::Universe actual_universe);
/// Option name.
std::string name_;
#include <dhcp/option6_iaaddr.h>
#include <util/buffer.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
#include <boost/pointer_cast.hpp>
#include <gtest/gtest.h>
#include <dhcp/option6_iaaddr.h>
#include <util/buffer.h>
-#include <iostream>
-#include <sstream>
-#include <arpa/inet.h>
#include <boost/pointer_cast.hpp>
#include <gtest/gtest.h>
// PERFORMANCE OF THIS SOFTWARE.
#include <config.h>
-#include <iostream>
-#include <sstream>
+
+#include <exceptions/exceptions.h>
+#include <asiolink/io_address.h>
+#include <dhcp/dhcp4.h>
+#include <dhcp/dhcp6.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_definition.h>
#include <gtest/gtest.h>
#include <boost/shared_ptr.hpp>
#include <boost/pointer_cast.hpp>
-#include <exceptions/exceptions.h>
-#include <asiolink/io_address.h>
-#include "dhcp/dhcp4.h"
-#include "dhcp/dhcp6.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_definition.h"
-
using namespace std;
using namespace isc;
using namespace isc::dhcp;
EXPECT_EQ(1, opt_def1.getCode());
EXPECT_EQ(OptionDefinition::STRING_TYPE, opt_def1.getType());
EXPECT_FALSE(opt_def1.getArrayType());
+ EXPECT_NO_THROW(opt_def1.validate());
// Specify the option data type as an enum value.
OptionDefinition opt_def2("OPTION_RAPID_COMMIT", 14,
EXPECT_EQ(14, opt_def2.getCode());
EXPECT_EQ(OptionDefinition::EMPTY_TYPE, opt_def2.getType());
EXPECT_FALSE(opt_def2.getArrayType());
+ EXPECT_NO_THROW(opt_def1.validate());
// Check if it is possible to set that option is an array.
OptionDefinition opt_def3("OPTION_NIS_SERVERS", 27,
EXPECT_EQ(27, opt_def3.getCode());
EXPECT_EQ(OptionDefinition::IPV6_ADDRESS_TYPE, opt_def3.getType());
EXPECT_TRUE(opt_def3.getArrayType());
+ EXPECT_NO_THROW(opt_def3.validate());
// The created object is invalid if invalid data type is specified but
// constructor shouldn't throw exception. The object is validated after
EXPECT_THROW(opt_def.addRecordField(invalid_type), isc::BadValue);
}
+TEST_F(OptionDefinitionTest, validate) {
+ // Not supported option type string is not allowed.
+ OptionDefinition opt_def1("OPTION_CLIENTID", D6O_CLIENTID, "non-existent-type");
+ EXPECT_THROW(opt_def1.validate(), isc::OutOfRange);
+
+ // Not supported option type enum value is not allowed.
+ OptionDefinition opt_def2("OPTION_CLIENTID", D6O_CLIENTID, OptionDefinition::UNKNOWN_TYPE);
+ EXPECT_THROW(opt_def2.validate(), isc::OutOfRange);
+
+ OptionDefinition opt_def3("OPTION_CLIENTID", D6O_CLIENTID,
+ static_cast<OptionDefinition::DataType>(OptionDefinition::UNKNOWN_TYPE
+ + 2));
+ EXPECT_THROW(opt_def3.validate(), isc::OutOfRange);
+
+ // Empty option name is not allowed.
+ OptionDefinition opt_def4("", D6O_CLIENTID, "string");
+ EXPECT_THROW(opt_def4.validate(), isc::BadValue);
+
+ // Option name must not contain spaces.
+ OptionDefinition opt_def5(" OPTION_CLIENTID", D6O_CLIENTID, "string");
+ EXPECT_THROW(opt_def5.validate(), isc::BadValue);
+
+ OptionDefinition opt_def6("OPTION CLIENTID", D6O_CLIENTID, "string");
+ EXPECT_THROW(opt_def6.validate(), isc::BadValue);
+}
TEST_F(OptionDefinitionTest, factoryAddrList6) {
OptionDefinition opt_def("OPTION_NIS_SERVERS", D6O_NIS_SERVERS,