Commit 9b2f0336 authored by Marcin Siodelski's avatar Marcin Siodelski
Browse files

[4497] Enable copying retrieved options in callouts.

parent b3f9652d
......@@ -467,6 +467,9 @@ Dhcpv4Srv::selectSubnet(const Pkt4Ptr& query) const {
// 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);
......@@ -735,6 +738,9 @@ Dhcpv4Srv::run_one() {
// 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);
......@@ -804,6 +810,9 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& 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);
......@@ -894,6 +903,9 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& 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);
......@@ -983,6 +995,10 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
// 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);
......@@ -2064,6 +2080,9 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
// 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);
......@@ -2207,6 +2226,9 @@ Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
// 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);
......
......@@ -200,6 +200,10 @@ public:
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);
}
......@@ -245,6 +249,11 @@ public:
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);
}
......@@ -312,6 +321,15 @@ public:
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);
}
......@@ -375,6 +393,11 @@ public:
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);
}
......@@ -417,6 +440,11 @@ public:
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);
}
......@@ -454,6 +482,11 @@ public:
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);
}
......@@ -471,6 +504,11 @@ public:
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);
}
......@@ -484,6 +522,10 @@ public:
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);
}
......@@ -509,6 +551,8 @@ public:
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
......@@ -542,6 +586,15 @@ public:
/// 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.
......@@ -555,6 +608,8 @@ ClientIdPtr HooksDhcpv4SrvTest::callback_clientid_;
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 {
......@@ -623,6 +678,9 @@ TEST_F(HooksDhcpv4SrvTest, Buffer4ReceiveSimple) {
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
......@@ -728,6 +786,9 @@ TEST_F(HooksDhcpv4SrvTest, pkt4ReceiveSimple) {
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
......@@ -865,6 +926,10 @@ TEST_F(HooksDhcpv4SrvTest, pkt4SendSimple) {
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
......@@ -1006,6 +1071,9 @@ TEST_F(HooksDhcpv4SrvTest, buffer4SendSimple) {
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
......@@ -1139,6 +1207,9 @@ TEST_F(HooksDhcpv4SrvTest, subnet4SelectSimple) {
// 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
......@@ -1300,6 +1371,9 @@ TEST_F(HooksDhcpv4SrvTest, lease4RenewSimple) {
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
......@@ -1456,6 +1530,9 @@ TEST_F(HooksDhcpv4SrvTest, lease4ReleaseSimple) {
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
......@@ -1564,6 +1641,9 @@ TEST_F(HooksDhcpv4SrvTest, HooksDecline) {
// 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.
......
......@@ -480,6 +480,9 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
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();
......@@ -575,6 +578,9 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
// 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);
......@@ -717,6 +723,9 @@ Dhcpv6Srv::processPacket(Pkt6Ptr& query, Pkt6Ptr& rsp) {
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();
......@@ -1014,6 +1023,9 @@ Dhcpv6Srv::selectSubnet(const Pkt6Ptr& question) {
// 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);
......@@ -2023,6 +2035,9 @@ Dhcpv6Srv::releaseIA_NA(const DuidPtr& duid, const Pkt6Ptr& query,
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();
......@@ -2706,6 +2721,9 @@ Dhcpv6Srv::declineLease(const Pkt6Ptr& decline, const Lease6Ptr lease,
// 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);
......
......@@ -147,6 +147,11 @@ public:
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);
}
......@@ -210,6 +215,11 @@ public:
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);
}
......@@ -284,6 +294,15 @@ public:
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);
}
......@@ -349,6 +368,11 @@ public:
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);
}
......@@ -387,6 +411,11 @@ public:
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);
}
......@@ -454,6 +483,11 @@ public:
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);
}
......@@ -523,6 +557,11 @@ public:
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);
}
......@@ -550,6 +589,10 @@ public:
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);
}
......@@ -585,6 +628,8 @@ public:
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
......@@ -615,6 +660,14 @@ public:
/// 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
......@@ -635,6 +688,8 @@ const Subnet6Collection* HooksDhcpv6SrvTest::callback_subnet6collection_;
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 {
......@@ -702,6 +757,8 @@ TEST_F(HooksDhcpv6SrvTest, simpleBuffer6Receive) {
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
......@@ -823,6 +880,8 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Receive) {
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
......@@ -947,6 +1006,9 @@ TEST_F(HooksDhcpv6SrvTest, simplePkt6Send) {
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
......@@ -1192,6 +1254,8 @@ TEST_F(HooksDhcpv6SrvTest, subnet6SselectChange) {
// 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,
......@@ -1291,6 +1355,8 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Renew) {
// 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,
......@@ -1537,6 +1603,8 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Release) {
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,
......@@ -1907,6 +1975,8 @@ TEST_F(HooksDhcpv6SrvTest, basicLease6Decline) {
// 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.
......
......@@ -14,11 +14,67 @@
#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
......
......@@ -1050,6 +1050,9 @@ AllocEngine::reuseExpiredLease(Lease6Ptr& expired, ClientContext6& ctx,
// 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
......@@ -1120,6 +1123,9 @@ Lease6Ptr AllocEngine::createLease6(ClientContext6& ctx,
// 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
......@@ -1338,6 +1344,9 @@ AllocEngine::extendLease6(ClientContext6& ctx, Lease6Ptr lease) {
// 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_);
......@@ -2524,6 +2533,9 @@ AllocEngine::createLease4(const ClientContext4& ctx, const IOAddress& addr) {
// 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_);
......@@ -2629,6 +2641,9 @@ AllocEngine::renewLease4(const Lease4Ptr& lease,
// 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
......@@ -2703,6 +2718,9 @@ AllocEngine::reuseExpiredLease4(Lease4Ptr& expired,
if (ctx.callout_handle_ && HooksManager::getHooksManager()
.calloutsPresent(hook_index_lease4_select_)) {