--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#include <config.h>
+
+#include <dhcpsrv/testutils/memory_host_data_source.h>
+
+using namespace std;
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+ConstHostCollection
+MemHostDataSource::getAll(const HWAddrPtr& /*hwaddr*/,
+ const DuidPtr& /*duid*/) const {
+ return (ConstHostCollection());
+}
+
+ConstHostCollection
+MemHostDataSource::getAll(const Host::IdentifierType& /*identifier_type*/,
+ const uint8_t* /*identifier_begin*/,
+ const size_t /*identifier_len*/) const {
+ return (ConstHostCollection());
+}
+
+ConstHostCollection
+MemHostDataSource::getAll4(const asiolink::IOAddress& /*address*/) const {
+ return (ConstHostCollection());
+}
+
+ConstHostPtr
+MemHostDataSource::get4(const SubnetID& /*subnet_id*/,
+ const HWAddrPtr& /*hwaddr*/,
+ const DuidPtr& /*duid*/) const {
+ return (ConstHostPtr());
+}
+
+ConstHostPtr
+MemHostDataSource::get4(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) const {
+ vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
+ for (auto h = store_.begin(); h != store_.end(); ++h) {
+ // If either subnet-id or identifier type do not match,
+ // it's not our host
+ if (((*h)->getIPv4SubnetID() != subnet_id) ||
+ ((*h)->getIdentifierType() != identifier_type)) {
+ continue;
+ }
+ // If the identifier matches, we found it!
+ if ((*h)->getIdentifier() == ident) {
+ return (*h);
+ }
+ }
+
+ // Nothing found
+ return (ConstHostPtr());
+}
+
+ConstHostPtr
+MemHostDataSource::get6(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) const {
+ vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
+ for (auto h = store_.begin(); h != store_.end(); ++h) {
+ // If either subnet-id or identifier type do not match,
+ // it's not our host
+ if (((*h)->getIPv6SubnetID() != subnet_id) ||
+ ((*h)->getIdentifierType() != identifier_type)) {
+ continue;
+ }
+ // If the identifier matches, we found it!
+ if ((*h)->getIdentifier() == ident) {
+ return (*h);
+ }
+ }
+
+ return (ConstHostPtr());
+}
+
+ConstHostPtr
+MemHostDataSource::get4(const SubnetID& subnet_id,
+ const asiolink::IOAddress& address) const {
+ for (auto h = store_.begin(); h != store_.end(); ++h) {
+ if ((*h)->getIPv4SubnetID() == subnet_id &&
+ (*h)->getIPv4Reservation() == address) {
+ return (*h);
+ }
+ }
+
+ return (ConstHostPtr());
+}
+
+ConstHostPtr
+MemHostDataSource::get6(const SubnetID& /*subnet_id*/,
+ const DuidPtr& /*duid*/,
+ const HWAddrPtr& /*hwaddr*/) const {
+ return (ConstHostPtr());
+}
+
+ConstHostPtr
+MemHostDataSource::get6(const asiolink::IOAddress& /*prefix*/,
+ const uint8_t /*prefix_len*/) const {
+ return (ConstHostPtr());
+}
+
+ConstHostPtr
+MemHostDataSource::get6(const SubnetID& subnet_id,
+ const asiolink::IOAddress& address) const {
+ for (auto h = store_.begin(); h != store_.end(); ++h) {
+
+ // Naive approach: check hosts one by one
+
+ // First check: subnet-id must match.
+ if ((*h)->getIPv6SubnetID() != subnet_id) {
+ // wrong subnet-id? ok, skip this one
+ continue;
+ }
+
+ // Second check: the v6 reservation must much. This is very simple
+ // as we ignore the reservation type.
+ auto resrvs = (*h)->getIPv6Reservations();
+ for (auto r = resrvs.first; r != resrvs.second; ++r) {
+ if ((*r).second.getPrefix() == address) {
+ return (*h);
+ }
+ }
+ }
+
+ return (ConstHostPtr());
+}
+
+bool
+MemHostDataSource::add(const HostPtr& host) {
+ store_.push_back(host);
+ return (true);
+}
+
+bool
+MemHostDataSource::del(const SubnetID& subnet_id,
+ const asiolink::IOAddress& addr) {
+ for (auto h = store_.begin(); h != store_.end(); ++h) {
+ if (addr.isV4()) {
+ if ((*h)->getIPv4SubnetID() == subnet_id &&
+ (*h)->getIPv4Reservation() == addr) {
+ store_.erase(h);
+ return (true);
+ }
+ } else {
+
+ if ((*h)->getIPv6SubnetID() != subnet_id) {
+ continue;
+ }
+
+ // Second check: the v6 reservation must much. This is very simple
+ // as we ignore the reservation type.
+ auto resrvs = (*h)->getIPv6Reservations();
+ for (auto r = resrvs.first; r != resrvs.second; ++r) {
+ if ((*r).second.getPrefix() == addr) {
+ store_.erase(h);
+ return (true);
+ }
+ }
+ }
+ }
+
+ return (false);
+}
+
+bool
+MemHostDataSource::del4(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) {
+ vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
+ for (auto h = store_.begin(); h != store_.end(); ++h) {
+ // If either subnet-id or identifier type do not match,
+ // it's not our host
+ if (((*h)->getIPv4SubnetID() != subnet_id) ||
+ ((*h)->getIdentifierType() != identifier_type)) {
+ continue;
+ }
+ // If the identifier matches, we found it!
+ if ((*h)->getIdentifier() == ident) {
+ store_.erase(h);
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+bool
+MemHostDataSource::del6(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) {
+ vector<uint8_t> ident(identifier_begin, identifier_begin + identifier_len);
+ for (auto h = store_.begin(); h != store_.end(); ++h) {
+ // If either subnet-id or identifier type do not match,
+ // it's not our host
+ if (((*h)->getIPv6SubnetID() != subnet_id) ||
+ ((*h)->getIdentifierType() != identifier_type)) {
+ continue;
+ }
+ // If the identifier matches, we found it!
+ if ((*h)->getIdentifier() == ident) {
+ store_.erase(h);
+ return (true);
+ }
+ }
+ return (false);
+}
+
+size_t
+MemHostDataSource::size() const {
+ return (store_.size());
+}
+
+BaseHostDataSource*
+memFactory(const DatabaseConnection::ParameterMap& /*parameters*/) {
+ return (new MemHostDataSource());
+}
+
+} // namespace isc::dhcp::test
+} // namespace isc::dhcp
+} // namespace isc
--- /dev/null
+// Copyright (C) 2018 Internet Systems Consortium, Inc. ("ISC")
+//
+// This Source Code Form is subject to the terms of the Mozilla Public
+// License, v. 2.0. If a copy of the MPL was not distributed with this
+// file, You can obtain one at http://mozilla.org/MPL/2.0/.
+
+#ifndef MEMORY_HOST_DATA_SOURCE_H
+#define MEMORY_HOST_DATA_SOURCE_H
+
+#include <dhcpsrv/host_data_source_factory.h>
+#include <boost/shared_ptr.hpp>
+#include <string>
+#include <vector>
+
+namespace isc {
+namespace dhcp {
+namespace test {
+
+/// @brief Simple host data source implementation for tests.
+///
+/// It used vector<HostPtr> as a storage and iterates through all hosts when
+/// conducting operations. Most operations are skeleton methods that don't
+/// work, just several are implemented. Those are used in the tests.
+class MemHostDataSource : public BaseHostDataSource {
+public:
+
+ /// @brief Destructor.
+ virtual ~MemHostDataSource() { }
+
+ /// BaseHostDataSource methods.
+
+ /// @brief Return all hosts for the specified HW address or DUID.
+ ///
+ /// @param hwaddr HW address of the client or NULL if no HW address
+ /// available.
+ /// @param duid client id or NULL if not available, e.g. DHCPv4 client case.
+ /// @return Empty collection of const @c Host objects.
+ virtual ConstHostCollection
+ getAll(const HWAddrPtr& hwaddr, const DuidPtr& duid = DuidPtr()) const;
+
+ /// @brief Return all hosts connected to any subnet for which reservations
+ /// have been made using a specified identifier.
+ ///
+ /// @param identifier_type Identifier type.
+ /// @param identifier_begin Pointer to a beginning of a buffer containing
+ /// an identifier.
+ /// @param identifier_len Identifier length.
+ /// @return Empty collection of const @c Host objects.
+ virtual ConstHostCollection
+ getAll(const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) const;
+
+ /// @brief Returns a collection of hosts using the specified IPv4 address.
+ ///
+ /// @param address IPv4 address for which the @c Host object is searched.
+ /// @return Empty collection of const @c Host objects.
+ virtual ConstHostCollection
+ getAll4(const asiolink::IOAddress& address) const;
+
+ /// @brief Returns a host connected to the IPv4 subnet.
+ ///
+ /// @param subnet_id Subnet identifier.
+ /// @param hwaddr HW address of the client or NULL if no HW address
+ /// available.
+ /// @param duid client id or NULL if not available.
+ /// @return Const @c Host object using a specified HW address or DUID.
+ virtual ConstHostPtr
+ get4(const SubnetID& subnet_id, const HWAddrPtr& hwaddr,
+ const DuidPtr& duid = DuidPtr()) const;
+
+
+ /// @brief Returns a host connected to the IPv4 subnet.
+ ///
+ /// @param subnet_id Subnet identifier.
+ /// @param identifier_type Identifier type.
+ /// @param identifier_begin Pointer to a beginning of a buffer containing
+ /// an identifier.
+ /// @param identifier_len Identifier length.
+ /// @return Const @c Host object for which reservation has been made using
+ /// the specified identifier.
+ virtual ConstHostPtr
+ get4(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) const;
+
+ /// @brief Returns a host connected to the IPv4 subnet and having
+ /// a reservation for a specified IPv4 address.
+ ///
+ /// @param subnet_id Subnet identifier.
+ /// @param address reserved IPv4 address.
+ /// @return Const @c Host object using a specified IPv4 address.
+ virtual ConstHostPtr
+ get4(const SubnetID& subnet_id,
+ const asiolink::IOAddress& address) const;
+
+ /// @brief Returns a host connected to the IPv6 subnet.
+ ///
+ /// @param subnet_id Subnet identifier.
+ /// @param hwaddr HW address of the client or NULL if no HW address
+ /// available.
+ /// @param duid DUID or NULL if not available.
+ /// @return Const @c Host object using a specified HW address or DUID.
+ virtual ConstHostPtr
+ get6(const SubnetID& subnet_id, const DuidPtr& duid,
+ const HWAddrPtr& hwaddr = HWAddrPtr()) const;
+
+ /// @brief Returns a host connected to the IPv6 subnet.
+ ///
+ /// @param subnet_id Subnet identifier.
+ /// @param identifier_type Identifier type.
+ /// @param identifier_begin Pointer to a beginning of a buffer containing
+ /// an identifier.
+ /// @param identifier_len Identifier length.
+ /// @return Const @c Host object for which reservation has been made using
+ /// the specified identifier.
+ virtual ConstHostPtr
+ get6(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin,
+ const size_t identifier_len) const;
+
+ /// @brief Returns a host using the specified IPv6 prefix.
+ ///
+ /// @param prefix IPv6 prefix for which the @c Host object is searched.
+ /// @param prefix_len IPv6 prefix length.
+ /// @return Const @c Host object using a specified HW address or DUID.
+ virtual ConstHostPtr
+ get6(const asiolink::IOAddress& prefix, const uint8_t prefix_len) const;
+
+ /// @brief Returns a host connected to the IPv6 subnet and having
+ /// a reservation for a specified IPv6 address or prefix.
+ ///
+ /// @param subnet_id Subnet identifier.
+ /// @param address reserved IPv6 address/prefix.
+ /// @return Const @c Host object using a specified IPv6 address/prefix.
+ virtual ConstHostPtr
+ get6(const SubnetID& subnet_id, const asiolink::IOAddress& address) const;
+
+ /// @brief Adds a new host to the collection.
+ ///
+ /// @param host Pointer to the new @c Host object being added.
+ /// @return true if addition was successful.
+ virtual bool add(const HostPtr& host);
+
+ /// @brief Attempts to delete a host by (subnet-id, address)
+ ///
+ /// @param subnet_id subnet identifier.
+ /// @param addr specified address.
+ /// @return true if deletion was successful, false if the host was not there.
+ /// @throw various exceptions in case of errors
+ virtual bool del(const SubnetID& subnet_id, const asiolink::IOAddress& addr);
+
+ /// @brief Attempts to delete a host by (subnet-id4, identifier, identifier-type)
+ ///
+ /// @param subnet_id IPv4 Subnet identifier.
+ /// @param identifier_type Identifier type.
+ /// @param identifier_begin Pointer to a beginning of a buffer containing
+ /// an identifier.
+ /// @param identifier_len Identifier length.
+ /// @return true if deletion was successful, false if the host was not there.
+ /// @throw various exceptions in case of errors
+ virtual bool del4(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin, const size_t identifier_len);
+
+ /// @brief Attempts to delete a host by (subnet-id6, identifier, identifier-type)
+ ///
+ /// @param subnet_id IPv6 Subnet identifier.
+ /// @param identifier_type Identifier type.
+ /// @param identifier_begin Pointer to a beginning of a buffer containing
+ /// an identifier.
+ /// @param identifier_len Identifier length.
+ /// @return true if deletion was successful, false if the host was not there.
+ /// @throw various exceptions in case of errors
+ virtual bool del6(const SubnetID& subnet_id,
+ const Host::IdentifierType& identifier_type,
+ const uint8_t* identifier_begin, const size_t identifier_len);
+
+ /// @brief Return backend type
+ ///
+ /// Returns the type of the backend (e.g. "mysql", "memfile" etc.)
+ ///
+ /// @return Type of the backend.
+ virtual std::string getType() const {
+ return ("mem");
+ }
+
+ /// More lease backend?
+
+ /// @brief Returns name of the database or file used by the backend
+ /// @return "mem" string"
+ virtual std::string getName() const {
+ return (std::string("mem"));
+ }
+
+ /// @brief Returns description of the backend.
+ /// @return description
+ virtual std::string getDescription() const {
+ return (std::string("In memory storage, mostly useful for testing."));
+ }
+
+ /// @brief Returns version this backend
+ /// @return two numbers that each represent practical value of this backend.
+ virtual std::pair<uint32_t, uint32_t> getVersion() const {
+ return (std::make_pair(0,0));
+ }
+
+ /// @brief Returns store size.
+ /// @return number of hosts in the store.
+ virtual size_t size() const;
+
+protected:
+ // This is very simple storage.
+
+ /// @brief Store
+ std::vector<HostPtr> store_;
+};
+
+/// Pointer to the Mem host data source.
+typedef boost::shared_ptr<MemHostDataSource> MemHostDataSourcePtr;
+
+/// @brief Factory function.
+///
+/// @param parameters
+/// @return A pointer to a base host data source instance.
+BaseHostDataSource*
+memFactory(const DatabaseConnection::ParameterMap& /*parameters*/);
+
+} // namespace isc::dhcp::test
+} // namespace isc::dhcp
+} // namespace isc
+
+#endif