summaryrefslogtreecommitdiff
path: root/implementation/endpoints/src
diff options
context:
space:
mode:
Diffstat (limited to 'implementation/endpoints/src')
-rw-r--r--implementation/endpoints/src/client_endpoint_impl.cpp24
-rw-r--r--implementation/endpoints/src/credentials.cpp109
-rw-r--r--implementation/endpoints/src/local_client_endpoint_impl.cpp54
-rw-r--r--implementation/endpoints/src/local_server_endpoint_impl.cpp82
-rw-r--r--implementation/endpoints/src/tcp_client_endpoint_impl.cpp4
-rw-r--r--implementation/endpoints/src/tcp_server_endpoint_impl.cpp9
-rw-r--r--implementation/endpoints/src/udp_server_endpoint_impl.cpp42
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) {