LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - ServiceManager.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 86.2 % 260 224
Test Date: 2026-11-13 15:04:32 Functions: 88.5 % 26 23

            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/ServiceManager.h"
      12              : 
      13              : #include "someip/IServiceAnnouncer.h"
      14              : #include "someip/ServiceAnnouncerTask.h"
      15              : #include "someip/ServiceDescription.h"
      16              : #include "someip/SomeIpConstants.h"
      17              : #include "someip/logger.h"
      18              : 
      19              : #include <etl/algorithm.h>
      20              : 
      21              : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
      22              : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
      23              : 
      24              : namespace someip
      25              : {
      26              : using ::util::logger::SOMEIP;
      27              : 
      28           99 : ServiceManager::ServiceManager(ServiceList& serviceList)
      29           99 : : _services(serviceList), _pServiceAnnouncer(nullptr), _stopCalled(false)
      30           99 : {}
      31              : 
      32           28 : void ServiceManager::wire(IServiceAnnouncer* const serviceAnnouncer)
      33              : {
      34           28 :     _pServiceAnnouncer = serviceAnnouncer;
      35           28 : }
      36              : 
      37            2 : void ServiceManager::start()
      38              : {
      39            6 :     for (ProvidedService* const service : _services)
      40              :     {
      41            4 :         if (service != nullptr)
      42              :         {
      43            4 :             service->init();
      44              :         }
      45              :     }
      46              : 
      47            2 :     _stopCalled = false;
      48            2 : }
      49              : 
      50            3 : void ServiceManager::stop()
      51              : {
      52            8 :     for (ProvidedService* const service : _services)
      53              :     {
      54            5 :         if (service != nullptr)
      55              :         {
      56            5 :             if (containsEventGroup(service->description))
      57              :             {
      58            2 :                 service->setState(ProvidedService::ProvidedServiceState::IDLE_PHASE);
      59              :             }
      60            3 :             else if (ProvidedService::ProvidedServiceState::REMOVAL_PHASE != service->getState())
      61              :             {
      62            2 :                 service->setState(ProvidedService::ProvidedServiceState::DENOUNCEMENT_PHASE);
      63              :             }
      64              :             else
      65              :             {
      66              :                 // do nothing
      67              :             }
      68              :         }
      69              :     }
      70              : 
      71            3 :     _stopCalled = true;
      72            3 : }
      73              : 
      74           48 : bool ServiceManager::registerService(ProvidedService& service)
      75              : {
      76           48 :     if (hasService(service))
      77              :     {
      78            2 :         return false;
      79              :     }
      80              : 
      81           92 :     if ((service.description.serviceId == service_id::INVALID)
      82           45 :         || (service.description.majorVersion == major_version::INVALID)
      83           45 :         || (service.description.instanceId == instance_id::ANY)
      84           45 :         || (service.description.port == port::INVALID)
      85           45 :         || ((service.description.eventGroup == eventgroup_id::ALL)
      86           29 :             && (service.description.proto == SomeIpConstants::INVALID_PROTO))
      87           91 :         || (service.getHandler() == nullptr))
      88              :     {
      89            2 :         ERROR_LOG(
      90              :             SOMEIP,
      91              :             "ServiceManager::registerService(service: %d, eventgroup: %d) invalid service",
      92              :             service.description.serviceId,
      93              :             service.description.eventGroup);
      94              : 
      95            2 :         return false;
      96              :     }
      97              : 
      98           44 :     INFO_LOG(
      99              :         SOMEIP,
     100              :         "ServiceManager::registerService(service: %d, version: %d, instance: %d, eventgroup: %d)",
     101              :         service.description.serviceId,
     102              :         service.description.majorVersion,
     103              :         service.description.instanceId,
     104              :         service.description.eventGroup);
     105              : 
     106           44 :     (void)_services.insert(&service);
     107              : 
     108           44 :     service.init();
     109              : 
     110           44 :     return true;
     111              : }
     112              : 
     113           30 : bool ServiceManager::unregisterService(ProvidedService& service)
     114              : {
     115           30 :     if (!hasService(service))
     116              :     {
     117            2 :         return false;
     118              :     }
     119              : 
     120           28 :     INFO_LOG(
     121              :         SOMEIP,
     122              :         "ServiceManager::unregisterService(service: %d, version: %d, instance: %d, eventgroup: %d)",
     123              :         service.description.serviceId,
     124              :         service.description.majorVersion,
     125              :         service.description.instanceId,
     126              :         service.description.eventGroup);
     127              : 
     128              :     ServiceList::const_iterator itr = etl::find_if(
     129           28 :         _services.cbegin(),
     130            0 :         _services.cend(),
     131           57 :         [serviceId = service.description.serviceId](ProvidedService const* s)
     132           85 :         { return s && s->description.serviceId >= serviceId; });
     133           32 :     for (; itr != _services.end(); ++itr)
     134              :     {
     135           32 :         ProvidedService& entry = *(*itr);
     136              : 
     137           32 :         if (entry.description.serviceId != service.description.serviceId)
     138              :         {
     139            0 :             break;
     140              :         }
     141              : 
     142           32 :         if (&entry == &service)
     143              :         {
     144           28 :             service.setState(ProvidedService::ProvidedServiceState::REMOVAL_PHASE);
     145              : 
     146           79 :             if ((_pServiceAnnouncer == nullptr) ||         // no SD
     147           40 :                 containsEventGroup(service.description) || // event-group
     148           12 :                 _stopCalled                                // already stopped
     149              :             )
     150              :             {
     151           17 :                 auto it = _services.find(&service);
     152           17 :                 if (it != _services.end())
     153              :                 {
     154           17 :                     _services.erase(it);
     155              :                 }
     156           17 :                 service.unregisterDone();
     157              :             }
     158              : 
     159           28 :             break;
     160              :         }
     161              :     }
     162              : 
     163           28 :     return true;
     164              : }
     165              : 
     166           92 : bool ServiceManager::hasService(ProvidedService& service) const
     167              : {
     168           92 :     return _services.contains(&service);
     169              : }
     170              : 
     171            6 : bool ServiceManager::hasServiceDescription(ServiceDescription const& service) const
     172              : {
     173              :     ServiceList::const_iterator itr = etl::find_if(
     174            6 :         _services.cbegin(),
     175            0 :         _services.cend(),
     176           10 :         [serviceId = service.serviceId](ProvidedService const* s)
     177           16 :         { return s && s->description.serviceId >= serviceId; });
     178            7 :     for (; itr != _services.cend(); ++itr)
     179              :     {
     180            4 :         if ((*itr)->description.serviceId != service.serviceId)
     181              :         {
     182            0 :             break;
     183              :         }
     184              : 
     185            4 :         if (isInstanceOf(service, (*itr)->description))
     186              :         {
     187            3 :             return true;
     188              :         }
     189              :     }
     190            3 :     return false;
     191              : }
     192              : 
     193           20 : void ServiceManager::updateServices(uint64_t const time)
     194              : {
     195           20 :     bool dirty = false;
     196              : 
     197           52 :     for (ProvidedService* const servicePtr : _services)
     198              :     {
     199           32 :         ProvidedService& service = *servicePtr;
     200              : 
     201           32 :         if (ProvidedService::ProvidedServiceState::INITIAL_WAIT_PHASE == service.getState())
     202              :         {
     203            6 :             if (service.getTimestamp() == 0U)
     204              :             {
     205            4 :                 service.setTimestamp(time); // start waiting
     206              :             }
     207              : 
     208            6 :             uint32_t const timePassed = static_cast<uint32_t>(time - service.getTimestamp());
     209            6 :             if (timePassed >= service.getSdConfig()._initialDelay)
     210              :             {
     211            4 :                 if (_pServiceAnnouncer != nullptr)
     212              :                 {
     213            4 :                     _pServiceAnnouncer->offer(service.description);
     214              :                 }
     215              : 
     216            4 :                 service.setState(ProvidedService::ProvidedServiceState::REPETITION_PHASE);
     217            4 :                 service.setTimestamp(time);
     218            4 :                 service.setRepetitionCount(1U);
     219              :             }
     220              :         }
     221           26 :         else if (ProvidedService::ProvidedServiceState::REPETITION_PHASE == service.getState())
     222              :         {
     223            8 :             uint32_t const timePassed = static_cast<uint32_t>(time - service.getTimestamp());
     224              :             uint32_t const repetitionDelay
     225              :                 = (static_cast<uint32_t>(1U)
     226           16 :                    << (service.getRepetitionCount() - static_cast<uint32_t>(1U)))
     227            8 :                   * service.getSdConfig()._repetitionsBaseDelay;
     228            8 :             if (timePassed >= repetitionDelay)
     229              :             {
     230            8 :                 if (_pServiceAnnouncer != nullptr)
     231              :                 {
     232            8 :                     _pServiceAnnouncer->offer(service.description);
     233              :                 }
     234              : 
     235            8 :                 service.setTimestamp(time);
     236            8 :                 service.setRepetitionCount(service.getRepetitionCount() + 1U);
     237              : 
     238            8 :                 if (service.getRepetitionCount() >= service.getSdConfig()._repetitionsMax)
     239              :                 {
     240              :                     // round to second which will make sure that the SOME/IP SD requirement
     241              :                     // of accumulating SD entries in as little frames as possible
     242            4 :                     service.setTimestamp((time / 1000) * 1000);
     243            4 :                     service.setState(ProvidedService::ProvidedServiceState::MAIN_PHASE);
     244              :                 }
     245              :             }
     246              :         }
     247           18 :         else if (ProvidedService::ProvidedServiceState::MAIN_PHASE == service.getState())
     248              :         {
     249            4 :             uint32_t const timePassed = static_cast<uint32_t>(time - service.getTimestamp());
     250            4 :             if (timePassed >= service.getSdConfig()._cyclicOfferDelay)
     251              :             {
     252            4 :                 if (_pServiceAnnouncer != nullptr)
     253              :                 {
     254            4 :                     _pServiceAnnouncer->offer(service.description);
     255              :                 }
     256              : 
     257            4 :                 service.setTimestamp(time);
     258              :             }
     259              :         }
     260           14 :         else if (ProvidedService::ProvidedServiceState::DENOUNCEMENT_PHASE == service.getState())
     261              :         {
     262            2 :             if (_pServiceAnnouncer != nullptr)
     263              :             {
     264            2 :                 _pServiceAnnouncer->stopOffer(service.description);
     265              :             }
     266              : 
     267            2 :             service.setState(ProvidedService::ProvidedServiceState::IDLE_PHASE);
     268            2 :             service.setTimestamp(0U);
     269              :         }
     270           12 :         else if (ProvidedService::ProvidedServiceState::REMOVAL_PHASE == service.getState())
     271              :         {
     272           12 :             if (_pServiceAnnouncer != nullptr)
     273              :             {
     274           12 :                 _pServiceAnnouncer->stopOffer(service.description);
     275              :             }
     276              : 
     277           12 :             dirty = true;
     278              :         }
     279              :     }
     280              : 
     281           20 :     if (dirty)
     282              :     {
     283           11 :         removeServices();
     284              :     }
     285           20 : }
     286              : 
     287              : // private
     288           12 : void ServiceManager::removeServices()
     289              : {
     290           12 :     ServiceList::const_iterator current = _services.begin();
     291              : 
     292           29 :     while (current != _services.end())
     293              :     {
     294           17 :         if (ProvidedService::ProvidedServiceState::REMOVAL_PHASE == (*current)->getState())
     295              :         {
     296           13 :             ProvidedService& tmp = *(*current);
     297           13 :             current              = _services.erase(current);
     298           13 :             tmp.unregisterDone();
     299              :         }
     300              :         else
     301              :         {
     302            4 :             ++current;
     303              :         }
     304              :     }
     305           12 : }
     306              : 
     307            0 : instance_id::type ServiceManager::getInstanceId(ServiceDescription const& service) const
     308              : {
     309              :     ServiceList::const_iterator itr = etl::find_if(
     310            0 :         _services.cbegin(),
     311            0 :         _services.cend(),
     312            0 :         [serviceId = service.serviceId](ProvidedService const* s)
     313            0 :         { return s && s->description.serviceId >= serviceId; });
     314            0 :     for (; itr != _services.cend(); ++itr)
     315              :     {
     316            0 :         ServiceDescription const& entry = (*itr)->description;
     317              : 
     318              :         // Once we encounter a different serviceId, we've passed the possible matches
     319            0 :         if (entry.serviceId != service.serviceId)
     320              :         {
     321            0 :             WARN_LOG(
     322              :                 SOMEIP,
     323              :                 "ServiceManager::getInstanceId() - Breaking loop: encountered different serviceId");
     324            0 :             break;
     325              :         }
     326              :         // Check if the majorVersion and port match as well
     327            0 :         if (entry.majorVersion == service.majorVersion && entry.port == service.port)
     328              :         {
     329            0 :             return entry.instanceId;
     330              :         }
     331              :     }
     332              : 
     333              :     // Return an invalid instance ID if not found
     334            0 :     return instance_id::ANY;
     335              : }
     336              : 
     337            6 : ProvidedService const* ServiceManager::getService(ServiceDescription const& service) const
     338              : {
     339            6 :     if ((service.serviceId == service_id::INVALID) || (service.instanceId == instance_id::ANY)
     340            6 :         || (service.majorVersion == major_version::INVALID))
     341              :     {
     342            0 :         WARN_LOG(SOMEIP, "ServiceManager::getService() invalid key");
     343            0 :         return nullptr;
     344              :     }
     345              : 
     346              :     ServiceList::const_iterator itr = etl::find_if(
     347            6 :         _services.cbegin(),
     348            0 :         _services.cend(),
     349           12 :         [serviceId = service.serviceId](ProvidedService const* s)
     350           18 :         { return s && s->description.serviceId >= serviceId; });
     351            8 :     for (; itr != _services.cend(); ++itr)
     352              :     {
     353            5 :         ServiceDescription const& entry = (*itr)->description;
     354              : 
     355            5 :         if (entry.serviceId != service.serviceId)
     356              :         {
     357            0 :             break;
     358              :         }
     359              : 
     360            5 :         if (entry.eventGroup != eventgroup_id::ALL)
     361              :         {
     362            0 :             continue;
     363              :         }
     364            5 :         if ((service.serviceId == entry.serviceId) && (service.instanceId == entry.instanceId)
     365            4 :             && (service.majorVersion == entry.majorVersion))
     366              :         {
     367            3 :             return *itr;
     368              :         }
     369              :     }
     370              : 
     371            3 :     return nullptr;
     372              : }
     373              : 
     374           13 : ProvidedService const* ServiceManager::getEventGroup(ServiceDescription const& service) const
     375              : {
     376           13 :     if ((service.serviceId == service_id::INVALID) || (service.instanceId == instance_id::ANY)
     377           13 :         || (service.majorVersion == major_version::INVALID)
     378           13 :         || (service.eventGroup == eventgroup_id::ALL))
     379              :     {
     380            0 :         WARN_LOG(SOMEIP, "ServiceManager::getEventGroup() invalid key");
     381            0 :         return nullptr;
     382              :     }
     383              : 
     384              :     ServiceList::const_iterator itr = etl::find_if(
     385           13 :         _services.cbegin(),
     386            0 :         _services.cend(),
     387           25 :         [serviceId = service.serviceId](ProvidedService const* s)
     388           38 :         { return s && s->description.serviceId >= serviceId; });
     389           18 :     for (; itr != _services.cend(); ++itr)
     390              :     {
     391           11 :         ServiceDescription const& entry = (*itr)->description;
     392              : 
     393           11 :         if (entry.serviceId != service.serviceId)
     394              :         {
     395            0 :             break;
     396              :         }
     397              : 
     398           11 :         if (entry.eventGroup == eventgroup_id::ALL)
     399              :         {
     400            0 :             continue;
     401              :         }
     402           11 :         if ((service.serviceId == entry.serviceId) && (service.instanceId == entry.instanceId)
     403           10 :             && (service.majorVersion == entry.majorVersion)
     404            7 :             && (service.eventGroup == entry.eventGroup))
     405              :         {
     406            6 :             return *itr;
     407              :         }
     408              :     }
     409              : 
     410            7 :     return nullptr;
     411              : }
     412              : 
     413              : ServiceHandler*
     414           16 : ServiceManager::getHandler(ServiceDescription const& service, FindServiceResult& result) const
     415              : {
     416           16 :     if ((service.serviceId == service_id::INVALID)
     417           15 :         || (service.majorVersion == major_version::INVALID) || (service.port == port::INVALID)
     418           14 :         || (service.proto == SomeIpConstants::INVALID_PROTO))
     419              :     {
     420            2 :         WARN_LOG(SOMEIP, "ServiceManager::getHandler() invalid key");
     421              : 
     422            2 :         result = FindServiceResult::FIND_SERVICE_UNKNOWN;
     423            2 :         return nullptr;
     424              :     }
     425              : 
     426              :     ServiceList::const_iterator itr = etl::find_if(
     427           14 :         _services.cbegin(),
     428            0 :         _services.cend(),
     429           27 :         [serviceId = service.serviceId](ProvidedService const* s)
     430           41 :         { return s && s->description.serviceId >= serviceId; });
     431           16 :     for (; itr != _services.cend(); ++itr)
     432              :     {
     433           13 :         ServiceDescription const& entry = (*itr)->description;
     434              : 
     435           13 :         if (entry.serviceId != service.serviceId)
     436              :         {
     437            0 :             break;
     438              :         }
     439              : 
     440           13 :         if (entry.eventGroup != eventgroup_id::ALL)
     441              :         {
     442            0 :             continue;
     443              :         }
     444           13 :         if ((service.serviceId == entry.serviceId) && (service.port == entry.port)
     445           12 :             && (service.proto == entry.proto))
     446              :         {
     447           11 :             if (service.majorVersion == entry.majorVersion)
     448              :             {
     449           10 :                 result = FindServiceResult::FIND_SERVICE_OK;
     450           10 :                 return (*itr)->getHandler();
     451              :             }
     452              : 
     453            1 :             result = FindServiceResult::FIND_SERVICE_WRONG_MAJOR_VERSION;
     454            1 :             return nullptr;
     455              :         }
     456              :     }
     457              : 
     458            3 :     result = FindServiceResult::FIND_SERVICE_UNKNOWN;
     459            3 :     return nullptr;
     460              : }
     461              : 
     462            4 : void ServiceManager::triggerOffers(ServiceAnnouncerTask const& task) const
     463              : {
     464            4 :     if (_pServiceAnnouncer == nullptr)
     465              :     {
     466            0 :         return;
     467              :     }
     468              : 
     469           12 :     for (ProvidedService* const service : _services)
     470              :     {
     471            8 :         if ((service != nullptr) && (task.isSame(service->description)))
     472              :         {
     473            6 :             _pServiceAnnouncer->offer(service->description);
     474              :         }
     475              :     }
     476              : }
     477              : 
     478            3 : void ServiceManager::triggerStopOffers()
     479              : {
     480            3 :     if (!_stopCalled)
     481              :     {
     482            2 :         WARN_LOG(SOMEIP, "ServiceManager::triggerStopOffers() force stop !");
     483              : 
     484            2 :         stop();
     485              :     }
     486              : 
     487            3 :     bool dirty = false;
     488              : 
     489            8 :     for (ProvidedService* const servicePtr : _services)
     490              :     {
     491            5 :         if (servicePtr != nullptr)
     492              :         {
     493            5 :             ProvidedService& service = *servicePtr;
     494              : 
     495            5 :             if ((ProvidedService::ProvidedServiceState::DENOUNCEMENT_PHASE == service.getState())
     496            5 :                 || (ProvidedService::ProvidedServiceState::REMOVAL_PHASE == service.getState()))
     497              :             {
     498            2 :                 if (_pServiceAnnouncer != nullptr)
     499              :                 {
     500            2 :                     _pServiceAnnouncer->stopOffer(service.description);
     501              :                 }
     502              : 
     503            2 :                 if (ProvidedService::ProvidedServiceState::DENOUNCEMENT_PHASE == service.getState())
     504              :                 {
     505            1 :                     service.setState(ProvidedService::ProvidedServiceState::IDLE_PHASE);
     506            1 :                     service.setTimestamp(0U);
     507              :                 }
     508              :                 else
     509              :                 {
     510            1 :                     dirty = true;
     511              :                 }
     512              :             }
     513              :         }
     514              :     }
     515              : 
     516            3 :     if (dirty)
     517              :     {
     518            1 :         removeServices();
     519              :     }
     520            3 : }
     521              : 
     522            4 : uint16_t ServiceManager::getNumberOfServices() const
     523              : {
     524            4 :     return static_cast<uint16_t>(_services.size());
     525              : }
     526              : 
     527            2 : uint16_t ServiceManager::getMaxNumberOfServices() const
     528              : {
     529            2 :     return static_cast<uint16_t>(_services.max_size());
     530              : }
     531              : 
     532          236 : bool ServiceManager::LessThanComparator::operator()(
     533              :     ProvidedService const* const lhs, ProvidedService const* const rhs) const
     534              : {
     535          236 :     uint32_t const lhsServiceId = lhs->description.serviceId;
     536          236 :     uint32_t const rhsServiceId = rhs->description.serviceId;
     537          236 :     if (lhsServiceId != rhsServiceId)
     538              :     {
     539            6 :         return lhsServiceId < rhsServiceId;
     540              :     }
     541              : 
     542          230 :     uint32_t const lhsInstanceId = lhs->description.instanceId;
     543          230 :     uint32_t const rhsInstanceId = rhs->description.instanceId;
     544          230 :     if (lhsInstanceId != rhsInstanceId)
     545              :     {
     546            0 :         return lhsInstanceId < rhsInstanceId;
     547              :     }
     548              : 
     549          230 :     uint32_t const lhsEventGroup = lhs->description.eventGroup;
     550          230 :     uint32_t const rhsEventGroup = rhs->description.eventGroup;
     551          230 :     if (lhsEventGroup != rhsEventGroup)
     552              :     {
     553           57 :         return lhsEventGroup < rhsEventGroup;
     554              :     }
     555              : 
     556          173 :     uint32_t const lhsMajorVersion = lhs->description.majorVersion;
     557          173 :     uint32_t const rhsMajorVersion = rhs->description.majorVersion;
     558          173 :     if (lhsMajorVersion != rhsMajorVersion)
     559              :     {
     560            0 :         return lhsMajorVersion < rhsMajorVersion;
     561              :     }
     562              : 
     563          173 :     uint32_t const lhsPort = lhs->description.port;
     564          173 :     uint32_t const rhsPort = rhs->description.port;
     565          173 :     if (lhsPort != rhsPort)
     566              :     {
     567            0 :         return lhsPort < rhsPort;
     568              :     }
     569              : 
     570          173 :     uint32_t const lhsProto = lhs->description.proto;
     571          173 :     uint32_t const rhsProto = rhs->description.proto;
     572          173 :     return lhsProto < rhsProto;
     573              : }
     574              : 
     575            0 : bool ServiceManager::ServiceIdComparator::operator()(
     576              :     ProvidedService const* const lhs, uint16_t const rhs) const
     577              : {
     578            0 :     return lhs->description.serviceId < rhs;
     579              : }
     580              : 
     581              : } // namespace someip
     582              : 
     583              : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
        

Generated by: LCOV version 2.0-1