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 "../include/endpoint_manager_base.hpp"
7
8 #include <vsomeip/internal/logger.hpp>
9 #include "../../utility/include/utility.hpp"
10 #include "../../routing/include/routing_manager_base.hpp"
11 #include "../../configuration/include/configuration.hpp"
12 #include "../include/local_client_endpoint_impl.hpp"
13 #include "../include/local_server_endpoint_impl.hpp"
14
15 #include <iomanip>
16
17 namespace vsomeip_v3 {
18
endpoint_manager_base(routing_manager_base * const _rm,boost::asio::io_service & _io,const std::shared_ptr<configuration> & _configuration)19 endpoint_manager_base::endpoint_manager_base(routing_manager_base* const _rm,
20 boost::asio::io_service& _io,
21 const std::shared_ptr<configuration>& _configuration) :
22 rm_(_rm),
23 io_(_io),
24 configuration_(_configuration){
25
26 }
27
create_local(client_t _client)28 std::shared_ptr<endpoint> endpoint_manager_base::create_local(client_t _client) {
29 std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
30 return create_local_unlocked(_client);
31 }
32
remove_local(client_t _client)33 void endpoint_manager_base::remove_local(client_t _client) {
34 std::shared_ptr<endpoint> its_endpoint(find_local(_client));
35 if (its_endpoint) {
36 its_endpoint->register_error_handler(nullptr);
37 its_endpoint->stop();
38 VSOMEIP_INFO << "Client [" << std::hex << rm_->get_client() << "] is closing connection to ["
39 << std::hex << _client << "]";
40 std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
41 local_endpoints_.erase(_client);
42 }
43 }
44
find_or_create_local(client_t _client)45 std::shared_ptr<endpoint> endpoint_manager_base::find_or_create_local(client_t _client) {
46 std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
47 std::shared_ptr<endpoint> its_endpoint(find_local_unlocked(_client));
48 if (!its_endpoint) {
49 its_endpoint = create_local_unlocked(_client);
50 its_endpoint->start();
51 }
52 return (its_endpoint);
53 }
54
find_local(client_t _client)55 std::shared_ptr<endpoint> endpoint_manager_base::find_local(client_t _client) {
56 std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
57 return find_local_unlocked(_client);
58 }
59
find_local(service_t _service,instance_t _instance)60 std::shared_ptr<endpoint> endpoint_manager_base::find_local(service_t _service,
61 instance_t _instance) {
62 return find_local(rm_->find_local_client(_service, _instance));
63 }
64
65
get_connected_clients() const66 std::unordered_set<client_t> endpoint_manager_base::get_connected_clients() const {
67 std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
68 std::unordered_set<client_t> clients;
69 for (const auto& its_client : local_endpoints_) {
70 clients.insert(its_client.first);
71 }
72 return clients;
73 }
74
create_local_server(const std::shared_ptr<routing_host> & _routing_host)75 std::shared_ptr<local_server_endpoint_impl> endpoint_manager_base::create_local_server(
76 const std::shared_ptr<routing_host>& _routing_host) {
77 std::shared_ptr<local_server_endpoint_impl> its_server_endpoint;
78 std::stringstream its_path;
79 its_path << utility::get_base_path(configuration_) << std::hex << rm_->get_client();
80 const client_t its_client = rm_->get_client();
81 #ifdef _WIN32
82 ::_unlink(its_path.str().c_str());
83 int port = VSOMEIP_INTERNAL_BASE_PORT + its_client;
84 #else
85 if (-1 == ::unlink(its_path.str().c_str()) && errno != ENOENT) {
86 VSOMEIP_ERROR << "endpoint_manager_base::init_receiver unlink failed ("
87 << its_path.str() << "): "<< std::strerror(errno);
88 }
89 #endif
90 try {
91 its_server_endpoint = std::make_shared<local_server_endpoint_impl>(
92 shared_from_this(), _routing_host,
93 #ifdef _WIN32
94 boost::asio::ip::tcp::endpoint(boost::asio::ip::tcp::v4(), port),
95 #else
96 boost::asio::local::stream_protocol_ext::endpoint(its_path.str()),
97 #endif
98 io_,
99 configuration_, false);
100 #ifdef _WIN32
101 VSOMEIP_INFO << "Listening at " << port;
102 #else
103 VSOMEIP_INFO << "Listening at " << its_path.str();
104 #endif
105 } catch (const std::exception &e) {
106 VSOMEIP_ERROR << "Local server endpoint creation failed. Client ID: "
107 << std::hex << std::setw(4) << std::setfill('0') << its_client
108 #ifdef _WIN32
109 << " Port: " << std::dec << port
110 #else
111 << " Path: " << its_path.str()
112 #endif
113 << " Reason: " << e.what();
114 }
115 return its_server_endpoint;
116 }
117
on_connect(std::shared_ptr<endpoint> _endpoint)118 void endpoint_manager_base::on_connect(std::shared_ptr<endpoint> _endpoint) {
119 rm_->on_connect(_endpoint);
120 }
121
on_disconnect(std::shared_ptr<endpoint> _endpoint)122 void endpoint_manager_base::on_disconnect(std::shared_ptr<endpoint> _endpoint) {
123 rm_->on_disconnect(_endpoint);
124 }
125
on_bind_error(std::shared_ptr<endpoint> _endpoint,uint16_t _remote_port)126 bool endpoint_manager_base::on_bind_error(std::shared_ptr<endpoint> _endpoint, uint16_t _remote_port) {
127 (void)_endpoint;
128 (void)_remote_port;
129 return true;
130 // intentionally left blank
131 }
132
on_error(const byte_t * _data,length_t _length,endpoint * const _receiver,const boost::asio::ip::address & _remote_address,std::uint16_t _remote_port)133 void endpoint_manager_base::on_error(
134 const byte_t *_data, length_t _length, endpoint* const _receiver,
135 const boost::asio::ip::address &_remote_address,
136 std::uint16_t _remote_port) {
137 (void)_data;
138 (void)_length;
139 (void)_receiver;
140 (void)_remote_address;
141 (void)_remote_port;
142 // intentionally left blank
143 }
144
release_port(uint16_t _port,bool _reliable)145 void endpoint_manager_base::release_port(uint16_t _port, bool _reliable) {
146 (void)_port;
147 (void)_reliable;
148 // intentionally left blank
149 }
150
get_client() const151 client_t endpoint_manager_base::get_client() const {
152 return rm_->get_client();
153 }
154
155 std::map<client_t, std::shared_ptr<endpoint>>
get_local_endpoints() const156 endpoint_manager_base::get_local_endpoints() const {
157 std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
158 return local_endpoints_;
159 }
160
161 void
log_client_states() const162 endpoint_manager_base::log_client_states() const {
163 std::vector<std::pair<client_t, size_t> > its_client_queue_sizes;
164 std::stringstream its_log;
165
166 {
167 std::lock_guard<std::mutex> its_lock(local_endpoint_mutex_);
168 for (const auto &e : local_endpoints_) {
169 size_t its_queue_size = e.second->get_queue_size();
170 if (its_queue_size > VSOMEIP_DEFAULT_QUEUE_WARN_SIZE) {
171 its_client_queue_sizes.push_back(
172 std::make_pair(e.first, its_queue_size));
173 }
174 }
175 }
176
177 std::sort(its_client_queue_sizes.begin(), its_client_queue_sizes.end(),
178 [](const std::pair<client_t, size_t> &_a,
179 const std::pair<client_t, size_t> &_b) {
180 return (_a.second > _b.second);
181 });
182
183 size_t its_max(std::min(size_t(10), its_client_queue_sizes.size()));
184 for (size_t i = 0; i < its_max; i++) {
185 its_log << std::hex << std::setw(4) << std::setfill('0')
186 << its_client_queue_sizes[i].first << ":"
187 << std::dec << its_client_queue_sizes[i].second;
188 if (i < its_max-1)
189 its_log << ", ";
190 }
191
192 if (its_log.str().length() > 0)
193 VSOMEIP_WARNING << "ICQ: [" << its_log.str() << "]";
194 }
195
create_local_unlocked(client_t _client)196 std::shared_ptr<endpoint> endpoint_manager_base::create_local_unlocked(client_t _client) {
197 std::stringstream its_path;
198 its_path << utility::get_base_path(configuration_) << std::hex << _client;
199 std::shared_ptr<local_client_endpoint_impl> its_endpoint;
200
201 #ifdef _WIN32
202 boost::asio::ip::address address = boost::asio::ip::address::from_string("127.0.0.1");
203 int port = VSOMEIP_INTERNAL_BASE_PORT + _client;
204 VSOMEIP_INFO << "Connecting to ["
205 << std::hex << _client << "] at " << port;
206 #else
207 VSOMEIP_INFO << "Client [" << std::hex << rm_->get_client() << "] is connecting to ["
208 << std::hex << _client << "] at " << its_path.str();
209 #endif
210 its_endpoint = std::make_shared<local_client_endpoint_impl>(
211 shared_from_this(), rm_->shared_from_this(),
212 #ifdef _WIN32
213 boost::asio::ip::tcp::endpoint(address, port)
214 #else
215 boost::asio::local::stream_protocol::endpoint(its_path.str())
216 #endif
217 , io_, configuration_);
218
219 // Messages sent to the VSOMEIP_ROUTING_CLIENT are meant to be routed to
220 // external devices. Therefore, its local endpoint must not be found by
221 // a call to find_local. Thus it must not be inserted to the list of local
222 // clients.
223 if (_client != VSOMEIP_ROUTING_CLIENT) {
224 local_endpoints_[_client] = its_endpoint;
225 }
226 rm_->register_client_error_handler(_client, its_endpoint);
227
228 return its_endpoint;
229 }
230
find_local_unlocked(client_t _client)231 std::shared_ptr<endpoint> endpoint_manager_base::find_local_unlocked(client_t _client) {
232 std::shared_ptr<endpoint> its_endpoint;
233 auto found_endpoint = local_endpoints_.find(_client);
234 if (found_endpoint != local_endpoints_.end()) {
235 its_endpoint = found_endpoint->second;
236 }
237 return (its_endpoint);
238 }
239
240 } // namespace vsomeip_v3
241