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 <iomanip>
7
8 #ifdef _WIN32
9 #include <iostream>
10 #include <tchar.h>
11 #include <intrin.h>
12 #else
13 #include <dlfcn.h>
14 #include <signal.h>
15 #include <unistd.h>
16 #include <fcntl.h>
17 #include <sys/mman.h>
18 #include <thread>
19 #include <sstream>
20 #endif
21
22 #include <sys/stat.h>
23
24 #include <vsomeip/constants.hpp>
25 #include <vsomeip/defines.hpp>
26 #include <vsomeip/internal/logger.hpp>
27
28 #include "../include/byteorder.hpp"
29 #include "../include/utility.hpp"
30 #include "../../configuration/include/configuration.hpp"
31
32 namespace vsomeip_v3 {
33
34 std::mutex utility::mutex__;
35 client_t utility::next_client__(VSOMEIP_CLIENT_UNSET);
36 std::map<client_t, std::string> utility::used_clients__;
37 #ifdef _WIN32
38 HANDLE utility::lock_handle__(INVALID_HANDLE_VALUE);
39 #else
40 int utility::lock_fd__(-1);
41 #endif
42 #ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
43 bool utility::is_checked__(false);
44 #else
45 std::set<std::string> utility::is_checked__;
46 #endif
47
get_message_size(const byte_t * _data,size_t _size)48 uint64_t utility::get_message_size(const byte_t *_data, size_t _size) {
49 uint64_t its_size(0);
50 if (VSOMEIP_SOMEIP_HEADER_SIZE <= _size) {
51 its_size = VSOMEIP_SOMEIP_HEADER_SIZE
52 + VSOMEIP_BYTES_TO_LONG(_data[4], _data[5], _data[6], _data[7]);
53 }
54 return (its_size);
55 }
56
get_payload_size(const byte_t * _data,uint32_t _size)57 uint32_t utility::get_payload_size(const byte_t *_data, uint32_t _size) {
58 uint32_t its_size(0);
59 if (VSOMEIP_SOMEIP_HEADER_SIZE <= _size) {
60 its_size = VSOMEIP_BYTES_TO_LONG(_data[4], _data[5], _data[6], _data[7])
61 - VSOMEIP_SOMEIP_HEADER_SIZE;
62 }
63 return (its_size);
64 }
65
is_routing_manager(const std::shared_ptr<configuration> & _config)66 bool utility::is_routing_manager(const std::shared_ptr<configuration> &_config) {
67 // Only the first caller can become routing manager.
68 // Therefore, subsequent calls can be immediately answered...
69 std::lock_guard<std::mutex> its_lock(mutex__);
70 #ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
71 if (is_checked__)
72 return false;
73
74 is_checked__ = true;
75 #else
76 if (is_checked__.find(_config->get_network()) != is_checked__.end())
77 return false;
78
79 is_checked__.insert(_config->get_network());
80 #endif
81 #ifdef _WIN32
82 wchar_t its_tmp_folder[MAX_PATH];
83 if (GetTempPathW(MAX_PATH, its_tmp_folder)) {
84 std::wstring its_lockfile(its_tmp_folder);
85 std::string its_network(_config->get_network() + ".lck");
86 its_lockfile.append(its_network.begin(), its_network.end());
87 lock_handle__ = CreateFileW(its_lockfile.c_str(), GENERIC_READ, 0, NULL, CREATE_NEW, 0, NULL);
88 if (lock_handle__ == INVALID_HANDLE_VALUE) {
89 VSOMEIP_ERROR << __func__ << ": CreateFileW failed: " << std::hex << GetLastError();
90 }
91 } else {
92 VSOMEIP_ERROR << __func__ << ": Could not get temp folder: "
93 << std::hex << GetLastError();
94 lock_handle__ = INVALID_HANDLE_VALUE;
95 }
96
97 return (lock_handle__ != INVALID_HANDLE_VALUE);
98 #else
99 std::string its_base_path(VSOMEIP_BASE_PATH + _config->get_network());
100 #ifdef __ANDROID__ // NDK
101 const char *env_base_path = getenv(VSOMEIP_ENV_BASE_PATH);
102 if (nullptr != env_base_path) {
103 its_base_path = {env_base_path + _config->get_network()};
104 }
105 #endif
106 std::string its_lockfile(its_base_path + ".lck");
107 int its_lock_ctrl(-1);
108
109 struct flock its_lock_data = { F_WRLCK, SEEK_SET, 0, 0, 0 };
110
111 lock_fd__ = open(its_lockfile.c_str(), O_WRONLY | O_CREAT, S_IWUSR | S_IWGRP);
112 if (-1 != lock_fd__) {
113 its_lock_data.l_pid = getpid();
114 its_lock_ctrl = fcntl(lock_fd__, F_SETLK, &its_lock_data);
115 } else {
116 VSOMEIP_ERROR << __func__
117 << ": Could not open " << its_lockfile << ": " << std::strerror(errno);
118 }
119
120 return (its_lock_ctrl != -1);
121 #endif
122 }
123
remove_lockfile(const std::shared_ptr<configuration> & _config)124 void utility::remove_lockfile(const std::shared_ptr<configuration> &_config) {
125 std::lock_guard<std::mutex> its_lock(mutex__);
126 #ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
127 if (!is_checked__) // No need to do anything as automatic
128 return;
129 #else
130 if (is_checked__.find(_config->get_network()) == is_checked__.end()) // No need to do anything as automatic
131 return;
132 #endif
133
134 #ifdef _WIN32
135 if (lock_handle__ != INVALID_HANDLE_VALUE) {
136 if (CloseHandle(lock_handle__) == 0) {
137 VSOMEIP_ERROR << __func__ << ": CloseHandle failed."
138 << std::hex << GetLastError();
139 }
140 wchar_t its_tmp_folder[MAX_PATH];
141 if (GetTempPathW(MAX_PATH, its_tmp_folder)) {
142 std::wstring its_lockfile(its_tmp_folder);
143 std::string its_network(_config->get_network() + ".lck");
144 its_lockfile.append(its_network.begin(), its_network.end());
145 if (DeleteFileW(its_lockfile.c_str()) == 0) {
146 VSOMEIP_ERROR << __func__ << ": DeleteFileW failed: "
147 << std::hex << GetLastError();
148
149 }
150 } else {
151 VSOMEIP_ERROR << __func__ << ": Could not get temp folder."
152 << std::hex << GetLastError();
153 }
154 }
155 #else
156 std::string its_base_path(VSOMEIP_BASE_PATH + _config->get_network());
157 #ifdef __ANDROID__ // NDK
158 const char *env_base_path = getenv(VSOMEIP_ENV_BASE_PATH);
159 if (nullptr != env_base_path) {
160 its_base_path = {env_base_path + _config->get_network()};
161 }
162 #endif
163 std::string its_lockfile(its_base_path + ".lck");
164
165 if (lock_fd__ != -1) {
166 if (close(lock_fd__) == -1) {
167 VSOMEIP_ERROR << __func__ << ": Could not close lock_fd__"
168 << std::strerror(errno);
169 }
170 }
171 if (remove(its_lockfile.c_str()) == -1) {
172 VSOMEIP_ERROR << __func__ << ": Could not remove " << its_lockfile
173 << ": " << std::strerror(errno);
174 }
175 #endif
176 #ifndef VSOMEIP_ENABLE_CONFIGURATION_OVERLAYS
177 is_checked__ = false;
178 #else
179 is_checked__.erase(_config->get_network());
180 #endif
181 }
182
exists(const std::string & _path)183 bool utility::exists(const std::string &_path) {
184 struct stat its_stat;
185 return (stat(_path.c_str(), &its_stat) == 0);
186 }
187
is_file(const std::string & _path)188 bool utility::is_file(const std::string &_path) {
189 struct stat its_stat;
190 if (stat(_path.c_str(), &its_stat) == 0) {
191 if (its_stat.st_mode & S_IFREG)
192 return true;
193 }
194 return false;
195 }
196
is_folder(const std::string & _path)197 bool utility::is_folder(const std::string &_path) {
198 struct stat its_stat;
199 if (stat(_path.c_str(), &its_stat) == 0) {
200 if (its_stat.st_mode & S_IFDIR)
201 return true;
202 }
203 return false;
204 }
205
get_base_path(const std::shared_ptr<configuration> & _config)206 const std::string utility::get_base_path(
207 const std::shared_ptr<configuration> &_config) {
208 #ifdef __ANDROID__ // NDK
209 const char *env_base_path = getenv(VSOMEIP_ENV_BASE_PATH);
210 if (nullptr != env_base_path) {
211 std::string its_base_path(env_base_path + _config->get_network());
212 return std::string(env_base_path + _config->get_network() + "-");
213 } else {
214 return std::string(VSOMEIP_BASE_PATH + _config->get_network() + "-");
215 }
216 #else
217 return std::string(VSOMEIP_BASE_PATH + _config->get_network() + "-");
218 #endif
219 }
220
221 client_t
request_client_id(const std::shared_ptr<configuration> & _config,const std::string & _name,client_t _client)222 utility::request_client_id(
223 const std::shared_ptr<configuration> &_config,
224 const std::string &_name, client_t _client) {
225 std::lock_guard<std::mutex> its_lock(mutex__);
226 static const std::uint16_t its_max_num_clients = get_max_client_number(_config);
227
228 static const std::uint16_t its_diagnosis_mask = _config->get_diagnosis_mask();
229 static const std::uint16_t its_client_mask = static_cast<std::uint16_t>(~its_diagnosis_mask);
230 static const client_t its_masked_diagnosis_address = static_cast<client_t>(
231 (_config->get_diagnosis_address() << 8) & its_diagnosis_mask);
232 static const client_t its_biggest_client = its_masked_diagnosis_address | its_client_mask;
233 static const client_t its_smallest_client = its_masked_diagnosis_address;
234
235 if (next_client__ == VSOMEIP_CLIENT_UNSET) {
236 next_client__ = its_smallest_client;
237 }
238
239 if (_client != VSOMEIP_CLIENT_UNSET) { // predefined client identifier
240 const auto its_iterator = used_clients__.find(_client);
241 if (its_iterator == used_clients__.end()) { // unused identifier
242 used_clients__[_client] = _name;
243 return _client;
244 } else { // already in use
245
246 // The name matches the assigned name --> return client
247 // NOTE: THIS REQUIRES A CONSISTENT CONFIGURATION!!!
248 if (its_iterator->second == _name) {
249 return _client;
250 }
251
252 VSOMEIP_WARNING << "Requested client identifier "
253 << std::setw(4) << std::setfill('0')
254 << std::hex << _client
255 << " is already used by application \""
256 << its_iterator->second
257 << "\".";
258 // intentionally fall through
259 }
260 }
261
262 if (next_client__ == its_biggest_client) {
263 // start at beginning of client range again when the biggest client was reached
264 next_client__ = its_smallest_client;
265 }
266 std::uint16_t increase_count = 0;
267 do {
268 next_client__ = (next_client__ & static_cast<std::uint16_t>(~its_client_mask)) // save diagnosis address bits
269 | (static_cast<std::uint16_t>((next_client__ // set all diagnosis address bits to one
270 | static_cast<std::uint16_t>(~its_client_mask)) + 1u) // and add one to the result
271 & its_client_mask); // set the diagnosis address bits to zero again
272 if (increase_count++ == its_max_num_clients) {
273 VSOMEIP_ERROR << __func__ << " no free client IDs left! "
274 "Max amount of possible concurrent active vsomeip "
275 "applications reached (" << std::dec << used_clients__.size()
276 << ").";
277 return VSOMEIP_CLIENT_UNSET;
278 }
279 } while (used_clients__.find(next_client__) != used_clients__.end()
280 || _config->is_configured_client_id(next_client__));
281
282 used_clients__[next_client__] = _name;
283 return next_client__;
284 }
285
286 void
release_client_id(client_t _client)287 utility::release_client_id(client_t _client) {
288 std::lock_guard<std::mutex> its_lock(mutex__);
289 used_clients__.erase(_client);
290 }
291
292 std::set<client_t>
get_used_client_ids()293 utility::get_used_client_ids() {
294 std::lock_guard<std::mutex> its_lock(mutex__);
295 std::set<client_t> its_used_clients;
296 for (const auto& c : used_clients__)
297 its_used_clients.insert(c.first);
298 return its_used_clients;
299 }
300
reset_client_ids()301 void utility::reset_client_ids() {
302 std::lock_guard<std::mutex> its_lock(mutex__);
303 used_clients__.clear();
304 next_client__ = VSOMEIP_CLIENT_UNSET;
305 }
306
307
308
get_max_client_number(const std::shared_ptr<configuration> & _config)309 std::uint16_t utility::get_max_client_number(
310 const std::shared_ptr<configuration> &_config) {
311 std::uint16_t its_max_clients(0);
312 const int bits_for_clients =
313 #ifdef _WIN32
314 __popcnt(
315 #else
316 __builtin_popcount(
317 #endif
318 static_cast<std::uint16_t>(~_config->get_diagnosis_mask()));
319 for (int var = 0; var < bits_for_clients; ++var) {
320 its_max_clients = static_cast<std::uint16_t>(its_max_clients | (1 << var));
321 }
322 return its_max_clients;
323 }
324
325 } // namespace vsomeip_v3
326