// We're reusing callout_handle from previous calls
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+
// Set new arguments
callout_handle->setArgument("query4", query);
callout_handle->setArgument("subnet4", subnet);
// Delete previously set arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> resp4_options_copy(rsp);
+
// Pass incoming packet as argument
callout_handle->setArgument("response4", rsp);
// Delete previously set arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+
// Pass incoming packet as argument
callout_handle->setArgument("query4", query);
// Delete previously set arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(query);
+
// Pass incoming packet as argument
callout_handle->setArgument("query4", query);
// Clear skip flag if it was set in previous callouts
callout_handle->setStatus(CalloutHandle::NEXT_STEP_CONTINUE);
+ // Enable copying options from the query and response packet within
+ // hook library.
+ ScopedEnableOptionsCopy<Pkt4> query_resp_options_copy(query, rsp);
+
// Set our response
callout_handle->setArgument("response4", rsp);
// Delete all previous arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(release);
+
// Pass the original packet
callout_handle->setArgument("query4", release);
// Delete previously set arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(decline);
+
// Pass incoming Decline and the lease to be declined.
callout_handle->setArgument("lease4", lease);
callout_handle->setArgument("query4", decline);
callout_handle.getArgument("query4", callback_qry_pkt4_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
return (0);
}
callout_handle.getArgument("query4", callback_qry_pkt4_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("query4", callback_qry_pkt4_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
+
+ if (callback_resp_pkt4_) {
+ callback_resp_options_copy_ = callback_resp_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("response4", callback_resp_pkt4_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_resp_pkt4_) {
+ callback_resp_options_copy_ = callback_resp_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("subnet4collection", callback_subnet4collection_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("lease4", callback_lease4_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("clientid", callback_clientid_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("query4", callback_qry_pkt4_);
callout_handle.getArgument("lease4", callback_lease4_);
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ = callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callback_subnet4_.reset();
callback_subnet4collection_ = NULL;
callback_argument_names_.clear();
+ callback_qry_options_copy_ = false;
+ callback_resp_options_copy_ = false;
}
/// pointer to Dhcpv4Srv that is used in tests
/// A list of all received arguments
static vector<string> callback_argument_names_;
+
+ /// Flag indicating if copying retrieved options was enabled for
+ /// a query during callout execution.
+ static bool callback_qry_options_copy_;
+
+ /// Flag indicating if copying retrieved options was enabled for
+ /// a response during callout execution.
+ static bool callback_resp_options_copy_;
+
};
// The following fields are used in testing pkt4_receive_callout.
Lease4Ptr HooksDhcpv4SrvTest::callback_lease4_;
const Subnet4Collection* HooksDhcpv4SrvTest::callback_subnet4collection_;
vector<string> HooksDhcpv4SrvTest::callback_argument_names_;
+bool HooksDhcpv4SrvTest::callback_qry_options_copy_;
+bool HooksDhcpv4SrvTest::callback_resp_options_copy_;
/// @brief Fixture class used to do basic library load/unload tests
class LoadUnloadDhcpv4SrvTest : public ::testing::Test {
expected_argument_names.push_back(string("query4"));
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// Checks if callouts installed on buffer4_receive is able to change
expected_argument_names.push_back(string("query4"));
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// Checks if callouts installed on pkt4_received is able to change
sort(callback_argument_names_.begin(), callback_argument_names_.end());
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
+ EXPECT_TRUE(callback_resp_options_copy_);
}
// Checks if callouts installed on pkt4_send is able to change
vector<string> expected_argument_names;
expected_argument_names.push_back(string("response4"));
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_resp_options_copy_);
}
// Checks if callouts installed on buffer4_send are indeed called and that
// Compare that the available subnets are reported as expected
EXPECT_TRUE((*exp_subnets)[0].get() == (*callback_subnet4collection_)[0].get());
EXPECT_TRUE((*exp_subnets)[1].get() == (*callback_subnet4collection_)[1].get());
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test checks if callout installed on subnet4_select hook point can pick
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
EXPECT_TRUE(LeaseMgrFactory::instance().deleteLease(addr));
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test verifies that a callout installed on lease4_renew can trigger
sort(callback_argument_names_.begin(), callback_argument_names_.end());
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test verifies that skip flag returned by a callout installed on the
// the lease manager) all match.
EXPECT_EQ(addr, from_mgr->addr_);
EXPECT_EQ(addr, callback_lease4_->addr_);
+
+ // Pkt passed to a callout must be configured to copy retrieved options.
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// Checks that decline4 hook is able to drop the packet.
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer6_receive_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(query);
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
+
// Delete previously set arguments
callout_handle->deleteAllArguments();
// Delete previously set arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
+
// Pass incoming packet as argument
callout_handle->setArgument("query6", query);
if (HooksManager::calloutsPresent(Hooks.hook_index_pkt6_send_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(query);
+ // Enable copying options from the packets within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query_resp_options_copy(query, rsp);
+
// Delete all previous arguments
callout_handle->deleteAllArguments();
// We're reusing callout_handle from previous calls
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(question);
+
// Set new arguments
callout_handle->setArgument("query6", question);
callout_handle->setArgument("subnet6", subnet);
if (HooksManager::calloutsPresent(Hooks.hook_index_lease6_release_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(query);
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(query);
+
// Delete all previous arguments
callout_handle->deleteAllArguments();
// Delete previously set arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(decline);
+
// Pass incoming packet as argument
callout_handle->setArgument("query6", decline);
callout_handle->setArgument("lease6", lease);
callout_handle.getArgument("query6", callback_qry_pkt6_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("query6", callback_qry_pkt6_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("query6", callback_qry_pkt6_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
+ if (callback_resp_pkt6_) {
+ callback_resp_options_copy_ = callback_resp_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("subnet6collection", callback_subnet6collection_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("ia_na", callback_ia_na_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("ia_na", callback_ia_na_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("lease6", callback_lease6_);
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callout_handle.getArgument("query6", callback_qry_pkt6_);
callout_handle.getArgument("lease6", callback_lease6_);
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ = callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
callback_ia_na_.reset();
callback_subnet6collection_ = NULL;
callback_argument_names_.clear();
+ callback_qry_options_copy_ = false;
+ callback_resp_options_copy_ = false;
}
/// Pointer to Dhcpv6Srv that is used in tests
/// A list of all received arguments
static vector<string> callback_argument_names_;
+
+ /// Flag indicating if copying retrieved options was enabled for
+ /// a query during callout execution.
+ static bool callback_qry_options_copy_;
+
+ /// Flag indicating if copying retrieved options was enabled for
+ /// a response during callout execution.
+ static bool callback_resp_options_copy_;
};
// The following parameters are used by callouts to override
vector<string> HooksDhcpv6SrvTest::callback_argument_names_;
Lease6Ptr HooksDhcpv6SrvTest::callback_lease6_;
boost::shared_ptr<Option6IA> HooksDhcpv6SrvTest::callback_ia_na_;
+bool HooksDhcpv6SrvTest::callback_qry_options_copy_;
+bool HooksDhcpv6SrvTest::callback_resp_options_copy_;
/// @brief Fixture class used to do basic library load/unload tests
class LoadUnloadDhcpv6SrvTest : public ::testing::Test {
expected_argument_names.push_back(string("query6"));
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// Checks if callouts installed on buffer6_receive is able to change
expected_argument_names.push_back(string("query6"));
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// Checks if callouts installed on pkt6_received is able to change
expected_argument_names.push_back(string("query6"));
expected_argument_names.push_back(string("response6"));
EXPECT_TRUE(expected_argument_names == callback_argument_names_);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
+ EXPECT_TRUE(callback_resp_options_copy_);
}
// Checks if callouts installed on pkt6_send is able to change
// in dynamic pool)
EXPECT_TRUE((*subnets)[1]->inRange(addr_opt->getAddress()));
EXPECT_TRUE((*subnets)[1]->inPool(Lease::TYPE_NA, addr_opt->getAddress()));
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test verifies that incoming (positive) RENEW can be handled properly,
// Check that the returned lease6 in callout is the same as the one in the
// database
EXPECT_TRUE(*callback_lease6_ == *l);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test verifies that incoming (positive) RENEW can be handled properly,
l = LeaseMgrFactory::instance().getLease6(Lease::TYPE_NA, *duid_, iaid,
subnet_->getID());
ASSERT_FALSE(l);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test verifies that incoming (positive) RELEASE can be handled properly,
// And that the parameters passed to callout are consistent with the database
EXPECT_EQ(addr, from_mgr->addr_);
EXPECT_EQ(addr, callback_lease6_->addr_);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// Test that the lease6_decline hook point can handle SKIP status.
#include <dhcp/classify.h>
#include <boost/date_time/posix_time/posix_time.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <utility>
namespace isc {
namespace dhcp {
+/// @brief RAII object enabling copying options retrieved from the
+/// packet.
+///
+/// This object enables copying retrieved options from a packet within
+/// a scope in which this object exists. When the object goes out of scope
+/// copying options is disabled. This is applicable in cases when the
+/// server is going to invoke a callout (hook library) where copying options
+/// must be enabled by default. When the callouts return copying options
+/// should be disabled. The use of RAII object eliminates the need for
+/// explicitly re-renabling options copying and is safer in case of
+/// exceptions thrown by callouts and a presence of multiple exit points.
+template<typename PktType>
+class ScopedEnableOptionsCopy {
+public:
+
+ /// @brief Pointer to an encapsulated packet.
+ typedef boost::shared_ptr<PktType> PktTypePtr;
+
+ /// @brief Constructor.
+ ///
+ /// Enables options copying on a packet(s).
+ ///
+ /// @param pkt1 Pointer to first packet.
+ /// @param pkt2 Optional pointer to the second packet.
+ ScopedEnableOptionsCopy(const PktTypePtr& pkt1,
+ const PktTypePtr& pkt2 = PktTypePtr())
+ : pkts_(pkt1, pkt2) {
+ if (pkt1) {
+ pkt1->setCopyRetrievedOptions(true);
+ }
+ if (pkt2) {
+ pkt2->setCopyRetrievedOptions(true);
+ }
+ }
+
+ /// @brief Destructor.
+ ///
+ /// Disables options copying on a packets.
+ ~ScopedEnableOptionsCopy() {
+ if (pkts_.first) {
+ pkts_.first->setCopyRetrievedOptions(false);
+ }
+ if (pkts_.second) {
+ pkts_.second->setCopyRetrievedOptions(false);
+ }
+ }
+
+private:
+
+ /// @brief Holds a pointers to the packets.
+ std::pair<PktTypePtr, PktTypePtr> pkts_;
+};
+
/// @brief Base class for classes representing DHCP messages.
///
/// This is a base class that holds common information (e.g. source
// Delete all previous arguments
ctx.callout_handle_->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(ctx.query_);
+
// Pass necessary arguments
// Pass the original packet
// Delete all previous arguments
ctx.callout_handle_->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(ctx.query_);
+
// Pass necessary arguments
// Pass the original packet
// Delete all previous arguments
callout_handle->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt6> query6_options_copy(ctx.query_);
+
// Pass the original packet
callout_handle->setArgument("query6", ctx.query_);
// Delete all previous arguments
ctx.callout_handle_->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(ctx.query_);
+
// Pass necessary arguments
// Pass the original client query
ctx.callout_handle_->setArgument("query4", ctx.query_);
// Delete all previous arguments
ctx.callout_handle_->deleteAllArguments();
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(ctx.query_);
+
// Subnet from which we do the allocation. Convert the general subnet
// pointer to a pointer to a Subnet4. Note that because we are using
// boost smart pointers here, we need to do the cast using the boost
if (ctx.callout_handle_ && HooksManager::getHooksManager()
.calloutsPresent(hook_index_lease4_select_)) {
+ // Enable copying options from the packet within hook library.
+ ScopedEnableOptionsCopy<Pkt4> query4_options_copy(ctx.query_);
+
// Delete all previous arguments
ctx.callout_handle_->deleteAllArguments();
callback_addr_original_ = IOAddress("::");
callback_addr_updated_ = IOAddress("::");
callback_qry_pkt6_.reset();
+ callback_qry_options_copy_ = false;
}
/// callback that stores received callout name and received values
callback_addr_original_ = callback_lease6_->addr_;
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt6_) {
+ callback_qry_options_copy_ =
+ callback_qry_pkt6_->isCopyRetrievedOptions();
+ }
+
return (0);
}
static bool callback_fake_allocation_;
static vector<string> callback_argument_names_;
static Pkt6Ptr callback_qry_pkt6_;
+ static bool callback_qry_options_copy_;
};
// For some reason intialization within a class makes the linker confused.
bool HookAllocEngine6Test::callback_fake_allocation_;
vector<string> HookAllocEngine6Test::callback_argument_names_;
Pkt6Ptr HookAllocEngine6Test::callback_qry_pkt6_;
+bool HookAllocEngine6Test::callback_qry_options_copy_;
// This test checks if the lease6_select callout is executed and expected
// parameters as passed.
sort(expected_argument_names.begin(), expected_argument_names.end());
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test checks if lease6_select callout is able to override the values
callback_addr_original_ = IOAddress("::");
callback_addr_updated_ = IOAddress("::");
callback_qry_pkt4_.reset();
+ callback_qry_options_copy_ = false;
}
/// callback that stores received callout name and received values
callback_addr_original_ = callback_lease4_->addr_;
callback_argument_names_ = callout_handle.getArgumentNames();
+
+ if (callback_qry_pkt4_) {
+ callback_qry_options_copy_ =
+ callback_qry_pkt4_->isCopyRetrievedOptions();
+ }
+
return (0);
}
static bool callback_fake_allocation_;
static vector<string> callback_argument_names_;
static Pkt4Ptr callback_qry_pkt4_;
+ static bool callback_qry_options_copy_;
};
// For some reason intialization within a class makes the linker confused.
bool HookAllocEngine4Test::callback_fake_allocation_;
vector<string> HookAllocEngine4Test::callback_argument_names_;
Pkt4Ptr HookAllocEngine4Test::callback_qry_pkt4_;
+bool HookAllocEngine4Test::callback_qry_options_copy_;
// This test checks if the lease4_select callout is executed and expected
// parameters as passed.
expected_argument_names.push_back("query4");
expected_argument_names.push_back("subnet4");
EXPECT_TRUE(callback_argument_names_ == expected_argument_names);
+
+ EXPECT_TRUE(callback_qry_options_copy_);
}
// This test checks if lease4_select callout is able to override the values