Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Modify network detection on QNX to delay SD #841

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions implementation/configuration/include/internal.hpp.in
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,27 @@

#define VSOMEIP_ROUTING_HOST_PORT_DEFAULT 31490

//
// Defines related to using the "simple_connector" for network monitoring as
// opposed to the netlink connector available on Linux systems. This is not
// available upstream. The original implementation allowed SD to start
// asynchronously and hence the variables below were named to support that. The
// implementation has moved on to the simple_connector, but the environment
// variable names remain.

// Env var that if exists will allow the simple_connector to launch a thread to
// wait for the network to be available and notify the routing manager. If not
// set, the simple_connector will assume the network is available and notify the
// routing manager as such.
#define VSOMEIP_ENV_USE_ASYNCHRONOUS_SD "VSOMEIP_USE_ASYNCHRONOUS_SD"

// The current waiting mechanism is to block until a file (specified by this
// define)
#define VSOMEIP_ENV_NETWORK_INT_READY_FILE "@VSOMEIP_NETWORK_INT_READY_FILE@"

// /end of async change
//

#ifdef _WIN32
#define VSOMEIP_CFG_LIBRARY "vsomeip3-cfg.dll"
#else
Expand Down
59 changes: 59 additions & 0 deletions implementation/endpoints/include/simple_connector.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
#ifndef VSOMEIP_V3_SIMPLE_CONNECTOR_HPP_
#define VSOMEIP_V3_SIMPLE_CONNECTOR_HPP_

#include <atomic>
#include <functional>
#include <string>
#include <string_view>
#include <thread>

#include <boost/enable_shared_from_this.hpp>

#ifdef ANDROID
#include "../../configuration/include/internal_android.hpp"
#else
#include "../../configuration/include/internal.hpp"
#endif

namespace vsomeip_v3 {

using simple_net_ready_handler_t =
std::function<void(bool, // true = is interface, false = is route
std::string, // interface name
bool) // available?
>;

/** \brief simple network connector, designed for use on QNX.
*
* This class is a simple network connector that is designed to be used on QNX
* to detect when the network interface is available. This is done by waiting
* for (`waitfor`) the presence of VSOMEIP_NETWORK_INT_READY_FILE which is
* created externally of vsomeip. An alternative implementation would be to use
* a service like PPS.
*/
class simple_connector : public std::enable_shared_from_this<simple_connector> {
public:
simple_connector();
~simple_connector();

void
register_net_if_changes_handler(const simple_net_ready_handler_t &_handler);
void unregister_net_if_changes_handler();

void start();
void stop();

private:
bool wait_for_interface();

static constexpr std::string_view if_name_ = "emac0";
std::atomic<bool> network_ready_;

std::thread wait_for_network_thread_;

simple_net_ready_handler_t handler_{nullptr};
};

} // namespace vsomeip_v3

#endif // VSOMEIP_V3_SIMPLE_CONNECTOR_HPP_
2 changes: 1 addition & 1 deletion implementation/endpoints/src/netlink_connector.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@

#include <boost/asio/write.hpp>
#include <boost/asio/read.hpp>
#include<sstream>
#include <sstream>

#include <vsomeip/internal/logger.hpp>

Expand Down
122 changes: 122 additions & 0 deletions implementation/endpoints/src/simple_connector.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,122 @@
#include <chrono>
#include <cstring>
#include <thread>

#ifdef __QNX__
#include <libgen.h>
#endif

#include <vsomeip/internal/logger.hpp>

#include "../include/simple_connector.hpp"

#ifndef VSOMEIP_ENV_USE_ASYNCHRONOUS_SD
#define VSOMEIP_ENV_USE_ASYNCHRONOUS_SD "VSOMEIP_USE_ASYNCHRONOUS_SD"
#endif

namespace vsomeip_v3 {

simple_connector::simple_connector()
: network_ready_(
#ifdef __QNX__
false
#else
true
#endif
) {
}

simple_connector::~simple_connector() {
if (wait_for_network_thread_.joinable()) {
wait_for_network_thread_.join();
}
}

void simple_connector::register_net_if_changes_handler(
const simple_net_ready_handler_t &_handler) {
handler_ = _handler;
}

void simple_connector::unregister_net_if_changes_handler() {
handler_ = nullptr;
}

void simple_connector::stop() { return; }

bool simple_connector::wait_for_interface() {
#ifdef __QNX__
namespace cr = std::chrono;
static std::string_view constexpr path = VSOMEIP_ENV_NETWORK_INT_READY_FILE;
if (path.empty()) {
VSOMEIP_ERROR << "No network interface signal path defined, service "
"discovery will effectively be disabled.";
return false;
}
// Indefinite delay. If the condition we're waiting for doesn't occur then
// we are in an error state and thus should not continue.
static auto constexpr delay_ms = std::numeric_limits<int>::max();
static int constexpr poll_ms = 50;

auto const start = cr::steady_clock::now();
VSOMEIP_DEBUG
<< "Waiting (blocking) indefinitely on network interface (signal=" << path
<< ")";
auto const r = waitfor(path.data(), delay_ms, poll_ms);
auto const end = cr::steady_clock::now();
auto diff = end - start;
if (0 == r) {
VSOMEIP_DEBUG << "Waited (blocked) for network interface (signal=" << path
<< ") for "
<< cr::duration_cast<cr::milliseconds>(diff).count()
<< " ms.";
return true;
} else {
VSOMEIP_ERROR << "Timedout waiting for network interface (signal=" << path
<< ") after "
<< cr::duration_cast<cr::milliseconds>(diff).count()
<< " ms: errno=" << errno << ", msg=" << strerror(errno);
return false;
}
#else
// Omitting a non-QNX implementation for now. The QNX implementation might be
// modified to use pps in the future, similar to how the Linux implementation
// uses Netlink.. A Linux implementation could also mirror what is above
// using ionotify, but it would only be useful for testing - in practice it
// would simple be a worse implementation than using netlink
return true;
#endif
}

void simple_connector::start() {
auto *const use_async_sd = getenv(VSOMEIP_ENV_USE_ASYNCHRONOUS_SD);
if (!use_async_sd) {
// If VSOMEIP_ENV_USE_ASYNCHRONOUS_SD is not set, so we will assume the
// network is "ready" and proceed normally.
network_ready_ = true;
handler_(true, if_name_.data(), true);
handler_(false, if_name_.data(), true);

return;
}

wait_for_network_thread_ = std::thread([this]() {
#if defined(__linux__) || defined(ANDROID) || defined(__QNX__)
{
auto err = pthread_setname_np(wait_for_network_thread_.native_handle(),
"wait_network");
if (err) {
VSOMEIP_ERROR << "Could not rename SD thread: " << errno << ":"
<< std::strerror(errno);
}
}
#endif
network_ready_ = wait_for_interface();

handler_(true, if_name_.data(), network_ready_);
handler_(false, if_name_.data(), network_ready_);
});

return;
}

} // namespace vsomeip_v3
6 changes: 6 additions & 0 deletions implementation/routing/include/routing_manager_impl.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,11 @@
#include "routing_manager_stub_host.hpp"
#include "types.hpp"

#if defined(__linux__) || defined(ANDROID)
#include "../../endpoints/include/netlink_connector.hpp"
#elif defined(__QNX__)
#include "../../endpoints/include/simple_connector.hpp"
#endif
#include "../../service_discovery/include/service_discovery_host.hpp"
#include "../../endpoints/include/endpoint_manager_impl.hpp"

Expand Down Expand Up @@ -509,6 +513,8 @@ class routing_manager_impl: public routing_manager_base,
std::vector<std::pair<service_t, instance_t>> pending_sd_offers_;
#if defined(__linux__) || defined(ANDROID)
std::shared_ptr<netlink_connector> netlink_connector_;
#elif defined(__QNX__)
std::shared_ptr<simple_connector> simple_connector_;
#endif

std::mutex pending_offers_mutex_;
Expand Down
13 changes: 10 additions & 3 deletions implementation/routing/src/routing_manager_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -235,7 +235,13 @@ void routing_manager_impl::start() {
this, std::placeholders::_1, std::placeholders::_2, std::placeholders::_3));
netlink_connector_->start();
#else
start_ip_routing();
simple_connector_ = std::make_shared<simple_connector>();
simple_connector_->register_net_if_changes_handler(
[this](bool is_interface, std::string interface_name, bool available) {
on_net_interface_or_route_state_changed(is_interface, interface_name,
available);
});
simple_connector_->start();
#endif

if (stub_)
Expand Down Expand Up @@ -4028,7 +4034,7 @@ void routing_manager_impl::on_net_interface_or_route_state_changed(
}

void routing_manager_impl::start_ip_routing() {
#if defined(_WIN32) || defined(__QNX__)
#if defined(_WIN32)
if_state_running_ = true;
#endif

Expand All @@ -4052,12 +4058,13 @@ void routing_manager_impl::start_ip_routing() {
pending_sd_offers_.clear();
VSOMEIP_INFO << "rmi::" << __func__ << ": clear pending_sd_offers_";
}

routing_running_ = true;
VSOMEIP_INFO << VSOMEIP_ROUTING_READY_MESSAGE;
}

inline bool routing_manager_impl::is_external_routing_ready() const {

return if_state_running_
&& (!configuration_->is_sd_enabled()
|| (configuration_->is_sd_enabled() && sd_route_set_));
Expand Down
Loading