diff options
Diffstat (limited to 'implementation/endpoints/src/local_uds_server_endpoint_impl.cpp')
-rw-r--r-- | implementation/endpoints/src/local_uds_server_endpoint_impl.cpp | 1067 |
1 files changed, 1067 insertions, 0 deletions
diff --git a/implementation/endpoints/src/local_uds_server_endpoint_impl.cpp b/implementation/endpoints/src/local_uds_server_endpoint_impl.cpp new file mode 100644 index 0000000..8aa2139 --- /dev/null +++ b/implementation/endpoints/src/local_uds_server_endpoint_impl.cpp @@ -0,0 +1,1067 @@ +// Copyright (C) 2014-2021 Bayerische Motoren Werke Aktiengesellschaft (BMW AG) +// This Source Code Form is subject to the terms of the Mozilla Public +// License, v. 2.0. If a copy of the MPL was not distributed with this +// file, You can obtain one at http://mozilla.org/MPL/2.0/. + +#include <deque> +#include <iomanip> +#include <sstream> + +#include <sys/types.h> +#include <boost/asio/write.hpp> + +#include <vsomeip/internal/logger.hpp> + +#include "../include/credentials.hpp" +#include "../include/endpoint_host.hpp" +#include "../include/local_uds_server_endpoint_impl.hpp" +#include "../include/local_server_endpoint_impl_receive_op.hpp" +#include "../../configuration/include/configuration.hpp" +#include "../../protocol/include/assign_client_command.hpp" +#include "../../protocol/include/assign_client_ack_command.hpp" +#include "../../routing/include/routing_host.hpp" +#include "../../security/include/policy_manager_impl.hpp" +#include "../../utility/include/byteorder.hpp" +#include "../../utility/include/utility.hpp" + +namespace vsomeip_v3 { + +local_uds_server_endpoint_impl::local_uds_server_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, boost::asio::io_context &_io, + const std::shared_ptr<configuration>& _configuration, + bool _is_routing_endpoint) + : local_uds_server_endpoint_base_impl(_endpoint_host, _routing_host, _local, + _io, + _configuration->get_max_message_size_local(), + _configuration->get_endpoint_queue_limit_local(), + _configuration), + acceptor_(_io), + buffer_shrink_threshold_(_configuration->get_buffer_shrink_threshold()), + is_routing_endpoint_(_is_routing_endpoint) { + is_supporting_magic_cookies_ = false; + + boost::system::error_code ec; + acceptor_.open(_local.protocol(), ec); + if (ec) + VSOMEIP_ERROR << __func__ + << ": open failed (" << ec.message() << ")"; + + acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec); + if (ec) + VSOMEIP_ERROR << __func__ + << ": set reuse address option failed (" << ec.message() << ")"; + + acceptor_.bind(_local, ec); + if (ec) + VSOMEIP_ERROR << __func__ + << ": bind failed (" << ec.message() << ")"; + + acceptor_.listen(boost::asio::socket_base::max_connections, ec); + if (ec) + VSOMEIP_ERROR << __func__ + << ": listen failed (" << ec.message() << ")"; + + if (chmod(_local.path().c_str(), + static_cast<mode_t>(_configuration->get_permissions_uds())) == -1) { + VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno); + } + credentials::activate_credentials(acceptor_.native_handle()); +} + +local_uds_server_endpoint_impl::local_uds_server_endpoint_impl( + const std::shared_ptr<endpoint_host>& _endpoint_host, + const std::shared_ptr<routing_host>& _routing_host, + const endpoint_type& _local, boost::asio::io_context &_io, + int native_socket, + const std::shared_ptr<configuration>& _configuration, + bool _is_routing_endpoint) + : local_uds_server_endpoint_base_impl(_endpoint_host, _routing_host, _local, _io, + _configuration->get_max_message_size_local(), + _configuration->get_endpoint_queue_limit_local(), + _configuration), + acceptor_(_io), + buffer_shrink_threshold_(configuration_->get_buffer_shrink_threshold()), + is_routing_endpoint_(_is_routing_endpoint) { + is_supporting_magic_cookies_ = false; + + boost::system::error_code ec; + acceptor_.assign(_local.protocol(), native_socket, ec); + if (ec) + VSOMEIP_ERROR << __func__ + << ": assign failed (" << ec.message() << ")"; + + if (chmod(_local.path().c_str(), + static_cast<mode_t>(_configuration->get_permissions_uds())) == -1) { + VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno); + } + credentials::activate_credentials(acceptor_.native_handle()); +} + +local_uds_server_endpoint_impl::~local_uds_server_endpoint_impl() { + +} + +bool local_uds_server_endpoint_impl::is_local() const { + + return true; +} + +void local_uds_server_endpoint_impl::start() { + + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if (acceptor_.is_open()) { + connection::ptr new_connection = connection::create( + std::dynamic_pointer_cast<local_uds_server_endpoint_impl>( + shared_from_this()), max_message_size_, + buffer_shrink_threshold_, + io_); + + { + std::unique_lock<std::mutex> its_lock(new_connection->get_socket_lock()); + acceptor_.async_accept( + new_connection->get_socket(), + std::bind( + &local_uds_server_endpoint_impl::accept_cbk, + std::dynamic_pointer_cast< + local_uds_server_endpoint_impl + >(shared_from_this()), + new_connection, + std::placeholders::_1 + ) + ); + } + } +} + +void local_uds_server_endpoint_impl::stop() { + + server_endpoint_impl::stop(); + { + std::lock_guard<std::mutex> its_lock(acceptor_mutex_); + if (acceptor_.is_open()) { + boost::system::error_code its_error; + acceptor_.close(its_error); + } + } + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + for (const auto &c : connections_) { + c.second->stop(); + } + connections_.clear(); + } +} + +bool local_uds_server_endpoint_impl::send(const uint8_t *_data, uint32_t _size) { +#if 0 + std::stringstream msg; + msg << "lse::send "; + for (uint32_t i = 0; i < _size; i++) + msg << std::setw(2) << std::setfill('0') << std::hex << (int)_data[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + std::lock_guard<std::mutex> its_lock(mutex_); + if (endpoint_impl::sending_blocked_) { + return false; + } + + client_t its_client; + std::memcpy(&its_client, &_data[protocol::COMMAND_HEADER_SIZE], sizeof(its_client)); + + connection::ptr its_connection; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + const auto its_iterator = connections_.find(its_client); + if (its_iterator == connections_.end()) { + return false; + } else { + its_connection = its_iterator->second; + } + } + + auto its_buffer = std::make_shared<message_buffer_t>(); + its_buffer->insert(its_buffer->end(), _data, _data + _size); + its_connection->send_queued(its_buffer); + + return true; +} + +bool local_uds_server_endpoint_impl::send_to( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + return false; +} + +bool local_uds_server_endpoint_impl::send_error( + const std::shared_ptr<endpoint_definition> _target, + const byte_t *_data, uint32_t _size) { + + (void)_target; + (void)_data; + (void)_size; + return false; +} + +bool local_uds_server_endpoint_impl::send_queued( + const target_data_iterator_type _it) { + + (void)_it; + + return false; +} + +void local_uds_server_endpoint_impl::receive() { + // intentionally left empty +} + +bool local_uds_server_endpoint_impl::get_default_target( + service_t, + local_uds_server_endpoint_impl::endpoint_type &) const { + + return false; +} + +bool local_uds_server_endpoint_impl::add_connection(const client_t &_client, + const std::shared_ptr<connection> &_connection) { + + bool ret = false; + std::lock_guard<std::mutex> its_lock(connections_mutex_); + auto find_connection = connections_.find(_client); + if (find_connection == connections_.end()) { + connections_[_client] = _connection; + ret = true; + } else { + VSOMEIP_WARNING << "Attempt to add already existing " + "connection to client " << std::hex << _client; + } + return ret; +} + +void local_uds_server_endpoint_impl::remove_connection( + const client_t &_client) { + + std::lock_guard<std::mutex> its_lock(connections_mutex_); + connections_.erase(_client); +} + +void local_uds_server_endpoint_impl::accept_cbk( + const connection::ptr& _connection, boost::system::error_code const &_error) { + if (_error != boost::asio::error::bad_descriptor + && _error != boost::asio::error::operation_aborted + && _error != boost::asio::error::no_descriptors) { + start(); + } else if (_error == boost::asio::error::no_descriptors) { + VSOMEIP_ERROR << "local_usd_server_endpoint_impl::accept_cbk: " + << _error.message() << " (" << std::dec << _error.value() + << ") Will try to accept again in 1000ms"; + std::shared_ptr<boost::asio::steady_timer> its_timer = + std::make_shared<boost::asio::steady_timer>(io_, + std::chrono::milliseconds(1000)); + auto its_ep = std::dynamic_pointer_cast<local_uds_server_endpoint_impl>( + shared_from_this()); + its_timer->async_wait([its_timer, its_ep] + (const boost::system::error_code& _error) { + if (!_error) { + its_ep->start(); + } + }); + } + + if (!_error) { + auto its_host = endpoint_host_.lock(); + client_t its_client = 0; + std::string its_client_host; + vsomeip_sec_client_t its_sec_client; + + its_sec_client.client_type = VSOMEIP_CLIENT_UDS; + its_sec_client.client.uds_client.user = ANY_UID; + its_sec_client.client.uds_client.group = ANY_GID; + + socket_type &its_socket = _connection->get_socket(); + if (auto creds = credentials::receive_credentials(its_socket.native_handle())) { + + its_client = std::get<0>(*creds); + its_client_host = std::get<3>(*creds); + + its_sec_client.client.uds_client.user = std::get<1>(*creds); + its_sec_client.client.uds_client.group = std::get<2>(*creds); + } else { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex << its_host->get_client() + << " is rejecting new connection because client credentials couldn't be received!"; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + + if (its_host && configuration_->is_security_enabled()) { + if (!configuration_->check_routing_credentials(its_client, &its_sec_client)) { + VSOMEIP_WARNING << "vSomeIP Security: Rejecting new connection with routing manager client ID 0x" + << std::hex << its_client + << " uid/gid= " << std::dec + << its_sec_client.client.uds_client.user << "/" + << its_sec_client.client.uds_client.group + << " because passed credentials do not match with routing manager credentials!"; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + + if (is_routing_endpoint_) { + // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> check later + _connection->set_bound_sec_client(its_sec_client); + _connection->set_bound_client_host(its_client_host); + } else { + { + std::lock_guard<std::mutex> its_connection_lock(connections_mutex_); + // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> check later + const auto found_client = connections_.find(its_client); + if (found_client != connections_.end()) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex + << its_host->get_client() << " is rejecting new connection with client ID 0x" + << its_client << " uid/gid= " << std::dec + << its_sec_client.client.uds_client.user << "/" + << its_sec_client.client.uds_client.group + << " because of already existing connection using same client ID"; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + } + + // Add to known clients (loads new config if needed) + std::shared_ptr<routing_host> its_routing_host = routing_host_.lock(); + its_routing_host->add_known_client(its_client, its_client_host); + + if (!policy_manager_impl::get()->check_credentials(its_client, &its_sec_client)) { + VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex + << its_host->get_client() << " received client credentials from client 0x" + << its_client << " which violates the security policy : uid/gid=" + << std::dec << its_sec_client.client.uds_client.user << "/" + << its_sec_client.client.uds_client.group; + boost::system::error_code er; + its_socket.shutdown(its_socket.shutdown_both, er); + its_socket.close(er); + return; + } + // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> set later + _connection->set_bound_client(its_client); + _connection->set_bound_client_host(its_client_host); + add_connection(its_client, _connection); + } + } else { + policy_manager_impl::get()->store_client_to_sec_client_mapping(its_client, &its_sec_client); + policy_manager_impl::get()->store_sec_client_to_client_mapping(&its_sec_client, its_client); + + if (!is_routing_endpoint_) { + std::shared_ptr<routing_host> its_routing_host = routing_host_.lock(); + its_routing_host->add_known_client(its_client, its_client_host); + _connection->set_bound_client(its_client); + } + _connection->set_bound_client_host(its_client_host); + } + + _connection->start(); + } +} + +/////////////////////////////////////////////////////////////////////////////// +// class local_service_impl::connection +/////////////////////////////////////////////////////////////////////////////// + +local_uds_server_endpoint_impl::connection::connection( + const std::shared_ptr<local_uds_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _initial_recv_buffer_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io) + : socket_(_io), + server_(_server), + recv_buffer_size_initial_(_initial_recv_buffer_size + 8), + max_message_size_(_max_message_size), + recv_buffer_(recv_buffer_size_initial_, 0), + recv_buffer_size_(0), + missing_capacity_(0), + shrink_count_(0), + buffer_shrink_threshold_(_buffer_shrink_threshold), + bound_client_(VSOMEIP_CLIENT_UNSET), + bound_client_host_(""), + assigned_client_(false) { + if (_server->is_routing_endpoint_ && + !_server->configuration_->is_security_enabled()) { + assigned_client_ = true; + } + + sec_client_.client_type = VSOMEIP_CLIENT_UDS; + sec_client_.client.uds_client.user = ANY_UID; + sec_client_.client.uds_client.group = ANY_GID; +} + +local_uds_server_endpoint_impl::connection::ptr +local_uds_server_endpoint_impl::connection::create( + const std::shared_ptr<local_uds_server_endpoint_impl>& _server, + std::uint32_t _max_message_size, + std::uint32_t _buffer_shrink_threshold, + boost::asio::io_context &_io) { + const std::uint32_t its_initial_buffer_size + = static_cast<std::uint32_t>(protocol::COMMAND_HEADER_SIZE + + sizeof(instance_t) + sizeof(bool) + sizeof(bool)); + return ptr(new connection(_server, _max_message_size, its_initial_buffer_size, + _buffer_shrink_threshold, _io)); +} + +local_uds_server_endpoint_impl::socket_type & +local_uds_server_endpoint_impl::connection::get_socket() { + return socket_; +} + +std::unique_lock<std::mutex> +local_uds_server_endpoint_impl::connection::get_socket_lock() { + return std::unique_lock<std::mutex>(socket_mutex_); +} + +void local_uds_server_endpoint_impl::connection::start() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_.is_open()) { + const std::size_t its_capacity(recv_buffer_.capacity()); + if (recv_buffer_size_ > its_capacity) { + VSOMEIP_ERROR << __func__ << "Received buffer size is greater than the buffer capacity!" + << " recv_buffer_size_: " << recv_buffer_size_ + << " its_capacity: " << its_capacity; + return; + } + size_t left_buffer_size = its_capacity - recv_buffer_size_; + try { + if (missing_capacity_) { + if (missing_capacity_ > MESSAGE_SIZE_UNLIMITED) { + VSOMEIP_ERROR << "Missing receive buffer capacity exceeds allowed maximum!"; + return; + } + const std::size_t its_required_capacity(recv_buffer_size_ + missing_capacity_); + if (its_capacity < its_required_capacity) { + // Make the resize to its_required_capacity + recv_buffer_.reserve(its_required_capacity); + recv_buffer_.resize(its_required_capacity, 0x0); + } + left_buffer_size = missing_capacity_; + missing_capacity_ = 0; + } else if (buffer_shrink_threshold_ + && shrink_count_ > buffer_shrink_threshold_ + && recv_buffer_size_ == 0) { + // In this case, make the resize to recv_buffer_size_initial_ + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + // And set buffer_size to recv_buffer_size_initial_, the same of our resize + left_buffer_size = recv_buffer_size_initial_; + shrink_count_ = 0; + } + } catch (const std::exception &e) { + handle_recv_buffer_exception(e); + // don't start receiving again + return; + } + +#if VSOMEIP_BOOST_VERSION >= 106600 + local_server_endpoint_impl_receive_op its_operation { + socket_, + std::bind( + &local_uds_server_endpoint_impl::connection::receive_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4 + ), + &recv_buffer_[recv_buffer_size_], + left_buffer_size, + std::numeric_limits<uint32_t>::max(), + std::numeric_limits<uint32_t>::max(), + std::numeric_limits<size_t>::min() + }; + socket_.async_wait(socket_type::wait_read, its_operation); +#else + socket_.async_receive( + boost::asio::buffer(&recv_buffer_[recv_buffer_size_], left_buffer_size), + std::bind( + &local_uds_server_endpoint_impl::connection::receive_cbk, + shared_from_this(), + std::placeholders::_1, + std::placeholders::_2, + std::placeholders::_3, + std::placeholders::_4 + ) + ); +#endif + } +} + +void local_uds_server_endpoint_impl::connection::stop() { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + if (socket_.is_open()) { + if (-1 == fcntl(socket_.native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_path_local(); + } + boost::system::error_code its_error; + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); + } +} + +void local_uds_server_endpoint_impl::connection::send_queued( + const message_buffer_ptr_t& _buffer) { + + std::shared_ptr<local_uds_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_TRACE << "local_uds_server_endpoint_impl::connection::send_queued " + " couldn't lock server_"; + return; + } + + static const byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 }; + static const byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 }; + std::vector<boost::asio::const_buffer> bufs; + +#if 0 + std::stringstream msg; + msg << "lse::sq: "; + for (std::size_t i = 0; i < _buffer->size(); i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int)(*_buffer)[i] << " "; + VSOMEIP_INFO << msg.str(); +#endif + + bufs.push_back(boost::asio::buffer(its_start_tag)); + bufs.push_back(boost::asio::buffer(*_buffer)); + bufs.push_back(boost::asio::buffer(its_end_tag)); + + { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + boost::asio::async_write( + socket_, + bufs, + std::bind( + &local_uds_server_endpoint_impl::connection::send_cbk, + shared_from_this(), + _buffer, + std::placeholders::_1, + std::placeholders::_2 + ) + ); + } +} + +client_t local_uds_server_endpoint_impl::assign_client( + const byte_t *_data, uint32_t _size) { + + std::vector<byte_t> its_data(_data, _data + _size); + + protocol::assign_client_command its_command; + protocol::error_e its_error; + + its_command.deserialize(its_data, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + VSOMEIP_ERROR << __func__ + << ": assign client command deserialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + return (VSOMEIP_CLIENT_UNSET); + } + + return (utility::request_client_id(configuration_, + its_command.get_name(), its_command.get_client())); +} + +void local_uds_server_endpoint_impl::get_configured_times_from_endpoint( + service_t _service, + method_t _method, std::chrono::nanoseconds *_debouncing, + std::chrono::nanoseconds *_maximum_retention) const { + (void)_service; + (void)_method; + (void)_debouncing; + (void)_maximum_retention; + VSOMEIP_ERROR << "local_uds_server_endpoint_impl::get_configured_times_from_endpoint."; +} + +void local_uds_server_endpoint_impl::connection::send_cbk(const message_buffer_ptr_t _buffer, + boost::system::error_code const &_error, std::size_t _bytes) { + (void)_buffer; + (void)_bytes; + if (_error) + VSOMEIP_WARNING << "sei::send_cbk received error: " << _error.message(); +} + +void local_uds_server_endpoint_impl::connection::receive_cbk( + boost::system::error_code const &_error, std::size_t _bytes, + std::uint32_t const &_uid, std::uint32_t const &_gid) +{ + std::shared_ptr<local_uds_server_endpoint_impl> its_server(server_.lock()); + if (!its_server) { + VSOMEIP_TRACE << "local_uds_server_endpoint_impl::connection::receive_cbk " + " couldn't lock server_"; + return; + } + std::shared_ptr<routing_host> its_host = its_server->routing_host_.lock(); + if (!its_host) + return; + + std::shared_ptr<vsomeip_v3::configuration> its_config = its_server->configuration_; + if (_error == boost::asio::error::operation_aborted) { + if (its_server->is_routing_endpoint_ && + bound_client_ != VSOMEIP_CLIENT_UNSET && its_config) { + utility::release_client_id(its_config->get_network(), + bound_client_); + set_bound_client(VSOMEIP_CLIENT_UNSET); + } + + // connection was stopped + return; + } + + bool is_error(false); + std::size_t its_start = 0; + std::size_t its_end = 0; + std::size_t its_iteration_gap = 0; + std::uint32_t its_command_size = 0; + + if (!_error && 0 < _bytes) { +#if 0 + std::stringstream msg; + msg << "lse::c<" << this << ">rcb: "; + for (std::size_t i = 0; i < _bytes + recv_buffer_size_; i++) + msg << std::setw(2) << std::setfill('0') << std::hex + << (int) (recv_buffer_[i]) << " "; + VSOMEIP_INFO << msg.str(); +#endif + + if (recv_buffer_size_ + _bytes < recv_buffer_size_) { + VSOMEIP_ERROR << "receive buffer overflow in local server endpoint ~> abort!"; + return; + } + recv_buffer_size_ += _bytes; + + bool message_is_empty(false); + bool found_message(false); + + do { + found_message = false; + message_is_empty = false; + + its_start = 0 + its_iteration_gap; + if (its_start + 3 < its_start) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!"; + return; + } + while (its_start + 3 < recv_buffer_size_ + its_iteration_gap && + (recv_buffer_[its_start] != 0x67 || + recv_buffer_[its_start+1] != 0x37 || + recv_buffer_[its_start+2] != 0x6d || + recv_buffer_[its_start+3] != 0x07)) { + its_start++; + } + + if (its_start + 3 == recv_buffer_size_ + its_iteration_gap) { + message_is_empty = true; + } else { + its_start += 4; + } + + if (!message_is_empty) { + if (its_start + protocol::COMMAND_POSITION_SIZE + 3 < recv_buffer_size_ + its_iteration_gap) { + its_command_size = VSOMEIP_BYTES_TO_LONG( + recv_buffer_[its_start + protocol::COMMAND_POSITION_SIZE+3], + recv_buffer_[its_start + protocol::COMMAND_POSITION_SIZE+2], + recv_buffer_[its_start + protocol::COMMAND_POSITION_SIZE+1], + recv_buffer_[its_start + protocol::COMMAND_POSITION_SIZE]); + + its_end = its_start + protocol::COMMAND_POSITION_SIZE + 3 + its_command_size; + } else { + its_end = its_start; + } + if (its_command_size && max_message_size_ != MESSAGE_SIZE_UNLIMITED + && its_command_size > max_message_size_) { + std::lock_guard<std::mutex> its_lock(socket_mutex_); + VSOMEIP_ERROR << "Received a local message which exceeds " + << "maximum message size (" << std::dec << its_command_size + << ") aborting! local: " << get_path_local() << " remote: " + << get_path_remote(); + recv_buffer_.resize(recv_buffer_size_initial_, 0x0); + recv_buffer_.shrink_to_fit(); + return; + } + if (its_end + 3 < its_end) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!"; + return; + } + while (its_end + 3 < recv_buffer_size_ + its_iteration_gap && + (recv_buffer_[its_end] != 0x07 || + recv_buffer_[its_end+1] != 0x6d || + recv_buffer_[its_end+2] != 0x37 || + recv_buffer_[its_end+3] != 0x67)) { + its_end ++; + } + if (its_end + 4 < its_end) { + VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!"; + return; + } + // check if we received a full message + if (recv_buffer_size_ + its_iteration_gap < its_end + 4 + || recv_buffer_[its_end] != 0x07 + || recv_buffer_[its_end+1] != 0x6d + || recv_buffer_[its_end+2] != 0x37 + || recv_buffer_[its_end+3] != 0x67) { + // command (1 Byte) + version (2 Byte) + client id (2 Byte) + // + command size (4 Byte) + data itself + stop tag (4 byte) + // = 13 Bytes not covered in command size. + // If need to change the recv_buffer_, change the value of missing_capacity_ + // in this if/else, otherwise it is 0 + if (its_start - its_iteration_gap + its_command_size + + protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE > recv_buffer_size_) { + missing_capacity_ = + std::uint32_t(its_start) - std::uint32_t(its_iteration_gap) + + its_command_size + std::uint32_t(protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE) + - std::uint32_t(recv_buffer_size_); + } else if (recv_buffer_size_ < protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE) { + // to little data to read out the command size + // minimal amount of data needed to read out command size = header + tag size + missing_capacity_ = static_cast<std::uint32_t>( + protocol::COMMAND_HEADER_SIZE + protocol::TAG_SIZE - recv_buffer_size_); + } else { + std::stringstream local_msg; + for (std::size_t i = its_iteration_gap; + i < recv_buffer_size_ + its_iteration_gap && + i - its_iteration_gap < 32; i++) { + local_msg << std::setw(2) << std::setfill('0') + << std::hex << (int) recv_buffer_[i] << " "; + } + VSOMEIP_ERROR << "lse::c<" << this + << ">rcb: recv_buffer_size is: " << std::dec + << recv_buffer_size_ << " but couldn't read " + "out command size. recv_buffer_capacity: " + << std::dec << recv_buffer_.capacity() + << " its_iteration_gap: " << std::dec + << its_iteration_gap << " bound client: 0x" + << std::hex << bound_client_ << " buffer: " + << local_msg.str(); + recv_buffer_size_ = 0; + missing_capacity_ = 0; + its_iteration_gap = 0; + message_is_empty = true; + } + } + } + + if (!message_is_empty && + its_end + 3 < recv_buffer_size_ + its_iteration_gap) { + + if (its_server->is_routing_endpoint_ + && recv_buffer_[its_start] == byte_t(protocol::id_e::ASSIGN_CLIENT_ID)) { + client_t its_client = its_server->assign_client( + &recv_buffer_[its_start], uint32_t(its_end - its_start)); + + if (its_config && its_config->is_security_enabled()) { + // Add to known clients (loads new config if needed) + its_host->add_known_client(its_client, get_bound_client_host()); + + if (!its_server->add_connection(its_client, shared_from_this())) { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " is rejecting new connection with client ID 0x" << its_client + << " uid/gid= " << std::dec + << sec_client_.client.uds_client.user << "/" + << sec_client_.client.uds_client.group + << " because of already existing connection using same client ID"; + stop(); + return; + } else if (!policy_manager_impl::get()->check_credentials( + its_client, &sec_client_)) { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " received client credentials from client 0x" << its_client + << " which violates the security policy : uid/gid=" + << std::dec << sec_client_.client.uds_client.user << "/" + << sec_client_.client.uds_client.group; + its_server->remove_connection(its_client); + utility::release_client_id(its_config->get_network(), + its_client); + stop(); + return; + } + else { + set_bound_client(its_client); + } + } else { + set_bound_client(its_client); + its_host->add_known_client(its_client, get_bound_client_host()); + its_server->add_connection(its_client, shared_from_this()); + } + its_server->send_client_identifier(its_client); + assigned_client_ = true; + } else if (!its_server->is_routing_endpoint_ || assigned_client_) { + + vsomeip_sec_client_t its_sec_client; + memset(&its_sec_client, 0, sizeof(its_sec_client)); + its_sec_client.client_type = VSOMEIP_CLIENT_UDS; + its_sec_client.client.uds_client.user = _uid; + its_sec_client.client.uds_client.group = _gid; + + its_host->on_message(&recv_buffer_[its_start], + uint32_t(its_end - its_start), its_server.get(), + false, bound_client_, &its_sec_client); + } else { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " didn't receive VSOMEIP_ASSIGN_CLIENT as first message"; + } + #if 0 + std::stringstream local_msg; + local_msg << "lse::c<" << this << ">rcb::thunk: "; + for (std::size_t i = its_start; i < its_end; i++) + local_msg << std::setw(2) << std::setfill('0') << std::hex + << (int) recv_buffer_[i] << " "; + VSOMEIP_INFO << local_msg.str(); + #endif + calculate_shrink_count(); + recv_buffer_size_ -= (its_end + 4 - its_iteration_gap); + missing_capacity_ = 0; + its_command_size = 0; + found_message = true; + its_iteration_gap = its_end + 4; + } else { + if (its_iteration_gap) { + // Message not complete and not in front of the buffer! + // Copy last part to front for consume in future receive_cbk call! + for (size_t i = 0; i < recv_buffer_size_; ++i) { + recv_buffer_[i] = recv_buffer_[i + its_iteration_gap]; + } + // Still more capacity needed after shifting everything to front? + if (missing_capacity_ && + missing_capacity_ <= recv_buffer_.capacity() - recv_buffer_size_) { + missing_capacity_ = 0; + } + } else if (message_is_empty) { + VSOMEIP_ERROR << "Received garbage data."; + is_error = true; + } + } + } while (recv_buffer_size_ > 0 && found_message); + } + + if (_error == boost::asio::error::eof + || _error == boost::asio::error::connection_reset + || is_error) { + stop(); + its_server->remove_connection(bound_client_); + policy_manager_impl::get()->remove_client_to_sec_client_mapping(bound_client_); + } else if (_error != boost::asio::error::bad_descriptor) { + start(); + } +} + +void local_uds_server_endpoint_impl::connection::set_bound_client(client_t _client) { + bound_client_ = _client; +} + +client_t local_uds_server_endpoint_impl::connection::get_bound_client() const { + return bound_client_; +} + +void local_uds_server_endpoint_impl::connection::set_bound_client_host( + const std::string &_bound_client_host) { + + bound_client_host_ = _bound_client_host; +} + +std::string local_uds_server_endpoint_impl::connection::get_bound_client_host() const { + return bound_client_host_; +} + + +void local_uds_server_endpoint_impl::connection::set_bound_sec_client( + const vsomeip_sec_client_t &_sec_client) { + + sec_client_ = _sec_client; +} + +void local_uds_server_endpoint_impl::connection::calculate_shrink_count() { + if (buffer_shrink_threshold_) { + if (recv_buffer_.capacity() != recv_buffer_size_initial_) { + if (recv_buffer_size_ < (recv_buffer_.capacity() >> 1)) { + shrink_count_++; + } else { + shrink_count_ = 0; + } + } + } +} + +std::string local_uds_server_endpoint_impl::connection::get_path_local() const { + boost::system::error_code ec; + std::string its_local_path; + if (socket_.is_open()) { + endpoint_type its_local_endpoint = socket_.local_endpoint(ec); + if (!ec) { + its_local_path += its_local_endpoint.path(); + } + } + return its_local_path; +} + +std::string local_uds_server_endpoint_impl::connection::get_path_remote() const { + boost::system::error_code ec; + std::string its_remote_path; + if (socket_.is_open()) { + endpoint_type its_remote_endpoint = socket_.remote_endpoint(ec); + if (!ec) { + its_remote_path += its_remote_endpoint.path(); + } + } + return its_remote_path; +} + +void local_uds_server_endpoint_impl::connection::handle_recv_buffer_exception( + const std::exception &_e) { + std::stringstream its_message; + its_message <<"local_uds_server_endpoint_impl::connection catched exception" + << _e.what() << " local: " << get_path_local() << " remote: " + << get_path_remote() << " shutting down connection. Start of buffer: "; + + for (std::size_t i = 0; i < recv_buffer_size_ && i < 16; i++) { + its_message << std::setw(2) << std::setfill('0') << std::hex + << (int) (recv_buffer_[i]) << " "; + } + + its_message << " Last 16 Bytes captured: "; + for (int i = 15; recv_buffer_size_ > 15u && i >= 0; i--) { + its_message << std::setw(2) << std::setfill('0') << std::hex + << (int) (recv_buffer_[static_cast<size_t>(i)]) << " "; + } + VSOMEIP_ERROR << its_message.str(); + recv_buffer_.clear(); + if (socket_.is_open()) { + if (-1 == fcntl(socket_.native_handle(), F_GETFD)) { + VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno)) + << "' (" << errno << ") " << get_path_local(); + } + boost::system::error_code its_error; + socket_.shutdown(socket_.shutdown_both, its_error); + socket_.close(its_error); + } + std::shared_ptr<local_uds_server_endpoint_impl> its_server = server_.lock(); + if (its_server) { + its_server->remove_connection(bound_client_); + } +} + +std::size_t +local_uds_server_endpoint_impl::connection::get_recv_buffer_capacity() const { + return recv_buffer_.capacity(); +} + +void local_uds_server_endpoint_impl::print_status() { + std::lock_guard<std::mutex> its_lock(mutex_); + connections_t its_connections; + { + std::lock_guard<std::mutex> its_lock(connections_mutex_); + its_connections = connections_; + } + + std::string its_local_path(local_.path()); + + VSOMEIP_INFO << "status lse: " << its_local_path << " connections: " + << std::dec << its_connections.size() << " targets: " + << std::dec << targets_.size(); + for (const auto &c : its_connections) { + std::string its_remote_path; // TODO: construct the path + + std::size_t its_recv_size(0); + { + std::unique_lock<std::mutex> c_s_lock(c.second->get_socket_lock()); + its_recv_size = c.second->get_recv_buffer_capacity(); + } + + VSOMEIP_INFO << "status lse: client: " << its_remote_path + << " recv_buffer: " << std::dec << its_recv_size; + } +} +std::string local_uds_server_endpoint_impl::get_remote_information( + const target_data_iterator_type _it) const { + + (void)_it; + return "local"; +} + +std::string local_uds_server_endpoint_impl::get_remote_information( + const endpoint_type& _remote) const { + + (void)_remote; + return "local"; +} + +bool local_uds_server_endpoint_impl::is_reliable() const { + return false; +} + +std::uint16_t local_uds_server_endpoint_impl::get_local_port() const { + + return 0; +} + +void local_uds_server_endpoint_impl::set_local_port(std::uint16_t _port) { + + (void)_port; + // Intentionally left empty +} + +bool local_uds_server_endpoint_impl::check_packetizer_space( + target_data_iterator_type _it, message_buffer_ptr_t* _packetizer, + std::uint32_t _size) { + + if ((*_packetizer)->size() + _size < (*_packetizer)->size()) { + VSOMEIP_ERROR << "Overflow in packetizer addition ~> abort sending!"; + return false; + } + if ((*_packetizer)->size() + _size > max_message_size_ + && !(*_packetizer)->empty()) { + _it->second.queue_.push_back(std::make_pair(*_packetizer, 0)); + _it->second.queue_size_ += (*_packetizer)->size(); + *_packetizer = std::make_shared<message_buffer_t>(); + } + return true; +} + +void +local_uds_server_endpoint_impl::send_client_identifier( + const client_t &_client) { + + protocol::assign_client_ack_command its_command; + its_command.set_client(VSOMEIP_ROUTING_CLIENT); + its_command.set_assigned(_client); + + std::vector<byte_t> its_buffer; + protocol::error_e its_error; + its_command.serialize(its_buffer, its_error); + if (its_error != protocol::error_e::ERROR_OK) { + + VSOMEIP_ERROR << __func__ + << ": assign client ack command serialization failed (" + << std::dec << static_cast<int>(its_error) << ")"; + return; + } + + send(&its_buffer[0], static_cast<uint32_t>(its_buffer.size())); +} + +bool local_uds_server_endpoint_impl::tp_segmentation_enabled( + service_t _service, method_t _method) const { + + (void)_service; + (void)_method; + return false; +} + +} // namespace vsomeip_v3 |