1 // Copyright (C) 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 #include "../include/channel_impl.hpp"
6 #include <vsomeip/internal/logger.hpp>
7 
8 namespace vsomeip_v3 {
9 namespace trace {
10 
11 const filter_id_t FILTER_ID_ERROR(0);
12 
channel_impl(const std::string & _id,const std::string & _name)13 channel_impl::channel_impl(const std::string &_id, const std::string &_name)
14     : id_(_id), name_(_name), current_filter_id_(1) {
15 }
16 
get_id() const17 std::string channel_impl::get_id() const {
18     return id_;
19 }
20 
get_name() const21 std::string channel_impl::get_name() const {
22     return name_;
23 }
24 
add_filter(const match_t & _match,bool _is_positive)25 filter_id_t channel_impl::add_filter(
26         const match_t &_match, bool _is_positive) {
27 
28     // Create a filter function
29     std::function<bool (service_t, instance_t, method_t)> its_filter_func;
30     if (std::get<0>(_match) != ANY_SERVICE) {
31         if (std::get<1>(_match) != ANY_INSTANCE) {
32             if (std::get<2>(_match) != ANY_METHOD) {
33                 its_filter_func
34                     = [_match](service_t _s, instance_t _i, method_t _m) {
35                           return (std::get<0>(_match) == _s
36                                   && std::get<1>(_match) == _i
37                                   && std::get<2>(_match) == _m);
38                       };
39             } else {
40                 its_filter_func
41                     = [_match](service_t _s, instance_t _i, method_t) {
42                           return (std::get<0>(_match) == _s
43                                   && std::get<1>(_match) == _i);
44                       };
45             }
46         } else {
47             if (std::get<2>(_match) != ANY_METHOD) {
48                 its_filter_func
49                     = [_match](service_t _s, instance_t, method_t _m) {
50                           return (std::get<0>(_match) == _s
51                                   && std::get<1>(_match) == _m);
52                       };
53             } else {
54                 its_filter_func
55                     = [_match](service_t _s, instance_t, method_t) {
56                           return (std::get<0>(_match) == _s);
57                       };
58             }
59         }
60     } else {
61         if (std::get<1>(_match) != ANY_INSTANCE) {
62             if (std::get<2>(_match) != ANY_METHOD) {
63                 its_filter_func
64                     = [_match](service_t, instance_t _i, method_t _m) {
65                           return (std::get<1>(_match) == _i
66                                   && std::get<2>(_match) == _m);
67                       };
68             } else {
69                 its_filter_func
70                     = [_match](service_t, instance_t _i, method_t) {
71                           return (std::get<1>(_match) == _i);
72                       };
73             }
74         } else {
75             if (std::get<2>(_match) != ANY_METHOD) {
76                 its_filter_func
77                     = [_match](service_t, instance_t, method_t _m) {
78                           return (std::get<2>(_match) == _m);
79                       };
80             } else {
81                 its_filter_func
82                     = [](service_t, instance_t, method_t) {
83                           return true;
84                       };
85             }
86         }
87     }
88 
89     return add_filter_intern(its_filter_func, _is_positive);
90 }
91 
add_filter(const std::vector<match_t> & _matches,bool _is_positive)92 filter_id_t channel_impl::add_filter(
93         const std::vector<match_t> &_matches, bool _is_positive) {
94     bool has_service(false);
95     bool has_instance(false);
96     bool has_method(false);
97 
98     for (auto m : _matches) {
99         if (std::get<0>(m) != ANY_SERVICE) has_service = true;
100         if (std::get<1>(m) != ANY_INSTANCE) has_instance = true;
101         if (std::get<2>(m) != ANY_METHOD) has_method = true;
102     }
103 
104     // Create a filter function
105     std::function<bool (service_t, instance_t, method_t)> its_filter_func;
106     if (has_service) {
107         if (has_instance) {
108             if (has_method) {
109                 its_filter_func
110                     = [_matches](service_t _s, instance_t _i, method_t _m) {
111                           for (const auto &m : _matches) {
112                               if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE)
113                                   && (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE)
114                                   && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) {
115                                   return true;
116                               }
117                           }
118                           return false;
119                       };
120             } else {
121                 its_filter_func
122                     = [_matches](service_t _s, instance_t _i, method_t) {
123                           for (const auto &m : _matches) {
124                               if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE)
125                                   && (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE)) {
126                                   return true;
127                               }
128                           }
129                           return false;
130                       };
131             }
132         } else {
133             if (has_method) {
134                 its_filter_func
135                     = [_matches](service_t _s, instance_t, method_t _m) {
136                           for (const auto &m : _matches) {
137                               if ((std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE)
138                                   && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) {
139                                   return true;
140                               }
141                           }
142                           return false;
143                       };
144             } else {
145                 its_filter_func
146                     = [_matches](service_t _s, instance_t, method_t) {
147                           for (auto &m : _matches) {
148                               if (std::get<0>(m) == _s || std::get<0>(m) == ANY_SERVICE) {
149                                   return true;
150                               }
151                           }
152                           return false;
153                       };
154             }
155         }
156     } else {
157         if (has_instance) {
158             if (has_method) {
159                 its_filter_func
160                     = [_matches](service_t, instance_t _i, method_t _m) {
161                           for (auto &m : _matches) {
162                               if ((std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE)
163                                   && (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD)) {
164                                   return true;
165                               }
166                           }
167                           return false;
168                       };
169             } else {
170                 its_filter_func
171                     = [_matches](service_t, instance_t _i, method_t) {
172                           for (auto &m : _matches) {
173                               if (std::get<1>(m) == _i || std::get<1>(m) == ANY_INSTANCE) {
174                                   return true;
175                               }
176                           }
177                           return false;
178                       };
179             }
180         } else {
181             if (has_method) {
182                 its_filter_func
183                     = [_matches](service_t, instance_t, method_t _m) {
184                           for (auto &m : _matches) {
185                               if (std::get<2>(m) == _m || std::get<2>(m) == ANY_METHOD) {
186                                   return true;
187                               }
188                           }
189                           return false;
190                       };
191             } else {
192                 its_filter_func
193                     = [](service_t, instance_t, method_t) {
194                           return true;
195                       };
196             }
197         }
198     }
199 
200     return add_filter_intern(its_filter_func, _is_positive);
201 }
202 
add_filter(const match_t & _from,const match_t & _to,bool _is_positive)203 filter_id_t channel_impl::add_filter(
204         const match_t &_from, const match_t &_to, bool _is_positive) {
205 
206     // Check usage of ANY_* which is forbidden here
207     if (std::get<0>(_from) == ANY_SERVICE ||
208       std::get<1>(_from) == ANY_INSTANCE ||
209       std::get<2>(_from) == ANY_METHOD ||
210       std::get<0>(_to) == ANY_SERVICE ||
211       std::get<1>(_to) == ANY_INSTANCE ||
212       std::get<2>(_to) == ANY_METHOD) {
213       VSOMEIP_ERROR << "Trace filter configuration error: "
214         "You must not use wildcards in range filters.";
215       return FILTER_ID_ERROR;
216     }
217 
218     std::function<bool (service_t, instance_t, method_t)> its_filter_func
219             = [_from, _to](service_t _s, instance_t _i, method_t _m) {
220         return (std::get<0>(_from) <= _s && _s <= std::get<0>(_to)
221                 && std::get<1>(_from) <= _i && _i <= std::get<1>(_to)
222                 && std::get<2>(_from) <= _m && _m <= std::get<2>(_to));
223     };
224 
225     return add_filter_intern(its_filter_func, _is_positive);
226 }
227 
remove_filter(filter_id_t _id)228 void channel_impl::remove_filter(filter_id_t _id) {
229     std::lock_guard<std::mutex> its_lock(mutex_);
230     positive_.erase(_id);
231     negative_.erase(_id);
232 }
233 
add_filter_intern(const filter_func_t & _func,bool _is_positive)234 filter_id_t channel_impl::add_filter_intern(const filter_func_t& _func, bool _is_positive) {
235     filter_id_t its_id = current_filter_id_.fetch_add(1);
236 
237     std::lock_guard<std::mutex> its_lock(mutex_);
238     if (_is_positive)
239         positive_[its_id] = _func;
240     else
241         negative_[its_id] = _func;
242 
243     return its_id;
244 }
245 
matches(service_t _service,instance_t _instance,method_t _method)246 bool channel_impl::matches(
247         service_t _service, instance_t _instance, method_t _method) {
248     std::lock_guard<std::mutex> its_lock(mutex_);
249 
250     // If a negative filter matches --> drop!
251     for (auto &its_filter : negative_) {
252         if (its_filter.second(_service, _instance, _method)) {
253             return false;
254         }
255     }
256 
257     // If no positive filter is defined --> forward!
258     if (positive_.size() == 0)
259         return true;
260 
261     // If a positive filter matches --> forward!
262     for (auto &its_filter : positive_) {
263         if (its_filter.second(_service, _instance, _method)) {
264             return true;
265         }
266     }
267 
268     // drop!
269     return false;
270 }
271 
272 } // namespace trace
273 } // namespace vsomeip_v3
274