Skip to content

Commit

Permalink
Add docs.
Browse files Browse the repository at this point in the history
  • Loading branch information
abeltrano committed May 7, 2024
1 parent 9ece533 commit e92f5b0
Show file tree
Hide file tree
Showing 4 changed files with 133 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct INetworkOperations
/**
* @brief Obtain information about the specified IP address. The returned map will contain the IP address as the key
* and the information as the value. In the case of a fixed address, the returned map will have a single entry. In
* the case of any "any" address (eg. 0.0.0.0, ::), the returned map will contain all available addresses.
* the case of any "any" address (eg. 0.0.0.0, ::, [::]), the returned map will contain all available addresses.
*
* @param ipAddress The ip address to obtain information for.
* @return std::unordered_map<std::string, IpAddressInformation>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,8 +15,20 @@

namespace Microsoft::Net::Remote
{
/**
* @brief Network service enabling clients to discover netremote servers on the network.
*/
struct NetRemoteDiscoveryService
{
/**
* @brief Construct a new NetRemoteDiscoveryService object with the specified hostname, port, and IP addresses.
*
* @param hostname The hostname of the service.
* @param port The IP port the service listens on.
* @param ipAddresses The IP addresses the service listens on. The map key specifies the IP address, and the value
* specifies information about the IP address needed by discovery clients, such as the IP family and type of
* interface.
*/
NetRemoteDiscoveryService(std::string hostname, uint32_t port, std::unordered_map<std::string, Microsoft::Net::IpAddressInformation> ipAddresses);

virtual ~NetRemoteDiscoveryService() = default;
Expand All @@ -31,19 +43,41 @@ struct NetRemoteDiscoveryService
NetRemoteDiscoveryService&
operator=(NetRemoteDiscoveryService&&) = delete;

/**
* @brief Start the discovery service. This will begin advertising the service on the network.
*/
virtual void
Start() = 0;

/**
* @brief Stop the discovery service. This will stop advertising the service on the network, preventing it from
* being discoverable by clients.
*/
virtual void
Stop() = 0;

protected:
/**
* @brief Get the host name of the service.
*
* @return std::string_view
*/
std::string_view
GetHostname() const noexcept;

/**
* @brief Get the port of the service.
*
* @return uint32_t
*/
uint32_t
GetPort() const noexcept;

/**
* @brief Get the IP addresses the service listens on.
*
* @return const std::unordered_map<std::string, Microsoft::Net::IpAddressInformation>&
*/
const std::unordered_map<std::string, Microsoft::Net::IpAddressInformation>&
GetIpAddresses() const noexcept;

Expand All @@ -53,24 +87,40 @@ private:
std::unordered_map<std::string, Microsoft::Net::IpAddressInformation> m_ipAddresses;
};

/**
* @brief Factory to create a NetRemoteDiscoveryService.
*
* This facilitates multiple implementations of the service, including across operating systems and mock implementations
* for testing.
*/
struct INetRemoteDiscoveryServiceFactory
{
virtual ~INetRemoteDiscoveryServiceFactory() = default;

/**
* @brief Create a new NetRemoteDiscoveryService object.
*
* @param hostname The hostname of the service.
* @param port The IP port the service listens on.
* @param ipAddresses The IP addresses the service listens on. The map key specifies the IP address, and the value
* specifies information about the IP address needed by discovery clients, such as the IP family and type of
* interface.
* @return std::shared_ptr<NetRemoteDiscoveryService>
*/
virtual std::shared_ptr<NetRemoteDiscoveryService>
Create(std::string hostname, uint32_t port, std::unordered_map<std::string, Microsoft::Net::IpAddressInformation> ipAddresses) = 0;
};

/**
* @brief Helper to build a NetRemoteDiscoveryService.
*
*
* Note that this is not thread-safe.
*/
struct NetRemoteDiscoveryServiceBuilder
{
/**
* @brief Construct a new NetRemoteDiscoveryServiceBuilder object.
*
*
* @param discoveryServiceFactory The factory to use to create the service instance.
* @param networkOperations The object to use when performing network operations.
*/
Expand Down Expand Up @@ -112,8 +162,8 @@ struct NetRemoteDiscoveryServiceBuilder

/**
* @brief Create a NetRemoteDiscoveryService object with the stored configuration.
*
* @return std::shared_ptr<NetRemoteDiscoveryService>
*
* @return std::shared_ptr<NetRemoteDiscoveryService>
*/
std::shared_ptr<NetRemoteDiscoveryService>
Build();
Expand Down
49 changes: 39 additions & 10 deletions src/linux/libnl-helpers/NetlinkRoute.cxx
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@

#include <array>
#include <cstdint>
#include <cstring>
#include <format>
#include <optional>
#include <string>
#include <string_view>
#include <system_error>
#include <unordered_set>
#include <utility>
#include <vector>

Expand All @@ -16,7 +19,6 @@
#include <netinet/in.h>
#include <netlink/addr.h>
#include <netlink/cache.h>
#include <netlink/errno.h>
#include <netlink/netlink.h>
#include <netlink/object.h>
#include <netlink/route/addr.h>
Expand All @@ -33,8 +35,14 @@ namespace detail
constexpr auto Ipv4AddressAsciiLengthMax{ INET_ADDRSTRLEN + 3 };
constexpr auto Ipv6AddressAsciiLengthMax{ INET6_ADDRSTRLEN + 5 };

/**
* @brief Get the (maximum) length of an address in ascii format.
*
* @param addressFamily The address family to get the length for. This must be either AF_INET or AF_INET6.
* @return std::size_t The maximum length of an address string corresponding to the specified IP family.
*/
std::size_t
GetAddressLength(int addressFamily) noexcept
GetAddressAsciiLength(int addressFamily) noexcept
{
switch (addressFamily) {
case AF_INET:
Expand All @@ -46,6 +54,13 @@ GetAddressLength(int addressFamily) noexcept
}
}

/**
* @brief Get a string representation of the specified IP address family.
*
* @param addressFamily The address family to get the name for. This must be either AF_INET or AF_INET6.
* @return constexpr std::string_view The name of the address family or "Unknown" if the address family is not
* recognized.
*/
constexpr std::string_view
GetAddressFamilyName(int addressFamily) noexcept
{
Expand All @@ -59,25 +74,39 @@ GetAddressFamilyName(int addressFamily) noexcept
}
}

/**
* @brief Helper function to use with nl_cache_foreach when processing an rtnl link cache. This will parse the netlink
* object and if it represents a valid netlink link, add an entry to the map specified by the context.
*
* @param nlObjectLink The netlink object representing a potential netlink link.
* @param context The context to populate with the result. This must be of type std::unordered_set<NetlinkLink>.
*/
void
OnLink(struct nl_object *nlObjectLink, void *context)
{
auto *rtnlLink = reinterpret_cast<struct rtnl_link *>(nlObjectLink); // NOLINT
auto netlinkLink = NetlinkLink::FromRtnlLink(rtnlLink);

// Populate output variable (context) with result.
auto& netlinkLinks = *static_cast<std::unordered_set<NetlinkLink> *>(context);
auto &netlinkLinks = *static_cast<std::unordered_set<NetlinkLink> *>(context);
netlinkLinks.emplace(std::move(netlinkLink));
}

/**
* @brief Helper function to use with nl_cache_foreach when processing an rtnl address cache. This parses the specified
* netlink object and if it represents a valid netlink address, add an entry to the map specified by the context.
*
* @param nlObjectAddress The netlink object representing a potential netlink address.
* @param context The context to populate with the result. This must be of type std::unordered_set<NetlinkIpAddress>.
*/
void
OnAddress(struct nl_object *nlObjectAddress, void *context)
{
auto *rtnlAddress = reinterpret_cast<struct rtnl_addr *>(nlObjectAddress); // NOLINT
auto netlinkAddress = NetlinkIpAddress::FromRtnlAddr(rtnlAddress);

// Populate output variable (context) with result.
auto& netlinkAddresses = *static_cast<std::unordered_set<NetlinkIpAddress> *>(context);
auto &netlinkAddresses = *static_cast<std::unordered_set<NetlinkIpAddress> *>(context);
netlinkAddresses.emplace(std::move(netlinkAddress));
}
} // namespace detail
Expand Down Expand Up @@ -106,7 +135,7 @@ NetlinkEnumerateLinks()
auto nlRouteSocket{ CreateNlRouteSocket() };

struct nl_cache *linkCache{ nullptr };
int ret = rtnl_link_alloc_cache(nlRouteSocket, AF_UNSPEC, &linkCache);
const int ret = rtnl_link_alloc_cache(nlRouteSocket, AF_UNSPEC, &linkCache);
if (ret != 0) {
const auto errorCode = MakeNetlinkErrorCode(-ret);
const auto message = std::format("Failed to allocate link cache with error {}", errorCode.value());
Expand All @@ -130,7 +159,7 @@ NetlinkEnumerateIpAddresses()
auto nlRouteSocket{ CreateNlRouteSocket() };

struct nl_cache *ipAddressCache{ nullptr };
int ret = rtnl_addr_alloc_cache(nlRouteSocket, &ipAddressCache);
const int ret = rtnl_addr_alloc_cache(nlRouteSocket, &ipAddressCache);
if (ret != 0) {
const auto errorCode = MakeNetlinkErrorCode(-ret);
const auto message = std::format("Failed to allocate address cache with error {}", errorCode.value());
Expand Down Expand Up @@ -158,7 +187,7 @@ NetlinkIpAddress::FromRtnlAddr(struct rtnl_addr *rtnlAddress)
const auto *local = rtnl_addr_get_local(rtnlAddress);

// Convert the address to a string then resize to actual null-terminated length.
std::string addressLocalAscii(detail::GetAddressLength(family), '\0');
std::string addressLocalAscii(detail::GetAddressAsciiLength(family), '\0');
nl_addr2str(local, std::data(addressLocalAscii), std::size(addressLocalAscii));
addressLocalAscii.resize(std::strlen(std::data(addressLocalAscii)));

Expand Down Expand Up @@ -192,15 +221,15 @@ std::optional<NetlinkLink>
NetlinkLink::FromInterfaceIndex(int interfaceIndex)
{
// Obtain interface/linlk name from interface index.
char interfaceName[IF_NAMESIZE]{ '\0' };
if_indextoname(static_cast<uint32_t>(interfaceIndex), interfaceName);
std::array<char, IF_NAMESIZE> interfaceName{ '\0' };
if_indextoname(static_cast<uint32_t>(interfaceIndex), std::data(interfaceName));

// Allocate a netlink socket to make the kernel request with.
auto nlRouteSocket{ CreateNlRouteSocket() };

// Send a kernel request to get the link information.
struct rtnl_link *rtnlLink{ nullptr };
int ret = rtnl_link_get_kernel(nlRouteSocket, interfaceIndex, interfaceName, &rtnlLink);
const int ret = rtnl_link_get_kernel(nlRouteSocket, interfaceIndex, std::data(interfaceName), &rtnlLink);
if (ret < 0) {
const auto errorCode = MakeNetlinkErrorCode(-ret);
const auto message = std::format("Failed to get link with error {}", errorCode.value());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,42 @@

namespace Microsoft::Net::Netlink
{
/**
* @brief Represents IP address information obtained from a netlink address (struct rtnl_addr) object.
*/
struct NetlinkIpAddress
{
int InterfaceIndex;
int Family;
int PrefixLength;
std::string Address;

static NetlinkIpAddress
FromRtnlAddr(struct rtnl_addr *addr);

// static std::optional<NetlinkIpAddress>
// FromAddress(std::string_view address, struct nl_cache *rtnlAddrCache = nullptr);

auto
operator<=>(const NetlinkIpAddress &) const = default;

/**
* @brief Parse a netlink address object and create a NetlinkIpAddress object from it.
*
* @param rtnlAddress The netlink address object to parse.
* @return NetlinkIpAddress
*/
static NetlinkIpAddress
FromRtnlAddr(struct rtnl_addr *rtnlAddress);

/**
* @brief Get a string representation of the IP address.
*
* @param showInterfaceIndex Whether to include the interface index in the string representation.
* @return std::string
*/
std::string
ToString(bool showInterfaceIndex = true) const;
};

/**
* @brief Represents link information obtained from a netlink link (struct rtnl_link) object. A link is mostly
* synonymous with a network interface.
*/
struct NetlinkLink
{
int InterfaceIndex;
Expand All @@ -44,12 +60,29 @@ struct NetlinkLink
auto
operator<=>(const NetlinkLink &) const = default;

/**
* @brief Parse a netlink link object and create a NetlinkLink object from it.
*
* @param link The netlink link object to parse.
* @return NetlinkLink
*/
static NetlinkLink
FromRtnlLink(struct rtnl_link *link);

/**
* @brief Get a NetlinkLink object from an interface index.
*
* @param interfaceIndex
* @return std::optional<NetlinkLink>
*/
static std::optional<NetlinkLink>
FromInterfaceIndex(int interfaceIndex);

/**
* @brief Get a string representation of the link.
*
* @return std::string
*/
std::string
ToString() const;
};
Expand Down

0 comments on commit e92f5b0

Please sign in to comment.