Line data Source code
1 : /********************************************************************************
2 : * Copyright (c) 2026 Accenture
3 : *
4 : * This program and the accompanying materials are made available under the
5 : * terms of the Apache License Version 2.0 which is available at
6 : * https://www.apache.org/licenses/LICENSE-2.0
7 : *
8 : * SPDX-License-Identifier: Apache-2.0
9 : ********************************************************************************/
10 :
11 : #include "someip/SubscriptionManager.h"
12 :
13 : #include "someip/SomeIpConstants.h"
14 : #include "someip/logger.h"
15 :
16 : #include <etl/algorithm.h>
17 :
18 : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
19 : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
20 :
21 : namespace someip
22 : {
23 : using ::ip::IPAddress;
24 : using ::util::logger::SOMEIP;
25 :
26 : // protected
27 20 : SubscriptionManager::SubscriptionManager(
28 : EventGroupList& groupList,
29 : internal::EventGroupPool& groupPool,
30 20 : internal::EndpointPool& endpointPool)
31 20 : : _eventgroups(groupList), _groupPool(groupPool), _endpoints(endpointPool)
32 20 : {}
33 :
34 3 : void SubscriptionManager::stop() { clear(); }
35 :
36 3 : void SubscriptionManager::clear()
37 : {
38 67 : for (auto eg = _eventgroups.rbegin(); eg != _eventgroups.rend(); ++eg)
39 : {
40 : SubscriptionEndpointList& endpoints
41 32 : = const_cast<SubscribedEventGroup&>(**eg).getEndpoints();
42 :
43 32 : SubscriptionEndpointList::iterator endpoint = endpoints.begin();
44 32 : SubscriptionEndpointList::iterator const prev = endpoints.before_begin();
45 :
46 64 : while (endpoint != endpoints.end())
47 : {
48 32 : endpoint->clear();
49 32 : SubscriptionEndpointList::iterator const current = endpoint;
50 32 : endpoint = endpoints.erase_after(prev);
51 32 : _endpoints.release(&(*current));
52 : }
53 :
54 32 : _groupPool.release(&(**eg));
55 32 : auto it = _eventgroups.find(*eg);
56 32 : if (it != _eventgroups.end())
57 : {
58 32 : _eventgroups.erase(it);
59 : }
60 : }
61 3 : }
62 :
63 : // virtual
64 139 : SubscriptionManager::InternalSubscribeResult SubscriptionManager::addSubscription(
65 : service_id::type const serviceId,
66 : major_version::type const majorVersion,
67 : instance_id::type const instanceId,
68 : eventgroup_id::type const eventgroupId,
69 : ttl::type const ttl,
70 : IPAddress const& ipAddress,
71 : uint16_t const port)
72 : {
73 139 : SubscribedEventGroup const eventgroup(serviceId, majorVersion, instanceId, eventgroupId);
74 139 : SubscriptionEndpoint const endpoint(ipAddress, port);
75 :
76 139 : internal::FindEventGroupCondition const condition(eventgroup);
77 :
78 139 : if (!condition.isValid())
79 : {
80 0 : WARN_LOG(SOMEIP, "SubscriptionManager::addSubscription() invalid condition");
81 0 : return InternalSubscribeResult::INTERNAL_SUBSCRIBE_ERROR;
82 : }
83 :
84 139 : SubscribedEventGroup* eg = nullptr;
85 139 : bool isNew = false;
86 :
87 : EventGroupList::const_iterator const findIter
88 139 : = _eventgroups.find(const_cast<SubscribedEventGroup*>(&eventgroup));
89 139 : if (findIter != _eventgroups.end()) // already contained
90 : {
91 55 : eg = *findIter;
92 : }
93 84 : else if (_eventgroups.full()) // list full
94 : {
95 1 : WARN_LOG(SOMEIP, "SubscriptionManager::addSubscription() eventgroup list full");
96 1 : return InternalSubscribeResult::INTERNAL_SUBSCRIBE_ERROR;
97 : }
98 : else // add as new
99 : {
100 83 : DEBUG_LOG(
101 : SOMEIP,
102 : "SubscriptionManager::addSubscription(service: %d, version: %d, instance: %d, "
103 : "eventgroup: %d, ttl: %d)",
104 : serviceId,
105 : majorVersion,
106 : instanceId,
107 : eventgroupId,
108 : ttl);
109 83 : SubscribedEventGroup* seg = _groupPool.create<SubscribedEventGroup>(
110 : serviceId, majorVersion, instanceId, eventgroupId);
111 83 : eg = seg;
112 83 : (void)_eventgroups.insert(eg);
113 83 : isNew = true;
114 : }
115 :
116 138 : SubscriptionEndpointList& endpoints = eg->getEndpoints();
117 537 : for (auto& ep : endpoints)
118 : {
119 400 : if (ep == endpoint)
120 : {
121 1 : ep.ttl = ttl;
122 1 : return InternalSubscribeResult::INTERNAL_ALREADY_SUBSCRIBED;
123 : }
124 : }
125 :
126 137 : if (_endpoints.full())
127 : {
128 2 : WARN_LOG(SOMEIP, "SubscriptionManager::addSubscription() endpoint pool full");
129 :
130 2 : if (isNew)
131 : {
132 0 : _groupPool.release(eg);
133 0 : auto it = _eventgroups.find(eg);
134 0 : if (it != _eventgroups.end())
135 : {
136 0 : _eventgroups.erase(it);
137 : }
138 : }
139 :
140 2 : return InternalSubscribeResult::INTERNAL_SUBSCRIBE_ERROR;
141 : }
142 :
143 135 : SubscriptionEndpoint& ep = *_endpoints.create<SubscriptionEndpoint>();
144 135 : endpoints.push_front(ep);
145 135 : ep.setAddress(ipAddress);
146 135 : ep.setPort(port);
147 135 : ep.ttl = ttl;
148 :
149 135 : return InternalSubscribeResult::INTERNAL_SUBSCRIBE_OK;
150 139 : }
151 :
152 : // virtual
153 3 : void SubscriptionManager::removeSubscription(
154 : service_id::type const serviceId,
155 : major_version::type const majorVersion,
156 : instance_id::type const instanceId,
157 : eventgroup_id::type const eventgroupId,
158 : IPAddress const& ipAddress,
159 : uint16_t const port)
160 : {
161 3 : SubscribedEventGroup const eventgroup(serviceId, majorVersion, instanceId, eventgroupId);
162 3 : SubscriptionEndpoint const endpoint(ipAddress, port);
163 :
164 3 : internal::FindEventGroupCondition const condition(eventgroup);
165 :
166 3 : if (!condition.isValid())
167 : {
168 0 : WARN_LOG(SOMEIP, "SubscriptionManager::removeSubscription() invalid condition");
169 0 : return;
170 : }
171 :
172 : EventGroupList::const_iterator const removeIter
173 3 : = _eventgroups.find(const_cast<SubscribedEventGroup*>(&eventgroup));
174 3 : if (removeIter == _eventgroups.end())
175 : {
176 0 : return;
177 : }
178 :
179 3 : DEBUG_LOG(
180 : SOMEIP,
181 : "SubscriptionManager::removeSubscription(service: %d, version: %d, instance: %d, "
182 : "eventgroup: %d)",
183 : serviceId,
184 : majorVersion,
185 : instanceId,
186 : eventgroupId);
187 3 : SubscribedEventGroup& eg = (**removeIter);
188 :
189 3 : SubscriptionEndpointList& endpoints = eg.getEndpoints();
190 4 : for (auto& ep : endpoints)
191 : {
192 4 : if (ep == endpoint)
193 : {
194 3 : ep.clear();
195 7 : endpoints.remove_if([&ep](SubscriptionEndpoint const& e) { return &e == &ep; });
196 3 : _endpoints.release(&ep);
197 :
198 3 : if (endpoints.empty())
199 : {
200 2 : _groupPool.release(&eg);
201 2 : auto it = _eventgroups.find(&eg);
202 2 : if (it != _eventgroups.end())
203 : {
204 2 : _eventgroups.erase(it);
205 : }
206 : }
207 :
208 3 : break;
209 : }
210 : }
211 3 : }
212 :
213 : // virtual
214 2 : void SubscriptionManager::removeSubscriptions(
215 : service_id::type const serviceId,
216 : major_version::type const majorVersion,
217 : instance_id::type const instanceId,
218 : eventgroup_id::type const eventgroupId)
219 : {
220 2 : SubscribedEventGroup const eventgroup(serviceId, majorVersion, instanceId, eventgroupId);
221 :
222 2 : internal::FindEventGroupCondition const condition(eventgroup);
223 :
224 2 : if (!condition.isValid())
225 : {
226 0 : WARN_LOG(SOMEIP, "SubscriptionManager::removeSubscriptions() invalid condition");
227 0 : return;
228 : }
229 :
230 : EventGroupList::const_iterator const removeIter
231 2 : = _eventgroups.find(const_cast<SubscribedEventGroup*>(&eventgroup));
232 2 : if (removeIter == _eventgroups.end())
233 : {
234 1 : return;
235 : }
236 :
237 1 : DEBUG_LOG(
238 : SOMEIP,
239 : "SubscriptionManager::removeSubscriptions(service: %d, version: %d, instance: %d, "
240 : "eventgroup: %d)",
241 : serviceId,
242 : majorVersion,
243 : instanceId,
244 : eventgroupId);
245 1 : SubscribedEventGroup& eg = (**removeIter);
246 :
247 1 : SubscriptionEndpointList& endpoints = eg.getEndpoints();
248 : // Release all endpoints back to pool
249 3 : while (!endpoints.empty())
250 : {
251 2 : auto& ep = endpoints.front();
252 2 : ep.clear();
253 2 : endpoints.pop_front();
254 2 : _endpoints.release(&ep);
255 : }
256 1 : _groupPool.release(&eg);
257 1 : auto it = _eventgroups.find(&eg);
258 1 : if (it != _eventgroups.end())
259 : {
260 1 : _eventgroups.erase(it);
261 : }
262 2 : }
263 :
264 : // virtual
265 3 : void SubscriptionManager::removeSubscriptions(IPAddress const& ipAddress)
266 : {
267 3 : RemoveIpCondition const condition(_endpoints, ipAddress, _groupPool);
268 3 : auto it = _eventgroups.begin();
269 8 : while (it != _eventgroups.end())
270 : {
271 5 : if (condition(*it))
272 : {
273 3 : it = _eventgroups.erase(it);
274 : }
275 : else
276 : {
277 2 : ++it;
278 : }
279 : }
280 3 : }
281 :
282 : // virtual
283 1 : void SubscriptionManager::updateTTLs(uint32_t const expiredSeconds)
284 : {
285 1 : internal::RemoveExpiredTtlCondition const condition(_endpoints, expiredSeconds, _groupPool);
286 1 : auto it = _eventgroups.begin();
287 2 : while (it != _eventgroups.end())
288 : {
289 1 : if (condition(*it))
290 : {
291 1 : it = _eventgroups.erase(it);
292 : }
293 : else
294 : {
295 0 : ++it;
296 : }
297 : }
298 1 : }
299 :
300 : // virtual
301 : SubscriptionEndpointList*
302 105 : SubscriptionManager::getSubscriptions(SubscribedEventGroup const& eventgroup) const
303 : {
304 105 : internal::FindEventGroupCondition const condition(eventgroup);
305 :
306 105 : if (!condition.isValid())
307 : {
308 0 : WARN_LOG(SOMEIP, "SubscriptionManager::getSubscriptions() invalid condition");
309 0 : return nullptr;
310 : }
311 :
312 : EventGroupList::const_iterator const itr
313 105 : = _eventgroups.find(const_cast<SubscribedEventGroup*>(&eventgroup));
314 105 : if (itr != _eventgroups.end())
315 : {
316 67 : if ((*itr) != nullptr)
317 : {
318 67 : return &((*itr)->getEndpoints());
319 : }
320 : }
321 :
322 38 : return nullptr;
323 : }
324 :
325 : // virtual
326 2 : uint16_t SubscriptionManager::getCurrentNumberOfSubscriptions() const
327 : {
328 2 : return static_cast<uint16_t>(_endpoints.size());
329 : }
330 :
331 : // virtual
332 2 : uint16_t SubscriptionManager::getMaximumNumberOfSubscriptions() const
333 : {
334 2 : return static_cast<uint16_t>(_endpoints.max_size());
335 : }
336 :
337 1040 : bool SubscriptionManager::LessThanComparator::operator()(
338 : SubscribedEventGroup const* const lhs, SubscribedEventGroup const* const rhs) const
339 : {
340 1040 : if (lhs->getServiceId() != rhs->getServiceId())
341 : {
342 0 : return lhs->getServiceId() < rhs->getServiceId();
343 : }
344 :
345 1040 : if (lhs->getInstanceId() != rhs->getInstanceId())
346 : {
347 552 : return lhs->getInstanceId() < rhs->getInstanceId();
348 : }
349 :
350 488 : if (lhs->getEventgroupId() != rhs->getEventgroupId())
351 : {
352 5 : return lhs->getEventgroupId() < rhs->getEventgroupId();
353 : }
354 :
355 483 : return lhs->getMajorVersion() < rhs->getMajorVersion();
356 : }
357 :
358 3 : SubscriptionManager::RemoveIpCondition::RemoveIpCondition(
359 3 : internal::EndpointPool& endpoints, IPAddress const& ipAddr, internal::EventGroupPool& groupPool)
360 3 : : _endpoints(endpoints), _ip(ipAddr), _groupPool(groupPool)
361 3 : {}
362 :
363 5 : bool SubscriptionManager::RemoveIpCondition::operator()(
364 : SubscribedEventGroup* const eventgroup) const
365 : {
366 5 : SubscriptionEndpointList& endpoints = eventgroup->getEndpoints();
367 :
368 5 : SubscriptionEndpointList::iterator endpoint = endpoints.begin();
369 5 : SubscriptionEndpointList::iterator prev = endpoints.before_begin();
370 :
371 12 : while (endpoint != endpoints.end())
372 : {
373 7 : if (endpoint->getAddress() == _ip)
374 : {
375 5 : endpoint->clear();
376 5 : SubscriptionEndpointList::iterator const current = endpoint;
377 5 : endpoint = endpoints.erase_after(prev);
378 5 : _endpoints.release(&(*current));
379 : }
380 : else
381 : {
382 2 : prev = endpoint;
383 2 : ++endpoint;
384 : }
385 : }
386 5 : if (endpoints.empty())
387 : {
388 3 : _groupPool.release(eventgroup);
389 3 : return true;
390 : }
391 2 : return false;
392 : }
393 :
394 : namespace internal
395 : {
396 249 : FindEventGroupCondition::FindEventGroupCondition(SubscribedEventGroup const& eventgroup)
397 249 : : _eventgroup(eventgroup)
398 249 : {}
399 :
400 249 : bool FindEventGroupCondition::isValid() const
401 : {
402 : return (
403 249 : (_eventgroup.getServiceId() != service_id::INVALID)
404 249 : && (_eventgroup.getMajorVersion() != major_version::INVALID)
405 249 : && (_eventgroup.getInstanceId() != instance_id::ANY)
406 498 : && (_eventgroup.getEventgroupId() != eventgroup_id::ALL));
407 : }
408 :
409 0 : bool FindEventGroupCondition::operator()(SubscribedEventGroup const* const eventgroup) const
410 : {
411 : return (
412 0 : (_eventgroup.getServiceId() == eventgroup->getServiceId())
413 0 : && (_eventgroup.getMajorVersion() == eventgroup->getMajorVersion())
414 0 : && (_eventgroup.getInstanceId() == eventgroup->getInstanceId())
415 0 : && (_eventgroup.getEventgroupId() == eventgroup->getEventgroupId()));
416 : }
417 :
418 1 : RemoveExpiredTtlCondition::RemoveExpiredTtlCondition(
419 1 : EndpointPool& endpoints, uint32_t const ticks, internal::EventGroupPool& groupPool)
420 1 : : _endpoints(endpoints), _ticks(ticks), _groupPool(groupPool)
421 1 : {}
422 :
423 1 : bool RemoveExpiredTtlCondition::operator()(SubscribedEventGroup* const eventgroup) const
424 : {
425 1 : SubscriptionEndpointList& endpoints = eventgroup->getEndpoints();
426 :
427 1 : SubscriptionEndpointList::iterator endpoint = endpoints.begin();
428 1 : SubscriptionEndpointList::iterator prev = endpoints.before_begin();
429 :
430 17 : while (endpoint != endpoints.end())
431 : {
432 16 : uint32_t const ticks = endpoint->ttl;
433 :
434 16 : if (ticks >= _ticks)
435 : {
436 0 : endpoint->ttl = ticks - _ticks;
437 0 : prev = endpoint;
438 0 : ++endpoint;
439 : }
440 : else // expired
441 : {
442 16 : INFO_LOG(
443 : SOMEIP,
444 : "SubscriptionManager::subscriptionExpired(service: %d, version: %d, instance: %d, "
445 : "eventgroup: %d)",
446 : eventgroup->getServiceId(),
447 : eventgroup->getMajorVersion(),
448 : eventgroup->getInstanceId(),
449 : eventgroup->getEventgroupId());
450 :
451 16 : endpoint->clear();
452 16 : SubscriptionEndpointList::iterator const current = endpoint;
453 16 : endpoint = endpoints.erase_after(prev);
454 16 : _endpoints.release(&(*current));
455 : }
456 : }
457 :
458 1 : if (endpoints.empty())
459 : {
460 1 : _groupPool.release(eventgroup);
461 1 : return true;
462 : }
463 0 : return false;
464 : }
465 :
466 : } // namespace internal
467 : } // namespace someip
468 :
469 : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
|