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