Commit fad91c5b authored by Marcin Siodelski's avatar Marcin Siodelski

[3390] Initial implementation of the dhcp4 test client.

parent fa9570d1
......@@ -88,6 +88,7 @@ dhcp4_unittests_SOURCES += ctrl_dhcp4_srv_unittest.cc
dhcp4_unittests_SOURCES += config_parser_unittest.cc
dhcp4_unittests_SOURCES += fqdn_unittest.cc
dhcp4_unittests_SOURCES += marker_file.cc
dhcp4_unittests_SOURCES += dhcp4_client.cc dhcp4_client.h
if CONFIG_BACKEND_BUNDY
# For Bundy backend, we only need to run the usual tests. There are no
......
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#include <dhcp/dhcp4.h>
#include <dhcp4/tests/dhcp4_client.h>
#include <cstdlib>
namespace isc {
namespace dhcp {
namespace test {
Dhcp4Client::Dhcp4Client() :
curr_transid_(0),
dest_addr_("255.255.255.255"),
hwaddr_(generateHWAddr()),
relay_addr_("10.0.0.2"),
srv_(boost::shared_ptr<NakedDhcpv4Srv>(new NakedDhcpv4Srv(0))),
use_relay_(false) {
}
Dhcp4Client::Dhcp4Client(boost::shared_ptr<NakedDhcpv4Srv>& srv) :
curr_transid_(0),
dest_addr_("255.255.255.255"),
hwaddr_(generateHWAddr()),
relay_addr_("10.0.0.2"),
srv_(srv),
use_relay_(false) {
}
Pkt4Ptr
Dhcp4Client::createMsg(const uint8_t msg_type) {
Pkt4Ptr msg(new Pkt4(msg_type, curr_transid_++));
msg->setHWAddr(hwaddr_);
return (msg);
}
void
Dhcp4Client::doInform() {
context_.query_ = createMsg(DHCPINFORM);
sendMsg(context_.query_);
context_.response_ = receiveOneMsg();
}
HWAddrPtr
Dhcp4Client::generateHWAddr(const uint8_t htype) const {
if (htype != HTYPE_ETHER) {
isc_throw(isc::NotImplemented,
"The harware address type " << static_cast<int>(htype)
<< " is currently not supported");
}
std::vector<uint8_t> hwaddr;
// Generate ethernet hardware address by assigning random byte values.
for (int i = 0; i < HWAddr::ETHERNET_HWADDR_LEN; ++i) {
hwaddr.push_back(static_cast<uint8_t>(rand() % 255));
}
return (HWAddrPtr(new HWAddr(hwaddr, htype)));
}
void
Dhcp4Client::modifyHWAddr() {
if (!hwaddr_) {
hwaddr_ = generateHWAddr();
return;
}
// Modify the HW address by adding 1 to its last byte.
++hwaddr_->hwaddr_[hwaddr_->hwaddr_.size() - 1];
}
Pkt4Ptr
Dhcp4Client::receiveOneMsg() {
// Return empty pointer if server hasn't responded.
if (srv_->fake_sent_.empty()) {
return (Pkt4Ptr());
}
Pkt4Ptr msg = srv_->fake_sent_.front();
srv_->fake_sent_.pop_front();
return (msg);
}
void
Dhcp4Client::sendMsg(const Pkt4Ptr& msg) {
srv_->shutdown_ = false;
if (use_relay_) {
msg->setGiaddr(relay_addr_);
}
// Repack the message to simulate wire-data parsing.
msg->pack();
Pkt4Ptr msg_copy(new Pkt4(static_cast<const uint8_t*>
(msg->getBuffer().getData()),
msg->getBuffer().getLength()));
msg_copy->setRemoteAddr(asiolink::IOAddress("0.0.0.0"));
msg_copy->setLocalAddr(dest_addr_);
msg_copy->setIface("eth0");
srv_->fakeReceive(msg_copy);
srv_->run();
}
} // end of namespace isc::dhcp::test
} // end of namespace isc::dhcp
} // end of namespace isc
// Copyright (C) 2014 Internet Systems Consortium, Inc. ("ISC")
//
// Permission to use, copy, modify, and/or distribute this software for any
// purpose with or without fee is hereby granted, provided that the above
// copyright notice and this permission notice appear in all copies.
//
// THE SOFTWARE IS PROVIDED "AS IS" AND ISC DISCLAIMS ALL WARRANTIES WITH
// REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
// AND FITNESS. IN NO EVENT SHALL ISC BE LIABLE FOR ANY SPECIAL, DIRECT,
// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
// LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE
// OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
// PERFORMANCE OF THIS SOFTWARE.
#ifndef DHCP4_CLIENT_H
#define DHCP4_CLIENT_H
#include <asiolink/io_address.h>
#include <dhcp/hwaddr.h>
#include <dhcp/pkt4.h>
#include <dhcp4/tests/dhcp4_test_utils.h>
#include <boost/noncopyable.hpp>
#include <boost/shared_ptr.hpp>
namespace isc {
namespace dhcp {
namespace test {
/// @brief DHCPv4 client used for unit testing.
///
/// This class implements a DHCPv4 "client" which interoperates with the
/// @c NakedDhcpv4Srv class. It calls @c NakedDhcpv4Srv::fakeRecive to
/// deliver client messages to the server for processing. The server places
/// the response in the @c NakedDhcpv4Srv::fake_sent_ container. The client
/// pops messages from this container which simulates reception of the
/// response from the server.
///
/// The client maintains the leases it acquired from the server
///
/// The client exposes a set of functions which simulate different exchange
/// types between the client and the server. It also provides the access to
/// the objects encapsulating responses from the server so as it is possible
/// to verify from the unit test that the server's response is correct.
class Dhcp4Client : public boost::noncopyable {
public:
/// @brief Holds the DHCPv4 messages taking part in transaction between
/// the client and the server.
struct Context {
/// @brief Holds the last sent message from the client to the server.
Pkt4Ptr query_;
/// @brief Holds the last sent message by the server to the client.
Pkt4Ptr response_; };
/// @brief Creates a new client.
Dhcp4Client();
/// @brief Creates a new client that communicates with a specified server.
///
/// @param srv An instance of the DHCPv4 server to be used.
Dhcp4Client(boost::shared_ptr<NakedDhcpv4Srv>& srv);
/// @brief Sends DHCPINFORM message to the server and receives response.
///
/// This function simulates sending the DHCPINFORM message to the server
/// and receiving server's response (if any).
///
/// @throw This function doesn't thrown exceptions on its own, but it calls
/// functions that are not exception safe, so it may emit an exception if
/// an error occurs.
void doInform();
/// @brief Generates a hardware address used by the client.
///
/// It assiges random values to the bytes of the harware address.
///
/// @param htype hardware address type. Currently the only type
/// supported is ethernet hardware address.
///
/// @return Pointer to the generated hardware address.
HWAddrPtr generateHWAddr(const uint8_t htype = HTYPE_ETHER) const;
/// @brief Returns HW address used by the client.
HWAddrPtr getHWAddress() const;
/// @brief Returns current context.
const Context& getContext() const {
return (context_);
}
/// @brief Returns the server that the client is communicating with.
boost::shared_ptr<NakedDhcpv4Srv> getServer() const {
return (srv_);
}
/// @brief Modifies the client's HW address (adds one to it).
///
/// The HW address should be modified to test negative scenarios when the
/// client acquires a lease and tries to renew it with a different HW
/// address. The server should detect the HW address mismatch and react
/// accordingly.
///
/// The HW address modification affects the value returned by the
/// @c Dhcp4Client::getHWAddress.
void modifyHWAddr();
/// @brief Sets destination address for the messages being sent by the
/// client.
///
/// By default, the client uses broadcast address 255.255.255.255 to
/// communicate with the server. In certain cases it may be desired
/// that different address is used. This function sets the new address
/// for all future exchanges with the server.
///
/// @param dest_addr New destination address.
void setDestAddress(const asiolink::IOAddress& dest_addr) {
dest_addr_ = dest_addr;
}
/// @brief Simulate sending messages through a relay.
///
/// @param use Parameter which 'true' value indicates that client should
/// simulate sending messages via relay.
/// @param relay_addr Relay address
void useRelay(const bool use = true,
const asiolink::IOAddress& relay_addr =
asiolink::IOAddress("10.0.0.2")) {
use_relay_ = use;
relay_addr_ = relay_addr;
}
private:
/// @brief Creates client's side DHCP message.
///
/// @param msg_type Type of the message to be created.
/// @return An instance of the message created.
Pkt4Ptr createMsg(const uint8_t msg_type);
/// @brief Simulates reception of the message from the server.
///
/// @return Received message.
Pkt4Ptr receiveOneMsg();
/// @brief Simulates sending a message to the server.
///
/// This function instantly triggers processing of the message by the
/// server. The server's response can be gathered by invoking the
/// @c receiveOneMsg function.
///
/// @param msg Message to be sent.
void sendMsg(const Pkt4Ptr& msg);
/// @brief Current context (sent and received message).
Context context_;
/// @biref Current transaction id (altered on each send).
uint32_t curr_transid_;
/// @brief Currently use destination address.
asiolink::IOAddress dest_addr_;
/// @brief Current hardware address of the client.
HWAddrPtr hwaddr_;
/// @brief Relay address to use.
asiolink::IOAddress relay_addr_;
/// @brief Pointer to the server that the client is communicating with.
boost::shared_ptr<NakedDhcpv4Srv> srv_;
/// @brief Enable relaying messages to the server.
bool use_relay_;
};
} // end of namespace isc::dhcp::test
} // end of namespace isc::dhcp
} // end of namespace isc
#endif // DHCP4_CLIENT
......@@ -204,6 +204,7 @@ public:
using Dhcpv4Srv::acceptMessageType;
using Dhcpv4Srv::selectSubnet;
using Dhcpv4Srv::VENDOR_CLASS_PREFIX;
using Dhcpv4Srv::shutdown_;
};
class Dhcpv4SrvTest : public ::testing::Test {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment