LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - SubscriptionManager.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 88.1 % 201 177
Test Date: 2026-09-11 12:05:06 Functions: 95.0 % 20 19

            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)
        

Generated by: LCOV version 2.0-1