| 2576 | } |
| 2577 | |
| 2578 | void routing_manager_impl::on_pong(client_t _client) { |
| 2579 | std::vector<std::pair<service_instance_t, std::set<client_t>>> requests_to_process; |
| 2580 | { |
| 2581 | std::scoped_lock its_lock{services_state_mutex_}; |
| 2582 | std::erase_if(pending_offers_, [_client](const auto& service_iter) { |
| 2583 | auto [major, minor, new_client, old_client] = service_iter.second; |
| 2584 | if (old_client == _client) { |
| 2585 | // received pong from an application were another application wants |
| 2586 | // to offer its service, delete the other applications offer as |
| 2587 | // the current offering application is still alive |
| 2588 | VSOMEIP_ERROR << "OFFER(" << hex4(new_client) << "): [" << hex4(service_iter.first.service()) << "." |
| 2589 | << hex4(service_iter.first.instance()) << ":" << std::uint32_t(major) << "." << minor |
| 2590 | << "] was rejected as application: " << hex4(_client) << " is still alive"; |
| 2591 | return true; |
| 2592 | } |
| 2593 | return false; |
| 2594 | }); |
| 2595 | |
| 2596 | for (auto iter = pending_requests_.begin(); iter != pending_requests_.end();) { |
| 2597 | const auto& its_key = iter->first; |
| 2598 | auto& [offering_client, requesting_clients] = iter->second; |
| 2599 | |
| 2600 | if (offering_client == _client) { |
| 2601 | // Received pong from an application where another application wants to request its service. Defer request processing until |
| 2602 | // after pending_commands_mutex_ is released to keep lock ordering consistent with request/release paths. |
| 2603 | requests_to_process.emplace_back(its_key, std::move(requesting_clients)); |
| 2604 | iter = pending_requests_.erase(iter); |
| 2605 | } else { |
| 2606 | ++iter; |
| 2607 | } |
| 2608 | } |
| 2609 | } |
| 2610 | |
| 2611 | // The requests_to_process is a local stack copy extracted under lock. |
| 2612 | // Only this thread can access it, and no other thread can obtain a reference to it. |
| 2613 | // This defers processing outside the critical section to maintain lock ordering. |
| 2614 | for (const auto& [service_instance, requesting_clients] : requests_to_process) { |
| 2615 | auto service_id = service_instance.service(); |
| 2616 | auto instance_id = service_instance.instance(); |
| 2617 | protocol::service its_request(service_id, instance_id, ANY_MAJOR, ANY_MINOR); |
| 2618 | std::set<protocol::service> requests; |
| 2619 | requests.insert(its_request); |
| 2620 | |
| 2621 | for (auto client_id : requesting_clients) { |
| 2622 | request_service(client_id, service_id, instance_id, ANY_MAJOR, ANY_MINOR); |
| 2623 | if (configuration_->is_security_enabled()) { |
| 2624 | stub_->handle_credentials(client_id, requests); |
| 2625 | } |
| 2626 | stub_->handle_requests(client_id, requests); |
| 2627 | VSOMEIP_INFO << "REQUEST(" << hex4(client_id) << "): [" << hex4(service_id) << "." << hex4(instance_id) << "] processed"; |
| 2628 | } |
| 2629 | } |
| 2630 | } |
| 2631 | |
| 2632 | void routing_manager_impl::register_client_error_handler(client_t _client, const std::shared_ptr<local_endpoint>& _endpoint) { |
| 2633 | _endpoint->register_cleanup_handler([weak_self = weak_from_this(), _client](bool) { |
nothing calls this directly
no test coverage detected