Skip to content

Commit

Permalink
LocalAddr, LocalAddrMAC: copy and remove templates
Browse files Browse the repository at this point in the history
  • Loading branch information
DavidB137 committed Sep 4, 2024
1 parent 773a9f4 commit 9de55c8
Show file tree
Hide file tree
Showing 5 changed files with 301 additions and 0 deletions.
88 changes: 88 additions & 0 deletions include/kvik/local_addr.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* @file local_addr.hpp
* @author Dávid Benko (davidbenko@davidbenko.dev)
* @brief Local layer address container
*
* @copyright Copyright (c) 2024
*
*/

#pragma once

#include <cstdint>
#include <string>
#include <vector>

namespace kvik
{
/**
* @brief Local layer address container
*
* Internal representation is decisive. Two addresses are the same if they
* have the same internal representation.
*
* This is base for other local address types, like MAC.
*/
struct LocalAddr
{
std::vector<uint8_t> addr; //!< Internal address representation

bool operator==(const LocalAddr &other) const
{
return addr == other.addr;
}

bool operator!=(const LocalAddr &other) const
{
return !this->operator==(other);
}

/**
* @brief Checks whether the address is empty
*
* @return true Local address is empty
* @return false Local address is not empty
*/
inline bool empty() const
{
return addr.empty();
}

/**
* @brief Converts internal representation into printable string
*
* This is also used during comunication with remote layer protocols
* (like MQTT).
*
* Most generic approach used by base class is to convert `addr` to
* hexdump.
*
* @return Printable string representation
*/
std::string toString() const
{
std::string str;
char buf[3];
for (const auto ch : addr)
{
sprintf(buf, "%02x", ch);
str += buf;
}
return str;
}
};
}

// Define hasher function
template <>
struct std::hash<kvik::LocalAddr>
{
std::size_t operator()(kvik::LocalAddr const &addr) const noexcept
{
// Convert internal representation to string
std::string addrStr(addr.addr.begin(), addr.addr.end());

// Hash it
return std::hash<std::string>{}(addrStr);
}
};
62 changes: 62 additions & 0 deletions include/kvik/local_addr_mac.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/**
* @file local_addr_mac.hpp
* @author Dávid Benko (davidbenko@davidbenko.dev)
* @brief Local layer address container for MAC address
*
* @copyright Copyright (c) 2024
*
*/

#pragma once

#include <string>
#include <vector>

#include "kvik/local_addr.hpp"

namespace kvik
{
/**
* @brief Local layer address container for MAC address
*/
struct LocalAddrMAC : public LocalAddr
{
/**
* @brief Constructs a new object
*
* @param mac MAC address (00:00:00:00:00:00 if `nullptr`)
*/
LocalAddrMAC(const uint8_t *mac = nullptr);

/**
* @brief Constructs a new object from 00:00:00:00:00:00 MAC address
*
* @return New `LocalAddrMAC` object
*/
static LocalAddrMAC zeroes();

/**
* @brief Constructs a new object from broadcast MAC address
*
* @return New `LocalAddrMAC` object
*/
static LocalAddrMAC broadcast();

/**
* @brief Converts `LocalAddrMAC` to array of bytes
*
* @param mac MAC address storage pointer
*/
void toMAC(uint8_t *mac) const;
};
}

// Define hasher function
template <>
struct std::hash<kvik::LocalAddrMAC>
{
std::size_t operator()(kvik::LocalAddrMAC const &addr) const noexcept
{
return std::hash<kvik::LocalAddr>{}(addr);
}
};
53 changes: 53 additions & 0 deletions src/common/local_addr_mac.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/**
* @file local_addr_mac.cpp
* @author Dávid Benko (davidbenko@davidbenko.dev)
* @brief Local layer address container for MAC address
*
* @copyright Copyright (c) 2024
*
*/

#include <cstring>
#include <memory>

#include "kvik/local_addr_mac.hpp"

namespace kvik
{
/**
* @brief Length of MAC address in bytes
*/
static constexpr size_t MAC_LEN = 6;

LocalAddrMAC::LocalAddrMAC(const uint8_t *mac)
{
uint8_t macZeroes[MAC_LEN] = {};
if (mac == nullptr)
{
mac = macZeroes;
}

// Internal representation
addr = std::vector<uint8_t>(mac, mac + MAC_LEN);
}

LocalAddrMAC LocalAddrMAC::zeroes()
{
return LocalAddrMAC();
}

LocalAddrMAC LocalAddrMAC::broadcast()
{
uint8_t mac[MAC_LEN];
memset(mac, 0xFF, MAC_LEN);
return LocalAddrMAC(mac);
}

void LocalAddrMAC::toMAC(uint8_t *mac) const
{
for (unsigned i = 0; i < addr.size(); i++)
{
mac[i] = addr[i];
}
}
}
48 changes: 48 additions & 0 deletions test/tests/local_addr.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
#include <catch2/catch_test_macros.hpp>

#include "kvik/local_addr.hpp"

using namespace kvik;

TEST_CASE("Empty", "[LocalAddr]")
{
REQUIRE(LocalAddr().empty());
}

TEST_CASE("Non-empty", "[LocalAddr]")
{
REQUIRE(!LocalAddr({{0x00}}).empty());
}

TEST_CASE("Comparison", "[LocalAddr]")
{
auto addr1 = LocalAddr({{0x00}});
auto addr2 = LocalAddr({{0x01}});
auto addr3 = LocalAddr({{0x00}});
auto addr4 = LocalAddr({{0x00, 0x01}});

SECTION("Equality")
{
REQUIRE(addr1 == addr3);
}

SECTION("Non-equality")
{
REQUIRE(addr1 != addr2);
}

SECTION("Non-equality of with common prefix")
{
REQUIRE(addr1 != addr4);
}

SECTION("Non-equality of with common suffix")
{
REQUIRE(addr2 != addr4);
}
}

TEST_CASE("String representation", "[LocalAddr]")
{
REQUIRE(LocalAddr({{0x00, 0x11, 0xAB}}).toString() == "0011ab");
}
50 changes: 50 additions & 0 deletions test/tests/local_addr_mac.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
#include <catch2/catch_test_macros.hpp>

#include "kvik/local_addr_mac.hpp"

using namespace kvik;

TEST_CASE("Zeroed MAC is not empty", "[LocalAddrMAC]")
{
REQUIRE(!LocalAddrMAC().empty());
}

TEST_CASE("Comparison", "[LocalAddrMAC]")
{
uint8_t mac1[] = {0x00, 0x11, 0x23, 0x00, 0x55, 0xFF};
uint8_t mac2[] = {0x00, 0x11, 0x23, 0x00, 0x55, 0xAA};
uint8_t mac3[] = {0x00, 0x11, 0x23, 0x00, 0x55, 0xFF};
uint8_t macZero[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
uint8_t macBroadcast[] = {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

SECTION("Equality")
{
REQUIRE(LocalAddrMAC(mac1) == LocalAddrMAC(mac3));
}

SECTION("Non-equality")
{
REQUIRE(LocalAddrMAC(mac1) != LocalAddrMAC(mac2));
}

SECTION("Default MAC is zeroed")
{
REQUIRE(LocalAddrMAC::zeroes() == LocalAddrMAC());
}

SECTION("Zeroed MAC equality")
{
REQUIRE(LocalAddrMAC::zeroes() == LocalAddrMAC(macZero));
}

SECTION("Broadcast MAC equality")
{
REQUIRE(LocalAddrMAC::broadcast() == LocalAddrMAC(macBroadcast));
}
}

TEST_CASE("String representation", "[LocalAddrMAC]")
{
uint8_t mac[] = {0x00, 0x11, 0x23, 0x00, 0x55, 0xFF};
REQUIRE(LocalAddrMAC(mac).toString() == "0011230055ff");
}

0 comments on commit 9de55c8

Please sign in to comment.