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