LCOV - code coverage report
Current view: top level - libs/bsw/cpp2someip/src - ServiceAnnouncer.cpp (source / functions) Coverage Total Hit
Test: coverage.info Lines: 59.8 % 415 248
Test Date: 2026-11-13 15:04:32 Functions: 60.9 % 46 28

            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/ServiceAnnouncer.h"
      12              : 
      13              : #include "bsp/timer/SystemTimer.h"
      14              : #include "someip/INetwork.h"
      15              : #include "someip/IServiceRegistry.h"
      16              : #include "someip/NetworkChannel.h"
      17              : #include "someip/ProvidedService.h"
      18              : #include "someip/ServiceDescription.h"
      19              : #include "someip/SomeIpConstants.h"
      20              : #include "someip/SomeIpMessage.h"
      21              : #include "someip/Statistics.h"
      22              : #include "someip/logger.h"
      23              : 
      24              : #include <etl/algorithm.h>
      25              : 
      26              : // Logger API uses printf-style varargs for fixed diagnostic messages in this module.
      27              : // NOLINTBEGIN(cppcoreguidelines-pro-type-vararg)
      28              : 
      29              : namespace someip
      30              : {
      31              : using ::util::logger::SOMEIP;
      32              : 
      33           24 : ServiceAnnouncer::ServiceAnnouncer(
      34              :     INetwork& network,
      35              :     ServiceManager& serviceManager,
      36              :     IServiceRegistry& serviceRegistry,
      37              :     ::async::ContextType const ethernetContext,
      38              :     QueryManager& queryManager,
      39           24 :     SessionManager& sessionManager)
      40           24 : : _network(network)
      41           24 : , _serviceManager(serviceManager)
      42           24 : , _serviceRegistry(serviceRegistry)
      43           24 : , _ethernetContext(ethernetContext)
      44           24 : , _cyclicFunction(
      45           48 :       ::async::Function::CallType::create<ServiceAnnouncer, &ServiceAnnouncer::cyclic>(*this))
      46              : , _cyclicTimeout()
      47           24 : , _eventFunction(
      48              :       ::async::Function::CallType::
      49           24 :           create<ServiceAnnouncer, &ServiceAnnouncer::checkPendingTasksAndSendDueMessages>(*this))
      50              : , _eventTimeout()
      51           24 : , _messageBuilder()
      52           24 : , _messageBuffer()
      53           24 : , _isStarted(false)
      54           24 : , _taskPool()
      55           24 : , _pendingBrowseRequests()
      56           24 : , _pendingTxMessages()
      57           24 : , _queryManager(queryManager)
      58           48 : , _sessionManager(sessionManager)
      59           24 : {}
      60              : 
      61           21 : void ServiceAnnouncer::init()
      62              : {
      63           21 :     _sessionManager.init();
      64           21 :     etl::fill(_messageBuffer.begin(), _messageBuffer.end(), 0);
      65              : 
      66           21 :     _taskPool.release_all();
      67           21 :     _pendingBrowseRequests.clear();
      68           21 :     _pendingTxMessages.clear();
      69           21 : }
      70              : 
      71            1 : void ServiceAnnouncer::shutdown() { stop(); }
      72              : 
      73           22 : void ServiceAnnouncer::start()
      74              : {
      75           22 :     if (!_isStarted)
      76              :     {
      77           21 :         async::scheduleAtFixedRate(
      78           21 :             _ethernetContext,
      79              :             _cyclicFunction,
      80           21 :             _cyclicTimeout,
      81              :             CYCLE_TIME_MS,
      82              :             ::async::TimeUnit::MILLISECONDS);
      83           21 :         _isStarted = true;
      84              :     }
      85           22 : }
      86              : 
      87            1 : void ServiceAnnouncer::stop()
      88              : {
      89            1 :     if (_isStarted)
      90              :     {
      91            1 :         checkPendingTasks(getSystemTimeMs32Bit());
      92            1 :         sendStopOffers();
      93            1 :         _cyclicTimeout.cancel();
      94            1 :         _eventTimeout.cancel();
      95            1 :         _isStarted = false;
      96              :     }
      97            1 : }
      98              : 
      99            5 : void ServiceAnnouncer::respondToFindService(
     100              :     service_id::type serviceId,
     101              :     instance_id::type instanceId,
     102              :     major_version::type majorVersion,
     103              :     minor_version::type minorVersion,
     104              :     ttl::type,
     105              :     ::ip::IPAddress const& sourceIpAddress,
     106              :     bool unicast)
     107              : {
     108            5 :     if ((instanceId == instance_id::ANY) || (majorVersion == major_version::ANY)
     109            2 :         || (minorVersion == minor_version::ANY))
     110              :     {
     111            4 :         if (!_taskPool.full())
     112              :         {
     113            4 :             ServiceAnnouncerTask& task = *_taskPool.create();
     114            4 :             task.init(
     115              :                 serviceId,
     116              :                 instance_id::ANY,
     117              :                 eventgroup_id::ALL,
     118              :                 ttl::INVALID,
     119              :                 majorVersion,
     120              :                 minorVersion);
     121              : 
     122            4 :             uint32_t const delay = REQ_RES_MAX_DELAY_MS; // TODO: determine delay randomly
     123            4 :             task.setDestinationAddress(sourceIpAddress);
     124            4 :             task.setUnicast(unicast);
     125            4 :             task.setTimestamp(getSystemTimeMs32Bit() + delay);
     126            4 :             _pendingBrowseRequests.push_front(task);
     127              : 
     128            4 :             if (_taskPool.full())
     129              :             {
     130            0 :                 checkPendingTasks(getSystemTimeMs32Bit());
     131              :             }
     132              :         }
     133              :         else
     134              :         {
     135            0 :             WARN_LOG(SOMEIP, "ServiceAnnouncer::respondToFindService() task pool is full");
     136              :         }
     137            4 :     }
     138              :     else
     139              :     {
     140            1 :         auto service         = ::someip::make<ServiceDescription>();
     141            1 :         service.serviceId    = serviceId;
     142            1 :         service.majorVersion = majorVersion;
     143            1 :         service.minorVersion = minorVersion; // don't care
     144            1 :         service.instanceId   = instanceId;
     145              : 
     146            1 :         ProvidedService const* const providedService = _serviceManager.getService(service);
     147              : 
     148              :         // only answer if service is in its MAIN phase
     149            1 :         if ((providedService != nullptr)
     150            1 :             && (ProvidedService::ProvidedServiceState::MAIN_PHASE == providedService->getState()))
     151              :         {
     152            1 :             if (!_taskPool.full())
     153              :             {
     154            1 :                 ServiceAnnouncerTask& task = *_taskPool.create();
     155              : 
     156            1 :                 task.initFrom(
     157            1 :                     providedService->description,
     158              :                     sourceIpAddress,
     159              :                     unicast,
     160            1 :                     getSystemTimeMs32Bit() + REQ_RES_MIN_DELAY_MS,
     161              :                     ServiceAnnouncerTask::TaskType::TASK_ANNOUNCE);
     162              : 
     163            1 :                 _pendingTxMessages.push_front(task);
     164              : 
     165            1 :                 if (_taskPool.full())
     166              :                 {
     167            0 :                     checkPendingTasks(getSystemTimeMs32Bit());
     168              :                 }
     169              :                 else
     170              :                 {
     171            1 :                     triggerEventTimeout();
     172              :                 }
     173              :             }
     174              :             else
     175              :             {
     176            0 :                 WARN_LOG(SOMEIP, "ServiceAnnouncer::respondToFindService() task pool is full");
     177              :             }
     178              :         }
     179              :     }
     180            5 : }
     181              : 
     182            4 : void ServiceAnnouncer::respondToSubscribe(
     183              :     service_id::type const serviceId,
     184              :     instance_id::type const instanceId,
     185              :     major_version::type const majorVersion,
     186              :     uint16_t const reserved,
     187              :     eventgroup_id::type const eventgroup,
     188              :     ttl::type const ttl,
     189              :     ::ip::IPAddress const& sourceIpAddress,
     190              :     ::ip::IPAddress const& endpointIpAddress,
     191              :     uint16_t const endpointPort,
     192              :     uint8_t const endpointProto)
     193              : {
     194              :     IServiceRegistry::SubscriptionResult result;
     195            4 :     result = _serviceRegistry.subscribeReceived(
     196              :         serviceId,
     197              :         instanceId,
     198              :         majorVersion,
     199              :         eventgroup,
     200              :         ttl,
     201              :         endpointIpAddress,
     202              :         endpointPort,
     203              :         endpointProto);
     204              : 
     205            4 :     if (IServiceRegistry::SubscriptionResult::SUBSCRIBE_OK == result)
     206              :     {
     207            0 :         sendSubscribeAck(
     208              :             serviceId, instanceId, eventgroup, majorVersion, reserved, ttl, sourceIpAddress);
     209              :     }
     210            4 :     else if (IServiceRegistry::SubscriptionResult::SUBSCRIBE_OK_MULTICAST == result)
     211              :     {
     212            2 :         auto service         = ::someip::make<ServiceDescription>();
     213            2 :         service.serviceId    = serviceId;
     214            2 :         service.instanceId   = instanceId;
     215            2 :         service.majorVersion = majorVersion;
     216            2 :         service.eventGroup   = eventgroup;
     217              : 
     218            2 :         ProvidedService const* const providedService = _serviceManager.getEventGroup(service);
     219              : 
     220            2 :         if (providedService != nullptr)
     221              :         {
     222            1 :             sendSubscribeAckMulticast(
     223              :                 serviceId,
     224              :                 instanceId,
     225              :                 eventgroup,
     226              :                 majorVersion,
     227              :                 reserved,
     228              :                 ttl,
     229            1 :                 providedService->description.ipAddress,
     230            1 :                 providedService->description.port,
     231              :                 sourceIpAddress);
     232              :         }
     233              :     }
     234            2 :     else if (IServiceRegistry::SubscriptionResult::SUBSCRIBE_ERROR == result)
     235              :     {
     236            1 :         sendSubscribeNack(
     237              :             serviceId, instanceId, eventgroup, majorVersion, reserved, sourceIpAddress);
     238              :     }
     239              :     else
     240              :     {
     241              :         // misra
     242              :     }
     243            4 : }
     244              : 
     245            1 : void ServiceAnnouncer::sendSubscribeAck(
     246              :     service_id::type const serviceId,
     247              :     instance_id::type const instanceId,
     248              :     eventgroup_id::type const eventgroup,
     249              :     major_version::type const majorVersion,
     250              :     uint16_t const reserved,
     251              :     ttl::type const ttl,
     252              :     ::ip::IPAddress const& sourceIpAddress)
     253              : {
     254            1 :     ServiceAnnouncerTask task;
     255            1 :     task.init(
     256              :         serviceId, instanceId, eventgroup, ttl, majorVersion, static_cast<uint32_t>(reserved));
     257            1 :     task.setDestinationAddress(sourceIpAddress);
     258            1 :     task.setTimestamp(getSystemTimeMs32Bit() + REQ_RES_MIN_DELAY_MS);
     259            1 :     task.setType(ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE_ACK);
     260            1 :     enqueueTxMessage(task);
     261            1 : }
     262              : 
     263            2 : void ServiceAnnouncer::sendSubscribeNack(
     264              :     service_id::type const serviceId,
     265              :     instance_id::type const instanceId,
     266              :     eventgroup_id::type const eventgroup,
     267              :     major_version::type const majorVersion,
     268              :     uint16_t const reserved,
     269              :     ::ip::IPAddress const& sourceIpAddress)
     270              : {
     271            2 :     ServiceAnnouncerTask task;
     272            2 :     task.init(serviceId, instanceId, eventgroup, 0U, majorVersion, static_cast<uint32_t>(reserved));
     273            2 :     task.setDestinationAddress(sourceIpAddress);
     274            2 :     task.setTimestamp(getSystemTimeMs32Bit() + REQ_RES_MIN_DELAY_MS);
     275            2 :     task.setType(ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE_NACK);
     276            2 :     enqueueTxMessage(task);
     277            2 : }
     278              : 
     279            3 : void ServiceAnnouncer::sendSubscribeAckMulticast(
     280              :     service_id::type const serviceId,
     281              :     instance_id::type const instanceId,
     282              :     eventgroup_id::type const eventgroup,
     283              :     major_version::type const majorVersion,
     284              :     uint16_t const reserved,
     285              :     ttl::type const ttl,
     286              :     ::ip::IPAddress const& endpointAddress,
     287              :     uint16_t const endpointPort,
     288              :     ::ip::IPAddress const& sourceIpAddress)
     289              : {
     290            3 :     ServiceAnnouncerTask task;
     291            3 :     task.init(
     292              :         serviceId, instanceId, eventgroup, ttl, majorVersion, static_cast<uint32_t>(reserved));
     293            3 :     task.setProto(proto::SD_L4_PROTO_UDP);
     294            3 :     task.setEndpoint(endpointAddress, endpointPort);
     295              : 
     296            3 :     task.setDestinationAddress(sourceIpAddress);
     297            3 :     task.setTimestamp(getSystemTimeMs32Bit() + REQ_RES_MIN_DELAY_MS);
     298            3 :     task.setType(ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE_ACK_MULTICAST);
     299            3 :     enqueueTxMessage(task);
     300            3 : }
     301              : 
     302            2 : void ServiceAnnouncer::subscribe(
     303              :     ServiceDescription const& service, ::ip::IPAddress const& sourceAddress)
     304              : {
     305            2 :     if (!containsEventGroup(service))
     306              :     {
     307            1 :         return; // only event groups can be subscribed
     308              :     }
     309              : 
     310            1 :     ServiceAnnouncerTask task;
     311              : 
     312            1 :     task.initFrom(
     313              :         service,
     314              :         sourceAddress,
     315              :         false,
     316            1 :         getSystemTimeMs32Bit() + REQ_RES_MIN_DELAY_MS,
     317              :         ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE);
     318              : 
     319            1 :     task.setMinorVersion(minor_version::INVALID);
     320            1 :     task.setEndpoint(_network.getLocalIp(), service.port);
     321            1 :     enqueueTxMessage(task);
     322              : }
     323              : 
     324            3 : void ServiceAnnouncer::unsubscribe(
     325              :     ServiceDescription const& service, ::ip::IPAddress const& sourceAddress)
     326              : {
     327            3 :     if (!containsEventGroup(service))
     328              :     {
     329            1 :         return; // only event groups can be unsubscribed
     330              :     }
     331              : 
     332            2 :     ServiceAnnouncerTask task;
     333              : 
     334            2 :     task.initFrom(
     335              :         service,
     336              :         sourceAddress,
     337              :         false,
     338            2 :         getSystemTimeMs32Bit() + REQ_RES_MIN_DELAY_MS,
     339              :         ServiceAnnouncerTask::TaskType::TASK_UNSUBSCRIBE);
     340              : 
     341            2 :     task.setMinorVersion(minor_version::INVALID);
     342            2 :     task.setEndpoint(_network.getLocalIp(), service.port);
     343            2 :     enqueueTxMessage(task);
     344              : }
     345              : 
     346            1 : void ServiceAnnouncer::sendStopOffers()
     347              : {
     348            1 :     initializeMulticastMessage();
     349            1 :     _serviceManager.triggerStopOffers(); // callback stopOffer
     350            1 :     finalizeMessage();
     351            1 : }
     352              : 
     353            0 : void ServiceAnnouncer::cyclic() { checkPendingTasksAndSendDueMessages(); }
     354              : 
     355            0 : void ServiceAnnouncer::sendDueMessages()
     356              : {
     357            0 :     initializeMulticastMessage();
     358            0 :     addProvidedServices(getSystemTimeMs32Bit());
     359            0 :     addQueries();
     360            0 :     finalizeMessage();
     361            0 : }
     362              : 
     363            9 : void ServiceAnnouncer::enqueueTxMessage(ServiceAnnouncerTask const& txMessage)
     364              : {
     365            9 :     if (!_taskPool.full())
     366              :     {
     367            9 :         ServiceAnnouncerTask& task = *_taskPool.create();
     368            9 :         task                       = txMessage;
     369            9 :         _pendingTxMessages.push_front(task);
     370              : 
     371            9 :         if (_taskPool.full())
     372              :         {
     373            0 :             checkPendingTasks(getSystemTimeMs32Bit());
     374              :         }
     375              :         else
     376              :         {
     377            9 :             triggerEventTimeout();
     378              :         }
     379              :     }
     380              :     else
     381              :     {
     382            0 :         WARN_LOG(SOMEIP, "ServiceAnnouncer::enqueueTxMessage() task pool is empty");
     383              :     }
     384            9 : }
     385              : 
     386            4 : void ServiceAnnouncer::checkPendingTasks(uint64_t const now)
     387              : {
     388            4 :     tPendingTaskList::iterator itr  = _pendingBrowseRequests.begin();
     389            4 :     tPendingTaskList::iterator prev = _pendingBrowseRequests.before_begin();
     390            4 :     while (itr != _pendingBrowseRequests.end())
     391              :     {
     392            0 :         if (itr->getTimestamp() <= now)
     393              :         {
     394            0 :             auto& task = *itr;
     395            0 :             initializeUnicastMessage(task.getDestinationAddress());
     396            0 :             ::ip::IPAddress const currentDestination = task.getDestinationAddress();
     397            0 :             processTaskBrowseResults(task);
     398            0 :             itr = _pendingBrowseRequests.erase_after(prev);
     399            0 :             releaseTask(task);
     400              : 
     401            0 :             while ((itr != _pendingBrowseRequests.end())
     402            0 :                    && (itr->getDestinationAddress() == currentDestination))
     403              :             {
     404            0 :                 if (itr->getTimestamp() <= now)
     405              :                 {
     406            0 :                     auto& followUpTask = *itr;
     407            0 :                     processTaskBrowseResults(followUpTask);
     408            0 :                     itr = _pendingBrowseRequests.erase_after(prev);
     409            0 :                     releaseTask(followUpTask);
     410              :                 }
     411              :                 else
     412              :                 {
     413            0 :                     prev = itr;
     414            0 :                     ++itr;
     415              :                 }
     416              :             }
     417            0 :             finalizeMessage();
     418              :         }
     419              :         else
     420              :         {
     421            0 :             prev = itr;
     422            0 :             ++itr;
     423              :         }
     424              :     }
     425              : 
     426            7 :     while (!_pendingTxMessages.empty())
     427              :     {
     428            3 :         ServiceAnnouncerTask& task = _pendingTxMessages.front();
     429            3 :         initializeUnicastMessage(task.getDestinationAddress());
     430            3 :         ::ip::IPAddress const currentDestination = task.getDestinationAddress();
     431            3 :         executeTask(task);
     432            3 :         _pendingTxMessages.pop_front();
     433            3 :         releaseTask(task);
     434              : 
     435            3 :         while ((!_pendingTxMessages.empty())
     436            3 :                && (_pendingTxMessages.front().getDestinationAddress() == currentDestination))
     437              :         {
     438            0 :             ServiceAnnouncerTask& followUpTask = _pendingTxMessages.front();
     439            0 :             executeTask(followUpTask);
     440            0 :             _pendingTxMessages.pop_front();
     441            0 :             releaseTask(followUpTask);
     442              :         }
     443            3 :         finalizeMessage();
     444              :     }
     445            4 : }
     446              : 
     447            0 : void ServiceAnnouncer::checkPendingTasksAndSendDueMessages()
     448              : {
     449            0 :     checkPendingTasks(getSystemTimeMs32Bit());
     450            0 :     sendDueMessages();
     451            0 : }
     452              : 
     453           10 : void ServiceAnnouncer::triggerEventTimeout()
     454              : {
     455           10 :     if (!_isStarted)
     456              :     {
     457            0 :         return;
     458              :     }
     459              : 
     460           10 :     _eventTimeout.cancel();
     461           10 :     async::schedule(
     462           10 :         _ethernetContext, _eventFunction, _eventTimeout, 1U, ::async::TimeUnit::MILLISECONDS);
     463              : }
     464              : 
     465            3 : void ServiceAnnouncer::executeTask(ServiceAnnouncerTask const& task)
     466              : {
     467            3 :     switch (task.getType())
     468              :     {
     469            0 :         case ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE:
     470              :         {
     471            0 :             processTaskSubscribe(task);
     472            0 :             break;
     473              :         }
     474            0 :         case ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE_ACK:
     475              :         {
     476            0 :             processTaskSubscribeAck(task);
     477            0 :             break;
     478              :         }
     479            0 :         case ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE_NACK:
     480              :         {
     481            0 :             processTaskSubscribeNack(task);
     482            0 :             break;
     483              :         }
     484            2 :         case ServiceAnnouncerTask::TaskType::TASK_SUBSCRIBE_ACK_MULTICAST:
     485              :         {
     486            2 :             processTaskSubscribeAckMulticast(task);
     487            2 :             break;
     488              :         }
     489            1 :         case ServiceAnnouncerTask::TaskType::TASK_UNSUBSCRIBE:
     490              :         {
     491            1 :             processTaskUnsubscribe(task);
     492            1 :             break;
     493              :         }
     494            0 :         case ServiceAnnouncerTask::TaskType::TASK_ANNOUNCE:
     495              :         {
     496            0 :             processTaskOffer(task);
     497            0 :             break;
     498              :         }
     499            0 :         default:
     500              :         {
     501            0 :             WARN_LOG(SOMEIP, "ServiceAnnouncer::executeTask() invalid task %d", task.getType());
     502            0 :             break;
     503              :         }
     504              :     }
     505            3 : }
     506              : 
     507            1 : void ServiceAnnouncer::initializeMulticastMessage()
     508              : {
     509              :     /*
     510              :      * No need to check the result of 'startMessage' if we know that provided message buffer
     511              :      * is enough to contain at least header at ServiceAnnouncer construction stage.
     512              :      * Message buffer is declared as a static array.
     513              :      */
     514            1 :     (void)_messageBuilder.startMessage(_messageBuffer);
     515            1 :     _destinationAddress = _network.getMulticastIp();
     516            1 : }
     517              : 
     518            3 : void ServiceAnnouncer::initializeUnicastMessage(::ip::IPAddress const& destinationAddress)
     519              : {
     520              :     /*
     521              :      * No need to check the result of 'startMessage' if we know that provided message buffer
     522              :      * is enough to contain at least header at ServiceAnnouncer construction stage.
     523              :      * Message buffer is declared as a static array.
     524              :      */
     525            3 :     (void)_messageBuilder.startMessage(_messageBuffer);
     526            3 :     _destinationAddress = destinationAddress;
     527            3 : }
     528              : 
     529            4 : void ServiceAnnouncer::finalizeMessage()
     530              : {
     531            4 :     if (_messageBuilder.isEmpty())
     532              :     {
     533            2 :         _messageBuilder.discardMessage();
     534              :     }
     535              :     else
     536              :     {
     537            2 :         uint16_t sessionId = 0U;
     538            2 :         bool rebootFlag    = false;
     539            2 :         getSessionInfoForNextMessage(sessionId, rebootFlag);
     540            2 :         (void)_messageBuilder.finishMessage(sessionId, rebootFlag);
     541              : 
     542            2 :         sendMessage();
     543              :     }
     544            4 :     etl::fill(_messageBuffer.begin(), _messageBuffer.end(), 0);
     545            4 : }
     546              : 
     547            2 : void ServiceAnnouncer::getSessionInfoForNextMessage(uint16_t& sessionId, bool& rebootFlag)
     548              : {
     549            2 :     if (_destinationAddress == _network.getMulticastIp())
     550              :     {
     551            0 :         _sessionManager.getSessionInfoForNextMulticastMessage(sessionId, rebootFlag);
     552              :     }
     553              :     else
     554              :     {
     555            2 :         _sessionManager.getSessionInfoForNextUnicastMessage(
     556            2 :             _destinationAddress, sessionId, rebootFlag);
     557              :     }
     558            2 : }
     559              : 
     560            0 : void ServiceAnnouncer::processTaskOffer(ServiceAnnouncerTask const& task)
     561              : {
     562            0 :     auto service = ::someip::make<ServiceDescription>();
     563            0 :     task.copyTo(service);
     564              : 
     565            0 :     addOffer(service);
     566            0 : }
     567              : 
     568            0 : void ServiceAnnouncer::processTaskBrowseResults(ServiceAnnouncerTask const& task) const
     569              : {
     570            0 :     _serviceManager.triggerOffers(task); // callback offer
     571            0 : }
     572              : 
     573            0 : void ServiceAnnouncer::processTaskSubscribe(ServiceAnnouncerTask const& task)
     574              : {
     575            0 :     if (!task.containsEventGroup())
     576              :     {
     577            0 :         return;
     578              :     }
     579              : 
     580            0 :     auto service = ::someip::make<ServiceDescription>();
     581            0 :     task.copyTo(service);
     582              : 
     583            0 :     addSubscribe(service);
     584              : }
     585              : 
     586            0 : void ServiceAnnouncer::processTaskSubscribeAck(ServiceAnnouncerTask const& task)
     587              : {
     588            0 :     auto service = ::someip::make<ServiceDescription>();
     589            0 :     task.copyTo(service);
     590              : 
     591            0 :     addSubscribeAck(service);
     592            0 : }
     593              : 
     594            0 : void ServiceAnnouncer::processTaskSubscribeNack(ServiceAnnouncerTask const& task)
     595              : {
     596            0 :     auto service = ::someip::make<ServiceDescription>();
     597            0 :     task.copyTo(service);
     598              : 
     599            0 :     addSubscribeNack(service);
     600            0 : }
     601              : 
     602            2 : void ServiceAnnouncer::processTaskSubscribeAckMulticast(ServiceAnnouncerTask const& task)
     603              : {
     604            2 :     if (!task.containsEventGroup())
     605              :     {
     606            1 :         return;
     607              :     }
     608              : 
     609            1 :     auto service = ::someip::make<ServiceDescription>();
     610            1 :     task.copyTo(service);
     611              : 
     612            1 :     addSubscribeAckMulticast(service);
     613              : }
     614              : 
     615            1 : void ServiceAnnouncer::processTaskUnsubscribe(ServiceAnnouncerTask const& task)
     616              : {
     617            1 :     if (!task.containsEventGroup())
     618              :     {
     619            0 :         return;
     620              :     }
     621              : 
     622            1 :     auto service = ::someip::make<ServiceDescription>();
     623            1 :     task.copyTo(service);
     624              : 
     625            1 :     addUnsubscribe(service);
     626              : }
     627              : 
     628            3 : void ServiceAnnouncer::releaseTask(ServiceAnnouncerTask& task)
     629              : {
     630            3 :     task.clear();
     631            3 :     _taskPool.release(&task);
     632            3 : }
     633              : 
     634            0 : void ServiceAnnouncer::addProvidedServices(uint64_t const now)
     635              : {
     636            0 :     _serviceManager.updateServices(now); // callback offer / stopOffer
     637            0 : }
     638              : 
     639            0 : void ServiceAnnouncer::addQueries() const
     640              : {
     641            0 :     uint64_t const now = getSystemTimeMs32Bit();
     642            0 :     _queryManager.updateQueries(now); // callback to ServiceAnnouncer::find()
     643            0 : }
     644              : 
     645            0 : void ServiceAnnouncer::find(ServiceDescription const& service)
     646              : {
     647              :     // find service
     648            0 :     resetIfFull(_messageBuilder.addFind(
     649            0 :         service.serviceId,
     650            0 :         service.instanceId,
     651            0 :         service.majorVersion,
     652            0 :         service.minorVersion,
     653            0 :         service.ttl));
     654            0 : }
     655              : 
     656            0 : void ServiceAnnouncer::offer(ServiceDescription const& service)
     657              : {
     658            0 :     ServiceDescription temp(service);
     659            0 :     addOffer(temp);
     660            0 : }
     661              : 
     662            0 : void ServiceAnnouncer::addOffer(ServiceDescription& service)
     663              : {
     664            0 :     if (containsEventGroup(service))
     665              :     {
     666            0 :         return; // eventgroups are not announced, only services
     667              :     }
     668              : 
     669            0 :     service.ipAddress = _network.getLocalIp();
     670            0 :     resetIfFull(_messageBuilder.addOffer(
     671            0 :         service.serviceId,
     672            0 :         service.instanceId,
     673            0 :         service.majorVersion,
     674              :         service.minorVersion,
     675              :         service.ttl,
     676            0 :         service.ipAddress,
     677            0 :         service.port,
     678            0 :         service.proto));
     679              : }
     680              : 
     681            0 : void ServiceAnnouncer::stopOffer(ServiceDescription const& service)
     682              : {
     683            0 :     ServiceDescription temp(service);
     684            0 :     addStopOffer(temp);
     685            0 : }
     686              : 
     687            0 : void ServiceAnnouncer::addStopOffer(ServiceDescription& service)
     688              : {
     689            0 :     if (containsEventGroup(service))
     690              :     {
     691            0 :         return; // eventgroups are not announced, only services
     692              :     }
     693              : 
     694            0 :     service.ipAddress = _network.getLocalIp();
     695            0 :     resetIfFull(_messageBuilder.addDenounce(
     696            0 :         service.serviceId,
     697            0 :         service.instanceId,
     698            0 :         service.majorVersion,
     699              :         service.minorVersion,
     700              :         service.ttl,
     701            0 :         service.ipAddress,
     702            0 :         service.port,
     703            0 :         service.proto));
     704              : }
     705              : 
     706            0 : void ServiceAnnouncer::addSubscribe(ServiceDescription& service)
     707              : {
     708            0 :     service.ipAddress = _network.getLocalIp();
     709            0 :     resetIfFull(_messageBuilder.addSubscribe(
     710            0 :         service.serviceId,
     711            0 :         service.instanceId,
     712            0 :         service.eventGroup,
     713            0 :         service.majorVersion,
     714              :         service.ttl,
     715            0 :         service.ipAddress,
     716            0 :         service.port,
     717            0 :         service.proto));
     718            0 : }
     719              : 
     720            1 : void ServiceAnnouncer::addUnsubscribe(ServiceDescription& service)
     721              : {
     722            1 :     service.ipAddress = _network.getLocalIp();
     723            1 :     resetIfFull(_messageBuilder.addUnsubscribe(
     724            1 :         service.serviceId,
     725            1 :         service.instanceId,
     726            1 :         service.eventGroup,
     727            1 :         service.majorVersion,
     728              :         service.ttl,
     729            1 :         service.ipAddress,
     730            1 :         service.port,
     731            1 :         service.proto));
     732            1 : }
     733              : 
     734            0 : void ServiceAnnouncer::addSubscribeAck(ServiceDescription const& service)
     735              : {
     736            0 :     resetIfFull(_messageBuilder.addSubscribeAck(
     737            0 :         service.serviceId,
     738            0 :         service.instanceId,
     739            0 :         service.eventGroup,
     740            0 :         service.majorVersion,
     741            0 :         service.minorVersion,
     742            0 :         service.ttl));
     743            0 : }
     744              : 
     745            1 : void ServiceAnnouncer::addSubscribeAckMulticast(ServiceDescription const& service)
     746              : {
     747            1 :     resetIfFull(_messageBuilder.addSubscribeAckMulticast(
     748            1 :         service.serviceId,
     749            1 :         service.instanceId,
     750            1 :         service.eventGroup,
     751            1 :         service.majorVersion,
     752            1 :         service.minorVersion,
     753            1 :         service.ttl,
     754            1 :         service.ipAddress,
     755            1 :         service.port,
     756            1 :         service.proto));
     757            1 : }
     758              : 
     759            0 : void ServiceAnnouncer::addSubscribeNack(ServiceDescription const& service)
     760              : {
     761            0 :     resetIfFull(_messageBuilder.addSubscribeNack(
     762            0 :         service.serviceId,
     763            0 :         service.instanceId,
     764            0 :         service.eventGroup,
     765            0 :         service.majorVersion,
     766            0 :         service.minorVersion,
     767            0 :         service.ttl));
     768            0 : }
     769              : 
     770            2 : void ServiceAnnouncer::resetIfFull(SdMessageReturnCode const returnCode)
     771              : {
     772            2 :     if (returnCode == SdMessageReturnCode::SD_MESSAGE_IS_FULL)
     773              :     {
     774            0 :         finalizeMessage();
     775              :         /*
     776              :          * No need to check the result of 'startMessage' if we know that provided message buffer
     777              :          * is enough to contain at least header at ServiceAnnouncer construction stage.
     778              :          * Message buffer is declared as a static array.
     779              :          */
     780            0 :         (void)_messageBuilder.startMessage(_messageBuffer);
     781              :     }
     782            2 : }
     783              : 
     784            2 : void ServiceAnnouncer::sendMessage()
     785              : {
     786            2 :     auto const portResult = _network.getSdPort();
     787              : 
     788            2 :     if (!portResult.has_value())
     789              :     {
     790            0 :         WARN_LOG(SOMEIP, "ServiceAnnouncer::sendMessage() no SD port available");
     791            0 :         return;
     792              :     }
     793              : 
     794            2 :     uint16_t const port = portResult.value();
     795              : 
     796            2 :     auto channel = _network.getSdChannel(port, ::ip::IPEndpoint(_destinationAddress, port));
     797              : 
     798            2 :     if (!channel.has_value())
     799              :     {
     800            2 :         WARN_LOG(SOMEIP, "ServiceAnnouncer::sendMessage() no channel");
     801            2 :         return;
     802              :     }
     803              : 
     804            0 :     uint32_t const length = readTotalLength(_messageBuffer);
     805            0 :     memcpy(channel->getOutputBuffer().data(), _messageBuffer.data(), length);
     806              : 
     807            0 :     if (!channel->send(length))
     808              :     {
     809            0 :         WARN_LOG(SOMEIP, "ServiceAnnouncer::sendMessage() send failed");
     810            0 :         return;
     811              :     }
     812              : 
     813            0 :     Statistics::incCounter(Statistics::Counter::SD_FRAME_TX);
     814            2 : }
     815              : 
     816              : } // namespace someip
     817              : 
     818              : // NOLINTEND(cppcoreguidelines-pro-type-vararg)
        

Generated by: LCOV version 2.0-1