From: Francis Dupont Date: Fri, 17 Jun 2016 16:09:41 +0000 (+0200) Subject: [4110a] Ported previous code + a lot of improvements (but still things to do) X-Git-Tag: trac4273_base~1^2~8 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=cbdcd2a80ea7ae2d27a40cd44885d5f8d2e40747;p=thirdparty%2Fkea.git [4110a] Ported previous code + a lot of improvements (but still things to do) --- diff --git a/src/bin/dhcp4/dhcp4_messages.mes b/src/bin/dhcp4/dhcp4_messages.mes index e1128c98e9..d176b3fed5 100644 --- a/src/bin/dhcp4/dhcp4_messages.mes +++ b/src/bin/dhcp4/dhcp4_messages.mes @@ -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. diff --git a/src/bin/dhcp4/dhcp4_srv.cc b/src/bin/dhcp4/dhcp4_srv.cc index 2c14b93f23..2b8cc95fef 100644 --- a/src/bin/dhcp4/dhcp4_srv.cc +++ b/src/bin/dhcp4/dhcp4_srv.cc @@ -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(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, diff --git a/src/bin/dhcp4/dhcp4_srv.h b/src/bin/dhcp4/dhcp4_srv.h index 907a5b95de..f1fc2468c3 100644 --- a/src/bin/dhcp4/dhcp4_srv.h +++ b/src/bin/dhcp4/dhcp4_srv.h @@ -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 diff --git a/src/bin/dhcp4/dhcp4to6_ipc.cc b/src/bin/dhcp4/dhcp4to6_ipc.cc index 05598a15a5..c3d64b0af3 100644 --- a/src/bin/dhcp4/dhcp4to6_ipc.cc +++ b/src/bin/dhcp4/dhcp4to6_ipc.cc @@ -8,10 +8,21 @@ #include #include +#include +#include +#include +#include #include +#include #include +#include +#include +#include +#include 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(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(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(rsp6->getType())) + .arg(rsp6->getRemoteAddr()) + .arg(rsp6->getIface()) + .arg(rsp->getLabel()) + .arg(rsp->getName()) + .arg(static_cast(rsp->getType())); + + LOG_DEBUG(packet4_logger, DBG_DHCP4_DETAIL_DATA, + DHCP4_DHCP4O6_RESPONSE_DATA) + .arg(rsp6->getLabel()) + .arg(rsp6->getName()) + .arg(static_cast(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 diff --git a/src/bin/dhcp4/dhcp4to6_ipc.h b/src/bin/dhcp4/dhcp4to6_ipc.h index a643a043fd..6b098585c5 100644 --- a/src/bin/dhcp4/dhcp4to6_ipc.h +++ b/src/bin/dhcp4/dhcp4to6_ipc.h @@ -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 diff --git a/src/bin/dhcp4/tests/dhcp4to6_ipc_unittest.cc b/src/bin/dhcp4/tests/dhcp4to6_ipc_unittest.cc index f5d7ac1fcb..08772fd8ab 100644 --- a/src/bin/dhcp4/tests/dhcp4to6_ipc_unittest.cc +++ b/src/bin/dhcp4/tests/dhcp4to6_ipc_unittest.cc @@ -5,13 +5,19 @@ // file, You can obtain one at http://mozilla.org/MPL/2.0/. #include + #include #include #include #include +#include #include +#include #include #include +#include +#include + #include #include @@ -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(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(pkt)); + 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 the DHCPv4 endpoint of the DHCPv4o6 IPC can +// process messages. +TEST_F(Dhcp4to6IpcTest, process) { + // 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. + TestIpc src_ipc(TEST_PORT, TestIpc::ENDPOINT_TYPE_V6); + + // Open both endpoints. + ASSERT_NO_THROW(ipc.open()); + ASSERT_NO_THROW(src_ipc.open()); + + // Create message to be sent over IPC. + Pkt6Ptr pkt(new Pkt6(DHCPV6_DHCPV4_QUERY, 1234)); + pkt->addOption(createDHCPv4MsgOption()); + pkt->setIface("eth0"); + pkt->setRemoteAddr(IOAddress("2001:db8:1::123")); + ASSERT_NO_THROW(pkt->pack()); + + // TODO: put enough in the packet and server config to make it pass + // through processPacket, in particular provide a subnet to select + + // 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); + ASSERT_NO_THROW(IfaceMgr::instance().receive6(1, 0)); + + // Make sure that the message has been received. + Pkt4Ptr pkt4_received = Dhcp4to6IpcTest::callback_recv_pkt_; + ASSERT_TRUE(pkt4_received); + Pkt4o6Ptr pkt_received = + boost::dynamic_pointer_cast(pkt4_received); + ASSERT_TRUE(pkt_received); + Pkt6Ptr pkt6_received = pkt_received->getPkt6(); + ASSERT_TRUE(pkt6_received); + EXPECT_EQ("eth0", pkt6_received->getIface()); + EXPECT_EQ("2001:db8:1::123", pkt6_received->getRemoteAddr().toText()); + + // Make sure that the message has been processed. + // Using the buffer4_send hook + Pkt4Ptr pkt4_sent = Dhcp4to6IpcTest::callback_sent_pkt_; +#if 0 + ASSERT_TRUE(pkt4_sent); + Pkt4o6Ptr pkt_sent = boost::dynamic_pointer_cast(pkt4_sent); + ASSERT_TRUE(pkt_sent); + Pkt6Ptr pkt6_sent = pkt_sent->getPkt6(); + ASSERT_TRUE(pkt6_sent); + EXPECT_EQ("eth0", pkt6_sent->getIface()); + EXPECT_EQ("2001:db8:1::123", pkt6_sent->getRemoteAddr().toText()); + // more tests +#endif } } // end of anonymous namespace