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