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 <vsomeip/constants.hpp>
7 #include <vsomeip/internal/logger.hpp>
8
9 #include "../include/channel_impl.hpp"
10 #include "../include/connector_impl.hpp"
11 #include "../include/defines.hpp"
12 #include "../../configuration/include/trace.hpp"
13 #include "../../utility/include/byteorder.hpp"
14
15 namespace vsomeip_v3 {
16 namespace trace {
17
18 const char *VSOMEIP_TC_DEFAULT_CHANNEL_ID = "TC";
19
get()20 std::shared_ptr<connector_impl> connector_impl::get() {
21 static std::shared_ptr<connector_impl> instance = std::make_shared<connector_impl>();
22 return instance;
23 }
24
connector_impl()25 connector_impl::connector_impl() :
26 is_enabled_(false),
27 is_sd_enabled_(false) {
28
29 channels_[VSOMEIP_TC_DEFAULT_CHANNEL_ID]
30 = std::make_shared<channel_impl>(VSOMEIP_TC_DEFAULT_CHANNEL_ID,
31 VSOMEIP_TC_DEFAULT_CHANNEL_NAME);
32 #ifdef USE_DLT
33 std::shared_ptr<DltContext> its_default_context
34 = std::make_shared<DltContext>();
35
36 contexts_[VSOMEIP_TC_DEFAULT_CHANNEL_ID] = its_default_context;
37 DLT_REGISTER_CONTEXT_LL_TS(*(its_default_context.get()),
38 VSOMEIP_TC_DEFAULT_CHANNEL_ID, VSOMEIP_TC_DEFAULT_CHANNEL_NAME,
39 DLT_LOG_INFO, DLT_TRACE_STATUS_ON);
40 #endif
41 }
42
~connector_impl()43 connector_impl::~connector_impl() {
44 reset();
45 }
46
configure(const std::shared_ptr<cfg::trace> & _configuration)47 void connector_impl::configure(const std::shared_ptr<cfg::trace> &_configuration) {
48 if (_configuration) {
49 is_enabled_ = _configuration->is_enabled_;
50 is_sd_enabled_ = _configuration->is_sd_enabled_;
51 }
52
53 if (is_enabled_) { // No need to create filters if tracing is disabled!
54 for (auto &its_channel : _configuration->channels_) {
55 if (!add_channel(its_channel->id_, its_channel->name_)) {
56 VSOMEIP_ERROR << "Channel " << its_channel->id_
57 << " has multiple definitions.";
58 }
59 }
60
61 for (auto &its_filter : _configuration->filters_) {
62 for (auto &its_channel : its_filter->channels_) {
63 std::shared_ptr<channel> its_channel_ptr = get_channel(its_channel);
64 if (its_channel_ptr) {
65 if (its_filter->is_range_) {
66 its_channel_ptr->add_filter(its_filter->matches_[0],
67 its_filter->matches_[1], its_filter->is_positive_);
68 } else {
69 its_channel_ptr->add_filter(its_filter->matches_,
70 its_filter->is_positive_);
71 }
72 }
73 }
74 }
75 }
76
77 VSOMEIP_INFO << "vsomeip tracing "
78 << (is_enabled_ ? "enabled " : "not enabled. ")
79 << ". vsomeip service discovery tracing "
80 << (is_sd_enabled_ ? "enabled " : "not enabled. ");
81 }
82
reset()83 void connector_impl::reset() {
84 #ifdef USE_DLT
85 std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_);
86 contexts_.clear();
87 #endif
88 // reset to default
89 std::lock_guard<std::mutex> its_lock_channels(channels_mutex_);
90 channels_.clear();
91 }
92
set_enabled(const bool _enabled)93 void connector_impl::set_enabled(const bool _enabled) {
94 is_enabled_ = _enabled;
95 }
96
is_enabled() const97 bool connector_impl::is_enabled() const {
98 return is_enabled_;
99 }
100
set_sd_enabled(const bool _sd_enabled)101 void connector_impl::set_sd_enabled(const bool _sd_enabled) {
102 is_sd_enabled_ = _sd_enabled;
103 }
104
is_sd_enabled() const105 bool connector_impl::is_sd_enabled() const {
106 return is_sd_enabled_;
107 }
108
is_sd_message(const byte_t * _data,uint16_t _data_size) const109 bool connector_impl::is_sd_message(const byte_t *_data, uint16_t _data_size) const {
110 if (VSOMEIP_METHOD_POS_MAX < _data_size) {
111 return (_data[VSOMEIP_SERVICE_POS_MIN] == 0xFF && _data[VSOMEIP_SERVICE_POS_MAX] == 0xFF &&
112 _data[VSOMEIP_METHOD_POS_MIN] == 0x81 && _data[VSOMEIP_METHOD_POS_MAX] == 0x00);
113 }
114 return false;
115 }
116
add_channel(const trace_channel_t & _id,const std::string & _name)117 std::shared_ptr<channel> connector_impl::add_channel(
118 const trace_channel_t &_id, const std::string &_name) {
119 std::lock_guard<std::mutex> its_channels_lock(channels_mutex_);
120
121 // check whether we already know the requested channel
122 if (channels_.find(_id) != channels_.end())
123 return nullptr;
124
125 // create new channel
126 std::shared_ptr<channel_impl> its_channel
127 = std::make_shared<channel_impl>(_id, _name);
128
129 // add channel
130 channels_[_id] = its_channel;
131
132 // register context
133 #ifdef USE_DLT
134 std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_);
135 std::shared_ptr<DltContext> its_context = std::make_shared<DltContext>();
136 contexts_[_id] = its_context;
137 DLT_REGISTER_CONTEXT_LL_TS(*(its_context.get()), _id.c_str(), _name.c_str(),
138 DLT_LOG_INFO, DLT_TRACE_STATUS_ON);
139 #endif
140
141 return its_channel;
142 }
143
remove_channel(const trace_channel_t & _id)144 bool connector_impl::remove_channel(const trace_channel_t &_id) {
145 if (_id == VSOMEIP_TC_DEFAULT_CHANNEL_ID) {
146 // the default channel can not be removed
147 return false;
148 }
149
150 std::lock_guard<std::mutex> its_channels_lock(channels_mutex_);
151 bool has_removed = (channels_.erase(_id) == 1);
152 if (has_removed) {
153 // unregister context
154 #ifdef USE_DLT
155 std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_);
156 auto its_context = contexts_.find(_id);
157 if (its_context != contexts_.end()) {
158 DLT_UNREGISTER_CONTEXT(*(its_context->second.get()));
159 }
160 #endif
161 }
162
163 return true;
164 }
165
get_channel(const std::string & _id) const166 std::shared_ptr<channel> connector_impl::get_channel(const std::string &_id) const {
167 std::lock_guard<std::mutex> its_channels_lock(channels_mutex_);
168 auto its_channel = channels_.find(_id);
169 return (its_channel != channels_.end() ? its_channel->second : nullptr);
170 }
171
trace(const byte_t * _header,uint16_t _header_size,const byte_t * _data,uint16_t _data_size)172 void connector_impl::trace(const byte_t *_header, uint16_t _header_size,
173 const byte_t *_data, uint16_t _data_size) {
174 #ifdef USE_DLT
175 if (!is_enabled_)
176 return;
177
178 if (_data_size == 0)
179 return; // no data
180
181 if (is_sd_message(_data, _data_size) && !is_sd_enabled_)
182 return; // tracing of service discovery messages is disabled!
183
184 service_t its_service = VSOMEIP_BYTES_TO_WORD(
185 _data[VSOMEIP_SERVICE_POS_MIN],
186 _data[VSOMEIP_SERVICE_POS_MAX]);
187
188 // Instance is not part of the SOME/IP header, read it from the trace
189 // header
190 instance_t its_instance = VSOMEIP_BYTES_TO_WORD(
191 _header[VSOMEIP_TC_INSTANCE_POS_MIN],
192 _header[VSOMEIP_TC_INSTANCE_POS_MAX]);
193
194 method_t its_method = VSOMEIP_BYTES_TO_WORD(
195 _data[VSOMEIP_METHOD_POS_MIN],
196 _data[VSOMEIP_METHOD_POS_MAX]);
197
198 // Forward to channel if the filter set of the channel allows
199 std::lock_guard<std::mutex> its_channels_lock(channels_mutex_);
200 std::lock_guard<std::mutex> its_contexts_lock(contexts_mutex_);
201 for (auto its_channel : channels_) {
202 if (its_channel.second->matches(its_service, its_instance, its_method)) {
203 auto its_context = contexts_.find(its_channel.second->get_id());
204 if (its_context != contexts_.end()) {
205 DLT_TRACE_NETWORK_SEGMENTED(*(its_context->second.get()),
206 DLT_NW_TRACE_IPC,
207 _header_size, static_cast<void *>(const_cast<byte_t *>(_header)),
208 _data_size, static_cast<void *>(const_cast<byte_t *>(_data)));
209 } else {
210 // This should never happen!
211 VSOMEIP_ERROR << "tracing: found channel without DLT context!";
212 }
213 }
214 }
215 #else
216 (void)_header;
217 (void)_header_size;
218 (void)_data;
219 (void)_data_size;
220 #endif
221 }
222
223 } // namespace trace
224 } // namespace vsomeip_v3
225