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