Commit 5765f9d6 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[master] Merge branch 'trac2304'

parents a9688bc1 9a52c2a5
......@@ -22,10 +22,14 @@ libb10_dhcp___la_SOURCES += iface_mgr_linux.cc
libb10_dhcp___la_SOURCES += iface_mgr_bsd.cc
libb10_dhcp___la_SOURCES += iface_mgr_sun.cc
libb10_dhcp___la_SOURCES += option.cc option.h
libb10_dhcp___la_SOURCES += option_data_types.h
libb10_dhcp___la_SOURCES += option_definition.cc option_definition.h
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 += dhcp6.h dhcp4.h
libb10_dhcp___la_SOURCES += pkt6.cc pkt6.h
libb10_dhcp___la_SOURCES += pkt4.cc pkt4.h
......
......@@ -20,6 +20,7 @@
#include <vector>
#include <boost/shared_ptr.hpp>
#include <boost/shared_array.hpp>
#include <asiolink/io_address.h>
#include <util/buffer.h>
#include <dhcp/option.h>
......
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef OPTION6_INT_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 (!OptionDataTypes<T>::valid) {
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 (!OptionDataTypes<T>::valid) {
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 unsiged or signed integers so there is not need to create
// special cases for intX_t types.
switch (OptionDataTypes<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");
}
LibDHCP::packOptions6(buf, options_);
}
/// @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 unsiged or signed integers so there is not need to create
// special cases for intX_t types.
int data_size_len = OptionDataTypes<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 OptionDataTypes<T>::len directly some versions
// of clang complain about unresolved reference to
// OptionDataTypes structure during linking.
begin += data_size_len;
LibDHCP::unpackOptions6(OptionBuffer(begin, end), options_);
}
/// @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_ */
// 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 (!OptionDataTypes<T>::valid) {
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 (!OptionDataTypes<T>::valid) {
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 (!OptionDataTypes<T>::valid) {
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 unsiged or signed integers so there is not need to create
// special cases for intX_t types.
switch (OptionDataTypes<T>::len) {
case 1:
buf.writeUint8(values_[i]);
break;
case 2:
buf.writeUint16(values_[i]);
break;
case 4:
buf.writeUint32(values_[i]);
break;
default:
isc_throw(dhcp::InvalidDataType, "non-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 unsiged or signed integers so there is not need to create
// special cases for intX_t types.
int data_size_len = OptionDataTypes<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 OptionDataTypes<T>::len directly some versions
// of clang complain about unresolved reference to
// OptionDataTypes 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_ */
// 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_DATA_TYPES_H_
#define OPTION_DATA_TYPES_H_
#include <exceptions/exceptions.h>
#include <stdint.h>
namespace isc {
namespace dhcp {
/// @brief Exception to be thrown when invalid type specified as template parameter.
class InvalidDataType : public Exception {
public:
InvalidDataType(const char* file, size_t line, const char* what) :
isc::Exception(file, line, what) { };
};
/// @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;
static const int len = 4;
};
} // isc::dhcp namespace
} // isc namespace
#endif /* OPTION_DATA_TYPES_H_ */
// Copyright (C) 2012 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#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;
namespace isc {
namespace dhcp {
OptionDefinition::DataTypeUtil::DataTypeUtil() {
data_types_["empty"] = EMPTY_TYPE;
data_types_["boolean"] = BOOLEAN_TYPE;
data_types_["int8"] = INT8_TYPE;
data_types_["int16"] = INT16_TYPE;
data_types_["int32"] = INT32_TYPE;
data_types_["uint8"] = UINT8_TYPE;
data_types_["uint16"] = UINT16_TYPE;
data_types_["uint32"] = UINT32_TYPE;
data_types_["ipv4-address"] = IPV4_ADDRESS_TYPE;
data_types_["ipv6-address"] = IPV6_ADDRESS_TYPE;
data_types_["string"] = STRING_TYPE;
data_types_["fqdn"] = FQDN_TYPE;
data_types_["record"] = RECORD_TYPE;
}
OptionDefinition::DataType
OptionDefinition::DataTypeUtil::getDataType(const std::string& data_type) {
std::map<std::string, DataType>::const_iterator data_type_it =
data_types_.find(data_type);
if (data_type_it != data_types_.end()) {
return (data_type_it->second);
}
return UNKNOWN_TYPE;
}
OptionDefinition::OptionDefinition(const std::string& name,
const uint16_t code,
const std::string& type,
const bool array_type /* = false */)
: name_(name),
code_(code),
type_(UNKNOWN_TYPE),
array_type_(array_type) {
// Data type is held as enum value by this class.
// Use the provided option type string to get the
// corresponding enum value.
type_ = DataTypeUtil::instance().getDataType(type);
}
OptionDefinition::OptionDefinition(const std::string& name,
const uint16_t code,
const DataType type,
const bool array_type /* = false */)
: name_(name),
code_(code),
type_(type),
array_type_(array_type) {
}
void
OptionDefinition::addRecordField(const std::string& data_type_name) {
DataType data_type = DataTypeUtil::instance().getDataType(data_type_name);
addRecordField(data_type);
}
void
OptionDefinition::addRecordField(const DataType data_type) {
if (type_ != RECORD_TYPE) {