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

Generated by: LCOV version 2.0-1