summaryrefslogtreecommitdiff
path: root/implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp
diff options
context:
space:
mode:
Diffstat (limited to 'implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp')
-rw-r--r--implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp118
1 files changed, 118 insertions, 0 deletions
diff --git a/implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp b/implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp
new file mode 100644
index 0000000..38e1662
--- /dev/null
+++ b/implementation/endpoints/include/local_server_endpoint_impl_receive_op.hpp
@@ -0,0 +1,118 @@
+// Copyright (C) 2020-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/.
+
+#ifndef VSOMEIP_V3_LOCAL_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_
+#define VSOMEIP_V3_LOCAL_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_
+
+#if VSOMEIP_BOOST_VERSION >= 106600
+#if defined(__linux__) || defined(ANDROID)
+
+#include <boost/asio/local/stream_protocol.hpp>
+
+namespace vsomeip_v3 {
+
+using socket_type_t = boost::asio::local::stream_protocol::socket;
+using receive_handler_t = std::function<
+ void (boost::system::error_code const &_error, size_t _size,
+ const std::uint32_t &, const std::uint32_t &)>;
+
+struct local_server_endpoint_impl_receive_op {
+
+ socket_type_t &socket_;
+ receive_handler_t handler_;
+ byte_t *buffer_;
+ size_t length_;
+ uid_t uid_;
+ gid_t gid_;
+ size_t bytes_;
+
+ void operator()(boost::system::error_code _error) {
+
+ if (!_error) {
+ if (!socket_.native_non_blocking())
+ socket_.native_non_blocking(true, _error);
+
+ for (;;) {
+ ssize_t its_result;
+ int its_flags(0);
+
+ // Set buffer
+ struct iovec its_vec[1];
+ its_vec[0].iov_base = buffer_;
+ its_vec[0].iov_len = length_;
+
+ union {
+ struct cmsghdr cmh;
+ char control[CMSG_SPACE(sizeof(struct ucred))];
+ } control_un;
+
+ // 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;
+
+ // Build header with all informations to call ::recvmsg
+ msghdr its_header = msghdr();
+ its_header.msg_iov = its_vec;
+ its_header.msg_iovlen = 1;
+ its_header.msg_control = control_un.control;
+ its_header.msg_controllen = sizeof(control_un.control);
+
+ // Call recvmsg and handle its result
+ errno = 0;
+ its_result = ::recvmsg(socket_.native_handle(), &its_header, its_flags);
+ _error = boost::system::error_code(its_result < 0 ? errno : 0,
+ boost::asio::error::get_system_category());
+ bytes_ += _error ? 0 : static_cast<size_t>(its_result);
+
+ if (_error == boost::asio::error::interrupted)
+ continue;
+
+ if (_error == boost::asio::error::would_block
+ || _error == boost::asio::error::try_again) {
+ socket_.async_wait(socket_type_t::wait_read, *this);
+ return;
+ }
+
+ if (_error)
+ break;
+
+ if (bytes_ == 0)
+ _error = boost::asio::error::eof;
+
+ // Extract credentials (UID/GID)
+ struct ucred *its_credentials;
+ for (struct cmsghdr *cmsg = CMSG_FIRSTHDR(&its_header);
+ cmsg != NULL;
+ cmsg = CMSG_NXTHDR(&its_header, cmsg))
+ {
+ if (cmsg->cmsg_level == SOL_SOCKET
+ && cmsg->cmsg_type == SCM_CREDENTIALS
+ && cmsg->cmsg_len == CMSG_LEN(sizeof(struct ucred))) {
+
+ its_credentials = (struct ucred *) CMSG_DATA(cmsg);
+ if (its_credentials) {
+ uid_ = its_credentials->uid;
+ gid_ = its_credentials->gid;
+ break;
+ }
+ }
+ }
+
+ break;
+ }
+ }
+
+ // Call the handler
+ handler_(_error, bytes_, uid_, gid_);
+ }
+};
+
+} // namespace vsomeip
+
+#endif // __linux__ || ANDROID
+#endif // VSOMEIP_BOOST_VERSION >= 106600
+
+#endif // VSOMEIP_V3_LOCAL_SERVER_ENDPOINT_IMPL_RECEIVE_OP_HPP_