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)
|