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