Release 3.7.5 part 2 - #1065
Merged
duartenfonseca merged 53 commits intoAug 14, 2026
Merged
Conversation
Remove invalid tests from test_boardnet.cpp. The test_shadow_events.permute_eventgroup_sub_subscribe_before_offer and test_shadow_events.permute_eventgroup_sub_late_field_offering tests were verifying cases that should not be accepted on vSomeIP. An application should never offer an event after their service were already offered.
Increase the waiting time for the start and add a predicate. The time used in run_condition_.wait_for() was too short. Under valgrind and heavy loaded environments, the test could take longer to send the notify_one used to wake it up, causing the test to never entering the start_test method. e.g.,: 2026-06-03 14:36:34.079966 service-sample [info] Using configuration file: "debounce_filter_test_service.json". ... 2026-06-03 14:36:39.245596 service-sample [info] Starting test The logs above prove that at least more than 5000 ms passed between the start of the test and the notify_one(). To prevent this, the waiting time was increased and a predicate was added to ensure we don't lose the notification due to spurious wake up or other possible races. The logging was also improved to facilitate future analysis.
Struct based approach for the routing info command Migrate the variable-length ROUTING_INFO command to the struct-based IPC approach. Unlike the fixed-size trivial commands, each entry carries a nested, variable-length payload (an optional IPv4 endpoint plus a list of services). NoteThe former routing_info_command class is marked deprecated but remains functional -- it will be removed once all dependent code paths are migrated in follow-up PRs. For reference: 1b1d43d fb7b611 da84c20 dd4f7a8 63ee6c9 7288f6c 75a1a83
Struct based approach for the register event command Migrate the variable-length REGISTER_EVENT command to the struct-based IPC approach. Unlike the fixed-size trivial commands, each registration carries a nested, variable-length payload, so the migration introduces: NoteThe former register_events_command class is marked [[deprecated]] but remains functional -- it will be removed once all dependent code paths are migrated in follow-up PRs. For reference: 1b1d43d fb7b611 da84c20 dd4f7a8 63ee6c9 7288f6c 75a1a83
When we receive a message, this should have been "requested". If there is no corresponding handler installed, this should imply the application is doing something funky, or is about to be torn down.
Drop the obsolete libvsomeip2 compatibility hack that upgraded a plain event to a selective event Remove the ET_SELECTIVE_EVENT special-case that erased superseded plain (ET_EVENT) entries from pending_event_registrations_. No supported app registers the same event under two types; the branch is dead code.
Create regression test send_error() erases the TCP send target while its async write completion (send_cbk) is still pending; once the target is recreated by a notification and the held completion is released, send_cbk runs on an empty queue and crashes in read_uint16_be.
Change the default configuration to use only a single io-thread.
And sync them under the consumer mutex. Meanwhile the endpoints are managed together with the routing_info. This avoids ping-pong between the rmc and the emb.
stop_application_from_dispatcher_thread does what the name says - but this is exactly a scenario where an application can outlive the "user code", because of the dispatcher thread This is very problematic if both new/old application should be the router, which is exactly what breaks the following test when this tight race happens
Remove export from helpers that do not need it, and add override where sensible
Replace the two remaining security commands
Get rid of virtuals usage to build up a SOMEIP message Build SOME/IP messages directly from a message_header_impl via new constructors on message_impl/message_base_impl, instead of constructing an empty message and populating it through virtual set_* setters.
Migrate variable-sized commands (CONFIG / ASSIGN_CLIENT) to the struct-based IPC approach. This follow-up introduces config_command_data and assign_client_command_data, value-type structs carrying a command_header and a zero-copy, string_view-based payload. deserialize.hpp gains a zero-copy key-value view for CONFIG payloads and a struct-fill overload for assign_client_data. serialize.hpp is extended with constexpr-if branches for config_entry, assign_client_data, std::string_view, and generic ranges. NoteThe former config_command and assign_client_command classes are marked [[deprecated]] but remain functional -- they will be removed once all dependent code paths are migrated in follow-up PRs. While at it, thread std::string_view through lazy_load and request_client_id to defer heap allocations. Consolidate round-trip unit tests into ut_commands_roundtrip.cpp. For reference: 1b1d43d fb7b611 da84c20 dd4f7a8 63ee6c9 7288f6c 29ab425 77a61c5 f4fbc72
Clear service info only doesnt remove ports. Previously, there was a failure for services that were offered on both tcp and udp ports, where the clear of the service info would clear one of its ports, but not the other, and as such the stop offer for said service would only have one of the ports instead of 2, potentially leading to an inconsistent state of availability in a client. To fix it, don't remove any of the ports of the service info before sending the stop offer, and only call it once.
Somewhat obvious, used helpers have no syncronization at all. It also fixes test_boardnet_helper.udp_connection_refused_send
Replace subscribe_command, unsubscribe_command and expire_command
Retry unreliable suspend trigger in suspend test cases. A supposed bug in the routing manager can lead to an OfferService being sent before the UDP endpoint is ready, leading to the UDP trigger being sent too early (and thus lost) by suspend_resume_test_connections. As a workaround, resend the trigger until the expected unavailability is observed. This is intended to be a temporary measure to make the test stable despite the supposed bug. The workaround should be removed again once the bug is fixed.
Fix another source of flakyness in suspend_resume_test_initial. Remove the special case of skipping SIGUSR1 in the first iteration. Without it, the client relies on the SD offer to expire due to the 2s eth0 blip to mark the service as unavailable, and depending on timing, that expiration might not happen at all due to network being restored before TTL of the offer is reached. Additionally, first iteration never actually expired the subscription (which is the gate on top of the loop), so its resume was emitted right before the next iteration's suspend, and depending on signal ordering (which is unspecified!), this could screw up expectations.
Remove the obsolete class-based command implementations Migration to follow struct based approach is completed. The struct-based command serialization is now consolidated in serialize.hpp, deserialize.hpp and command_types.hpp. The ut_compatibility_*.cpp unit tests only existed to prove the new structs serialized byte-for-byte identically to the old classes; with the old classes gone they serve no purpose and are removed as well. Pure removal — 97 files, no functional change.
Move availability state and subscription/event-caching from application_impl into routing_manager_client. move available_state_, per-subscription state, and initial-event-received flags to routing_manager_client on_availability notifications are collected while consumer_mutex_ is held and fired after it is released, preventing a race where a concurrently registering availability handler could initialize its shadow against stale state. subscribe() now checks whether the subscription is already acknowledged: if so it immediately delivers cached events and fires the ACK locally without re-sending a subscribe message to the router. Incoming notifications are dropped at the RMC layer if no active subscription is present.
Reconnect upon receiving new client id Previously, if for some reason a client received a second assign client id ack message, it would leave the client in a inconsistent state, where it would update its client id internally, but not update security policies or its server endpoint client id. To minimize synchronization errors that might happen while updating the client id on the go, trigger a new register so that the whole registration sequence is done in a clean state.
The Android build fails compiling routing_manager_stub.cpp with clang: routing_manager_stub.cpp:1054: error: non-constant-expression cannot be narrowed from type 'vsomeip_v3::length_t' (aka 'unsigned int') to 'std::span<...>::index_type' (aka 'int') in initializer list [-Wc++11-narrowing]
Two adaptations are required: when the service turns available when the service is already available Note: This change is only for ipc. No behavior change for boardnet. Meanwhile: Simplify the parsing of command_messages.
Most of these are subtle off-by-one overflows, code that would parse specific fields from the SOME/IP header, and check that the packet had just enough length. For these overflows, incorrectly These length checks are folly - such code should instead check that the packet contains at least a SOME/IP header. It is less error-prune While at it, minor code simplifications
Add a condition to process REGISTER_EVENT with RT_UNKNOWN When a client requests an event without specifying reliability RT_UNKNOWN(255), it’s basically saying, “I, the app, don’t know / don’t care—vsomeip, figure it out yourself based on the offer.” So we should keep the reliability that’s already set instead of logging an error.
Parallelize network tests. In order to allow for full parallelization, execute network test cases inside a sandbox (via bubblewrap) isolating things like PIDs and tmpfs. Establish a private network namespace for each test run, so even lower-level communication does not interfere. Test cases invoked via CTest now are launched through a new script 'run_isolated.sh' that takes care of setting everything up; no changes are required to the test cases themselves. Many of the network test cases require access and communication to a slave container. The slave container cannot be shared with other test runs. In order to allow for parallelization of such test cases, it is possible to have Docker spin up a pool of slaves, via adding a parameter '--scale slave=N' to the invocation of 'docker compose', for example: docker compose --project-directory zuul/network-tests up --scale slave=16 This will spin up 16 slave containers in addition to the master. CTest provides a way to safely allocate [1] such slaves to specific test cases for the duration of their run, and schedules parallel test cases accordingly. To tell CTest about slave(s) being required for a particular test case, the 'add_custom_test()' function now takes a an optional argument 'SLAVES N' where N is the number of slaves required; usually 1, but more or no slaves are supported too. As a result, concurrency is now constrained by two factors: Overall concurrency limit which is defined by the number of available CPU threads, and the number of available, unused slave containers at any given time for the test cases that need them. As tests are now executed within a network sandbox, they can no longer access the slave containers directly (and in fact, on the master side the slaves get assigned dynamic IPs, which test configs cannot deal with). Instead, the isolation script creates a virtual LAN inside the sandbox and bridges the needed slave(s) into it. In order to avoid collisions with host-side communication, the isolated VXLAN uses a distinct address range 10.99.0.X, with the master being assigned 10.99.0.254 and the slave(s) being assigned consecutive IPs starting from 10.99.0.1. As these IPs are fixed both inside the sandbox and inside the slave container(s), hardcoding the value in test configs continues to work. Some test cases rely on filesystem-based communication between the host sandbox and the slave container. To make this possible, for each test case there is now a directory created (inside a tmpfs) that is both exported into the host-side sandbox under /home/shared, and on the slave side symlinked to that same path. The path is put in the test's environment as TEST_SHARED_DIR, and a utility function get_test_shared_dir() is provided for use in the C++ parts of tests. [1] https://cmake.org/cmake/help/latest/manual/ctest.1.html#ctest-resource-allocation
Demote "Service property mismatch" log from error to warning in routing_manager_impl::request_service. The routing manager already handles the mismatch gracefully, therefore WARNING suffices.
This is a behavior preserving change and serves as preliminary work to enable the local_offering_table to store multiple service, instance pairs for different major versions. It is assumed that the flat-buffer storage for the services, should be cache friendly, while still allowing wild-card searches.
fix the e2e tests Previously, in the e2e, the application was introducing 2 sleeps of 1 second upon receiving the service availability, and subscribing in the middle of the sleeps. This is wrong since the service can be subscribed before receiving the availability, and the sleep before subscribing the service would delay the subscription enough (when running with valgrind) that the client would send the subscribe very close to the next cyclic offer. If, due to valgrind delays, the client received the cyclic offer while having sent the subscribe to the service but had not received the subscribe ack, it would trigger the resending of the initial events that lead to the failure in this test. To fix this, subscribe to the service before starting and dont sleep when receiving availability,
Log buffer on endpoint receive_cbk errors Improve logging deficiencies when endpoint receive_cbk had errors. This will help debug future issues of malformed messages received
Reserve port ranges used by test cases. Prevent port ranges hardcoded in test cases to be used by the kernel for ephemeral ports. Otherwise, the kernel may have assigned a port that a test case expects to be using to something else, such as the ssh connection to a slave container. This lead to spurious test failures in the past.
Service announces availability before all endpoints are up Problem 1 — Server offers a UDP+TCP service before both endpoints are up A provider configured with both an unreliable (UDP) and a reliable (TCP) endpoint could send an OfferService that carried only one endpoint, because the SD offer was serialized in the window between the two server endpoints being created. A consumer then became available from that incomplete (e.g. TCP-only) offer and, when it sent a message to the not-yet-existing UDP endpoint, the message was dropped. Now, service_discovery_impl::are_offer_endpoints_ready() withholds the OfferService of an RT_BOTH service until both endpoints exist. Problem 2 — Consumer drops a request when the requested reliability isn't up yet On the consumer, a request looks up the remote client for the requested reliability (find_or_create_remote_client(reliable)). When a service is available through one reliability only — a genuinely single-reliability service, or the transient window while a remote ECU offers its endpoints incrementally (UDP-only offer, then UDP+TCP) — the endpoint for the other reliability does not exist yet, so the lookup returns null and the request is dropped with the same Routing info for remote service could not be found error. Now, in routing_manager_impl::send(), if the remote client for the requested reliability is missing, fall back to the other endpoint when it is valid (the service is available, so one endpoint is guaranteed reachable); only when neither exists do we keep the original error.
Fix spurious rmi::send() ERROR logs during STR teardown and normalize drop-path log format. Three send() drop paths in rmi logged ERROR for conditions that are expected during teardown: Response to deregistered client (local path): downgraded to WARNING — client intentionally disconnected, message correctly dropped. Request to remote service during suspension: downgraded to WARNING with (suspended) tag — routing info was cleared as part of the suspend procedure. Request to remote service (outside suspension): kept ERROR. All three now share a consistent format including message type.
Mark the endpoint as no longer established before reporting the disconnect. Currently, the endpoint's established state (state_) is only reset when restart() runs, but some callers (e.g., TCP send_cbk / wait_until_sent) invoke on_disconnect before restart() is called. So there's a window where the connection is already gone but the endpoint still reports is_established() as true. During that window, the disconnect path calls service_endpoint_disconnected(), which then calls on_stop_offer_service() while the SD thread concurrently runs rmi::add_routing_info(). It then read is_established() == true, and re-offer the service via on_offer_service(). Since the two transitions are unsynchronized, the re-offer can land after the stop-offer, leaving the remote service spuriously available even though the connection has dropped. To fix the issue, this PR adds a common path on the client_endpoint_impl called notify_disconnect and a new offer_service_if_established method for the routing_manager_impl, with both locking the same mutex to prevent this specific race from happening.
Drop E_MALFORMED_MESSAGE when usei receives bad length. Drop E_MALFORMED_MESSAGE in the magic cookie logic. It's neither necessary nor specified anywhere
Since we only transmit complete messages within internal communication, having to wait for more then 5s for a remainder of a message can be used as a very strong hint, that the sender might have send corrupted data.
Add handler exception logs Previously, when there was an exception in an application handler, the log printed would just be the blocking call. With this change, there is a dedicated log for exceptions, that should help the debugging.
The eventgroupinfo is a 90% boardnet class. The rmc should not use this class at all. As part of this PR the provider is already removed.
It ought to be a uint32_t so the rest of the codebase does not have to do any casting
The test sends quite a few messages, so under load it could timeout
A memory corruption was detected in SOME/IP-TP where fully overlapping segments would trigger an unsigned length underflow and lead to a crash. The received packet should correctly reassemble overlapping and duplicated segments by overwriting using the content of the first segment received. This PR fixes the incorrect segment ordering (could make a fully overlapped segment to be ordered first, though its start offset is higher) and ignore the received segment.
Unused since.. 2019, since 9befbcd
Fix crash of TCP socket closed mid send There was a crash where a subscriber's local-TCP connection was torn down while sending a message. This PR fixes that crash. The ASIO socket wrappers held their Boost socket by value, and async completion handlers only captured weak_from_this — nothing kept the underlying socket alive for the duration of a send. With more than one io-thread there is a specific case where the daemon sends a large notification over local TCP while at the same time the sockets are being destroyed due to the clients being closed causing a std::terminate(). The socket/acceptor wrappers (asio_tcp_socket, asio_udp_socket, asio_uds_socket, asio_uds_acceptor) now hold their underlying Boost socket/acceptor via std::shared_ptr, and every async operation captures a copy of that pointer into its completion handler. A unit test was failing because with sockets now outliving a reset, the test's pending async_receive_from handler reads unicast_socket_ under sync_ after the test resets it. Added a lock for the sync_ mutex.
Fix load_eventgroup silently dropping all but the first event of an eventgroup's events array due to a reused std::stringstream left in EOF state. Regression from commit b1e7bab (COVESA#840), which removed the previously local std::stringstream from the events loop. Fixed by resetting the shared converter (its_converter.str(""); its_converter.clear();) at the top of the events k-loop in implementation/configuration/src/configuration_impl.cpp. Added TEST(configuration_test, eventgroup_multiple_events), which declares an eventgroup with three events (only defined via the eventgroup) and asserts get_event_reliability() returns RT_UNRELIABLE for all three — failing under the bug (RT_UNKNOWN) and passing with the fix.
Drop orphaned SOME/IP responses/errors addressed to a consumer that no longer requests the remote service, preventing client-id-reuse cross-talk. A consumer requests a remote service and sends a request; the reply returns asynchronously. If it meanwhile deregisters, releases the service, or its connection drops and its client id is recycled to another app, the late reply reaches the host routing manager addressed to a client id that no longer requests the service and is forwarded blindly — so an unrelated app receives a response it never asked for (id-reuse cross-talk). This PR drops such replies unless the target is still a requester. Scope: only remote services via the host send(); local proxy-to-proxy bypasses it, where the receiving client drops it if no handler matches the service/instance/method, and with CommonAPI it drops by session id.
Add Sanitizers/Valgrinds log on build This information was removed by ef26b9d
Decouple consumer vs. provider error handler A routing_manager_client can be, toward the same peer, both a provider (accepted socket, for a service it offers) and a consumer (outbound socket, for a service it consumes) — two distinct local sockets keyed only by client_t. The connection-error handler did not carry the role, so an error on either socket tore down BOTH roles' state: a consumer-socket failure dropped remote subscribers of our offered services, and a provider-socket failure marked peer-offered services unavailable and closed our outbound consumer endpoint.
vsomeip-lib build was failing due to the usage of to_address.
The provider side of routing_manager_client tracked offered services in two parallel containers: provided_services_ (a services_t map of serviceinfo) and pending_offers_ (a std::setprotocol::serviceprotocol::service). The two containers held overlapping state that had to be kept in sync across offer_service, stop_offer_service, and reconnect handling. This PR merges them into a single local_service_table offered_services_, reducing the complexity of the bookkeeping.
Allow the same service instance to be offered under multiple major versions by different local applications, and let local clients consume the specific version they request. Previously the router stored at most one offer per service instance, so a second application offering the same instance under a different major version would be rejected. This change makes the routing state version-aware: The local offering table is now keyed by (service, instance, major), so offers for distinct majors of the same instance coexist. The internal service map is extended to service → instance → major → serviceinfo. Availability, requests and offers are resolved per major version, so a client only sees the version it requested become available. The existing recovery mechanisms are preserved and made version-aware: the pending-offers and pending-requests bookkeeping (used to ping a still-alive server when a client re-requests a service, or when another application tries to offer an already-offered service) now tracks the major version alongside the service instance. Scope / limitations Local offering and consuming only; no boardnet (remote) support for multiple major versions yet. No support for offering or consuming different versions within the same application. Several find_service call sites still resolve with ANY_MAJOR (marked with TODOs). These sit on the remote/boardnet paths and will be resolved as part of the boardnet enablement.
Refactor: Struct based IPC for SERVICE commands Increase TTL offer test big sd msg fix climate_test Fix double connect improve message reception error logs Synchronize pending_offers and provided_services Add sender info to error logs Batch Executions Enhancement Fix flaky test_boardnet_with_fake_sockets Refactor: Struct based to single field commands Consolidate memcheck suppressions standardize test scripts Migrate multiple_services command Optimize restart routing test remove offer commands Remove routing_manager_base Use host-provided version of Boost for network tests Fix port checks in external_local_* and routing tests Fix timing issue in suspend_resume_test_service Fix local routing test with multiple dispatcher threads Make debounce_filter test slightly more jitter-tolerant Convert blocking rmc::stop to async continuation approach Fix potential race in test_connection_restoration Fix offer stop offer Turn external_routing_ready_ into a property Fix potential hang in intial_event tests add tracking logs Upgrade compatibility to Boost 1.91 rmc: fix on_message check Refactor: Struct based to aggregate simple commands Log file descriptors Modernize service_instance_t idc23 cpp compatibility Fix header_factory_test for multi-dispatch Fix race condition in client_id_test_service Add Android NDK r25b portability gate Fake sockets - Record SOME/IP and SD messages on gate Add network-tests image pull fallback and seed job Fix a race in test_boardnet replace send command Turn last_session into a property and add mutex replace the subscribe_answer commands rmc: drop available_services_history_ Remove several magic sleeps from test cases Fix race condition in restart_routing_test Prevent double start of netlink_connector ucei: reuse receive buffer Fix race in malicious_data_tests Enforce single dispatch for big_payload tests Fix offered_services_info_test SonarQube Baseline Frequency use timer utility in rmc rmi: remove some dead code Cleanup pending event registration Fix additional boardnet tests Introduce test timeout scaling Try to make debounce_filter_test more robust under load Remove deprecated tests Harden debounce_filter_test against timing issues Refactor: Struct base approach on routing info cmd Refactor: Struct based approach for register event command log a warning when no message handler is installed Drop obsolete hack event promotion plain -> selective Create regression test for Change default number of io threads to 1 move consumer eps into rmc Ignore SQ rules due to clang-r450784d tests: fix rare application_tests failure message: minor export cleanup Replace update security commands Get rid of virtuals usage to build up a SOMEIP message Refactor: Struct based to some variable-sized commands clear service info doesnt remove ports tests: fix race in udp_connection_refused_recv replace subscribe command Retry unreliable suspend trigger in suspend test cases Fix more flakyness in suspend_resume_test_initial Drops all VSOMEIP commands former implementation move event caching to rmc Reconnect upon receiving new client id Fix Android build issues Forward only requested service version misc: fix a few overflows IDCEVO event::set_reliability error Parallelize network tests Cache Boost for Android in Artifactory Demote+Rephrase service property mismatch log refactor the local_offering_table fix e2e tests Log buffer on endpoint receive_cbk errors Nodeset Refactor Reserve port ranges used in test cases Service announces availability before all endpoints are up Logging: improves routing error logging Set established as false early on disconnect endpoints: drop unneeded errors Drop connection on suspicious message Add handler exception logs Remove the eventgroupinfo from rmc as provider simpler get_message_size tests: fix usei_fixture.corrupted_data timeout Ignore fully overlaping segments misc: dead code removal Change sockets to shared_ptrs Check eventgroup with multiple events drop remote response for recycled/released client id Add Sanitizers/Valgrinds log on build Decouple consumer vs. provider error handler fix daemon build Run the full NDK build in the android r25b job Merge pending_offers_ + provided_services_ in rmc enable multiple major version offerings
fcmonteiro
approved these changes
Aug 14, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
No description provided.