Skip to main content

RuntimeConfig

Struct RuntimeConfig 

Source
pub struct RuntimeConfig {
Show 27 fields pub tick_period: Duration, pub spdp_period: Duration, pub initial_announce_count: u32, pub initial_announce_period: Duration, pub spdp_multicast_group: Ipv4Addr, pub multicast_interface: Ipv4Addr, pub spdp_multicast_send: bool, pub discovery_server: bool, pub max_reassembly_sample_bytes: usize, pub initial_peers: Vec<Locator>, pub user_transport: Option<UserTransportKind>, pub user_transports: Vec<UserTransportKind>, pub announce_secure_endpoints: bool, pub enable_secure_spdp: bool, pub wlp_period: Duration, pub participant_lease_duration: Duration, pub user_data: Vec<u8>, pub observability: SharedSink, pub recv_thread_priority: Option<i32>, pub tick_thread_priority: Option<i32>, pub recv_thread_cpus: Option<Vec<usize>>, pub tick_thread_cpus: Option<Vec<usize>>, pub extra_recv_threads: usize, pub data_representation_offer: Vec<i16>, pub data_rep_match_mode: DataRepMatchMode, pub external_tick: bool, pub scheduler_tick: bool,
}
Expand description

Configuration for the runtime. Exposed via DomainParticipant factory methods.

Fields§

§tick_period: Duration

Tick period of the event loop. Default 50 ms.

§spdp_period: Duration

SPDP announce period. Default 5 s.

§initial_announce_count: u32

C3 WiFi-robust discovery — number of initial SPDP announces sent at the fast Self::initial_announce_period cadence (instead of spdp_period) while no peer is yet discovered. Default DEFAULT_INITIAL_ANNOUNCE_COUNT. 0 disables the burst (legacy single-announce-then-spdp_period behaviour).

§initial_announce_period: Duration

Period between initial-announcement-burst SPDP sends. Default DEFAULT_INITIAL_ANNOUNCE_PERIOD.

§spdp_multicast_group: Ipv4Addr

SPDP multicast group (IPv4). Default 239.255.0.1 (Spec §9.6.1.4.1).

§multicast_interface: Ipv4Addr

Interface address for the multicast join. Default 0.0.0.0 (the kernel picks the default interface).

§spdp_multicast_send: bool

C1: whether SPDP beacons are sent via multicast. Default true (spec behavior). false (env ZERODDS_NO_MULTICAST) → pure unicast discovery via Self::initial_peers, not a single multicast packet — for networks that drop multicast (WiFi/cloud VPC), and for a rigorous multicast-free discovery proof.

§discovery_server: bool

A1: discovery-server mode. When true, this participant relays the raw SPDP (participant-locator) announcements between the clients that point their Self::initial_peers at it — so N clients discover each other through one well-known address instead of an O(N²) peer list or multicast. Crucially it relays only SPDP (participant discovery); SEDP (endpoint discovery, incl. dynamically-created ROS-2 Action endpoints) then happens directly peer-to-peer between the real participants — which is exactly why ROS-2 Actions work over it, unlike a SEDP-proxying discovery server. Default false. Plain discovery only (DDS-Security secured discovery-server relay is a follow-up).

§max_reassembly_sample_bytes: usize

C3: max reassemblable sample size (DoS cap of the fragment assembler). Larger samples are silently discarded. The rtps default was 1 MiB (the phase-1 assumption “large images = no use case”) — too small for ROS PointCloud2/Image (often several MB). Default here 16 MiB; env ZERODDS_MAX_SAMPLE_BYTES (bytes) overrides. Still a deliberate DoS guard, just ROS-realistic.

§initial_peers: Vec<Locator>

C1 multicast-free discovery: unicast initial-peer locators to which SPDP beacons are sent in addition to multicast. Default empty (= pure multicast behavior as before). Populated via RuntimeConfig::default from the env ZERODDS_PEERS (comma list of ip or ip:port). An ip without a port is expanded to the well-known SPDP unicast ports of participant indices 0..N (see [expand_initial_peer]).

§user_transport: Option<UserTransportKind>

Transport for DCPS user traffic. None (default) → fall back to the env var ZERODDS_USER_TRANSPORT, otherwise UDPv4. Discovery (SPDP/SEDP) remains UDPv4 multicast independently of this. Ignored when Self::user_transports is non-empty.

§user_transports: Vec<UserTransportKind>

Preference-ordered set of transports for DCPS user traffic. When non-empty, the runtime builds a LayeredUserTransport over all of them: each datagram is routed to the first transport whose locator kind matches the destination (so list the fast/local transport first — e.g. [Shm, UdpV4] — and the fallback last), and receives are multiplexed from all of them. Empty (default) → single-transport via Self::user_transport.

§announce_secure_endpoints: bool

true → the SPDP beacon additionally announces the 12 secure discovery bits (16..27, DDS-Security 1.2 §7.4.7.1). Default false — only standard bits are announced. Set by the DCPS factory once a PolicyEngine is configured. This flag is available even without the security feature, so that tests can check bit presence without activating the whole crypto crate.

§enable_secure_spdp: bool

FastDDS interop: run the reliable secure SPDP channel (0xff0101c2/c7, ENTITYID_SPDP_RELIABLE_BUILTIN_PARTICIPANT_SECURE_*). FastDDS announces its full secured participant data (identity_token/security_info) over this channel and gates the crypto-token reciprocation/endpoint matching on it; cyclone does NOT need it (cyclone↔zerodds runs without). Default off — enable only for FastDDS cross-vendor.

§wlp_period: Duration

WLP-Tick-Periode (Writer-Liveliness-Protocol, RTPS 2.5 §8.4.13). Duration::ZERO → default participant_lease_duration / 3 (spec recommendation: three misses before the reader marks the writer as not-alive). A direct override enables aggressive tests.

§participant_lease_duration: Duration

Lease duration announced in the SPDP beacon as PARTICIPANT_LEASE_DURATION (spec default 100 s). Also used as the basis for the AUTOMATIC WLP tick (wlp_period = participant_lease_duration / 3 if wlp_period == Duration::ZERO).

§user_data: Vec<u8>

USER_DATA bytes of the participant (DDS 1.4 §2.2.3.1 UserDataQosPolicy). Announced in the SPDP beacon as PID_USER_DATA (DDSI-RTPS §9.6.3.2) and exposed on the receiver side in ParticipantBuiltinTopicData.user_data. Default empty.

§observability: SharedSink

Observability sink. Default is null_sink() — each event emit is then a direct return without allocation on the consumer side. Consumers inject e.g. zerodds_foundation::observability::StderrJsonSink (JSON lines for Vector/fluentd/Datadog) or their own OTLP bridge.

§recv_thread_priority: Option<i32>

Sprint D.5d lever C — RT pinning + priority. Linux-only; on macOS/Windows the hooks are no-ops.

SCHED_FIFO priority (1-99) for the three recv workers (SPDP MC, metatraffic, user data). None = default scheduler (CFS). Some(80) is the spec recommendation for real-time paths. Requires CAP_SYS_NICE or an RLIMIT_RTPRIO-permitted user.

§tick_thread_priority: Option<i32>

Like Self::recv_thread_priority, but for the tick worker.

§recv_thread_cpus: Option<Vec<usize>>

CPU affinity mask for the recv workers. None = no affinity (the kernel schedules freely). A list of CPU indices, e.g. vec![2, 3] for cores 2+3. Set via sched_setaffinity; all three recv threads share the same mask.

§tick_thread_cpus: Option<Vec<usize>>

Like Self::recv_thread_cpus, but for the tick worker.

§extra_recv_threads: usize

Opt-3 (Spec zerodds-zero-copy-1.0 §9): number of additional user-data recv workers that listen on the same port as user_unicast via SO_REUSEPORT. 0 (default) = only the primary recv_user_data_loop worker. Under high recv load the pool scales linearly with cores (kernel flow hashing distributes incoming datagrams). Recommended values: 1-3 additional workers per CPU core.

§data_representation_offer: Vec<i16>

D.5g — default DataRepresentation list announced in SEDP PublicationData and SEDP SubscriptionData, when not overridden per-writer/reader (UserWriterConfig/UserReaderConfig).

Important: per strict spec (XTypes 1.3 §7.6.3.1.2) the first element is the writer’s “offered” and must be in the reader’s “accepted” list for a match to happen. Default [XCDR1, XCDR2] = legacy-first → max interop with the RTI Connext Shapes Demo (XCDR1-only). Pure-XCDR2 deployments can switch this to [XCDR2] or [XCDR2, XCDR1] for bandwidth efficiency and @appendable/@mutable support.

Empty (vec![]) is interpreted per spec as [XCDR1].

§data_rep_match_mode: DataRepMatchMode

D.5g — default match mode for DataRepresentation negotiation.

Strict (XTypes 1.3 §7.6.3.1.2 normative): writer.first ∈ reader.list = match. Tolerant (industry norm): any overlap = match, picks the first overlap as the wire format.

Default Tolerant because Cyclone DDS and FastDDS match this way — maximizes interop. The strict setting is only meaningful for formal spec-compliance tests.

§external_tick: bool

zerodds-async-1.0 §4 — when true, start() does not spawn the dedicated zdds-tick std::thread. The periodic tick (SPDP announce, SEDP/WLP, deadline/lifespan/liveliness) must then be driven externally via DcpsRuntime::tick_driver. Used by the async API’s spawn_in_tokio, which multiplexes many participants’ tick loops onto a tokio runtime instead of one thread each. Default false (internal thread, unchanged behaviour). The recv worker threads are unaffected — they block on socket recv and stay regardless.

§scheduler_tick: bool

D.5e Phase 3 — when true, start() drives the periodic tick via the event-driven deadline scheduler (crate::scheduler) instead of the fixed-tick_period poll: the worker parks until the next due deadline (SPDP announce, or a fine floor while user endpoints/QoS timers are active) or until a write/recv raise wakes it — no busy-poll, lower idle CPU, lower tail latency. The work done per wake is the unchanged run_tick_iteration (identical wire output + cadence — cross-vendor safe). Default true since D.5e Phase C (2026-06-14) — set ZERODDS_SCHEDULER_TICK=0 or this field to false for the classic fixed-period tick_loop. Mutually exclusive with external_tick (external wins).

Implementations§

Source§

impl RuntimeConfig

Source

pub fn ros_defaults() -> Self

C4: robotics-capable defaults for out-of-the-box ROS-2 interop. Saves the manual env tuning otherwise needed for real ROS-2 nodes. Specifically, compared to RuntimeConfig::default:

  • data_representation_offer = [XCDR1, XCDR2]: rmw_cyclonedds/ rmw_fastrtps write XCDR1 for final/simple types (e.g. std_msgs/String). An XCDR2-only reader does not match an XCDR1 writer — so the ROS reader here offers both legacy-first (tolerant match is already the default). This is the clean, ROS-specific variant of the ZERODDS_DATA_REPR_OFFER env workaround, WITHOUT changing the global DEFAULT_OFFER (XCDR2-only, deliberately for FastDDS/OpenDDS XCDR2 readers).

The ROS-realistic reassembly cap (16 MiB, PointCloud2/Image) is already the global default and is carried over here.

Source

pub fn multi_robot() -> Self

C6 multi-robot / WAN / cross-subnet profile.

A named profile for fleets that span subnets, the cloud, or WiFi — environments that drop IP multicast, so SPDP discovery cannot rely on the multicast beacon. It is the ros_defaults representation offer plus:

  • Multicast-free discovery (spdp_multicast_send = false): participants find each other purely through unicast initial peers, regardless of the ZERODDS_NO_MULTICAST env. Set the peers via ZERODDS_PEERS (a comma list of ip or ip:port); a port-less ip is expanded to the well-known SPDP unicast ports of the first N participant indices (ZERODDS_MAX_PEER_PARTICIPANTS).
  • WAN-tolerant liveliness: a longer participant lease (300 s vs the 100 s spec default) so transient cross-subnet RTT spikes or brief link drops do not trigger a false liveliness loss.

Domain isolation is the caller’s lever: pass a fleet-dedicated domain_id to DcpsRuntime::start to keep robots off the default domain 0. The profile deliberately does not pick a domain for you.

use zerodds_dcps::runtime::RuntimeConfig;
let cfg = RuntimeConfig::multi_robot();
assert!(!cfg.spdp_multicast_send); // unicast-only discovery
Source

pub fn discovery_server() -> Self

A1 — discovery-server profile (the server side). Multicast-free, with the SPDP relay on (Self::discovery_server): clients point their initial_peers/ZERODDS_PEERS at this one well-known address and the server bridges their participant discovery, so N clients find each other without an O(N²) peer list or multicast. SEDP (incl. ROS-2 Action endpoints) stays direct peer-to-peer — no SEDP proxy, no Action breakage.

Clients run with RuntimeConfig::multi_robot (or any multicast-free config) and set ZERODDS_PEERS to the server’s address.

use zerodds_dcps::runtime::RuntimeConfig;
let server = RuntimeConfig::discovery_server();
assert!(server.discovery_server);
assert!(!server.spdp_multicast_send); // unicast-only

Trait Implementations§

Source§

impl Clone for RuntimeConfig

Source§

fn clone(&self) -> RuntimeConfig

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for RuntimeConfig

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for RuntimeConfig

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.