1 // Copyright (C) 2014-2017 Bayerische Motoren Werke Aktiengesellschaft (BMW AG)
2 // This Source Code Form is subject to the terms of the Mozilla Public
3 // License, v. 2.0. If a copy of the MPL was not distributed with this
4 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
5 
6 #include <deque>
7 #include <iomanip>
8 #include <sstream>
9 
10 #include <sys/types.h>
11 #include <boost/asio/write.hpp>
12 
13 #include <vsomeip/internal/logger.hpp>
14 
15 #include "../include/endpoint_host.hpp"
16 #include "../../routing/include/routing_host.hpp"
17 #include "../include/local_server_endpoint_impl.hpp"
18 #include "../../security/include/security.hpp"
19 #include "../../utility/include/byteorder.hpp"
20 #include "../../configuration/include/configuration.hpp"
21 #include "../../utility/include/utility.hpp"
22 
23 // Credentials
24 #ifndef _WIN32
25 #include "../include/credentials.hpp"
26 #endif
27 
28 namespace vsomeip_v3 {
29 
local_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_service & _io,const std::shared_ptr<configuration> & _configuration,bool _is_routing_endpoint)30 local_server_endpoint_impl::local_server_endpoint_impl(
31         const std::shared_ptr<endpoint_host>& _endpoint_host,
32         const std::shared_ptr<routing_host>& _routing_host,
33         const endpoint_type& _local, boost::asio::io_service &_io,
34         const std::shared_ptr<configuration>& _configuration,
35         bool _is_routing_endpoint)
36     : local_server_endpoint_base_impl(_endpoint_host, _routing_host, _local,
37                                       _io,
38                                       _configuration->get_max_message_size_local(),
39                                       _configuration->get_endpoint_queue_limit_local(),
40                                       _configuration),
41       acceptor_(_io),
42       buffer_shrink_threshold_(_configuration->get_buffer_shrink_threshold()),
43       is_routing_endpoint_(_is_routing_endpoint) {
44     is_supporting_magic_cookies_ = false;
45 
46     boost::system::error_code ec;
47     acceptor_.open(_local.protocol(), ec);
48     boost::asio::detail::throw_error(ec, "acceptor open");
49     acceptor_.set_option(boost::asio::socket_base::reuse_address(true), ec);
50     boost::asio::detail::throw_error(ec, "acceptor set_option");
51     acceptor_.bind(_local, ec);
52     boost::asio::detail::throw_error(ec, "acceptor bind");
53     acceptor_.listen(boost::asio::socket_base::max_connections, ec);
54     boost::asio::detail::throw_error(ec, "acceptor listen");
55 
56 #ifndef _WIN32
57     if (chmod(_local.path().c_str(),
58             static_cast<mode_t>(_configuration->get_permissions_uds())) == -1) {
59         VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno);
60     }
61     credentials::activate_credentials(acceptor_.native_handle());
62 #endif
63 }
64 
local_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_service & _io,int native_socket,const std::shared_ptr<configuration> & _configuration,bool _is_routing_endpoint)65 local_server_endpoint_impl::local_server_endpoint_impl(
66         const std::shared_ptr<endpoint_host>& _endpoint_host,
67         const std::shared_ptr<routing_host>& _routing_host,
68         const endpoint_type& _local, boost::asio::io_service &_io,
69         int native_socket,
70         const std::shared_ptr<configuration>& _configuration,
71         bool _is_routing_endpoint)
72     : local_server_endpoint_base_impl(_endpoint_host, _routing_host, _local, _io,
73                                       _configuration->get_max_message_size_local(),
74                                       _configuration->get_endpoint_queue_limit_local(),
75                                       _configuration),
76       acceptor_(_io),
77       buffer_shrink_threshold_(configuration_->get_buffer_shrink_threshold()),
78       is_routing_endpoint_(_is_routing_endpoint) {
79     is_supporting_magic_cookies_ = false;
80 
81    boost::system::error_code ec;
82    acceptor_.assign(_local.protocol(), native_socket, ec);
83    boost::asio::detail::throw_error(ec, "acceptor assign native socket");
84 
85 #ifndef _WIN32
86     if (chmod(_local.path().c_str(),
87             static_cast<mode_t>(_configuration->get_permissions_uds())) == -1) {
88        VSOMEIP_ERROR << __func__ << ": chmod: " << strerror(errno);
89     }
90     credentials::activate_credentials(acceptor_.native_handle());
91 #endif
92 }
93 
~local_server_endpoint_impl()94 local_server_endpoint_impl::~local_server_endpoint_impl() {
95 }
96 
is_local() const97 bool local_server_endpoint_impl::is_local() const {
98     return true;
99 }
100 
start()101 void local_server_endpoint_impl::start() {
102     std::lock_guard<std::mutex> its_lock(acceptor_mutex_);
103     if (acceptor_.is_open()) {
104         connection::ptr new_connection = connection::create(
105                 std::dynamic_pointer_cast<local_server_endpoint_impl>(
106                         shared_from_this()), max_message_size_,
107                         buffer_shrink_threshold_,
108                         service_);
109 
110         {
111             std::unique_lock<std::mutex> its_lock(new_connection->get_socket_lock());
112             acceptor_.async_accept(
113                 new_connection->get_socket(),
114                 std::bind(
115                     &local_server_endpoint_impl::accept_cbk,
116                     std::dynamic_pointer_cast<
117                         local_server_endpoint_impl
118                     >(shared_from_this()),
119                     new_connection,
120                     std::placeholders::_1
121                 )
122             );
123         }
124     }
125 }
126 
stop()127 void local_server_endpoint_impl::stop() {
128     server_endpoint_impl::stop();
129     {
130         std::lock_guard<std::mutex> its_lock(acceptor_mutex_);
131         if (acceptor_.is_open()) {
132             boost::system::error_code its_error;
133             acceptor_.close(its_error);
134         }
135     }
136     {
137         std::lock_guard<std::mutex> its_lock(connections_mutex_);
138         for (const auto &c : connections_) {
139             c.second->stop();
140         }
141         connections_.clear();
142     }
143 }
144 
send(const uint8_t * _data,uint32_t _size)145 bool local_server_endpoint_impl::send(const uint8_t *_data, uint32_t _size) {
146 #if 0
147     std::stringstream msg;
148     msg << "lse::send ";
149     for (uint32_t i = 0; i < _size; i++)
150         msg << std::setw(2) << std::setfill('0') << std::hex << (int)_data[i] << " ";
151     VSOMEIP_INFO << msg.str();
152 #endif
153     std::lock_guard<std::mutex> its_lock(mutex_);
154     if (endpoint_impl::sending_blocked_) {
155         return false;
156     }
157 
158     client_t its_client;
159     std::memcpy(&its_client, &_data[7], sizeof(its_client));
160 
161     connection::ptr its_connection;
162     {
163         std::lock_guard<std::mutex> its_lock(connections_mutex_);
164         const auto its_iterator = connections_.find(its_client);
165         if (its_iterator == connections_.end()) {
166             return false;
167         } else {
168             its_connection = its_iterator->second;
169         }
170     }
171 
172     auto its_buffer = std::make_shared<message_buffer_t>();
173     its_buffer->insert(its_buffer->end(), _data, _data + _size);
174     its_connection->send_queued(its_buffer);
175 
176     return true;
177 }
178 
send_to(const std::shared_ptr<endpoint_definition> _target,const byte_t * _data,uint32_t _size)179 bool local_server_endpoint_impl::send_to(
180         const std::shared_ptr<endpoint_definition> _target,
181         const byte_t *_data, uint32_t _size) {
182     (void)_target;
183     (void)_data;
184     (void)_size;
185     return false;
186 }
187 
send_error(const std::shared_ptr<endpoint_definition> _target,const byte_t * _data,uint32_t _size)188 bool local_server_endpoint_impl::send_error(
189         const std::shared_ptr<endpoint_definition> _target,
190         const byte_t *_data, uint32_t _size) {
191     (void)_target;
192     (void)_data;
193     (void)_size;
194     return false;
195 }
196 
send_queued(const queue_iterator_type _queue_iterator)197 void local_server_endpoint_impl::send_queued(
198         const queue_iterator_type _queue_iterator) {
199     (void)_queue_iterator;
200 }
201 
receive()202 void local_server_endpoint_impl::receive() {
203     // intentionally left empty
204 }
205 
get_default_target(service_t,local_server_endpoint_impl::endpoint_type &) const206 bool local_server_endpoint_impl::get_default_target(
207         service_t,
208         local_server_endpoint_impl::endpoint_type &) const {
209     return false;
210 }
211 
add_connection(const client_t & _client,const std::shared_ptr<connection> & _connection)212 bool local_server_endpoint_impl::add_connection(const client_t &_client,
213         const std::shared_ptr<connection> &_connection) {
214     bool ret = false;
215     std::lock_guard<std::mutex> its_lock(connections_mutex_);
216     auto find_connection = connections_.find(_client);
217     if (find_connection == connections_.end()) {
218         connections_[_client] = _connection;
219         ret = true;
220     } else {
221         VSOMEIP_WARNING << "Attempt to add already existing "
222             "connection to client " << std::hex << _client;
223     }
224     return ret;
225 }
226 
remove_connection(const client_t & _client)227 void local_server_endpoint_impl::remove_connection(
228         const client_t &_client) {
229     std::lock_guard<std::mutex> its_lock(connections_mutex_);
230     connections_.erase(_client);
231 }
232 
accept_cbk(const connection::ptr & _connection,boost::system::error_code const & _error)233 void local_server_endpoint_impl::accept_cbk(
234         const connection::ptr& _connection, boost::system::error_code const &_error) {
235     if (_error != boost::asio::error::bad_descriptor
236             && _error != boost::asio::error::operation_aborted
237             && _error != boost::asio::error::no_descriptors) {
238         start();
239     } else if (_error == boost::asio::error::no_descriptors) {
240         VSOMEIP_ERROR << "local_server_endpoint_impl::accept_cbk: "
241                 << _error.message() << " (" << std::dec << _error.value()
242                 << ") Will try to accept again in 1000ms";
243         std::shared_ptr<boost::asio::steady_timer> its_timer =
244                 std::make_shared<boost::asio::steady_timer>(service_,
245                         std::chrono::milliseconds(1000));
246         auto its_ep = std::dynamic_pointer_cast<local_server_endpoint_impl>(
247                 shared_from_this());
248         its_timer->async_wait([its_timer, its_ep]
249                                (const boost::system::error_code& _error) {
250             if (!_error) {
251                 its_ep->start();
252             }
253         });
254     }
255 
256     if (!_error) {
257 #ifndef _WIN32
258         auto its_host = endpoint_host_.lock();
259         client_t client = 0;
260 
261         socket_type &new_connection_socket = _connection->get_socket();
262         uid_t uid(ANY_UID);
263         gid_t gid(ANY_GID);
264         client = credentials::receive_credentials(
265              new_connection_socket.native_handle(), uid, gid);
266 
267         if (its_host && security::get()->is_enabled()) {
268             if (!configuration_->check_routing_credentials(client, uid, gid)) {
269                 VSOMEIP_WARNING << "vSomeIP Security: Rejecting new connection with routing manager client ID 0x" << std::hex << client
270                         << " uid/gid= " << std::dec << uid << "/" << gid
271                         << " because passed credentials do not match with routing manager credentials!";
272                 boost::system::error_code er;
273                 new_connection_socket.shutdown(new_connection_socket.shutdown_both, er);
274                 new_connection_socket.close(er);
275                 return;
276             }
277 
278             if (is_routing_endpoint_) {
279                 // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> check later
280                 _connection->set_bound_uid_gid(uid, gid);
281             } else {
282                 {
283                     std::lock_guard<std::mutex> its_connection_lock(connections_mutex_);
284                     // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> check later
285                     const auto found_client = connections_.find(client);
286                     if (found_client != connections_.end()) {
287                         VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex
288                                 << its_host->get_client() << " is rejecting new connection with client ID 0x"
289                                 << client << " uid/gid= " << std::dec << uid << "/" << gid
290                                 << " because of already existing connection using same client ID";
291                         boost::system::error_code er;
292                         new_connection_socket.shutdown(new_connection_socket.shutdown_both, er);
293                         new_connection_socket.close(er);
294                         return;
295                     }
296                 }
297                 if (!security::get()->check_credentials(client, uid, gid)) {
298                      VSOMEIP_WARNING << "vSomeIP Security: Client 0x" << std::hex
299                              << its_host->get_client() << " received client credentials from client 0x"
300                              << client << " which violates the security policy : uid/gid="
301                              << std::dec << uid << "/" << gid;
302                      boost::system::error_code er;
303                      new_connection_socket.shutdown(new_connection_socket.shutdown_both, er);
304                      new_connection_socket.close(er);
305                      return;
306                 }
307                 // rm_impl receives VSOMEIP_CLIENT_UNSET initially -> set later
308                 _connection->set_bound_client(client);
309                 add_connection(client, _connection);
310             }
311         } else {
312             security::get()->store_client_to_uid_gid_mapping(client, uid, gid);
313             security::get()->store_uid_gid_to_client_mapping(uid, gid, client);
314         }
315 #endif
316         _connection->start();
317     }
318 }
319 
320 ///////////////////////////////////////////////////////////////////////////////
321 // class local_service_impl::connection
322 ///////////////////////////////////////////////////////////////////////////////
323 
connection(const std::shared_ptr<local_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_service & _io_service)324 local_server_endpoint_impl::connection::connection(
325         const std::shared_ptr<local_server_endpoint_impl>& _server,
326         std::uint32_t _max_message_size,
327         std::uint32_t _initial_recv_buffer_size,
328         std::uint32_t _buffer_shrink_threshold,
329         boost::asio::io_service &_io_service)
330     : socket_(_io_service),
331       server_(_server),
332       recv_buffer_size_initial_(_initial_recv_buffer_size + 8),
333       max_message_size_(_max_message_size),
334       recv_buffer_(recv_buffer_size_initial_, 0),
335       recv_buffer_size_(0),
336       missing_capacity_(0),
337       shrink_count_(0),
338       buffer_shrink_threshold_(_buffer_shrink_threshold),
339       bound_client_(VSOMEIP_CLIENT_UNSET),
340 #ifndef _WIN32
341       bound_uid_(ANY_UID),
342       bound_gid_(ANY_GID),
343 #endif
344       assigned_client_(false) {
345     if (_server->is_routing_endpoint_ &&
346             !security::get()->is_enabled()) {
347         assigned_client_ = true;
348     }
349 }
350 
351 local_server_endpoint_impl::connection::ptr
create(const std::shared_ptr<local_server_endpoint_impl> & _server,std::uint32_t _max_message_size,std::uint32_t _buffer_shrink_threshold,boost::asio::io_service & _io_service)352 local_server_endpoint_impl::connection::create(
353         const std::shared_ptr<local_server_endpoint_impl>& _server,
354         std::uint32_t _max_message_size,
355         std::uint32_t _buffer_shrink_threshold,
356         boost::asio::io_service &_io_service) {
357     const std::uint32_t its_initial_buffer_size = VSOMEIP_COMMAND_HEADER_SIZE
358             + static_cast<std::uint32_t>(sizeof(instance_t) + sizeof(bool)
359                     + sizeof(bool));
360     return ptr(new connection(_server, _max_message_size, its_initial_buffer_size,
361             _buffer_shrink_threshold, _io_service));
362 }
363 
364 local_server_endpoint_impl::socket_type &
get_socket()365 local_server_endpoint_impl::connection::get_socket() {
366     return socket_;
367 }
368 
369 std::unique_lock<std::mutex>
get_socket_lock()370 local_server_endpoint_impl::connection::get_socket_lock() {
371     return std::unique_lock<std::mutex>(socket_mutex_);
372 }
373 
start()374 void local_server_endpoint_impl::connection::start() {
375     std::lock_guard<std::mutex> its_lock(socket_mutex_);
376     if (socket_.is_open()) {
377         const std::size_t its_capacity(recv_buffer_.capacity());
378         size_t buffer_size = its_capacity - recv_buffer_size_;
379         try {
380             if (missing_capacity_) {
381                 if (missing_capacity_ > MESSAGE_SIZE_UNLIMITED) {
382                     VSOMEIP_ERROR << "Missing receive buffer capacity exceeds allowed maximum!";
383                     return;
384                 }
385                 const std::size_t its_required_capacity(recv_buffer_size_ + missing_capacity_);
386                 if (its_capacity < its_required_capacity) {
387                     recv_buffer_.reserve(its_required_capacity);
388                     recv_buffer_.resize(its_required_capacity, 0x0);
389                 }
390                 buffer_size = missing_capacity_;
391                 missing_capacity_ = 0;
392             } else if (buffer_shrink_threshold_
393                     && shrink_count_ > buffer_shrink_threshold_
394                     && recv_buffer_size_ == 0) {
395                 recv_buffer_.resize(recv_buffer_size_initial_, 0x0);
396                 recv_buffer_.shrink_to_fit();
397                 buffer_size = recv_buffer_size_initial_;
398                 shrink_count_ = 0;
399             }
400         } catch (const std::exception &e) {
401             handle_recv_buffer_exception(e);
402             // don't start receiving again
403             return;
404         }
405 #ifndef _WIN32
406         socket_.async_receive(
407             boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size),
408             std::bind(
409                 &local_server_endpoint_impl::connection::receive_cbk,
410                 shared_from_this(),
411                 std::placeholders::_1,
412                 std::placeholders::_2,
413                 std::placeholders::_3,
414                 std::placeholders::_4
415             )
416         );
417 #else
418         socket_.async_receive(
419             boost::asio::buffer(&recv_buffer_[recv_buffer_size_], buffer_size),
420             std::bind(
421                 &local_server_endpoint_impl::connection::receive_cbk,
422                 shared_from_this(),
423                 std::placeholders::_1,
424                 std::placeholders::_2
425             )
426         );
427 #endif
428     }
429 }
430 
stop()431 void local_server_endpoint_impl::connection::stop() {
432     std::lock_guard<std::mutex> its_lock(socket_mutex_);
433     if (socket_.is_open()) {
434 #ifndef _WIN32
435         if (-1 == fcntl(socket_.native_handle(), F_GETFD)) {
436             VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno))
437                           << "' (" << errno << ") " << get_path_local();
438         }
439 #endif
440         boost::system::error_code its_error;
441         socket_.shutdown(socket_.shutdown_both, its_error);
442         socket_.close(its_error);
443     }
444 }
445 
send_queued(const message_buffer_ptr_t & _buffer)446 void local_server_endpoint_impl::connection::send_queued(
447         const message_buffer_ptr_t& _buffer) {
448     std::shared_ptr<local_server_endpoint_impl> its_server(server_.lock());
449     if (!its_server) {
450         VSOMEIP_TRACE << "local_server_endpoint_impl::connection::send_queued "
451                 " couldn't lock server_";
452         return;
453     }
454 
455     static const byte_t its_start_tag[] = { 0x67, 0x37, 0x6D, 0x07 };
456     static const byte_t its_end_tag[] = { 0x07, 0x6D, 0x37, 0x67 };
457     std::vector<boost::asio::const_buffer> bufs;
458 
459 #if 0
460         std::stringstream msg;
461         msg << "lse::sq: ";
462         for (std::size_t i = 0; i < _buffer->size(); i++)
463             msg << std::setw(2) << std::setfill('0') << std::hex
464                 << (int)(*_buffer)[i] << " ";
465         VSOMEIP_INFO << msg.str();
466 #endif
467 
468     bufs.push_back(boost::asio::buffer(its_start_tag));
469     bufs.push_back(boost::asio::buffer(*_buffer));
470     bufs.push_back(boost::asio::buffer(its_end_tag));
471 
472     {
473         std::lock_guard<std::mutex> its_lock(socket_mutex_);
474         boost::asio::async_write(
475             socket_,
476             bufs,
477             std::bind(
478                 &local_server_endpoint_impl::connection::send_cbk,
479                 shared_from_this(),
480                 _buffer,
481                 std::placeholders::_1,
482                 std::placeholders::_2
483             )
484         );
485     }
486 }
487 
assign_client(const byte_t * _data,uint32_t _size)488 client_t local_server_endpoint_impl::assign_client(
489         const byte_t *_data, uint32_t _size) {
490     client_t its_client(VSOMEIP_CLIENT_UNSET);
491     std::string its_name;
492     uint32_t its_name_length;
493 
494     if (_size >= VSOMEIP_COMMAND_PAYLOAD_POS) {
495         std::memcpy(&its_client, &_data[VSOMEIP_COMMAND_CLIENT_POS], sizeof(its_client));
496         std::memcpy(&its_name_length, &_data[VSOMEIP_COMMAND_SIZE_POS_MIN],
497             sizeof(its_name_length));
498 
499         if (its_name_length > 0)
500             its_name.assign(reinterpret_cast<const char *>(
501                     &_data[VSOMEIP_COMMAND_PAYLOAD_POS]), its_name_length);
502     }
503 
504     its_client = utility::request_client_id(configuration_, its_name, its_client);
505 
506     return its_client;
507 }
508 
get_configured_times_from_endpoint(service_t _service,method_t _method,std::chrono::nanoseconds * _debouncing,std::chrono::nanoseconds * _maximum_retention) const509 void local_server_endpoint_impl::get_configured_times_from_endpoint(
510         service_t _service,
511         method_t _method, std::chrono::nanoseconds *_debouncing,
512         std::chrono::nanoseconds *_maximum_retention) const {
513     (void)_service;
514     (void)_method;
515     (void)_debouncing;
516     (void)_maximum_retention;
517     VSOMEIP_ERROR << "local_server_endpoint_impl::get_configured_times_from_endpoint.";
518 }
519 
send_cbk(const message_buffer_ptr_t _buffer,boost::system::error_code const & _error,std::size_t _bytes)520 void local_server_endpoint_impl::connection::send_cbk(const message_buffer_ptr_t _buffer,
521         boost::system::error_code const &_error, std::size_t _bytes) {
522     (void)_buffer;
523     (void)_bytes;
524     if (_error)
525         VSOMEIP_WARNING << "sei::send_cbk received error: " << _error.message();
526 }
527 
receive_cbk(boost::system::error_code const & _error,std::size_t _bytes,std::uint32_t const & _uid,std::uint32_t const & _gid)528 void local_server_endpoint_impl::connection::receive_cbk(
529         boost::system::error_code const &_error, std::size_t _bytes
530 #ifndef _WIN32
531         , std::uint32_t const &_uid, std::uint32_t const &_gid
532 #endif
533         )
534 {
535     std::shared_ptr<local_server_endpoint_impl> its_server(server_.lock());
536     if (!its_server) {
537         VSOMEIP_TRACE << "local_server_endpoint_impl::connection::receive_cbk "
538                 " couldn't lock server_";
539         return;
540     }
541 
542     std::shared_ptr<routing_host> its_host = its_server->routing_host_.lock();
543     if (!its_host)
544         return;
545 
546     if (_error == boost::asio::error::operation_aborted) {
547         if (its_server->is_routing_endpoint_ &&
548                 bound_client_ != VSOMEIP_CLIENT_UNSET) {
549             utility::release_client_id(bound_client_);
550             set_bound_client(VSOMEIP_CLIENT_UNSET);
551         }
552 
553         // connection was stopped
554         return;
555     }
556 
557     bool is_error(false);
558     std::size_t its_start = 0;
559     std::size_t its_end = 0;
560     std::size_t its_iteration_gap = 0;
561     std::uint32_t its_command_size = 0;
562 
563     if (!_error && 0 < _bytes) {
564 #if 0
565         std::stringstream msg;
566         msg << "lse::c<" << this << ">rcb: ";
567         for (std::size_t i = 0; i < _bytes + recv_buffer_size_; i++)
568             msg << std::setw(2) << std::setfill('0') << std::hex
569                 << (int) (recv_buffer_[i]) << " ";
570         VSOMEIP_INFO << msg.str();
571 #endif
572 
573         if (recv_buffer_size_ + _bytes < recv_buffer_size_) {
574             VSOMEIP_ERROR << "receive buffer overflow in local server endpoint ~> abort!";
575             return;
576         }
577         recv_buffer_size_ += _bytes;
578 
579         bool message_is_empty(false);
580         bool found_message(false);
581 
582         do {
583             found_message = false;
584             message_is_empty = false;
585 
586             its_start = 0 + its_iteration_gap;
587             if (its_start + 3 < its_start) {
588                 VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!";
589                 return;
590             }
591             while (its_start + 3 < recv_buffer_size_ + its_iteration_gap &&
592                 (recv_buffer_[its_start] != 0x67 ||
593                 recv_buffer_[its_start+1] != 0x37 ||
594                 recv_buffer_[its_start+2] != 0x6d ||
595                 recv_buffer_[its_start+3] != 0x07)) {
596                 its_start++;
597             }
598 
599             if (its_start + 3 == recv_buffer_size_ + its_iteration_gap) {
600                 message_is_empty = true;
601             } else {
602                 its_start += 4;
603             }
604 
605             if (!message_is_empty) {
606                 if (its_start + 6 < recv_buffer_size_ + its_iteration_gap) {
607                     its_command_size = VSOMEIP_BYTES_TO_LONG(
608                                     recv_buffer_[its_start + 6],
609                                     recv_buffer_[its_start + 5],
610                                     recv_buffer_[its_start + 4],
611                                     recv_buffer_[its_start + 3]);
612 
613                     its_end = its_start + 6 + its_command_size;
614                 } else {
615                     its_end = its_start;
616                 }
617                 if (its_command_size && max_message_size_ != MESSAGE_SIZE_UNLIMITED
618                         && its_command_size > max_message_size_) {
619                     std::lock_guard<std::mutex> its_lock(socket_mutex_);
620                     VSOMEIP_ERROR << "Received a local message which exceeds "
621                           << "maximum message size (" << std::dec << its_command_size
622                           << ") aborting! local: " << get_path_local() << " remote: "
623                           << get_path_remote();
624                     recv_buffer_.resize(recv_buffer_size_initial_, 0x0);
625                     recv_buffer_.shrink_to_fit();
626                     return;
627                 }
628                 if (its_end + 3 < its_end) {
629                     VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!";
630                     return;
631                 }
632                 while (its_end + 3 < recv_buffer_size_ + its_iteration_gap &&
633                     (recv_buffer_[its_end] != 0x07 ||
634                     recv_buffer_[its_end+1] != 0x6d ||
635                     recv_buffer_[its_end+2] != 0x37 ||
636                     recv_buffer_[its_end+3] != 0x67)) {
637                     its_end ++;
638                 }
639                 if (its_end + 4 < its_end) {
640                     VSOMEIP_ERROR << "buffer overflow in local server endpoint ~> abort!";
641                     return;
642                 }
643                 // check if we received a full message
644                 if (recv_buffer_size_ + its_iteration_gap < its_end + 4
645                         || recv_buffer_[its_end] != 0x07
646                         || recv_buffer_[its_end+1] != 0x6d
647                         || recv_buffer_[its_end+2] != 0x37
648                         || recv_buffer_[its_end+3] != 0x67) {
649                     // command (1 Byte) + client id (2 Byte)
650                     // + command size (4 Byte) + data itself + stop tag (4 byte)
651                     // = 11 Bytes not covered in command size.
652                     if (its_start - its_iteration_gap + its_command_size + 11 > recv_buffer_size_) {
653                         missing_capacity_ =
654                                 std::uint32_t(its_start) - std::uint32_t(its_iteration_gap)
655                                 + its_command_size + 11 - std::uint32_t(recv_buffer_size_);
656                     } else if (recv_buffer_size_ < 11) {
657                         // to little data to read out the command size
658                         // minimal amount of data needed to read out command size = 11
659                         missing_capacity_ = 11 - static_cast<std::uint32_t>(recv_buffer_size_);
660                     } else {
661                         std::stringstream local_msg;
662                         for (std::size_t i = its_iteration_gap;
663                                 i < recv_buffer_size_ + its_iteration_gap &&
664                                 i - its_iteration_gap < 32; i++) {
665                             local_msg << std::setw(2) << std::setfill('0')
666                                 << std::hex << (int) recv_buffer_[i] << " ";
667                         }
668                         VSOMEIP_ERROR << "lse::c<" << this
669                                 << ">rcb: recv_buffer_size is: " << std::dec
670                                 << recv_buffer_size_ << " but couldn't read "
671                                 "out command size. recv_buffer_capacity: "
672                                 << std::dec << recv_buffer_.capacity()
673                                 << " its_iteration_gap: " << std::dec
674                                 << its_iteration_gap << " bound client: 0x"
675                                 << std::hex << bound_client_ << " buffer: "
676                                 << local_msg.str();
677                         recv_buffer_size_ = 0;
678                         missing_capacity_ = 0;
679                         its_iteration_gap = 0;
680                         message_is_empty = true;
681                     }
682                 }
683             }
684 
685             if (!message_is_empty &&
686                 its_end + 3 < recv_buffer_size_ + its_iteration_gap) {
687 
688                 if (its_server->is_routing_endpoint_
689                         && recv_buffer_[its_start] == VSOMEIP_ASSIGN_CLIENT) {
690                     client_t its_client = its_server->assign_client(
691                             &recv_buffer_[its_start], uint32_t(its_end - its_start));
692 #ifndef _WIN32
693                     if (security::get()->is_enabled()) {
694                         if (!its_server->add_connection(its_client, shared_from_this())) {
695                             VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client()
696                                     << " is rejecting new connection with client ID 0x" << its_client
697                                     << " uid/gid= " << std::dec << bound_uid_ << "/" << bound_gid_
698                                     << " because of already existing connection using same client ID";
699                             stop();
700                             return;
701                         } else if (!security::get()->check_credentials(
702                                 its_client, bound_uid_, bound_gid_)) {
703                             VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client()
704                                     << " received client credentials from client 0x" << its_client
705                                     << " which violates the security policy : uid/gid="
706                                     << std::dec << bound_uid_ << "/" << bound_gid_;
707                             its_server->remove_connection(its_client);
708                             utility::release_client_id(its_client);
709                             stop();
710                             return;
711                         } else {
712                             set_bound_client(its_client);
713                         }
714                     } else
715 #endif
716                     {
717                         set_bound_client(its_client);
718                         its_server->add_connection(its_client, shared_from_this());
719                     }
720                     its_server->send_client_identifier(its_client);
721                     assigned_client_ = true;
722                 } else if (!its_server->is_routing_endpoint_ || assigned_client_) {
723 #ifndef _WIN32
724                     credentials_t its_credentials = std::make_pair(_uid, _gid);
725 #else
726                     credentials_t its_credentials = std::make_pair(ANY_UID, ANY_GID);
727 #endif
728                     its_host->on_message(&recv_buffer_[its_start],
729                                          uint32_t(its_end - its_start), its_server.get(),
730                                          boost::asio::ip::address(), bound_client_, its_credentials);
731                 } else {
732                     VSOMEIP_WARNING << std::hex << "Client 0x" << its_host->get_client()
733                             << " didn't receive VSOMEIP_ASSIGN_CLIENT as first message";
734                 }
735                 #if 0
736                         std::stringstream local_msg;
737                         local_msg << "lse::c<" << this << ">rcb::thunk: ";
738                         for (std::size_t i = its_start; i < its_end; i++)
739                             local_msg << std::setw(2) << std::setfill('0') << std::hex
740                                 << (int) recv_buffer_[i] << " ";
741                         VSOMEIP_INFO << local_msg.str();
742                 #endif
743                 calculate_shrink_count();
744                 recv_buffer_size_ -= (its_end + 4 - its_iteration_gap);
745                 missing_capacity_ = 0;
746                 its_command_size = 0;
747                 found_message = true;
748                 its_iteration_gap = its_end + 4;
749             } else {
750                 if (its_iteration_gap) {
751                     // Message not complete and not in front of the buffer!
752                     // Copy last part to front for consume in future receive_cbk call!
753                     for (size_t i = 0; i < recv_buffer_size_; ++i) {
754                         recv_buffer_[i] = recv_buffer_[i + its_iteration_gap];
755                     }
756                     // Still more capacity needed after shifting everything to front?
757                     if (missing_capacity_ &&
758                             missing_capacity_ <= recv_buffer_.capacity() - recv_buffer_size_) {
759                         missing_capacity_ = 0;
760                     }
761                 } else if (message_is_empty) {
762                     VSOMEIP_ERROR << "Received garbage data.";
763                     is_error = true;
764                 }
765             }
766         } while (recv_buffer_size_ > 0 && found_message);
767     }
768 
769     if (_error == boost::asio::error::eof
770             || _error == boost::asio::error::connection_reset
771             || is_error) {
772         stop();
773         its_server->remove_connection(bound_client_);
774         security::get()->remove_client_to_uid_gid_mapping(bound_client_);
775     } else if (_error != boost::asio::error::bad_descriptor) {
776         start();
777     }
778 }
779 
set_bound_client(client_t _client)780 void local_server_endpoint_impl::connection::set_bound_client(client_t _client) {
781     bound_client_ = _client;
782 }
783 
get_bound_client() const784 client_t local_server_endpoint_impl::connection::get_bound_client() const {
785     return bound_client_;
786 }
787 
788 #ifndef _WIN32
set_bound_uid_gid(uid_t _uid,gid_t _gid)789 void local_server_endpoint_impl::connection::set_bound_uid_gid(uid_t _uid, gid_t _gid) {
790     bound_uid_ = _uid;
791     bound_gid_ = _gid;
792 }
793 #endif
794 
calculate_shrink_count()795 void local_server_endpoint_impl::connection::calculate_shrink_count() {
796     if (buffer_shrink_threshold_) {
797         if (recv_buffer_.capacity() != recv_buffer_size_initial_) {
798             if (recv_buffer_size_ < (recv_buffer_.capacity() >> 1)) {
799                 shrink_count_++;
800             } else {
801                 shrink_count_ = 0;
802             }
803         }
804     }
805 }
806 
get_path_local() const807 const std::string local_server_endpoint_impl::connection::get_path_local() const {
808     boost::system::error_code ec;
809     std::string its_local_path;
810     if (socket_.is_open()) {
811         endpoint_type its_local_endpoint = socket_.local_endpoint(ec);
812         if (!ec) {
813 #ifdef _WIN32
814             its_local_path += its_local_endpoint.address().to_string(ec);
815             its_local_path += ":";
816             its_local_path += std::to_string(its_local_endpoint.port());
817 #else
818             its_local_path += its_local_endpoint.path();
819 #endif
820 
821         }
822     }
823     return its_local_path;
824 }
825 
get_path_remote() const826 const std::string local_server_endpoint_impl::connection::get_path_remote() const {
827     boost::system::error_code ec;
828     std::string its_remote_path;
829     if (socket_.is_open()) {
830         endpoint_type its_remote_endpoint = socket_.remote_endpoint(ec);
831         if (!ec) {
832 #ifdef _WIN32
833             its_remote_path += its_remote_endpoint.address().to_string(ec);
834             its_remote_path += ":";
835             its_remote_path += std::to_string(its_remote_endpoint.port());
836 #else
837             its_remote_path += its_remote_endpoint.path();
838 #endif
839         }
840     }
841     return its_remote_path;
842 }
843 
handle_recv_buffer_exception(const std::exception & _e)844 void local_server_endpoint_impl::connection::handle_recv_buffer_exception(
845         const std::exception &_e) {
846     std::stringstream its_message;
847     its_message <<"local_server_endpoint_impl::connection catched exception"
848             << _e.what() << " local: " << get_path_local() << " remote: "
849             << get_path_remote() << " shutting down connection. Start of buffer: ";
850 
851     for (std::size_t i = 0; i < recv_buffer_size_ && i < 16; i++) {
852         its_message << std::setw(2) << std::setfill('0') << std::hex
853             << (int) (recv_buffer_[i]) << " ";
854     }
855 
856     its_message << " Last 16 Bytes captured: ";
857     for (int i = 15; recv_buffer_size_ > 15u && i >= 0; i--) {
858         its_message << std::setw(2) << std::setfill('0') << std::hex
859             << (int) (recv_buffer_[static_cast<size_t>(i)]) << " ";
860     }
861     VSOMEIP_ERROR << its_message.str();
862     recv_buffer_.clear();
863     if (socket_.is_open()) {
864 #ifndef _WIN32
865         if (-1 == fcntl(socket_.native_handle(), F_GETFD)) {
866             VSOMEIP_ERROR << "lse: socket/handle closed already '" << std::string(std::strerror(errno))
867                           << "' (" << errno << ") " << get_path_local();
868         }
869 #endif
870         boost::system::error_code its_error;
871         socket_.shutdown(socket_.shutdown_both, its_error);
872         socket_.close(its_error);
873     }
874     std::shared_ptr<local_server_endpoint_impl> its_server = server_.lock();
875     if (its_server) {
876         its_server->remove_connection(bound_client_);
877     }
878 }
879 
880 std::size_t
get_recv_buffer_capacity() const881 local_server_endpoint_impl::connection::get_recv_buffer_capacity() const {
882     return recv_buffer_.capacity();
883 }
884 
print_status()885 void local_server_endpoint_impl::print_status() {
886     std::lock_guard<std::mutex> its_lock(mutex_);
887     connections_t its_connections;
888     {
889         std::lock_guard<std::mutex> its_lock(connections_mutex_);
890         its_connections = connections_;
891     }
892 #ifndef _WIN32
893     std::string its_local_path(local_.path());
894 #else
895     std::string its_local_path("");
896 #endif
897     VSOMEIP_INFO << "status lse: " << its_local_path << " connections: "
898             << std::dec << its_connections.size() << " queues: "
899             << std::dec << queues_.size();
900     for (const auto &c : its_connections) {
901 #ifndef _WIN32
902         std::string its_remote_path; // TODO: construct the path
903 #else
904         std::string its_remote_path("");
905 #endif
906 
907         std::size_t its_recv_size(0);
908         {
909             std::unique_lock<std::mutex> c_s_lock(c.second->get_socket_lock());
910             its_recv_size = c.second->get_recv_buffer_capacity();
911         }
912 
913         VSOMEIP_INFO << "status lse: client: " << its_remote_path
914                 << " recv_buffer: " << std::dec << its_recv_size;
915     }
916 }
get_remote_information(const queue_iterator_type _queue_iterator) const917 std::string local_server_endpoint_impl::get_remote_information(
918         const queue_iterator_type _queue_iterator) const {
919 #ifdef _WIN32
920     boost::system::error_code ec;
921     return _queue_iterator->first.address().to_string(ec) + ":"
922             + std::to_string(_queue_iterator->first.port());
923 #else
924     (void)_queue_iterator;
925     return "local";
926 #endif
927 }
928 
get_remote_information(const endpoint_type & _remote) const929 std::string local_server_endpoint_impl::get_remote_information(
930         const endpoint_type& _remote) const {
931 #ifdef _WIN32
932     boost::system::error_code ec;
933     return _remote.address().to_string(ec) + ":"
934             + std::to_string(_remote.port());
935 #else
936     (void)_remote;
937     return "local";
938 #endif
939 }
940 
is_reliable() const941 bool local_server_endpoint_impl::is_reliable() const {
942     return false;
943 }
944 
get_local_port() const945 std::uint16_t local_server_endpoint_impl::get_local_port() const {
946     return 0;
947 }
948 
set_local_port(std::uint16_t _port)949 void local_server_endpoint_impl::set_local_port(std::uint16_t _port) {
950     (void) _port;
951 }
952 
check_packetizer_space(queue_iterator_type _queue_iterator,message_buffer_ptr_t * _packetizer,std::uint32_t _size)953 bool local_server_endpoint_impl::check_packetizer_space(
954         queue_iterator_type _queue_iterator, message_buffer_ptr_t* _packetizer,
955         std::uint32_t _size) {
956     if ((*_packetizer)->size() + _size < (*_packetizer)->size()) {
957         VSOMEIP_ERROR << "Overflow in packetizer addition ~> abort sending!";
958         return false;
959     }
960     if ((*_packetizer)->size() + _size > max_message_size_
961             && !(*_packetizer)->empty()) {
962         _queue_iterator->second.second.push_back(*_packetizer);
963         _queue_iterator->second.first += (*_packetizer)->size();
964         *_packetizer = std::make_shared<message_buffer_t>();
965     }
966     return true;
967 }
968 
969 void
send_client_identifier(const client_t & _client)970 local_server_endpoint_impl::send_client_identifier(
971         const client_t &_client) {
972     byte_t its_command[] = {
973             VSOMEIP_ASSIGN_CLIENT_ACK,
974             0x0, 0x0, // client
975             0x2, 0x0, 0x0, 0x0, // size
976             0x0, 0x0 // assigned client
977     };
978 
979     std::memcpy(its_command+7, &_client, sizeof(_client));
980 
981     send(its_command, sizeof(its_command));
982 }
983 
984 
tp_segmentation_enabled(service_t _service,method_t _method) const985 bool local_server_endpoint_impl::tp_segmentation_enabled(
986         service_t _service, method_t _method) const {
987     (void)_service;
988     (void)_method;
989     return false;
990 }
991 
992 
993 } // namespace vsomeip_v3
994