Commit cbdcd2a8 authored by Francis Dupont's avatar Francis Dupont

[4110a] Ported previous code + a lot of improvements (but still things to do)

parent 5bde5c0d
......@@ -198,6 +198,41 @@ detected as a duplicate (i.e. another device in the network is using this addres
However, the server does not have a record for this address. This may indicate
a client's error or a server's purged database.
% DHCP4_DHCP4O6_BAD_PACKET received malformed DHCPv4o6 packet: %1
A malformed DHCPv4o6 packet was received.
% DHCP6_DHCP4O6_PACKET_RECEIVED received DHCPv4o6 packet from DHCPv6 server (type %1) for %2 on interface %3
This debug message is printed when the server is receiving a DHCPv4o6
from the DHCPv6 server over inter-process communication.
% DHCP4_DHCP4O6_PACKET_SEND %1: trying to send packet %2 (type %3) to %4 on interface %5 encapsulating %6 %7 (type %8)
The arguments specify the client identification information (HW address
and client identifier), DHCP message name and type, source IPv4
address and port, destination IPv4 address and port and the
interface name.
% DHCP4_DHCP4O6_PACKET_SEND_FAIL %1: failed to send DHCPv4o6 packet: %2
This error is output if the IPv4 DHCP server fails to send an
DHCPv4o6 message to the IPv6 DHCP server. The reason for the
error is included in the message.
% DHCP4_DHCP4O6_RECEIVE_FAIL failed to receive DHCPv4o6: %1
This debug message indicates the inter-process communication with the
DHCPv6 server failed. The reason for the error is included in
the message.
% DHCP4_DHCP4O6_RECEIVING receiving DHCPv4o6 packet from DHCPv6 server
This debug message is printed when the server is receiving a DHCPv4o6
from the DHCPv6 server over inter-process communication socket.
% DHCP4_DHCP4O6_RESPONSE_DATA %1: responding with packet %2 (type %3), packet details: %4
A debug message including the detailed data about the packet being
sent to the DHCPv6 server to be forwarded to the client. The first
argument contains the client and the transaction identification
information. The second and third argument contains the packet name
and type respectively. The fourth argument contains detailed packet
information.
% DHCP4_DISCOVER_CLASS_PROCESSING_FAILED %1: client class specific processing failed for DHCPDISCOVER
This debug message means that the server processing that is unique for each
client class has reported a failure. The response packet will not be sent.
......
......@@ -70,34 +70,6 @@ using namespace isc::log;
using namespace isc::stats;
using namespace std;
/// Structure that holds registered hook indexes
struct Dhcp4Hooks {
int hook_index_buffer4_receive_;///< index for "buffer4_receive" hook point
int hook_index_pkt4_receive_; ///< index for "pkt4_receive" hook point
int hook_index_subnet4_select_; ///< index for "subnet4_select" hook point
int hook_index_lease4_release_; ///< index for "lease4_release" hook point
int hook_index_pkt4_send_; ///< index for "pkt4_send" hook point
int hook_index_buffer4_send_; ///< index for "buffer4_send" hook point
int hook_index_lease4_decline_; ///< index for "lease4_decline" hook point
/// Constructor that registers hook points for DHCPv4 engine
Dhcp4Hooks() {
hook_index_buffer4_receive_= HooksManager::registerHook("buffer4_receive");
hook_index_pkt4_receive_ = HooksManager::registerHook("pkt4_receive");
hook_index_subnet4_select_ = HooksManager::registerHook("subnet4_select");
hook_index_pkt4_send_ = HooksManager::registerHook("pkt4_send");
hook_index_lease4_release_ = HooksManager::registerHook("lease4_release");
hook_index_buffer4_send_ = HooksManager::registerHook("buffer4_send");
hook_index_lease4_decline_ = HooksManager::registerHook("lease4_decline");
}
};
// Declare a Hooks object. As this is outside any function or method, it
// will be instantiated (and the constructor run) when the module is loaded.
// As a result, the hook indexes will be defined before any method in this
// module is called.
Dhcp4Hooks Hooks;
namespace isc {
namespace dhcp {
......@@ -330,13 +302,30 @@ Dhcpv4Exchange::setHostIdentifiers() {
}
}
// Static values so instantiated when the module is loaded.
// As a result, the hook indexes will be defined before any method in this
// module is called.
int Dhcpv4Srv::hook_index_buffer4_receive_=
HooksManager::registerHook("buffer4_receive");
int Dhcpv4Srv::hook_index_pkt4_receive_ =
HooksManager::registerHook("pkt4_receive");
int Dhcpv4Srv::hook_index_subnet4_select_ =
HooksManager::registerHook("subnet4_select");
int Dhcpv4Srv::hook_index_pkt4_send_ =
HooksManager::registerHook("pkt4_send");
int Dhcpv4Srv::hook_index_lease4_release_ =
HooksManager::registerHook("lease4_release");
int Dhcpv4Srv::hook_index_buffer4_send_ =
HooksManager::registerHook("buffer4_send");
int Dhcpv4Srv::hook_index_lease4_decline_ =
HooksManager::registerHook("lease4_decline");
const std::string Dhcpv4Srv::VENDOR_CLASS_PREFIX("VENDOR_CLASS_");
Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const bool use_bcast,
const bool direct_response_desired)
: shutdown_(true), alloc_engine_(), port_(port),
use_bcast_(use_bcast), hook_index_pkt4_receive_(-1),
hook_index_subnet4_select_(-1), hook_index_pkt4_send_(-1) {
: shutdown_(true), alloc_engine_(), port_(port), use_bcast_(use_bcast) {
LOG_DEBUG(dhcp4_logger, DBG_DHCP4_START, DHCP4_OPEN_SOCKET).arg(port);
try {
......@@ -360,11 +349,6 @@ Dhcpv4Srv::Dhcpv4Srv(uint16_t port, const bool use_bcast,
alloc_engine_.reset(new AllocEngine(AllocEngine::ALLOC_ITERATIVE, 0,
false /* false = IPv4 */));
// Register hook points
hook_index_pkt4_receive_ = Hooks.hook_index_pkt4_receive_;
hook_index_subnet4_select_ = Hooks.hook_index_subnet4_select_;
hook_index_pkt4_send_ = Hooks.hook_index_pkt4_send_;
/// @todo call loadLibraries() when handling configuration changes
} catch (const std::exception &e) {
......@@ -576,7 +560,7 @@ Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query) const {
// Handle a DHCPv6 relayed query
Pkt4o6Ptr query4o6 = boost::dynamic_pointer_cast<Pkt4o6>(query);
if (!query4o6) {
isc_throw(Unexpected, "Can't get DHCP4o6 message");
isc_throw(Unexpected, "Can't get DHCP4o6 message");
}
const Pkt6Ptr& query6 = query4o6->getPkt6();
......@@ -591,7 +575,7 @@ Dhcpv4Srv::selectSubnet4o6(const Pkt4Ptr& query) const {
}
selector.interface_id_ =
query6->getAnyRelayOption(D6O_INTERFACE_ID,
Pkt6::RELAY_GET_FIRST);
Pkt6::RELAY_GET_FIRST);
}
CfgMgr& cfgmgr = CfgMgr::instance();
......@@ -762,7 +746,7 @@ Dhcpv4Srv::run_one() {
// Option objects modification does not make sense anymore. Hooks
// can only manipulate wire buffer at this stage.
// Let's execute all callouts registered for buffer4_send
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_send_)) {
if (HooksManager::calloutsPresent(hook_index_buffer4_send_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(query);
// Delete previously set arguments
......@@ -772,7 +756,7 @@ Dhcpv4Srv::run_one() {
callout_handle->setArgument("response4", rsp);
// Call callouts
HooksManager::callCallouts(Hooks.hook_index_buffer4_send_,
HooksManager::callCallouts(hook_index_buffer4_send_,
*callout_handle);
// Callouts decided to skip the next processing step. The next
......@@ -831,7 +815,7 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
// The packet has just been received so contains the uninterpreted wire
// data; execute callouts registered for buffer4_receive.
if (HooksManager::calloutsPresent(Hooks.hook_index_buffer4_receive_)) {
if (HooksManager::calloutsPresent(hook_index_buffer4_receive_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(query);
// Delete previously set arguments
......@@ -841,7 +825,7 @@ Dhcpv4Srv::processPacket(Pkt4Ptr& query, Pkt4Ptr& rsp) {
callout_handle->setArgument("query4", query);
// Call callouts
HooksManager::callCallouts(Hooks.hook_index_buffer4_receive_,
HooksManager::callCallouts(hook_index_buffer4_receive_,
*callout_handle);
// Callouts decided to skip the next processing step. The next
......@@ -2091,7 +2075,7 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
bool skip = false;
// Execute all callouts registered for lease4_release
if (HooksManager::calloutsPresent(Hooks.hook_index_lease4_release_)) {
if (HooksManager::calloutsPresent(hook_index_lease4_release_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(release);
// Delete all previous arguments
......@@ -2104,7 +2088,7 @@ Dhcpv4Srv::processRelease(Pkt4Ptr& release) {
callout_handle->setArgument("lease4", lease);
// Call all installed callouts
HooksManager::callCallouts(Hooks.hook_index_lease4_release_,
HooksManager::callCallouts(hook_index_lease4_release_,
*callout_handle);
// Callouts decided to skip the next processing step. The next
......@@ -2234,7 +2218,7 @@ Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
// Let's check if there are hooks installed for decline4 hook point.
// If they are, let's pass the lease and client's packet. If the hook
// sets status to drop, we reject this Decline.
if (HooksManager::calloutsPresent(Hooks.hook_index_lease4_decline_)) {
if (HooksManager::calloutsPresent(hook_index_lease4_decline_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(decline);
// Delete previously set arguments
......@@ -2245,7 +2229,7 @@ Dhcpv4Srv::declineLease(const Lease4Ptr& lease, const Pkt4Ptr& decline) {
callout_handle->setArgument("query4", decline);
// Call callouts
HooksManager::callCallouts(Hooks.hook_index_lease4_decline_,
HooksManager::callCallouts(hook_index_lease4_decline_,
*callout_handle);
// Check if callouts decided to drop the packet. If any of them did,
......
......@@ -790,6 +790,12 @@ private:
/// @return Option that contains netmask information
static OptionPtr getNetmaskOption(const Subnet4Ptr& subnet);
uint16_t port_; ///< UDP port number on which server listens.
bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
public:
/// Class methods and variables for DHCPv4-over-DHCPv6 handler
/// @brief Updates statistics for received packets
/// @param query packet received
static void processStatsReceived(const Pkt4Ptr& query);
......@@ -798,13 +804,28 @@ private:
/// @param query packet transmitted
static void processStatsSent(const Pkt4Ptr& response);
uint16_t port_; ///< UDP port number on which server listens.
bool use_bcast_; ///< Should broadcast be enabled on sockets (if true).
/// Indexes for registered hook points
int hook_index_pkt4_receive_;
int hook_index_subnet4_select_;
int hook_index_pkt4_send_;
/// @brief index for "buffer4_receive" hook point
static int hook_index_buffer4_receive_;
/// @brief index for "pkt4_receive" hook point
static int hook_index_pkt4_receive_;
/// @brief index for "subnet4_select" hook point
static int hook_index_subnet4_select_;
/// @brief index for "lease4_release" hook point
static int hook_index_lease4_release_;
/// @brief index for "pkt4_send" hook point
static int hook_index_pkt4_send_;
/// @brief index for "buffer4_send" hook point
static int hook_index_buffer4_send_;
/// @brief index for "lease4_decline" hook point
static int hook_index_lease4_decline_;
};
}; // namespace isc::dhcp
......
......@@ -8,10 +8,21 @@
#include <util/buffer.h>
#include <dhcp/iface_mgr.h>
#include <dhcp/pkt4.h>
#include <dhcp/pkt4o6.h>
#include <dhcp/pkt6.h>
#include <dhcpsrv/callout_handle_store.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4to6_ipc.h>
#include <dhcp4/dhcp4_log.h>
#include <hooks/callout_handle.h>
#include <hooks/hooks_log.h>
#include <hooks/hooks_manager.h>
using namespace std;
using namespace isc::dhcp;
using namespace isc::hooks;
namespace isc {
namespace dhcp {
......@@ -44,13 +55,25 @@ void Dhcp4to6Ipc::open() {
void Dhcp4to6Ipc::handler() {
Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
Pkt6Ptr pkt;
try {
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_RECEIVING);
// Receive message from the IPC socket.
pkt = ipc.receive();
// from Dhcpv4Srv::run_one() after receivePacket()
if (pkt) {
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP6_DHCP4O6_PACKET_RECEIVED)
.arg(static_cast<int>(pkt->getType()))
.arg(pkt->getRemoteAddr().toText())
.arg(pkt->getIface());
}
} catch (const std::exception& e) {
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_RECEIVE_FAIL)
.arg(e.what());
}
// Reset received message in case we return from this method before the
// received message pointer is updated.
ipc.received_.reset();
// Receive message from the IPC socket.
Pkt6Ptr pkt = ipc.receive();
if (!pkt) {
return;
}
......@@ -58,25 +81,101 @@ void Dhcp4to6Ipc::handler() {
// Each message must contain option holding DHCPv4 message.
OptionCollection msgs = pkt->getOptions(D6O_DHCPV4_MSG);
if (msgs.empty()) {
isc_throw(Dhcp4o6IpcError, "DHCPv4 message option not present in the"
" DHCPv4o6 message received by the DHCPv4 server");
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
.arg("DHCPv4 message option not present");
return;
} else if (msgs.size() > 1) {
isc_throw(Dhcp4o6IpcError, "expected exactly one DHCPv4 message within"
" DHCPv4 message option received by the DHCPv4 server");
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
.arg("more than one DHCPv4 message option");
return;
}
// Get the DHCPv4 message
OptionPtr msg = msgs.begin()->second;
if (!msg) {
isc_throw(Dhcp4o6IpcError, "null DHCPv4 message option in the"
" DHCPv4o6 message received by the DHCPv4 server");
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL, DHCP4_DHCP4O6_BAD_PACKET)
.arg("null DHCPv4 message option");
return;
}
// Record this message.
ipc.received_.reset(new Pkt4o6(msg->getData(), pkt));
}
// Extract the DHCPv4 packet with DHCPv6 packet attached
Pkt4Ptr query(new Pkt4o6(msg->getData(), pkt));
Pkt4o6Ptr& Dhcp4to6Ipc::getReceived() {
return (received_);
// From Dhcpv4Srv::run_one() processing and after
Pkt4Ptr rsp;
ControlledDhcpv4Srv::getInstance()->processPacket(query, rsp);
if (!rsp) {
return;
}
try {
// Now all fields and options are constructed into output wire buffer.
// Option objects modification does not make sense anymore. Hooks
// can only manipulate wire buffer at this stage.
// Let's execute all callouts registered for buffer4_send
if (HooksManager::calloutsPresent(Dhcpv4Srv::hook_index_buffer4_send_)) {
CalloutHandlePtr callout_handle = getCalloutHandle(query);
// Delete previously set arguments
callout_handle->deleteAllArguments();
// Pass incoming packet as argument
callout_handle->setArgument("response4", rsp);
// Call callouts
HooksManager::callCallouts(Dhcpv4Srv::hook_index_buffer4_send_,
*callout_handle);
// Callouts decided to skip the next processing step. The next
// processing step would to parse the packet, so skip at this
// stage means drop.
if (callout_handle->getStatus() == CalloutHandle::NEXT_STEP_SKIP) {
LOG_DEBUG(hooks_logger, DBG_DHCP4_HOOKS,
DHCP4_HOOK_BUFFER_SEND_SKIP)
.arg(rsp->getLabel());
return;
}
/// @todo: Add support for DROP status.
callout_handle->getArgument("response4", rsp);
}
Pkt4o6Ptr rsp6 = boost::dynamic_pointer_cast<Pkt4o6>(rsp);
// Should not happen
if (!rsp6) {
isc_throw(Unexpected, "Dhcp4o6 packet cast fail");
}
LOG_DEBUG(packet4_logger, DBG_DHCP4_BASIC, DHCP4_DHCP4O6_PACKET_SEND)
.arg(rsp6->getLabel())
.arg(rsp6->getName())
.arg(static_cast<int>(rsp6->getType()))
.arg(rsp6->getRemoteAddr())
.arg(rsp6->getIface())
.arg(rsp->getLabel())
.arg(rsp->getName())
.arg(static_cast<int>(rsp->getType()));
LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA,
DHCP4_DHCP4O6_RESPONSE_DATA)
.arg(rsp6->getLabel())
.arg(rsp6->getName())
.arg(static_cast<int>(rsp6->getType()))
.arg(rsp6->toText());
ipc.send(rsp6->getPkt6());
// Update statistics accordingly for sent packet.
Dhcpv4Srv::processStatsSent(rsp);
} catch (const std::exception& e) {
LOG_ERROR(packet4_logger, DHCP4_DHCP4O6_PACKET_SEND_FAIL)
.arg(rsp->getLabel())
.arg(e.what());
}
}
}; // namespace dhcp
......
......@@ -48,16 +48,6 @@ public:
/// The handler processes the DHCPv4-query DHCPv6 packet and
/// sends the DHCPv4-response DHCPv6 packet back to the DHCPv6 server
static void handler();
/// @brief Returns last received packet
///
/// @return a reference to a shared pointer to the last received packet
/// @note This reference should be cleared after use
Pkt4o6Ptr& getReceived();
private:
/// @brief last received packet
Pkt4o6Ptr received_;
};
} // namespace isc
......
......@@ -5,13 +5,19 @@
// file, You can obtain one at http://mozilla.org/MPL/2.0/.
#include <config.h>
#include <asiolink/io_address.h>
#include <dhcp/pkt4o6.h>
#include <dhcp/pkt6.h>
#include <dhcp/tests/iface_mgr_test_config.h>
#include <dhcp4/ctrl_dhcp4_srv.h>
#include <dhcp4/dhcp4to6_ipc.h>
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <dhcpsrv/cfgmgr.h>
#include <dhcpsrv/testutils/dhcp4o6_test_ipc.h>
#include <hooks/callout_handle.h>
#include <hooks/hooks_manager.h>
#include <gtest/gtest.h>
#include <stdint.h>
......@@ -19,6 +25,7 @@ using namespace isc;
using namespace isc::asiolink;
using namespace isc::dhcp;
using namespace isc::dhcp::test;
using namespace isc::hooks;
using namespace isc::util;
namespace {
......@@ -30,7 +37,7 @@ const uint16_t TEST_PORT = 32000;
typedef Dhcp4o6TestIpc TestIpc;
/// @brief Test fixture class for DHCPv4 endpoint of DHCPv4o6 IPC.
class Dhcp4to6IpcTest : public ::testing::Test {
class Dhcp4to6IpcTest : public Dhcpv4SrvTest {
public:
/// @brief Constructor
......@@ -38,8 +45,16 @@ public:
/// Configures IPC to use a test port. It also provides a fake
/// configuration of interfaces.
Dhcp4to6IpcTest()
: iface_mgr_test_config_(true) {
: Dhcpv4SrvTest(),
iface_mgr_test_config_(true) {
configurePort(TEST_PORT);
// Install buffer4_receive_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().
registerCallout("buffer4_receive",
buffer4_receive_callout));
// Install buffer4_send_callout
EXPECT_NO_THROW(HooksManager::preCalloutsLibraryHandle().
registerCallout("buffer4_send", buffer4_send_callout));
}
/// @brief Configure DHCP4o6 port.
......@@ -55,6 +70,42 @@ public:
/// @return Pointer to the instance of the DHCPv4-query Message option.
OptionPtr createDHCPv4MsgOption() const;
/// @brief Handler for the buffer4_receive hook
///
/// This hook is at the beginning of processPacket
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
buffer4_receive_callout(CalloutHandle& callout_handle) {
callout_handle.getArgument("query4", callback_recv_pkt_);
return (0);
}
/// @brief Handler for the buffer4_send hook
///
/// This hook is at the end of the DHCPv4o6 packet handler
///
/// @param callout_handle handle passed by the hooks framework
/// @return always 0
static int
buffer4_send_callout(CalloutHandle& callout_handle) {
callout_handle.getArgument("response4", callback_sent_pkt_);
return (0);
}
/// @brief Response Pkt4 shared pointer returned in the receive callout
static Pkt4Ptr callback_recv_pkt_;
/// @brief Response Pkt4 shared pointer returned in the send callout
static Pkt4Ptr callback_sent_pkt_;
/// @brief reference to a controlled server
///
/// Dhcp4to6Ipc::handler() uses the instance of the controlled server
/// so it has to be build. This reference does this.
ControlledDhcpv4Srv srv;
private:
/// @brief Provides fake configuration of interfaces.
......@@ -62,6 +113,9 @@ private:
};
Pkt4Ptr Dhcp4to6IpcTest::callback_recv_pkt_;
Pkt4Ptr Dhcp4to6IpcTest::callback_sent_pkt_;
void
Dhcp4to6IpcTest::configurePort(uint16_t port) {
CfgMgr::instance().getStagingCfg()->setDhcp4o6Port(port);
......@@ -94,6 +148,11 @@ TEST_F(Dhcp4to6IpcTest, invalidPortError) {
// This test verifies that the DHCPv4 endpoint of the DHCPv4o6 IPC can
// receive messages.
TEST_F(Dhcp4to6IpcTest, receive) {
// Verify we have a controlled server
ControlledDhcpv4Srv* srv = NULL;
ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
ASSERT_TRUE(srv);
// Create instance of the IPC endpoint under test.
Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
// Create instance of the IPC endpoint being used as a source of messages.
......@@ -110,12 +169,20 @@ TEST_F(Dhcp4to6IpcTest, receive) {
pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
ASSERT_NO_THROW(pkt->pack());
// Reset the received packet
Dhcp4to6IpcTest::callback_recv_pkt_.reset();
// Send and wait up to 1 second to receive it.
ASSERT_NO_THROW(src_ipc.send(pkt));
ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
// Make sure that the message has been received.
Pkt4o6Ptr pkt_received = ipc.getReceived();
// The buffer4_receive hook is at the beginning of processPacket
// so this proves it was passed to it.
Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
ASSERT_TRUE(pkt4_received);
Pkt4o6Ptr pkt_received =
boost::dynamic_pointer_cast<Pkt4o6>(pkt4_received);
ASSERT_TRUE(pkt_received);
Pkt6Ptr pkt6_received = pkt_received->getPkt6();
ASSERT_TRUE(pkt6_received);
......@@ -126,6 +193,11 @@ TEST_F(Dhcp4to6IpcTest, receive) {
// This test verifies that message with multiple DHCPv4 query options
// is rejected.
TEST_F(Dhcp4to6IpcTest, receiveMultipleQueries) {
// Verify we have a controlled server
ControlledDhcpv4Srv* srv = NULL;
ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
ASSERT_TRUE(srv);
// Create instance of the IPC endpoint under test.
Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
// Create instance of the IPC endpoint being used as a source of messages.
......@@ -144,14 +216,25 @@ TEST_F(Dhcp4to6IpcTest, receiveMultipleQueries) {
pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
ASSERT_NO_THROW(pkt->pack());
// Send message.
// Reset the received packet
Dhcp4to6IpcTest::callback_recv_pkt_.reset();
// Send and wait up to 1 second to receive it.
ASSERT_NO_THROW(src_ipc.send(pkt));
// Reception handler should throw exception.
EXPECT_THROW(IfaceMgr::instance().receive6(1, 0), Dhcp4o6IpcError);
EXPECT_NO_THROW(IfaceMgr::instance().receive6(1, 0));
// No message should has been sent.
Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_;
EXPECT_FALSE(pkt4_received);
}
// This test verifies that message with no DHCPv4 query options is rejected.
TEST_F(Dhcp4to6IpcTest, receiveNoQueries) {
// Verify we have a controlled server
ControlledDhcpv4Srv* srv = NULL;
ASSERT_NO_THROW(srv = ControlledDhcpv4Srv::getInstance());
ASSERT_TRUE(srv);
// Create instance of the IPC endpoint under test.
Dhcp4to6Ipc& ipc = Dhcp4to6Ipc::instance();
// Create instance of the IPC endpoint being used as a source of messages.
......@@ -167,10 +250,76 @@ TEST_F(Dhcp4to6IpcTest, receiveNoQueries) {
pkt->setRemoteAddr(IOAddress("2001:db8:1::123"));
ASSERT_NO_THROW(pkt->pack());
// Send message.
// Reset the received packet
Dhcp4to6IpcTest::callback_recv_pkt_.reset();
// Send and wait up to 1 second to receive it.
ASSERT_NO_THROW(src_ipc.send(</