diff options
Diffstat (limited to 'implementation/endpoints/src')
7 files changed, 264 insertions, 60 deletions
diff --git a/implementation/endpoints/src/client_endpoint_impl.cpp b/implementation/endpoints/src/client_endpoint_impl.cpp index 3d2a752..9a33aad 100644 --- a/implementation/endpoints/src/client_endpoint_impl.cpp +++ b/implementation/endpoints/src/client_endpoint_impl.cpp @@ -73,9 +73,11 @@ void client_endpoint_impl<Protocol>::stop() { times_slept++;
}
}
-
- if (socket_.is_open()) {
- socket_.cancel();
+ {
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ if (socket_.is_open()) {
+ socket_.cancel();
+ }
}
}
}
@@ -86,6 +88,7 @@ void client_endpoint_impl<Protocol>::restart() { std::lock_guard<std::mutex> its_lock(mutex_);
queue_.clear();
}
+ shutdown_and_close_socket();
is_connected_ = false;
connect_timer_.expires_from_now(
std::chrono::milliseconds(connect_timeout_));
@@ -141,10 +144,12 @@ bool client_endpoint_impl<Protocol>::send(const uint8_t *_data, flush_timer_.expires_from_now(
std::chrono::milliseconds(VSOMEIP_DEFAULT_FLUSH_TIMEOUT)); // TODO: use config variable
flush_timer_.async_wait(
- std::bind(
- &client_endpoint_impl<Protocol>::flush_cbk,
- this->shared_from_this(),
- std::placeholders::_1));
+ std::bind(
+ &client_endpoint_impl<Protocol>::flush_cbk,
+ this->shared_from_this(),
+ std::placeholders::_1
+ )
+ );
}
if (queue_size_zero_on_entry && !queue_.empty()) { // no writing in progress
@@ -251,9 +256,7 @@ void client_endpoint_impl<Protocol>::send_cbk( }
}
if (socket_.is_open()) {
- boost::system::error_code its_error;
- socket_.shutdown(Protocol::socket::shutdown_both, its_error);
- socket_.close(its_error);
+ shutdown_and_close_socket();
}
connect();
} else if (_error == boost::asio::error::not_connected
@@ -283,6 +286,7 @@ void client_endpoint_impl<Protocol>::register_error_callback( template<typename Protocol>
void client_endpoint_impl<Protocol>::shutdown_and_close_socket() {
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
if (socket_.is_open()) {
boost::system::error_code its_error;
socket_.shutdown(Protocol::socket::shutdown_both, its_error);
diff --git a/implementation/endpoints/src/credentials.cpp b/implementation/endpoints/src/credentials.cpp new file mode 100644 index 0000000..b718bd4 --- /dev/null +++ b/implementation/endpoints/src/credentials.cpp @@ -0,0 +1,109 @@ +// Copyright (C) 2014-2016 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/. + +#ifndef WIN32 + +#include <sys/socket.h> + +#include "../include/credentials.hpp" + +#include "../../configuration/include/internal.hpp" +#include "../../logging/include/logger.hpp" + +namespace vsomeip { + +void credentials::activate_credentials(const int _fd) { + int optval = 1; + if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) { + VSOMEIP_ERROR << "Activating socket option for receiving credentials failed."; + } +} + +void credentials::deactivate_credentials(const int _fd) { + int optval = 0; + if (setsockopt(_fd, SOL_SOCKET, SO_PASSCRED, &optval, sizeof(optval)) == -1) { + VSOMEIP_ERROR << "Deactivating socket option for receiving credentials failed."; + } +} + +client_t credentials::receive_credentials(const int _fd, uid_t& _uid, gid_t& _gid) { + struct ucred *ucredp; + struct msghdr msgh; + struct iovec iov; + union { + struct cmsghdr cmh; + char control[CMSG_SPACE(sizeof(struct ucred))]; + } control_un; + struct cmsghdr *cmhp; + // Sender client_id will be received as data + client_t client = VSOMEIP_ROUTING_CLIENT; + + // Set 'control_un' to describe ancillary data that we want to receive + control_un.cmh.cmsg_len = CMSG_LEN(sizeof(struct ucred)); + control_un.cmh.cmsg_level = SOL_SOCKET; + control_un.cmh.cmsg_type = SCM_CREDENTIALS; + + // Set 'msgh' fields to describe 'control_un' + msgh.msg_control = control_un.control; + msgh.msg_controllen = sizeof(control_un.control); + + // Set fields of 'msgh' to point to buffer used to receive (real) data read by recvmsg() + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + iov.iov_base = &client; + iov.iov_len = sizeof(client_t); + + // We don't need address of peer as we using connect + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + // Receive client_id plus ancillary data + ssize_t nr = recvmsg(_fd, &msgh, 0); + if (nr == -1) { + VSOMEIP_ERROR << "Receiving credentials failed. No data."; + } + + cmhp = CMSG_FIRSTHDR(&msgh); + if (cmhp == NULL || cmhp->cmsg_len != CMSG_LEN(sizeof(struct ucred)) + || cmhp->cmsg_level != SOL_SOCKET || cmhp->cmsg_type != SCM_CREDENTIALS) { + VSOMEIP_ERROR << "Receiving credentials failed. Invalid data."; + } else { + ucredp = (struct ucred *) CMSG_DATA(cmhp); + _uid = ucredp->uid; + _gid = ucredp->gid; + } + + return client; +} + +void credentials::send_credentials(const int _fd, client_t _client) { + struct msghdr msgh; + struct iovec iov; + + // data to send + msgh.msg_iov = &iov; + msgh.msg_iovlen = 1; + iov.iov_base = &_client; + iov.iov_len = sizeof(client_t); + + // destination not needed as we use connect + msgh.msg_name = NULL; + msgh.msg_namelen = 0; + + // credentials not need to set explicitly + msgh.msg_control = NULL; + msgh.msg_controllen = 0; + + // send client id with credentials + ssize_t ns = sendmsg(_fd, &msgh, 0); + if (ns == -1) { + VSOMEIP_ERROR << "Sending credentials failed."; + } +} + +} // namespace vsomeip + +#endif + diff --git a/implementation/endpoints/src/local_client_endpoint_impl.cpp b/implementation/endpoints/src/local_client_endpoint_impl.cpp index 7e633e0..1a13e91 100644 --- a/implementation/endpoints/src/local_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_client_endpoint_impl.cpp @@ -13,6 +13,13 @@ #include "../include/endpoint_host.hpp"
#include "../include/local_client_endpoint_impl.hpp"
#include "../../logging/include/logger.hpp"
+#include "../include/local_server_endpoint_impl.hpp"
+#include "../../configuration/include/configuration.hpp"
+
+// Credentials
+#ifndef WIN32
+#include "../include/credentials.hpp"
+#endif
namespace vsomeip {
@@ -21,9 +28,10 @@ local_client_endpoint_impl::local_client_endpoint_impl( endpoint_type _remote,
boost::asio::io_service &_io,
std::uint32_t _max_message_size)
- : local_client_endpoint_base_impl(_host, _remote, _remote, _io, _max_message_size) {
- // Using _remote for the local(!) endpoint is ok,
- // because we have no bind for local endpoints!
+ : local_client_endpoint_base_impl(_host, _remote, _remote, _io, _max_message_size),
+ // Using _remote for the local(!) endpoint is ok,
+ // because we have no bind for local endpoints!
+ recv_buffer_(1,0) {
is_supporting_magic_cookies_ = false;
}
@@ -38,10 +46,13 @@ bool local_client_endpoint_impl::is_local() const { void local_client_endpoint_impl::start() {
if (socket_.is_open()) {
sending_blocked_ = false;
- boost::system::error_code its_error;
- socket_.cancel(its_error);
- socket_.shutdown(socket_type::shutdown_both, its_error);
- socket_.close(its_error);
+ {
+ std::lock_guard<std::mutex> its_lock(stop_mutex_);
+ boost::system::error_code its_error;
+ socket_.cancel(its_error);
+ socket_.shutdown(socket_type::shutdown_both, its_error);
+ socket_.close(its_error);
+ }
restart();
} else {
connect();
@@ -53,9 +64,23 @@ void local_client_endpoint_impl::connect() { socket_.open(remote_.protocol(), its_error);
if (!its_error || its_error == boost::asio::error::already_open) {
- socket_.set_option(boost::asio::socket_base::reuse_address(true));
boost::system::error_code error;
+ socket_.set_option(boost::asio::socket_base::reuse_address(true), error);
error = socket_.connect(remote_, error);
+
+// Credentials
+#ifndef WIN32
+ if (!error) {
+ auto its_host = host_.lock();
+ if (its_host) {
+ if (its_host->get_configuration()->is_security_enabled()) {
+ credentials::send_credentials(socket_.native(),
+ its_host->get_client());
+ }
+ }
+ }
+#endif
+
connect_cbk(error);
} else {
VSOMEIP_WARNING << "local_client_endpoint::connect: Error opening socket: "
@@ -65,9 +90,8 @@ void local_client_endpoint_impl::connect() { void local_client_endpoint_impl::receive() {
#ifndef WIN32
- receive_buffer_t its_buffer(VSOMEIP_MAX_LOCAL_MESSAGE_SIZE , 0);
socket_.async_receive(
- boost::asio::buffer(its_buffer),
+ boost::asio::buffer(recv_buffer_),
std::bind(
&local_client_endpoint_impl::receive_cbk,
std::dynamic_pointer_cast<
@@ -129,11 +153,15 @@ void local_client_endpoint_impl::receive_cbk( // endpoint was stopped
shutdown_and_close_socket();
} else if (_error == boost::asio::error::connection_reset
- || _error == boost::asio::error::eof) {
- VSOMEIP_TRACE << "local_client_endpoint: connection_reseted/EOF";
- } else {
+ || _error == boost::asio::error::eof
+ || _error != boost::asio::error::bad_descriptor) {
+ VSOMEIP_TRACE << "local_client_endpoint:"
+ " connection_reseted/EOF/bad_descriptor";
+ } else if (_error) {
VSOMEIP_ERROR << "Local endpoint received message ("
<< _error.message() << ")";
+ } else {
+ receive();
}
}
diff --git a/implementation/endpoints/src/local_server_endpoint_impl.cpp b/implementation/endpoints/src/local_server_endpoint_impl.cpp index 42ffc2b..851185a 100644 --- a/implementation/endpoints/src/local_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/local_server_endpoint_impl.cpp @@ -7,12 +7,19 @@ #include <iomanip> #include <sstream> +#include <sys/types.h> #include <boost/asio/write.hpp> #include "../include/endpoint_host.hpp" #include "../include/local_server_endpoint_impl.hpp" #include "../../logging/include/logger.hpp" +#include "../../configuration/include/configuration.hpp" + +// Credentials +#ifndef WIN32 +#include "../include/credentials.hpp" +#endif namespace vsomeip { @@ -33,6 +40,32 @@ local_server_endpoint_impl::local_server_endpoint_impl( boost::asio::detail::throw_error(ec, "acceptor bind"); acceptor_.listen(boost::asio::socket_base::max_connections, ec); boost::asio::detail::throw_error(ec, "acceptor listen"); + +#ifndef WIN32 + if (_host->get_configuration()->is_security_enabled()) { + credentials::activate_credentials(acceptor_.native()); + } +#endif +} + +local_server_endpoint_impl::local_server_endpoint_impl( + std::shared_ptr< endpoint_host > _host, + endpoint_type _local, boost::asio::io_service &_io, + std::uint32_t _max_message_size, + int native_socket) + : local_server_endpoint_base_impl(_host, _local, _io, _max_message_size), + acceptor_(_io), current_(nullptr) { + is_supporting_magic_cookies_ = false; + + boost::system::error_code ec; + acceptor_.assign(_local.protocol(), native_socket, ec); + boost::asio::detail::throw_error(ec, "acceptor assign native socket"); + +#ifndef WIN32 + if (_host->get_configuration()->is_security_enabled()) { + credentials::activate_credentials(acceptor_.native()); + } +#endif } local_server_endpoint_impl::~local_server_endpoint_impl() { @@ -106,12 +139,6 @@ void local_server_endpoint_impl::restart() { current_->start(); } -local_server_endpoint_impl::endpoint_type -local_server_endpoint_impl::get_remote() const { - boost::system::error_code its_error; - return current_->get_socket().remote_endpoint(its_error); -} - bool local_server_endpoint_impl::get_default_target( service_t, local_server_endpoint_impl::endpoint_type &) const { @@ -134,21 +161,43 @@ void local_server_endpoint_impl::remove_connection( void local_server_endpoint_impl::accept_cbk( connection::ptr _connection, boost::system::error_code const &_error) { + if (_error != boost::asio::error::bad_descriptor && + _error != boost::asio::error::operation_aborted) { + start(); + } + if (!_error) { socket_type &new_connection_socket = _connection->get_socket(); +#ifndef WIN32 + auto its_host = host_.lock(); + if (its_host) { + if (its_host->get_configuration()->is_security_enabled()) { + uid_t uid; + gid_t gid; + client_t client = credentials::receive_credentials( + new_connection_socket.native(), uid, gid); + if (!its_host->check_credentials(client, uid, gid)) { + VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client() + << " received client credentials from client 0x" << client + << " which violates the security policy : uid/gid=" + << std::dec << uid << "/" << gid; + boost::system::error_code er; + new_connection_socket.close(er); + return; + } + _connection->set_bound_client(client); + credentials::deactivate_credentials(new_connection_socket.native()); + } + } +#endif boost::system::error_code its_error; endpoint_type remote = new_connection_socket.remote_endpoint(its_error); - if(!its_error) { + if (!its_error) { std::lock_guard<std::mutex> its_lock(connections_mutex_); connections_[remote] = _connection; _connection->start(); } } - - if (_error != boost::asio::error::bad_descriptor && - _error != boost::asio::error::operation_aborted) { - start(); - } } /////////////////////////////////////////////////////////////////////////////// @@ -162,7 +211,7 @@ local_server_endpoint_impl::connection::connection( server_(_server), max_message_size_(_max_message_size + 8), recv_buffer_(max_message_size_, 0), - recv_buffer_size_(0) { + recv_buffer_size_(0), bound_client_(VSOMEIP_ROUTING_CLIENT) { } local_server_endpoint_impl::connection::ptr @@ -303,7 +352,8 @@ void local_server_endpoint_impl::connection::receive_cbk( if (its_start != MESSAGE_IS_EMPTY && its_end + 3 < recv_buffer_size_ + its_iteration_gap) { its_host->on_message(&recv_buffer_[its_start], - uint32_t(its_end - its_start), its_server.get()); + uint32_t(its_end - its_start), its_server.get(), + boost::asio::ip::address(), bound_client_); #if 0 std::stringstream local_msg; @@ -342,4 +392,8 @@ void local_server_endpoint_impl::connection::receive_cbk( } } +void local_server_endpoint_impl::connection::set_bound_client(client_t _client) { + bound_client_ = _client; +} + } // namespace vsomeip diff --git a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp index 97e5579..5165e4b 100644 --- a/implementation/endpoints/src/tcp_client_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_client_endpoint_impl.cpp @@ -52,12 +52,12 @@ void tcp_client_endpoint_impl::connect() { if (!its_error || its_error == boost::asio::error::already_open) {
// Nagle algorithm off
- socket_.set_option(ip::tcp::no_delay(true));
+ socket_.set_option(ip::tcp::no_delay(true), its_error);
// Enable SO_REUSEADDR to avoid bind problems with services going offline
// and coming online again and the user has specified only a small number
// of ports in the clients section for one service instance
- socket_.set_option(boost::asio::socket_base::reuse_address(true));
+ socket_.set_option(boost::asio::socket_base::reuse_address(true), its_error);
// In case a client endpoint port was configured,
// bind to it before connecting
diff --git a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp index f3035ef..8e98fd0 100644 --- a/implementation/endpoints/src/tcp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/tcp_server_endpoint_impl.cpp @@ -121,12 +121,6 @@ bool tcp_server_endpoint_impl::is_established(std::shared_ptr<endpoint_definitio return is_connected; } -tcp_server_endpoint_impl::endpoint_type -tcp_server_endpoint_impl::get_remote() const { - boost::system::error_code its_error; - return current_->get_socket().remote_endpoint(its_error); -} - bool tcp_server_endpoint_impl::get_remote_address( boost::asio::ip::address &_address) const { @@ -232,7 +226,8 @@ tcp_server_endpoint_impl::connection::get_socket() { void tcp_server_endpoint_impl::connection::start() { receive(); // Nagle algorithm off - socket_.set_option(ip::tcp::no_delay(true)); + boost::system::error_code ec; + socket_.set_option(ip::tcp::no_delay(true), ec); } void tcp_server_endpoint_impl::connection::receive() { diff --git a/implementation/endpoints/src/udp_server_endpoint_impl.cpp b/implementation/endpoints/src/udp_server_endpoint_impl.cpp index f1cd692..1585826 100644 --- a/implementation/endpoints/src/udp_server_endpoint_impl.cpp +++ b/implementation/endpoints/src/udp_server_endpoint_impl.cpp @@ -32,26 +32,30 @@ udp_server_endpoint_impl::udp_server_endpoint_impl( boost::system::error_code ec; boost::asio::socket_base::reuse_address optionReuseAddress(true); - socket_.set_option(optionReuseAddress); + socket_.set_option(optionReuseAddress, ec); + boost::asio::detail::throw_error(ec, "reuse address"); + + socket_.bind(_local, ec); + boost::asio::detail::throw_error(ec, "bind"); if (_local.address().is_v4()) { boost::asio::ip::address_v4 its_unicast_address - = configuration::get()->get_unicast_address().to_v4(); + = _host->get_configuration()->get_unicast_address().to_v4(); boost::asio::ip::multicast::outbound_interface option(its_unicast_address); - socket_.set_option(option); + socket_.set_option(option, ec); + boost::asio::detail::throw_error(ec, "outbound interface option IPv4"); } else if (_local.address().is_v6()) { boost::asio::ip::address_v6 its_unicast_address - = configuration::get()->get_unicast_address().to_v6(); + = _host->get_configuration()->get_unicast_address().to_v6(); boost::asio::ip::multicast::outbound_interface option( static_cast<unsigned int>(its_unicast_address.scope_id())); - socket_.set_option(option); + socket_.set_option(option, ec); + boost::asio::detail::throw_error(ec, "outbound interface option IPv6"); } - socket_.bind(_local, ec); - boost::asio::detail::throw_error(ec, "bind"); - boost::asio::socket_base::broadcast option(true); - socket_.set_option(option); + socket_.set_option(option, ec); + boost::asio::detail::throw_error(ec, "broadcast option"); #ifdef WIN32 const char* optval("0001"); @@ -140,11 +144,6 @@ void udp_server_endpoint_impl::send_queued( ); } -udp_server_endpoint_impl::endpoint_type -udp_server_endpoint_impl::get_remote() const { - return remote_; -} - bool udp_server_endpoint_impl::get_remote_address( boost::asio::ip::address &_address) const { boost::asio::ip::address its_address = remote_.address(); @@ -171,16 +170,31 @@ void udp_server_endpoint_impl::join(const std::string &_address) { socket_.set_option(ip::udp_ext::socket::reuse_address(true)); socket_.set_option( boost::asio::ip::multicast::enable_loopback(false)); +#ifdef WIN32 + socket_.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string(_address).to_v4(), + local_.address().to_v4())); +#else socket_.set_option(boost::asio::ip::multicast::join_group( boost::asio::ip::address::from_string(_address).to_v4())); +#endif } else if (local_.address().is_v6()) { socket_.set_option(ip::udp_ext::socket::reuse_address(true)); socket_.set_option( boost::asio::ip::multicast::enable_loopback(false)); +#ifdef WIN32 + socket_.set_option(boost::asio::ip::multicast::join_group( + boost::asio::ip::address::from_string(_address).to_v6(), + local_.address().to_v6().scope_id())); +#else socket_.set_option(boost::asio::ip::multicast::join_group( boost::asio::ip::address::from_string(_address).to_v6())); +#endif } joined_.insert(_address); + } else { + VSOMEIP_DEBUG << "udp_server_endpoint_impl::join: " + "Trying to join already joined address: " << _address; } } catch (const std::exception &e) { |