Skip to content

Commit

Permalink
[Core Service] Added support for .local mDNS in eCAL Services (#1586)
Browse files Browse the repository at this point in the history
Added support for resolving Hostname.local (-> mDNS) hosts

- eCAL Services Lib now supports a list of endpoints to connect to. They will be tried one after another
- eCAL Core uses a list of {Hostname, Hostname.local} to make the service client connect to the mDNS TLD host, if the Hostname alone was not sufficient
  • Loading branch information
FlorianReimold authored May 7, 2024
1 parent 650d969 commit 1fd8cde
Show file tree
Hide file tree
Showing 31 changed files with 1,044 additions and 272 deletions.
7 changes: 6 additions & 1 deletion ecal/core/src/service/ecal_service_client_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -751,7 +751,12 @@ namespace eCAL
const auto port_to_use = (protocol_version == 0 ? iter.tcp_port_v0 : iter.tcp_port_v1);

// Create the client and add it to the map
const auto new_client_session = client_manager->create_client(static_cast<uint8_t>(protocol_version), iter.hname, port_to_use, event_callback);
const std::vector<std::pair<std::string, uint16_t>> endpoint_list
{
{iter.hname, port_to_use},
{iter.hname + ".local", port_to_use}, // TODO: Make this configurable from the ecal.ini
};
const auto new_client_session = client_manager->create_client(static_cast<uint8_t>(protocol_version), endpoint_list, event_callback);
if (new_client_session)
m_client_map[iter.key] = new_client_session;
}
Expand Down
9 changes: 7 additions & 2 deletions ecal/service/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,20 @@
#
# ========================= eCAL LICENSE =================================

cmake_minimum_required(VERSION 3.16)
project(ecal_service)

# Main library
add_subdirectory(ecal_service)

# Samples
if(ECAL_CORE_BUILD_SAMPLES)
add_subdirectory(sample)
add_subdirectory(samples/sample_client)
add_subdirectory(samples/sample_server)
add_subdirectory(samples/sample_standalone)
endif()

# Tests
if(ECAL_CORE_BUILD_TESTS)
add_subdirectory(test)
endif()
endif()
20 changes: 12 additions & 8 deletions ecal/service/ecal_service/include/ecal/service/client_manager.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,16 @@
#include <cstdint>
#include <map>
#include <memory>

#include <ecal/service/client_session.h>
#include <mutex>
#include <string>
#include <utility>
#include <vector>

#include <asio.hpp>

#include <ecal/service/logger.h>

#include <ecal/service/client_session.h> // IWYU pragma: export

namespace eCAL
{
Expand Down Expand Up @@ -141,16 +147,14 @@ namespace eCAL
* stopped from this central place.
*
* @param protocol_version The protocol version to use for the client session. If 0, the legacy buggy protocol will be used.
* @param address The address of the server to connect to
* @param port The port of the server to connect to
* @param server_list A list of endpoints to connect to. Must not be empty. The endpoints will be tried in the given order until a working endpoint is found.
* @param event_callback The callback, that will be called, when the client has connected to the server or disconnected from it. The callback will be executed in the io_context thread.
*
* @return A shared_ptr to the newly created ClientSession instance
*/
std::shared_ptr<ClientSession> create_client(std::uint8_t protocol_version
, const std::string& address
, std::uint16_t port
, const ClientSession::EventCallbackT& event_callback);
std::shared_ptr<ClientSession> create_client(std::uint8_t protocol_version
, const std::vector<std::pair<std::string, std::uint16_t>>& server_list
, const ClientSession::EventCallbackT& event_callback);

/**
* @brief Returns the number of managed client sessions
Expand Down
89 changes: 50 additions & 39 deletions ecal/service/ecal_service/include/ecal/service/client_session.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
#include <functional>
#include <memory>
#include <string>
#include <utility>
#include <vector>

#ifdef _MSC_VER
#pragma warning(push)
Expand All @@ -34,6 +36,7 @@
#endif

#include <ecal/service/client_session_types.h>
#include <ecal/service/error.h>
#include <ecal/service/logger.h>
#include <ecal/service/state.h>

Expand Down Expand Up @@ -133,43 +136,38 @@ namespace eCAL
*
* @param io_context The io_context to use for the session and all callbacks.
* @param protocol_version The protocol version to use for the session. When this is 0, the legacy buggy protocol is used.
* @param address The address of the server to connect to. May be an IP or a Hostname, IPv6 is supported.
* @param port The port of the server to connect to.
* @param server_list A list of endpoints to connect to. Must not be empty. The endpoints will be tried in the given order until a working endpoint is found.
* @param event_callback The callback to be called when the session's state changes, i.e. when the session successfully connected to a server or disconnected from it.
* @param logger The logger to use for logging.
* @param delete_callback The callback to be called when the session is deleted. This is useful for the eCAL::service::ClientManager to keep track of the number of active sessions.
*
* @return The new ClientSession instance as a shared_ptr.
*/
static std::shared_ptr<ClientSession> create(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::string& address
, std::uint16_t port
, const EventCallbackT& event_callback
, const LoggerT& logger
, const DeleteCallbackT& delete_callback);
static std::shared_ptr<ClientSession> create(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::vector<std::pair<std::string, std::uint16_t>>& server_list
, const EventCallbackT& event_callback
, const LoggerT& logger
, const DeleteCallbackT& delete_callback);

static std::shared_ptr<ClientSession> create(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::string& address
, std::uint16_t port
, const EventCallbackT& event_callback
, const LoggerT& logger = default_logger("Service Client"));
static std::shared_ptr<ClientSession> create(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::vector<std::pair<std::string, std::uint16_t>>& server_list
, const EventCallbackT& event_callback
, const LoggerT& logger = default_logger("Service Client"));

static std::shared_ptr<ClientSession> create(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::string& address
, std::uint16_t port
, const EventCallbackT& event_callback
, const DeleteCallbackT& delete_callback);
static std::shared_ptr<ClientSession> create(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::vector<std::pair<std::string, std::uint16_t>>& server_list
, const EventCallbackT& event_callback
, const DeleteCallbackT& delete_callback);

protected:
ClientSession(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::string& address
, std::uint16_t port
, const EventCallbackT& event_callback
, const LoggerT& logger);
ClientSession(const std::shared_ptr<asio::io_context>& io_context
, std::uint8_t protocol_version
, const std::vector<std::pair<std::string, std::uint16_t>>& server_list
, const EventCallbackT& event_callback
, const LoggerT& logger);

public:
// Delete copy constructor and assignment operator
Expand Down Expand Up @@ -227,28 +225,41 @@ namespace eCAL
eCAL::service::Error call_service(const std::shared_ptr<const std::string>& request, std::shared_ptr<std::string>& response);

/**
* @brief Get the address that this client session has been created with.
* @brief Get the host that this client is connected to.
*
* This function returns the address that this client session has been
* created with. It will not return the address of the server that this
* client session is connected to, which would actually be the same
* address, but probably resolved to an IP.
* Get the host that this client is connected to.
* If the client is not connected, this function will return an empty
* string. Otherwise, it will return the hostname from the list
* server_list that the client is connected to.
*
* @return The address that this client session has been created with.
* The host is not resolved to an IP address. Use get_remote_endpoint()
* to get the actual IP address.
*
* @return The host that this client is connected to.
*/
std::string get_address() const;
std::string get_host() const;

/**
* @brief Get the port that this client session has been created with.
* @brief Get the port that this client session is connected to.
*
* This function returns the port that this client session has been
* created with. It is not said, that the connection has been established
* successfully.
* Get the port that this client session is connected to. If the client
* is not connected, this function will return 0. Otherwise, it will
* return the port from the list server_list that the client is connected
* to.
*
* @return The port that this client session has been created with.
* @return The port that this client is connected to
*/
std::uint16_t get_port() const;

/**
* @brief Get the remote endpoint that this client session is connected to.
*
* Get the remote endpoint that this client session is connected to. Only
* valid, if the client session is actually connected to a server. If a
* hostname was given, this function will return the resolved IP address.
*/
asio::ip::tcp::endpoint get_remote_endpoint() const;

/**
* @brief Get the state of this client session.
*
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,14 @@
#include <cstdint>
#include <map>
#include <memory>

#include <ecal/service/server.h>
#include <mutex>

#include <asio.hpp>

#include <ecal/service/logger.h>

#include <ecal/service/server.h> // IWYU pragma: export

namespace eCAL
{
namespace service
Expand Down
19 changes: 13 additions & 6 deletions ecal/service/ecal_service/src/client_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,14 +17,22 @@
* ========================= eCAL LICENSE =================================
*/

#include <ecal/service/client_manager.h>

#include <cstddef>
#include <cstdint>
#include <ecal/service/client_manager.h>
#include <map>
#include <memory>
#include <mutex>
#include <string>

#include <asio.hpp>

#include <ecal/service/client_session.h>
#include <ecal/service/logger.h>
#include <utility>
#include <vector>

namespace eCAL
{
namespace service
Expand Down Expand Up @@ -52,10 +60,9 @@ namespace eCAL
///////////////////////////////////////////////////////
// Public API
///////////////////////////////////////////////////////
std::shared_ptr<ClientSession> ClientManager::create_client(std::uint8_t protocol_version
, const std::string& address
, std::uint16_t port
, const ClientSession::EventCallbackT& event_callback)
std::shared_ptr<ClientSession> ClientManager::create_client(std::uint8_t protocol_version
, const std::vector<std::pair<std::string, std::uint16_t>>& server_list
, const ClientSession::EventCallbackT& event_callback)
{
const std::lock_guard<std::mutex> lock(client_manager_mutex_);
if (stopped_)
Expand All @@ -74,7 +81,7 @@ namespace eCAL
}
};

auto client = ClientSession::create(io_context_, protocol_version, address, port, event_callback, logger_, deleter);
auto client = ClientSession::create(io_context_, protocol_version, server_list, event_callback, logger_, deleter);
sessions_.emplace(client.get(), client);
return client;
}
Expand Down
Loading

0 comments on commit 1fd8cde

Please sign in to comment.