-// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
void
Option::unpackOptions(const OptionBuffer& buf) {
- // If custom option parsing function has been set, use this function
- // to parse options. Otherwise, use standard function from libdhcp++.
- if (!callback_.empty()) {
- callback_(buf, getEncapsulatedSpace(), options_, 0, 0);
- return;
- }
-
switch (universe_) {
case V4:
LibDHCP::unpackOptions4(buf, getEncapsulatedSpace(), options_);
-// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/// A pointer to an OptionCollection
typedef boost::shared_ptr<OptionCollection> OptionCollectionPtr;
-/// @brief This type describes a callback function to parse options from buffer.
-///
-/// @note The last two parameters should be specified in the callback function
-/// parameters list only if DHCPv6 options are parsed. Exclude these parameters
-/// from the callback function defined to parse DHCPv4 options.
-///
-/// @param buffer A buffer holding options to be parsed.
-/// @param encapsulated_space A name of the option space to which options being
-/// parsed belong.
-/// @param [out] options A container to which parsed options should be appended.
-/// @param relay_msg_offset A pointer to a size_t value. It indicates the
-/// offset to beginning of relay_msg option. This parameter should be specified
-/// for DHCPv6 options only.
-/// @param relay_msg_len A pointer to a size_t value. It holds the length of
-/// of the relay_msg option. This parameter should be specified for DHCPv6
-/// options only.
-///
-/// @return An offset to the first byte after last parsed option.
-typedef boost::function< size_t(const OptionBuffer& buffer,
- const std::string encapsulated_space,
- OptionCollection& options,
- size_t* relay_msg_offset,
- size_t* relay_msg_len)
- > UnpackOptionsCallback;
-
-
class Option {
public:
/// length of the usual DHCPv4 option header (there are exceptions)
return (encapsulated_space_);
}
- /// @brief Set callback function to be used to parse options.
- ///
- /// @param callback An instance of the callback function or NULL to
- /// uninstall callback.
- void setCallback(UnpackOptionsCallback callback) {
- callback_ = callback;
- }
-
/// just to force that every option has virtual dtor
virtual ~Option();
/// Name of the option space being encapsulated by this option.
std::string encapsulated_space_;
- /// A callback to be called to unpack options from the packet.
- UnpackOptionsCallback callback_;
-
/// @todo probably 2 different containers have to be used for v4 (unique
/// options) and v6 (options with the same type can repeat)
};
OptionPtr
OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
OptionBufferConstIter begin,
- OptionBufferConstIter end,
- UnpackOptionsCallback callback) const {
+ OptionBufferConstIter end) const {
try {
// Some of the options are represented by the specialized classes derived
// type to be returned. Therefore, we first check that if we are dealing
// with such an option. If the instance is returned we just exit at this
// point. If not, we will search for a generic option type to return.
- OptionPtr option = factorySpecialFormatOption(u, begin, end, callback);
+ OptionPtr option = factorySpecialFormatOption(u, begin, end);
if (option) {
return (option);
}
return (array_type_ ?
factoryIntegerArray<uint8_t>(u, type, begin, end) :
factoryInteger<uint8_t>(u, type, getEncapsulatedSpace(),
- begin, end, callback));
+ begin, end));
case OPT_INT8_TYPE:
return (array_type_ ?
factoryIntegerArray<int8_t>(u, type, begin, end) :
factoryInteger<int8_t>(u, type, getEncapsulatedSpace(),
- begin, end, callback));
+ begin, end));
case OPT_UINT16_TYPE:
return (array_type_ ?
factoryIntegerArray<uint16_t>(u, type, begin, end) :
factoryInteger<uint16_t>(u, type, getEncapsulatedSpace(),
- begin, end, callback));
+ begin, end));
case OPT_INT16_TYPE:
return (array_type_ ?
factoryIntegerArray<uint16_t>(u, type, begin, end) :
factoryInteger<int16_t>(u, type, getEncapsulatedSpace(),
- begin, end, callback));
+ begin, end));
case OPT_UINT32_TYPE:
return (array_type_ ?
factoryIntegerArray<uint32_t>(u, type, begin, end) :
factoryInteger<uint32_t>(u, type, getEncapsulatedSpace(),
- begin, end, callback));
+ begin, end));
case OPT_INT32_TYPE:
return (array_type_ ?
factoryIntegerArray<uint32_t>(u, type, begin, end) :
factoryInteger<int32_t>(u, type, getEncapsulatedSpace(),
- begin, end, callback));
+ begin, end));
case OPT_IPV4_ADDRESS_TYPE:
// If definition specifies that an option is an array
OptionPtr
OptionDefinition::optionFactory(Option::Universe u, uint16_t type,
- const OptionBuffer& buf,
- UnpackOptionsCallback callback) const {
- return (optionFactory(u, type, buf.begin(), buf.end(), callback));
+ const OptionBuffer& buf) const {
+ return (optionFactory(u, type, buf.begin(), buf.end()));
}
OptionPtr
OptionPtr
OptionDefinition::factorySpecialFormatOption(Option::Universe u,
OptionBufferConstIter begin,
- OptionBufferConstIter end,
- UnpackOptionsCallback) const {
+ OptionBufferConstIter end) const {
if (u == Option::V6) {
if ((getCode() == D6O_IA_NA || getCode() == D6O_IA_PD) &&
haveIA6Format()) {
-// Copyright (C) 2012-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2012-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/// @param type option type.
/// @param begin beginning of the option buffer.
/// @param end end of the option buffer.
- /// @param callback An instance of the function which parses packet options.
- /// If this is set to non NULL value this function will be used instead of
- /// @c isc::dhcp::LibDHCP::unpackOptions6 and
- /// isc::dhcp::LibDHCP::unpackOptions4.
///
/// @return instance of the DHCP option.
/// @throw InvalidOptionValue if data for the option is invalid.
OptionPtr optionFactory(Option::Universe u, uint16_t type,
OptionBufferConstIter begin,
- OptionBufferConstIter end,
- UnpackOptionsCallback callback = NULL) const;
+ OptionBufferConstIter end) const;
/// @brief Option factory.
///
/// @param u option universe (V4 or V6).
/// @param type option type.
/// @param buf option buffer.
- /// @param callback An instance of the function which parses packet options.
- /// If this is set to non NULL value this function will be used instead of
- /// @c isc::dhcp::LibDHCP::unpackOptions6 and
- /// isc::dhcp::LibDHCP::unpackOptions4.
///
/// @return instance of the DHCP option.
/// @throw InvalidOptionValue if data for the option is invalid.
OptionPtr optionFactory(Option::Universe u, uint16_t type,
- const OptionBuffer& buf = OptionBuffer(),
- UnpackOptionsCallback callback = NULL) const;
+ const OptionBuffer& buf = OptionBuffer()) const;
/// @brief Option factory.
///
/// encapsulated option space are sub options of this option.
/// @param begin iterator pointing to the beginning of the buffer.
/// @param end iterator pointing to the end of the buffer.
- /// @param callback An instance of the function which parses packet options.
- /// If this is set to non NULL value this function will be used instead of
- /// @c isc::dhcp::LibDHCP::unpackOptions6 and
- /// isc::dhcp::LibDHCP::unpackOptions4.
/// @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.
static OptionPtr factoryInteger(Option::Universe u, uint16_t type,
const std::string& encapsulated_space,
OptionBufferConstIter begin,
- OptionBufferConstIter end,
- UnpackOptionsCallback callback) {
+ OptionBufferConstIter end) {
OptionPtr option(new OptionInt<T>(u, type, 0));
option->setEncapsulatedSpace(encapsulated_space);
- option->setCallback(callback);
option->unpack(begin, end);
return (option);
}
/// @param u A universe (V4 or V6).
/// @param begin beginning of the option buffer.
/// @param end end of the option buffer.
- /// @param callback An instance of the function which parses packet options.
- /// If this is set to non NULL value this function will be used instead of
- /// @c isc::dhcp::LibDHCP::unpackOptions6 and
- /// isc::dhcp::LibDHCP::unpackOptions4.
///
/// @return An instance of the option having special format or NULL if
/// such an option can't be created because an option with the given
/// option code hasn't got the special format.
OptionPtr factorySpecialFormatOption(Option::Universe u,
OptionBufferConstIter begin,
- OptionBufferConstIter end,
- UnpackOptionsCallback callback) const;
+ OptionBufferConstIter end) const;
/// @brief Check if specified option format is a record with 3 fields
/// where first one is custom, and two others are uint32.
-// Copyright (C) 2014-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2014-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
/// that we just received, a copy between those two buffers is necessary.
void repack();
- /// @brief Set callback function to be used to parse options.
- ///
- /// @param callback An instance of the callback function or NULL to
- /// uninstall callback.
- void setCallback(UnpackOptionsCallback callback) {
- callback_ = callback;
- }
-
/// @brief Sets remote IP address.
///
/// @param remote specifies remote address
// remote HW address (src if receiving packet, dst if sending packet)
HWAddrPtr remote_hwaddr_;
- /// A callback to be called to unpack options from the packet.
- UnpackOptionsCallback callback_;
-
private:
/// @brief Generic method that validates and sets HW address.
// Use readVector because a function which parses option requires
// a vector as an input.
- size_t offset;
buffer_in.readVector(opts_buffer, opts_len);
- if (callback_.empty()) {
- offset = LibDHCP::unpackOptions4(opts_buffer, "dhcp4", options_);
- } else {
- // The last two arguments are set to NULL because they are
- // specific to DHCPv6 options parsing. They are unused for
- // DHCPv4 case. In DHCPv6 case they hold are the relay message
- // offset and length.
- offset = callback_(opts_buffer, "dhcp4", options_, NULL, NULL);
- }
+
+ size_t offset = LibDHCP::unpackOptions4(opts_buffer, "dhcp4", options_);
// If offset is not equal to the size and there is no DHO_END,
// then something is wrong here. We either parsed past input
// If custom option parsing function has been set, use this function
// to parse options. Otherwise, use standard function from libdhcp.
- size_t offset;
- if (callback_.empty()) {
- offset = LibDHCP::unpackOptions6(opt_buffer, "dhcp6", options_);
- } else {
- // The last two arguments hold the DHCPv6 Relay message offset and
- // length. Setting them to NULL because we are dealing with the
- // not-relayed message.
- offset = callback_(opt_buffer, "dhcp6", options_, NULL, NULL);
- }
+ size_t offset = LibDHCP::unpackOptions6(opt_buffer, "dhcp6", options_);
// If offset is not equal to the size, then something is wrong here. We
// either parsed past input buffer (bug in our code) or we haven't parsed
// If custom option parsing function has been set, use this function
// to parse options. Otherwise, use standard function from libdhcp.
- if (callback_.empty()) {
- LibDHCP::unpackOptions6(opt_buffer, "dhcp6", relay.options_,
- &relay_msg_offset, &relay_msg_len);
- } else {
- callback_(opt_buffer, "dhcp6", relay.options_,
- &relay_msg_offset, &relay_msg_len);
- }
+ LibDHCP::unpackOptions6(opt_buffer, "dhcp6", relay.options_,
+ &relay_msg_offset, &relay_msg_len);
/// @todo: check that each option appears at most once
//relay.interface_id_ = options->getOption(D6O_INTERFACE_ID);
OptionBuffer buf(1);
EXPECT_THROW(
OptionDefinition::factoryInteger<bool>(Option::V6, D6O_PREFERENCE, "dhcp6",
- buf.begin(), buf.end(), NULL),
+ buf.begin(), buf.end()),
isc::dhcp::InvalidDataType
);
}
-// Copyright (C) 2011-2015 Internet Systems Consortium, Inc. ("ISC")
+// Copyright (C) 2011-2016 Internet Systems Consortium, Inc. ("ISC")
//
// This Source Code Form is subject to the terms of the Mozilla Public
// License, v. 2.0. If a copy of the MPL was not distributed with this
namespace {
-/// @brief A class which contains a custom callback function to unpack options.
-///
-/// This is a class used by the tests which verify that the custom callback
-/// functions can be installed to unpack options from a message. When the
-/// callback function is called, the executed_ member is set to true to allow
-/// verification that the callback was really called. Internally, this class
-/// uses libdhcp++ to unpack options so the options parsing algorithm remains
-/// unchanged after installation of the callback.
-class CustomUnpackCallback {
-public:
-
- /// @brief Constructor
- ///
- /// Marks that callback hasn't been called.
- CustomUnpackCallback()
- : executed_(false) {
- }
-
- /// @brief A callback
- ///
- /// Contains custom implementation of the callback.
- ///
- /// @param buf a A buffer holding options in on-wire format.
- /// @param option_space A name of the option space being encapsulated by
- /// the option being parsed.
- /// @param [out] options A reference to the collection where parsed options
- /// will be stored.
- /// @param relay_msg_offset Reference to a size_t structure. If specified,
- /// offset to beginning of relay_msg option will be stored in it.
- /// @param relay_msg_len reference to a size_t structure. If specified,
- /// length of the relay_msg option will be stored in it.
- /// @return An offset to the first byte after last parsed option.
- size_t execute(const OptionBuffer& buf,
- const std::string& option_space,
- isc::dhcp::OptionCollection& options,
- size_t* relay_msg_offset,
- size_t* relay_msg_len) {
- // Set the executed_ member to true to allow verification that the
- // callback has been actually called.
- executed_ = true;
- // Use default implementation of the unpack algorithm to parse options.
- return (LibDHCP::unpackOptions6(buf, option_space, options, relay_msg_offset,
- relay_msg_len));
- }
-
- /// A flag which indicates if callback function has been called.
- bool executed_;
-};
-
/// @brief A class which derives from option and exposes protected members.
class NakedOption : public Option {
public:
}
-// This test verifies that it is possible to specify custom implementation of
-// the option parsing algorithm by installing a callback function.
-TEST_F(OptionTest, unpackCallback) {
- // Create a buffer which holds two sub options.
- const char opt_data[] = {
- 0x00, 0x01, // sub option code = 1
- 0x00, 0x02, // sub option length = 2
- 0x00, 0x01, // sub option data (2 bytes)
- 0x00, 0x02, // sub option code = 2
- 0x00, 0x02, // sub option length = 2
- 0x01, 0x01 // sub option data (2 bytes)
- };
- OptionBuffer opt_buf(opt_data, opt_data + sizeof(opt_data));
-
- // Make sure that the flag which indicates if the callback function has
- // been called is not set. Otherwise, our test doesn't make sense.
- CustomUnpackCallback cb;
- ASSERT_FALSE(cb.executed_);
- // Create an option and install a callback.
- NakedOption option;
- // Parameters from _1 to _5 are placeholders for the actual values
- // to be passed to the callback function. See: boost::bind documentation
- // at http://www.boost.org/doc/libs/1_54_0/libs/bind/bind.html.
- // Also, see UnpackOptionsCallback in option.h for description of the
- // parameter values.
- option.setCallback(boost::bind(&CustomUnpackCallback::execute, &cb,
- _1, _2, _3, _4, _5));
- // Parse options. It should result in a call to our callback function.
- // This function uses LibDHCP to parse options so they should be parsed
- // correctly.
- ASSERT_NO_THROW(option.unpackOptions(opt_buf));
- EXPECT_TRUE(option.getOption(1));
- EXPECT_TRUE(option.getOption(2));
- EXPECT_FALSE(option.getOption(3));
- // The callback should have been registered.
- EXPECT_TRUE(cb.executed_);
- // Reset the flag because now we are going to uninstall the callback and
- // verify that it was NOT called.
- cb.executed_ = false;
- // Uninstall the callback.
- option.setCallback(NULL);
- ASSERT_NO_THROW(option.unpackOptions(opt_buf));
- // Options should still get unpacked...
- EXPECT_TRUE(option.getOption(1));
- EXPECT_TRUE(option.getOption(2));
- EXPECT_FALSE(option.getOption(3));
- // ... but not via callback.
- EXPECT_FALSE(cb.executed_);
-}
-
-
}
namespace {
-/// @brief A class which contains a custom callback function to unpack options.
-///
-/// This is a class used by the tests which verify that the custom callback
-/// functions can be installed to unpack options from a message. When the
-/// callback function is called, the executed_ member is set to true to allow
-/// verification that the callback was really called. Internally, this class
-/// uses libdhcp++ to unpack options so the options parsing algorithm remains
-/// unchanged after installation of the callback.
-class CustomUnpackCallback {
-public:
-
- /// @brief Constructor
- ///
- /// Marks that callback hasn't been called.
- CustomUnpackCallback()
- : executed_(false) {
- }
-
- /// @brief A callback
- ///
- /// Contains custom implementation of the callback.
- ///
- /// @param buf a A buffer holding options in on-wire format.
- /// @param option_space A name of the option space being encapsulated by
- /// the option being parsed.
- /// @param [out] options A reference to the collection where parsed options
- /// will be stored.
- /// @return An offset to the first byte after last parsed option.
- size_t execute(const OptionBuffer& buf,
- const std::string& option_space,
- isc::dhcp::OptionCollection& options) {
- // Set the executed_ member to true to allow verification that the
- // callback has been actually called.
- executed_ = true;
- // Use default implementation of the unpack algorithm to parse options.
- return (LibDHCP::unpackOptions4(buf, option_space, options));
- }
-
- /// A flag which indicates if callback function has been called.
- bool executed_;
-};
-
/// V4 Options being used for pack/unpack testing.
/// For test simplicity, all selected options have
/// variable length data so as there are no restrictions
EXPECT_THROW(too_short_pkt->unpack(), InvalidOptionValue);
}
-// This test verifies that it is possible to specify custom implementation of
-// the option parsing algorithm by installing a callback function.
-TEST_F(Pkt4Test, unpackOptionsWithCallback) {
- vector<uint8_t> expectedFormat = generateTestPacket2();
-
- expectedFormat.push_back(0x63);
- expectedFormat.push_back(0x82);
- expectedFormat.push_back(0x53);
- expectedFormat.push_back(0x63);
-
- for (size_t i = 0; i < sizeof(v4_opts); i++) {
- expectedFormat.push_back(v4_opts[i]);
- }
-
- // now expectedFormat contains fixed format and 5 options
-
- boost::shared_ptr<Pkt4> pkt(new Pkt4(&expectedFormat[0],
- expectedFormat.size()));
-
- CustomUnpackCallback cb;
- pkt->setCallback(boost::bind(&CustomUnpackCallback::execute, &cb,
- _1, _2, _3));
-
- ASSERT_FALSE(cb.executed_);
-
- EXPECT_NO_THROW(pkt->unpack());
-
- EXPECT_TRUE(cb.executed_);
- verifyParsedOptions(pkt);
-
- // Reset the indicator to perform another check: uninstall the callback.
- cb.executed_ = false;
- // By setting the callback to NULL we effectively uninstall the callback.
- pkt->setCallback(NULL);
- // Do another unpack.
- EXPECT_NO_THROW(pkt->unpack());
- // Callback should not be executed.
- EXPECT_FALSE(cb.executed_);
-
-}
-
// This test verifies methods that are used for manipulating meta fields
// i.e. fields that are not part of DHCPv4 (e.g. interface name).
TEST_F(Pkt4Test, metaFields) {
namespace {
-/// @brief A class which contains a custom callback function to unpack options.
-///
-/// This is a class used by the tests which verify that the custom callback
-/// functions can be installed to unpack options from a message. When the
-/// callback function is called, the executed_ member is set to true to allow
-/// verification that the callback was really called. Internally, this class
-/// uses libdhcp++ to unpack options so the options parsing algorithm remains
-/// unchanged after installation of the callback.
-class CustomUnpackCallback {
-public:
-
- /// @brief Constructor
- ///
- /// Marks that callback hasn't been called.
- CustomUnpackCallback()
- : executed_(false) {
- }
-
- /// @brief A callback
- ///
- /// Contains custom implementation of the callback.
- ///
- /// @param buf a A buffer holding options in on-wire format.
- /// @param option_space A name of the option space encapsulated by the
- /// option being parsed.
- /// @param [out] options A reference to the collection where parsed options
- /// will be stored.
- /// @param relay_msg_offset Reference to a size_t structure. If specified,
- /// offset to beginning of relay_msg option will be stored in it.
- /// @param relay_msg_len reference to a size_t structure. If specified,
- /// length of the relay_msg option will be stored in it.
- /// @return An offset to the first byte after last parsed option.
- size_t execute(const OptionBuffer& buf,
- const std::string& option_space,
- isc::dhcp::OptionCollection& options,
- size_t* relay_msg_offset,
- size_t* relay_msg_len) {
- // Set the executed_ member to true to allow verification that the
- // callback has been actually called.
- executed_ = true;
- // Use default implementation of the unpack algorithm to parse options.
- return (LibDHCP::unpackOptions6(buf, option_space, options,
- relay_msg_offset, relay_msg_len));
- }
-
- /// A flag which indicates if callback function has been called.
- bool executed_;
-};
-
class Pkt6Test : public ::testing::Test {
public:
Pkt6Test() {
EXPECT_THROW(too_short_option_pkt->unpack(), OutOfRange);
}
-// This test verifies that it is possible to specify custom implementation of
-// the option parsing algorithm by installing a callback function.
-TEST_F(Pkt6Test, packUnpackWithCallback) {
- // Create an on-wire representation of the test packet and clone it.
- Pkt6Ptr pkt(new Pkt6(DHCPV6_SOLICIT, 0x020304));
- Pkt6Ptr clone = packAndClone(pkt);
-
- // Install the custom callback function. We expect that this function
- // will be called to parse options in the packet instead of
- // LibDHCP::unpackOptions6.
- CustomUnpackCallback cb;
- clone->setCallback(boost::bind(&CustomUnpackCallback::execute, &cb,
- _1, _2, _3, _4, _5));
- // Make sure that the flag which indicates if the callback function has
- // been called is not set. Otherwise, our test doesn't make sense.
- ASSERT_FALSE(cb.executed_);
-
- // Now recreate options list
- ASSERT_NO_THROW(clone->unpack());
-
- // An object which holds a callback should now have a flag set which
- // indicates that callback has been called.
- EXPECT_TRUE(cb.executed_);
-
- // transid, message-type should be the same as before
- EXPECT_EQ(0x020304, clone->getTransid());
- EXPECT_EQ(DHCPV6_SOLICIT, clone->getType());
-
- EXPECT_TRUE(clone->getOption(1));
- EXPECT_TRUE(clone->getOption(2));
- EXPECT_TRUE(clone->getOption(100));
- EXPECT_FALSE(clone->getOption(4));
-
- // Reset the indicator to perform another check: uninstall the callback.
- cb.executed_ = false;
- // By setting the callback to NULL we effectively uninstall the callback.
- clone->setCallback(NULL);
- // Do another unpack.
- ASSERT_NO_THROW(clone->unpack());
- // Callback should not be executed.
- EXPECT_FALSE(cb.executed_);
-}
-
// This test verifies that options can be added (addOption()), retrieved
// (getOption(), getOptions()) and deleted (delOption()).
TEST_F(Pkt6Test, addGetDelOptions) {