blob: ddf950bd645ebdbfea9fa390e695856fe50713b9 [file] [log] [blame]
//
// daemon.cpp
//
// Author: Lutz Bichler
//
// This file is part of the BMW Some/IP implementation.
//
// Copyright © 2013, 2014 Bayerische Motoren Werke AG (BMW).
// All rights reserved.
//
#include <algorithm>
#include <fstream>
#include <boost/algorithm/string.hpp>
#include <boost/bind.hpp>
#include <boost/log/core.hpp>
#include <boost/log/expressions.hpp>
#include <boost/log/sinks/text_file_backend.hpp>
#include <boost/log/support/date_time.hpp>
#include <boost/log/utility/setup/console.hpp>
#include <boost/log/utility/setup/file.hpp>
#include <boost/log/utility/setup/common_attributes.hpp>
#include <boost/program_options.hpp>
#include <boost/thread.hpp>
#include <vsomeip/service.hpp>
#include <vsomeip/internal/endpoint_impl.hpp>
#include <vsomeip/internal/tcp_service_impl.hpp>
#include <vsomeip/internal/udp_service_impl.hpp>
#include <vsomeip/service_discovery/factory.hpp>
#include <vsomeip/service_discovery/message.hpp>
#include <vsomeip/service_discovery/entry.hpp>
#include <vsomeip/service_discovery/eventgroup_entry.hpp>
#include <vsomeip/service_discovery/service_entry.hpp>
#include <vsomeip/service_discovery/internal/daemon-config.hpp>
#include <vsomeip/service_discovery/internal/daemon.hpp>
namespace options = boost::program_options;
namespace logging = boost::log;
namespace keywords = boost::log::keywords;
namespace expressions = boost::log::expressions;
using namespace boost::log::trivial;
#define SERVICE_DISCOVERY_SERVICE_ID 0xFFFF
#define SERVICE_DISCOVERY_METHOD_ID 0x8100
namespace vsomeip {
namespace service_discovery {
severity_level loglevel_from_string(const std::string &_loglevel);
daemon*
daemon::get_instance() {
static daemon daemon__;
return &daemon__;
}
daemon::daemon()
: acceptor_(is_) {
port_ = VSOMEIP_VALUE_PORT_DEFAULT;
registry_path_ = VSOMEIP_VALUE_REGISTRY_PATH_DEFAULT;
loglevel_ = info;
is_virtual_mode_ = VSOMEIP_VALUE_IS_VIRTUAL_MODE_DEFAULT;
is_service_discovery_mode_ =
VSOMEIP_VALUE_IS_SERVICE_DISCOVERY_MODE_DEFAULT;
}
void daemon::init(int argc, char **argv) {
// logging first
logging::add_common_attributes();
auto daemon_log_format = expressions::stream
<< expressions::format_date_time<boost::posix_time::ptime>(
"TimeStamp", "%Y-%m-%d %H:%M:%S.%f") << " ["
<< expressions::attr<severity_level>("Severity") << "] "
<< expressions::smessage;
logging::add_console_log(std::clog,
keywords::filter = severity >= loglevel_, keywords::format =
daemon_log_format);
logging::add_file_log(keywords::file_name = "vsomeipd_%N.log",
keywords::rotation_size = 10 * 1024 * 1024,
keywords::time_based_rotation =
logging::sinks::file::rotation_at_time_point(0, 0, 0),
keywords::filter = severity >= loglevel_, keywords::format =
daemon_log_format);
boost::log::core::get()->set_filter(severity >= info);
options::variables_map commandline_configuration;
try {
options::options_description valid_options("allowed");
valid_options.add_options()("help", "Print help message")("config",
options::value<std::string>()->default_value("vsomeipd.conf"),
"Path to configuration file")("loglevel",
options::value<std::string>(),
"Log level to be used by vsomeip daemon")("port",
options::value<int>(), "IP port to be used by vsomeip daemon")(
"service_discovery_enabled", options::value<bool>(),
"Enable/Disable service discovery by vsomeip daemon")(
"virtual_mode_enabled", options::value<bool>(),
"Enable/Disable virtual mode by vsomeip daemon");
options::store(options::parse_command_line(argc, argv, valid_options),
commandline_configuration);
options::notify(commandline_configuration);
}
catch (...) {
BOOST_LOG_SEV(log_, error)<< "Command line configuration (partly) invalid.";
}
std::string configuration_path(VSOMEIP_DEFAULT_CONFIGURATION_FILE);
if (commandline_configuration.count("config")) {
configuration_path =
commandline_configuration["config"].as<std::string>();
}
BOOST_LOG_SEV(log_, info)<< "Using configuration file \""
<< configuration_path << "\"";
options::variables_map configuration;
options::options_description configuration_description;
configuration_description.add_options()
( "someip.daemon.loglevel",
options::value<std::string>(),
"Log level to be used by vsomeip daemon" )
( "someip.daemon.logger",
options::value<std::string>(),
"Logger(s) to be used" )
( "someip.daemon.port",
options::value<int>(),
"IP port to be used by vsomeip daemon" )
( "someip.daemon.service_discovery_enabled",
options::value<bool>(),
"Enable service discovery by vsomeip daemon" )
( "someip.daemon.virtual_mode_enabled",
options::value<bool>(),
"Enable virtual mode by vsomeip daemon" );
std::ifstream configuration_file;
configuration_file.open(configuration_path.c_str());
if (configuration_file.is_open()) {
try {
options::store(
options::parse_config_file(configuration_file,
configuration_description, true), configuration);
options::notify(configuration);
}
catch (...) {
BOOST_LOG_SEV(log_, error)
<< "Command line configuration (partly) invalid.";
}
if (configuration.count("someip.daemon.logger")) {
set_loggers(configuration["someip.daemon.logger"].as< std::string >());
}
if (configuration.count("someip.daemon.loglevel"))
loglevel_ = loglevel_from_string(
configuration["someip.daemon.loglevel"].
as< std::string>());
if (configuration.count("someip.daemon.port"))
port_ = configuration["someip.daemon.port"].as<int>();
if (configuration.count("someip.daemon.registry"))
registry_path_ = configuration["someip.daemon.registry"].as<std::string>();
if (configuration.count("someip.daemon.virtual_mode_enabled"))
is_virtual_mode_ = configuration["someip.daemon.virtual_mode_enabled"].as< bool >();
if (configuration.count("someip.daemon.service_discovery_enabled"))
is_service_discovery_mode_ = configuration["someip.daemon.service_discovery_enabled"].as< bool >();
} else {
BOOST_LOG_SEV(log_, error)
<< "Could not open configuration file \""
<< configuration_path << "\"";
}
// Command line overwrites configuration file
if (commandline_configuration.count("log_level"))
loglevel_ = loglevel_from_string(
configuration["someip.daemon.loglevel"].as<std::string>());
if (commandline_configuration.count("port"))
port_ = commandline_configuration["port"].as<int>();
if (commandline_configuration.count("virtual_mode_enabled"))
is_virtual_mode_ = commandline_configuration["virtual_mode_enabled"].as<
bool>();
if (commandline_configuration.count("service_discovery_enabled"))
is_service_discovery_mode_ =
commandline_configuration["service_discovery_enabled"].as<bool>();
}
void daemon::start() {
// Check whether the daemon makes any sense
if (!is_virtual_mode_ && !is_service_discovery_mode_) {
BOOST_LOG_SEV(log_, error)<< "Neither virtual mode nor service discovery "
"mode active, exiting.";
stop();
} else {
BOOST_LOG_SEV(log_, info) << "Using port " << port_;
//BOOST_LOG_DEV(log_, info) << "Using log level " << _log_level;
if (is_virtual_mode_) {
BOOST_LOG_SEV(log_, info) << "Virtual mode: on";
}
if (is_service_discovery_mode_) {
BOOST_LOG_SEV(log_, info) << "Service discovery mode: on";
}
// Enable internal registry interface
::unlink(registry_path_.c_str());
registry_ = new service_registry(is_, registry_path_);
// create a UDP & a TCP service as we want to listen to a port and
// send/receive Some/IP messages
endpoint *udp_endpoint = new endpoint_impl("127.0.0.1", port_,
ip_protocol::UDP, ip_version::V4);
endpoint *tcp_endpoint = new endpoint_impl("127.0.0.1", port_,
ip_protocol::TCP, ip_version::V4);
factory *default_factory = factory::get_default_factory();
udp_daemon_
= new udp_service_impl(default_factory, udp_endpoint, is_);
tcp_daemon_
= new tcp_service_impl(default_factory, tcp_endpoint, is_);
tcp_daemon_->register_for(this,
SERVICE_DISCOVERY_SERVICE_ID,
SERVICE_DISCOVERY_METHOD_ID);
udp_daemon_->register_for(this,
SERVICE_DISCOVERY_SERVICE_ID,
SERVICE_DISCOVERY_METHOD_ID);
udp_daemon_->start();
tcp_daemon_->start();
boost::thread io_thread(boost::bind(&daemon::run_service, this));
is_running_ = true;
io_thread.join();
}
}
void daemon::stop() {
is_running_ = false;
}
void daemon::run_service() {
while (is_running_) {
BOOST_LOG_SEV(log_, info)<< "(Re-)Starting service";
is_.run();
}
}
void daemon::receive(const message_base *_message) {
const message *requests = dynamic_cast<const message *>(_message);
if (0 != requests) {
const std::vector<entry *>& entries = requests->get_entries();
for (auto e : entries) {
consume_request(*e, _message->get_endpoint());
}
} else {
BOOST_LOG_SEV(log_, warning)<< "Received unstructued Some/IP service discovery message!";
}
}
void daemon::consume_request(const entry &_entry, endpoint *_target) {
if (_entry.get_type() == entry_type::FIND_SERVICE) {
const service_entry& s = reinterpret_cast<const service_entry &>(_entry);
service_info *found = registry_->find(s.get_service_id(), s.get_instance_id());
if (found) {
send_offer_service(found, _target);
} else {
BOOST_LOG_SEV(log_, warning)<< "Service " << std::hex
<< (int)s.get_service_id()
<< "."
<< (int)s.get_instance_id()
<< " not available!";
}
}
}
void daemon::send_offer_service(service_info *_service, endpoint *_target) {
boost::shared_ptr<message> m(
factory::get_default_factory()->create_service_discovery_message());
m->set_endpoint(_target);
service_entry& s = m->create_service_entry();
s.set_type(entry_type::OFFER_SERVICE);
s.set_service_id(_service->service_);
s.set_instance_id(_service->instance_);
udp_daemon_->send(m.get());
}
void daemon::set_loggers(const std::string &_logger_configuration) {
std::string logger_configuration(_logger_configuration);
boost::algorithm::trim(logger_configuration);
std::vector<std::string> loggers;
boost::split(loggers, logger_configuration, boost::is_any_of("|"));
for (auto i: loggers) {
boost::algorithm::trim(i);
if ("console" == i) use_console_ = true;
else if ("file" == i) use_file_ = true;
else if ("dlt" == i) use_dlt_ = true;
}
}
severity_level loglevel_from_string(const std::string &_loglevel) {
if (_loglevel == "info")
return info;
if (_loglevel == "debug")
return debug;
if (_loglevel == "trace")
return trace;
if (_loglevel == "warning")
return warning;
if (_loglevel == "error")
return error;
if (_loglevel == "fatal")
return fatal;
return info;
}
} // namespace service_discovery
} // namespace vsomeip