dhcp4_client.h 9.62 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
// 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>
24
#include <set>
25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53

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.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68
        Pkt4Ptr response_;
    };

    /// @brief Holds the configuration of the client received from the
    /// DHCP server.
    struct Configuration {
        Option4AddrLst::AddressContainer routers_;
        Option4AddrLst::AddressContainer dns_servers_;
        Lease4 lease_;
        asiolink::IOAddress serverid_;

        Configuration();

        void reset();
    };
69 70 71 72 73 74 75 76 77

    /// @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);

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92
    /// @brief Creates a lease for the client using the specified address
    /// and valid lifetime.
    ///
    /// This method creates the lease using the specified address and
    /// valid lease lifetime. The client will use this lease in any
    /// future communication with the DHCP server. One of the use cases
    /// for this method is to pre-configure the client with the explicitly
    /// given address before it sends the DHCPINFORM to the DHCP server.
    /// The client will inject the leased address into the ciaddr field
    /// of the DHCPINFORM message.
    ///
    /// @param addr Lease address.
    /// @param valid_lft Valid lifetime.
    void createLease(const asiolink::IOAddress& addr, const uint32_t valid_lft);

93 94 95 96 97
    /// @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).
    ///
98 99 100 101 102
    /// @param set_ciaddr Indicates if the ciaddr should be set for an
    /// outgoing message and defaults to true. Note, that the RFC2131 mandates
    /// setting the ciaddr for DHCPINFORM but the server may still want to
    /// respond if the ciaddr is not set.
    ///
103 104 105
    /// @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.
106
    void doInform(const bool set_ciaddr = true);
107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141

    /// @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();

142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
    /// @brief Specify an option to be requested by a client.
    ///
    /// This function adds option code to the collection of option
    /// codes to be requested by a client.
    ///
    /// @param option Option code to be requested. The value of 0 is
    /// ignored and the function is no-op.
    void requestOption(const uint8_t option);

    /// @brief Specifies options to be requested by the client.
    ///
    /// This function configures the client to request options having
    /// specified codes using Parameter Request List option. The default
    /// value of 0 specify that the option is not requested.
    ///
    /// If there are options specified to be requested before the function
    /// is called, the new option codes override previously specified ones.
    /// In order to clear the list of requested options call
    /// @c requestOptions(0).
    ///
    /// @param option1 First option to be requested.
    /// @param option2 Second option to be requested (optional).
    /// @param option3 Third option to be requested (optional).
    void requestOptions(const uint8_t option1,
                        const uint8_t option2 = 0,
                        const uint8_t option3 = 0);

169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188
    /// @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 =
189 190
                  asiolink::IOAddress("192.0.2.2"),
                  const asiolink::IOAddress& sf_relay_addr =
191 192 193
                  asiolink::IOAddress("10.0.0.2")) {
        use_relay_ = use;
        relay_addr_ = relay_addr;
194
        server_facing_relay_addr_ = sf_relay_addr;
195 196
    }

197 198 199
    /// @brief Current client's configuration obtained from the server.
    Configuration config_;

200 201
private:

202 203 204
    /// @brief Stores configuration received from the server.
    void applyConfiguration();

205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239
    /// @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_;

240 241 242 243 244 245
    /// @brief Collection of options codes to be requested by the client.
    std::set<uint8_t> requested_options_;

    /// @brief Address of the relay interface connected to the server.
    asiolink::IOAddress server_facing_relay_addr_;

246 247 248 249 250 251 252 253 254 255 256 257
    /// @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