#include <vector>
#include <exceptions/exceptions.h>
+#include <stdint.h>
+#include <util/io_utilities.h>
#include <dhcp/duid.h>
namespace isc {
return (this->duid_ != other.duid_);
}
+/// constructor based on vector<uint8_t>
+ClientId::ClientId(const std::vector<uint8_t>& clientid)
+ :DUID(clientid) {
+}
+
+/// constructor based on C-style data
+ClientId::ClientId(const uint8_t *clientid, size_t len)
+ :DUID(clientid, len) {
+}
+
+/// constructor based on IOAddress
+ClientId::ClientId(const isc::asiolink::IOAddress& addr)
+ :DUID(std::vector<uint8_t>(4, 0)) {
+ if (addr.getFamily() != AF_INET) {
+ isc_throw(BadValue, "Client-id supports only IPv4 addresses");
+ }
+ isc::util::writeUint32(addr, &duid_[0]);
+}
+
+/// @brief returns reference to the client-id data
+const std::vector<uint8_t> ClientId::getClientId() const {
+ return duid_;
+}
+
+isc::asiolink::IOAddress ClientId::getAddress() const {
+ if (duid_.size() != sizeof(uint32_t)) {
+ isc_throw(BadValue, "This client-id is not an IPv4 address");
+ }
+
+ return isc::asiolink::IOAddress( isc::util::readUint32(&duid_[0]) );
+}
+
+bool ClientId::isAddress() const {
+ return (duid_.size() == sizeof(uint32_t));
+}
+
+// compares two client-ids
+bool ClientId::operator == (const ClientId& other) const {
+ return (this->duid_ == other.duid_);
+}
+
+// compares two client-ids
+bool ClientId::operator != (const ClientId& other) const {
+ return (this->duid_ != other.duid_);
+}
+
}; // end of isc::dhcp namespace
}; // end of isc namespace
#include <stdint.h>
#include <unistd.h>
#include <vector>
+#include <asiolink/io_address.h>
+
namespace isc {
namespace dhcp {
std::vector<uint8_t> duid_;
};
+/// @brief Holds Client identifier or client IPv4 address
+///
+/// This class is intended to be a generic IPv4 client identifier. It can hold
+/// a client-id
+class ClientId : DUID {
+ public:
+
+ /// constructor based on vector<uint8_t>
+ ClientId(const std::vector<uint8_t>& clientid);
+
+ /// constructor based on C-style data
+ ClientId(const uint8_t *clientid, size_t len);
+
+ /// constructor based on IOAddress
+ ///
+ /// @throw BadValue if specified address is not IPv4
+ ClientId(const isc::asiolink::IOAddress& addr);
+
+ /// @brief returns reference to the client-id data
+ ///
+ /// This reference is only valid as long as the object
+ /// that returned it.
+ const std::vector<uint8_t> getClientId() const;
+
+ /// @brief return an IPv4 address represented by this client-id
+ ///
+ /// @throw BadValue if this client-id is not an IPv4 address
+ isc::asiolink::IOAddress getAddress() const;
+
+ /// @brief returns if client-id is an address
+ bool isAddress() const;
+
+ // compares two client-ids
+ bool operator == (const ClientId& other) const;
+
+ // compares two client-ids
+ bool operator != (const ClientId& other) const;
+};
+
}; // end of isc::dhcp namespace
}; // end of isc namespace
#include <gtest/gtest.h>
#include <exceptions/exceptions.h>
#include <boost/scoped_ptr.hpp>
+#include <asiolink/io_address.h>
#include <dhcp/duid.h>
using namespace std;
using namespace isc;
using namespace isc::dhcp;
+using namespace isc::asiolink;
// don't import the entire boost namespace. It will unexpectedly hide uint8_t
// for some systems.
EXPECT_TRUE(*duid1 != *duid3);
}
+TEST(ClientIdTest, constructor) {
+ IOAddress addr2("192.0.2.1");
+ IOAddress addr3("2001:db8:1::1");
+ uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6};
+ vector<uint8_t> data2(data1, data1 + sizeof(data1));
+ uint8_t data3[] = {192, 0 , 2, 1 };
+
+ // checks for C-style construtor (uint8_t * + len)
+ scoped_ptr<ClientId> id1(new ClientId(data1, sizeof(data1)));
+ vector<uint8_t> vecdata = id1->getClientId();
+ EXPECT_EQ(data2, vecdata);
+ EXPECT_FALSE(id1->isAddress());
+ EXPECT_THROW(id1->getAddress(), BadValue);
+
+ // checks for vector-based constructor
+ scoped_ptr<ClientId> id2(new ClientId(data2));
+ vecdata = id2->getClientId();
+ EXPECT_EQ(data2, vecdata);
+ EXPECT_FALSE(id1->isAddress());
+ EXPECT_THROW(id1->getAddress(), BadValue);
+
+ // checks for IOAddress based constructor
+ scoped_ptr<ClientId> id3(new ClientId(addr2));
+ vecdata = id3->getClientId();
+ EXPECT_TRUE(vecdata == vector<uint8_t>(data3, data3 + 4));
+ EXPECT_EQ("192.0.2.1", id3->getAddress().toText());
+
+ // should support v4 address only, v6 is a wrong address here
+ EXPECT_THROW(new ClientId(addr3), BadValue);
+}
+
+TEST(ClientIdTest, operators) {
+ uint8_t data1[] = {0, 1, 2, 3, 4, 5, 6};
+ uint8_t data2[] = {0, 1, 2, 3, 4};
+ uint8_t data3[] = {0, 1, 2, 3, 4, 5, 7}; // last digit different
+ uint8_t data4[] = {0, 1, 2, 3, 4, 5, 6}; // the same as 1
+
+ scoped_ptr<ClientId> id1(new ClientId(data1, sizeof(data1)));
+ scoped_ptr<ClientId> id2(new ClientId(data2, sizeof(data2)));
+ scoped_ptr<ClientId> id3(new ClientId(data3, sizeof(data3)));
+ scoped_ptr<ClientId> id4(new ClientId(data4, sizeof(data4)));
+
+ EXPECT_TRUE(*id1 == *id4);
+ EXPECT_FALSE(*id1 == *id2);
+ EXPECT_FALSE(*id1 == *id3);
+
+ EXPECT_FALSE(*id1 != *id4);
+ EXPECT_TRUE(*id1 != *id2);
+ EXPECT_TRUE(*id1 != *id3);
+}
} // end of anonymous namespace