LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - ServiceTracker.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 93.2 % 176 164
Test Date: 2026-09-11 12:05:06 Functions: 100.0 % 24 24

            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/ServiceTracker.h"
      12              : 
      13              : #include "bsp/timer/SystemTimer.h"
      14              : #include "someip/IServiceListener.h"
      15              : #include "someip/IServiceTrackerListener.h"
      16              : #include "someip/ServiceQuery.h"
      17              : #include "someip/SomeIpConstants.h"
      18              : #include "someip/logger.h"
      19              : 
      20              : #include <etl/algorithm.h>
      21              : 
      22              : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
      23              : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
      24              : 
      25              : namespace someip
      26              : {
      27              : using ::ip::IPAddress;
      28              : using ::util::logger::SOMEIP;
      29              : 
      30              : // protected
      31           54 : ServiceTracker::ServiceTracker(ServiceList& serviceList)
      32           54 : : _services(serviceList), _pListener(nullptr), _reliabilityConfig{0, 0}
      33           54 : {}
      34              : 
      35            1 : ServiceTracker::ServiceTracker(
      36            1 :     ServiceList& serviceList, ServiceReliabilityConfig const& reliabilityConfig)
      37            1 : : _services(serviceList), _pListener(nullptr), _reliabilityConfig(reliabilityConfig)
      38            1 : {}
      39              : 
      40           35 : void ServiceTracker::init(IServiceTrackerListener& listener)
      41              : {
      42           35 :     _services.clear();
      43           35 :     _pListener = &listener;
      44           35 : }
      45              : 
      46           46 : bool ServiceTracker::addService(ServiceDescription const& service)
      47              : {
      48           46 :     ttl::type const ttl = service.ttl;
      49           46 :     if ((ttl == 0U) || (ttl == ttl::INVALID))
      50              :     {
      51            5 :         WARN_LOG(SOMEIP, "ServiceTracker:addService() invalid ttl");
      52            5 :         return false;
      53              :     }
      54              : 
      55           41 :     internal::FindServiceCondition const condition(service);
      56           41 :     if (!condition.isValid())
      57              :     {
      58            0 :         WARN_LOG(SOMEIP, "ServiceTracker:addService() invalid condition");
      59            0 :         return false;
      60              :     }
      61              : 
      62              :     ServiceList::const_iterator const itr
      63           41 :         = ::etl::find_if(_services.begin(), _services.end(), condition);
      64              : 
      65           41 :     if (itr != _services.end()) // already contained
      66              :     {
      67            9 :         DEBUG_LOG(
      68              :             SOMEIP,
      69              :             "ServiceTracker::updateService(service: %d, version: %d, instance: %d, ttl: %d)",
      70              :             service.serviceId,
      71              :             service.majorVersion,
      72              :             service.instanceId,
      73              :             service.ttl);
      74              : 
      75            9 :         internal::TrackedService& entry = const_cast<internal::TrackedService&>(*itr);
      76            9 :         entry.serviceDescription.ttl    = service.ttl;
      77              : 
      78            9 :         if ((entry.serviceDescription.ipAddress != service.ipAddress)
      79            7 :             || (entry.serviceDescription.port != service.port)
      80           16 :             || (entry.serviceDescription.proto != service.proto))
      81              :         {
      82            4 :             entry.serviceDescription       = service;
      83            4 :             entry.lastOfferTimestamp       = getSystemTimeMs32Bit();
      84            4 :             entry.sequentialOffersReceived = 1U;
      85              : 
      86            4 :             if (_pListener != nullptr)
      87              :             {
      88            4 :                 _pListener->serviceTrackerChanged(
      89              :                     service, IServiceTrackerListener::ServiceTrackerStatus::SERVICE_CHANGED);
      90              :             }
      91              :         }
      92              :         else
      93              :         {
      94            5 :             if ((_reliabilityConfig.expectedOfferPeriodMs > 0)
      95            2 :                 && (_reliabilityConfig.offerCountThreshold > 0))
      96              :             {
      97            2 :                 uint64_t const now      = getSystemTimeMs32Bit();
      98            2 :                 uint64_t const timeDiff = static_cast<uint64_t>(now - entry.lastOfferTimestamp);
      99            2 :                 uint64_t const timeAccuracyMs = 999U;
     100            2 :                 if (timeDiff <= (_reliabilityConfig.expectedOfferPeriodMs + timeAccuracyMs))
     101              :                 {
     102            2 :                     if (entry.sequentialOffersReceived < _reliabilityConfig.offerCountThreshold)
     103              :                     {
     104            2 :                         ++(entry.sequentialOffersReceived);
     105            2 :                         if (entry.sequentialOffersReceived
     106            2 :                             == _reliabilityConfig.offerCountThreshold)
     107              :                         {
     108            1 :                             if (_pListener != nullptr)
     109              :                             {
     110            1 :                                 _pListener->serviceTrackerChanged(
     111              :                                     service,
     112              :                                     IServiceTrackerListener::ServiceTrackerStatus::
     113              :                                         SERVICE_RELIABLE);
     114              :                             }
     115              :                             else
     116              :                             {
     117              :                                 // no listener
     118              :                             }
     119              :                         }
     120              :                         else
     121              :                         {
     122              :                             // keep counting
     123              :                         }
     124              :                     }
     125              :                     else
     126              :                     {
     127              :                         // already reliable
     128              :                     }
     129              :                 }
     130              :                 else
     131              :                 {
     132              :                     // if once reliable don't go back to unreliable, that transition is done when
     133              :                     // ttl is exceeded.
     134            0 :                     if (entry.sequentialOffersReceived < _reliabilityConfig.offerCountThreshold)
     135              :                     {
     136            0 :                         entry.sequentialOffersReceived = 1U;
     137              :                     }
     138              :                     else
     139              :                     {
     140              :                         // already reliable
     141              :                     }
     142              :                 }
     143            2 :                 entry.lastOfferTimestamp = now;
     144              :             }
     145              :             else
     146              :             {
     147              :                 // reliable service feature is disabled
     148              :             }
     149              :         }
     150              :     }
     151           32 :     else if (_services.full()) // list full
     152              :     {
     153            1 :         WARN_LOG(SOMEIP, "ServiceTracker:addService() list full");
     154            1 :         return false;
     155              :     }
     156              :     else // add as new
     157              :     {
     158           31 :         INFO_LOG(
     159              :             SOMEIP,
     160              :             "ServiceTracker::addService(service: %d, version: %d, instance: %d, ttl: %d)",
     161              :             service.serviceId,
     162              :             service.majorVersion,
     163              :             service.instanceId,
     164              :             service.ttl);
     165              : 
     166           31 :         (void)_services.insert({service, 1U, getSystemTimeMs32Bit()});
     167              : 
     168           31 :         if (_pListener != nullptr)
     169              :         {
     170           30 :             _pListener->serviceTrackerChanged(
     171              :                 service, IServiceTrackerListener::ServiceTrackerStatus::SERVICE_ADDED);
     172              :         }
     173              :     }
     174              : 
     175           40 :     return true;
     176              : }
     177              : 
     178           13 : void ServiceTracker::removeService(ServiceDescription const& service)
     179              : {
     180           13 :     internal::FindServiceCondition const condition(service);
     181           13 :     if (!condition.isValid())
     182              :     {
     183            0 :         WARN_LOG(SOMEIP, "ServiceTracker:removeService() invalid condition");
     184            0 :         return;
     185              :     }
     186              : 
     187           13 :     ServiceList::size_type const before = _services.size();
     188              : 
     189           13 :     auto it = _services.begin();
     190           30 :     while (it != _services.end())
     191              :     {
     192           17 :         if (condition(*it))
     193              :         {
     194            9 :             it = _services.erase(it);
     195              :         }
     196              :         else
     197              :         {
     198            8 :             ++it;
     199              :         }
     200              :     }
     201              : 
     202           13 :     if (_services.size() < before)
     203              :     {
     204            9 :         INFO_LOG(
     205              :             SOMEIP,
     206              :             "ServiceTracker::removeService(service: %d, version: %d, instance: %d)",
     207              :             service.serviceId,
     208              :             service.majorVersion,
     209              :             service.instanceId);
     210              : 
     211            9 :         if (_pListener != nullptr)
     212              :         {
     213            8 :             _pListener->serviceTrackerChanged(
     214              :                 service, IServiceTrackerListener::ServiceTrackerStatus::SERVICE_REMOVED);
     215              :         }
     216              :     }
     217              : }
     218              : 
     219            1 : void ServiceTracker::stop() { _services.clear(); }
     220              : 
     221           10 : bool ServiceTracker::getService(ServiceDescription& service) const
     222              : {
     223           10 :     internal::FindServiceCondition const condition(service);
     224           10 :     if (!condition.isValid())
     225              :     {
     226            0 :         WARN_LOG(SOMEIP, "ServiceTracker:getService() invalid condition");
     227            0 :         return false;
     228              :     }
     229              : 
     230              :     ServiceList::const_iterator const itr
     231           10 :         = ::etl::find_if(_services.begin(), _services.end(), condition);
     232              : 
     233           10 :     if (itr != _services.end())
     234              :     {
     235            6 :         service = itr->serviceDescription;
     236            6 :         return true;
     237              :     }
     238              : 
     239            4 :     return false;
     240              : }
     241              : 
     242           10 : instance_id::type ServiceTracker::getInstanceId(ServiceDescription const& service) const
     243              : {
     244           10 :     internal::FindInstanceCondition const condition(service);
     245           10 :     if (!condition.isValid())
     246              :     {
     247            0 :         WARN_LOG(SOMEIP, "ServiceTracker:getInstanceId() invalid condition");
     248            0 :         return instance_id::ANY;
     249              :     }
     250              : 
     251              :     ServiceList::const_iterator const itr
     252           10 :         = ::etl::find_if(_services.begin(), _services.end(), condition);
     253              : 
     254           10 :     if (itr == _services.end())
     255              :     {
     256            5 :         return instance_id::ANY;
     257              :     }
     258              : 
     259            5 :     return itr->serviceDescription.instanceId;
     260              : }
     261              : 
     262            3 : void ServiceTracker::rebootDetected(IPAddress const& ipAddr)
     263              : {
     264            3 :     internal::RemoveIpCondition const condition(ipAddr, _pListener);
     265            3 :     auto it = _services.begin();
     266           10 :     while (it != _services.end())
     267              :     {
     268            7 :         if (condition(*it))
     269              :         {
     270            5 :             it = _services.erase(it);
     271              :         }
     272              :         else
     273              :         {
     274            2 :             ++it;
     275              :         }
     276              :     }
     277            3 : }
     278              : 
     279            4 : void ServiceTracker::updateTTLs(uint32_t const ticks)
     280              : {
     281            4 :     internal::UpdateTTLCondition const condition(ticks, _pListener);
     282            4 :     auto it = _services.begin();
     283           15 :     while (it != _services.end())
     284              :     {
     285           11 :         if (condition(*it))
     286              :         {
     287            3 :             it = _services.erase(it);
     288              :         }
     289              :         else
     290              :         {
     291            8 :             ++it;
     292              :         }
     293              :     }
     294            4 : }
     295              : 
     296           10 : void ServiceTracker::notifyServices(ServiceQuery& query) const
     297              : {
     298           10 :     if (query.listener == nullptr)
     299              :     {
     300            1 :         return;
     301              :     }
     302              : 
     303              :     internal::FindServiceCondition const condition(
     304            9 :         query.description, (query.description.instanceId == instance_id::ANY));
     305            9 :     if (!condition.isValid())
     306              :     {
     307            0 :         WARN_LOG(SOMEIP, "ServiceTracker:notifyServices() invalid condition");
     308            0 :         return;
     309              :     }
     310              : 
     311            9 :     ServiceList::const_iterator itr = ::etl::find_if(_services.begin(), _services.end(), condition);
     312              : 
     313           13 :     while ((itr != _services.end()) && (condition(*itr)))
     314              :     {
     315            8 :         query.listener->serviceStatusChanged(
     316            4 :             itr->serviceDescription, IServiceListener::ServiceStatus::SERVICE_AVAILABLE);
     317            4 :         ++itr;
     318              :     }
     319              : }
     320              : 
     321            5 : uint16_t ServiceTracker::getCurrentNumberOfServices() const
     322              : {
     323            5 :     return static_cast<uint16_t>(_services.size());
     324              : }
     325              : 
     326            2 : uint16_t ServiceTracker::getMaximumNumberOfServices() const
     327              : {
     328            2 :     return static_cast<uint16_t>(_services.max_size());
     329              : }
     330              : 
     331              : namespace internal
     332              : {
     333           24 : bool LessThanComparator::operator()(TrackedService const& lhs, TrackedService const& rhs) const
     334              : {
     335              :     return (
     336           24 :         (lhs.serviceDescription.serviceId < rhs.serviceDescription.serviceId)
     337           18 :         || (lhs.serviceDescription.majorVersion < rhs.serviceDescription.majorVersion)
     338           42 :         || (lhs.serviceDescription.instanceId < rhs.serviceDescription.instanceId));
     339              : }
     340              : 
     341           73 : FindServiceCondition::FindServiceCondition(
     342           73 :     ServiceDescription const& service, bool const instanceAny)
     343           73 : : _service(service), _instanceAny(instanceAny)
     344           73 : {}
     345              : 
     346           73 : bool FindServiceCondition::isValid() const
     347              : {
     348              :     return (
     349           73 :         (_service.serviceId != service_id::INVALID)
     350           73 :         && (_service.majorVersion != major_version::INVALID)
     351          146 :         && (_instanceAny || (_service.instanceId != instance_id::ANY)));
     352              : }
     353              : 
     354           82 : bool FindServiceCondition::operator()(TrackedService const& service) const
     355              : {
     356              :     return (
     357           82 :         (_service.serviceId == service.serviceDescription.serviceId)
     358           47 :         && (_service.majorVersion == service.serviceDescription.majorVersion)
     359          129 :         && (_instanceAny || (_service.instanceId == service.serviceDescription.instanceId)));
     360              : }
     361              : 
     362           10 : FindInstanceCondition::FindInstanceCondition(ServiceDescription const& service) : _service(service)
     363           10 : {}
     364              : 
     365           10 : bool FindInstanceCondition::isValid() const
     366              : {
     367              :     return (
     368           10 :         (_service.serviceId != service_id::INVALID)
     369           10 :         && (_service.majorVersion != major_version::INVALID)
     370           20 :         && (!::ip::isUnspecified(_service.ipAddress)) && (_service.port != port::INVALID));
     371              : }
     372              : 
     373           12 : bool FindInstanceCondition::operator()(TrackedService const& service) const
     374              : {
     375              :     return (
     376           12 :         (_service.serviceId == service.serviceDescription.serviceId)
     377           12 :         && (_service.majorVersion == service.serviceDescription.majorVersion)
     378           24 :         && (_service.ipAddress == service.serviceDescription.ipAddress));
     379              : }
     380              : 
     381            3 : RemoveIpCondition::RemoveIpCondition(
     382            3 :     IPAddress const& ipAddr, IServiceTrackerListener* const listener)
     383            3 : : _ip(ipAddr), _pListener(listener)
     384            3 : {}
     385              : 
     386            7 : bool RemoveIpCondition::operator()(TrackedService const& service) const
     387              : {
     388            7 :     if (service.serviceDescription.ipAddress != _ip)
     389              :     {
     390            2 :         return false;
     391              :     }
     392              : 
     393            5 :     if (_pListener != nullptr)
     394              :     {
     395            5 :         ServiceDescription temp(service.serviceDescription);
     396            5 :         temp.ttl = 0U;
     397              : 
     398            5 :         _pListener->serviceTrackerChanged(
     399              :             temp, IServiceTrackerListener::ServiceTrackerStatus::SERVICE_REMOVED);
     400              :     }
     401              : 
     402            5 :     return true;
     403              : }
     404              : 
     405            4 : UpdateTTLCondition::UpdateTTLCondition(
     406            4 :     uint32_t const ticks, IServiceTrackerListener* const listener)
     407            4 : : _ticks(ticks), _pListener(listener)
     408            4 : {}
     409              : 
     410           11 : bool UpdateTTLCondition::operator()(TrackedService const& service) const
     411              : {
     412           11 :     uint32_t const ticks = service.serviceDescription.ttl;
     413           11 :     if (ticks >= _ticks)
     414              :     {
     415            8 :         const_cast<ServiceDescription&>(service.serviceDescription).ttl = ticks - _ticks;
     416            8 :         return false;
     417              :     }
     418              : 
     419            3 :     INFO_LOG(
     420              :         SOMEIP,
     421              :         "ServiceTracker::serviceExpired(service: %d, version: %d, instance: %d)",
     422              :         service.serviceDescription.serviceId,
     423              :         service.serviceDescription.majorVersion,
     424              :         service.serviceDescription.instanceId);
     425              : 
     426            3 :     ServiceDescription temp(service.serviceDescription);
     427            3 :     temp.ttl = 0U;
     428              : 
     429            3 :     if (_pListener != nullptr)
     430              :     {
     431            3 :         _pListener->serviceTrackerChanged(
     432              :             temp, IServiceTrackerListener::ServiceTrackerStatus::SERVICE_REMOVED);
     433              :     }
     434              : 
     435            3 :     return true;
     436              : }
     437              : 
     438              : } // namespace internal
     439              : } // namespace someip
     440              : 
     441              : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
        

Generated by: LCOV version 2.0-1