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