Skip to content

Conversation

@rijulraju
Copy link

New UdpMultiConnection tracks multiple client addresses and broadcasts to all. Oldest client evicted when max reached. If max not specified, defaults to 64.

New UdpMultiConnection tracks multiple client addresses and
broadcasts to all. Oldest client evicted when max reached.
If max not specified, defaults to 64.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR introduces a new UDP connection type UdpMultiConnection that supports broadcasting MAVLink messages to multiple client addresses simultaneously. The implementation tracks client addresses as they send messages and automatically evicts the oldest client when the configured maximum is reached (default: 64 clients). The new connection type can be created using the udpins function with the format udpins:host:port[:max].

Key Changes:

  • Added UdpMultiConnection and UdpMultiWrite structs for managing multiple UDP client destinations
  • Implemented RawConnection trait for UdpMultiConnection to support raw message routing
  • Created udpins function to parse connection strings and initialize multi-client UDP servers

Reviewed changes

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

File Description
src/connection/udp.rs Adds UdpMultiConnection struct, UdpMultiWrite for tracking multiple destinations, and udpins parsing function with configurable max clients
src/connection/routing.rs Implements RawConnection<M> trait for UdpMultiConnection, enabling raw message broadcast to all tracked clients and automatic client registration from incoming packets

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- implement MavConnection trait for UdpMultiConnection
- fix raw_write to return message length not sum of all sends
- use swap_remove(0) for O(1) client eviction
- remove .min(64) capacity cap to respect user max_clients
- use proper error handling instead of expect for address parsing
@rijulraju
Copy link
Author

Addressing Copilot Review Comments

Fixed in 76e73c7:

  • routing.rs:351 - Removed unused sequence counter increment
  • udp.rs:225 - Removed .min(64) cap so Vec capacity respects user's max_clients value
  • routing.rs:369 - Changed to swap_remove(0) for O(1) eviction (order preservation not critical)
  • routing.rs:356 - Now returns msg.len() representing message size, consistent with typical IO semantics
  • udp.rs:243 - Now uses ok_or_else() to return proper io::Error instead of panicking

Intentionally not changing:

  • udp.rs:246 (select_protocol) - SMURF uses the RawConnection trait directly and doesn't go through the standard connection API. Added MavConnection trait implementation to support set_protocol_version.
  • udp.rs:238 (address parsing) - Current parsing works correctly for host:port[:max]. Using rsplit_once on 127.0.0.1:8080:100 yields ("127.0.0.1:8080", "100") which is the desired behavior.
  • routing.rs:372 (nested locking) - Intentional design. We need to update destinations when receiving from a new client. Rust's Mutex guarantees no deadlock (same lock order). Performance tradeoff acceptable since client registration is infrequent.
  • routing.rs:356 (silent send failures) - Matches existing codebase patterns and is appropriate for UDP telemetry where occasional packet loss is expected. Adding logging would be too noisy.

Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 9 comments.

Comments suppressed due to low confidence (2)

src/connection/udp.rs:27

  • The documentation in connection/mod.rs (lines 70-78) lists all supported connection formats but is not updated to include the new udpins:<addr>:<port>[:max] format. Users reading the documentation won't know about this new connection type.
pub fn select_protocol<M: Message>(address: &str) -> io::Result<Box<dyn MavConnection<M>>> {
    let connection = if let Some(address) = address.strip_prefix("udpin:") {
        udpin(address)
    } else if let Some(address) = address.strip_prefix("udpout:") {
        udpout(address)
    } else if let Some(address) = address.strip_prefix("udpbcast:") {
        udpbcast(address)
    } else {
        Err(io::Error::new(
            io::ErrorKind::AddrNotAvailable,
            "Protocol unsupported",
        ))
    };

    Ok(Box::new(connection?))

src/connection/udp.rs:27

  • The new udpins protocol is not integrated into the select_protocol function. The PR description mentions this adds support for "udpins:host:port[:max]" connection strings, but the select_protocol function doesn't have a case to handle the "udpins:" prefix. This means users cannot create this connection type using the standard connect() API.
pub fn select_protocol<M: Message>(address: &str) -> io::Result<Box<dyn MavConnection<M>>> {
    let connection = if let Some(address) = address.strip_prefix("udpin:") {
        udpin(address)
    } else if let Some(address) = address.strip_prefix("udpout:") {
        udpout(address)
    } else if let Some(address) = address.strip_prefix("udpbcast:") {
        udpbcast(address)
    } else {
        Err(io::Error::new(
            io::ErrorKind::AddrNotAvailable,
            "Protocol unsupported",
        ))
    };

    Ok(Box::new(connection?))

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

- mirror UdpConnection patterns in raw_write/raw_read for consistency
- add timing debug logs matching UdpConnection
- use if/else structure matching UdpConnection
- fix double parsing of max_clients parameter
- add doc comments for UdpMultiConnection and udpins()
Try parsing the entire address as a socket address first.
Only if that fails, attempt to split off a trailing max_clients value.
This fixes the bug where "host:port" would incorrectly treat the
port as max_clients.
Copy link

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 2 out of 2 changed files in this pull request and generated 8 comments.

Comments suppressed due to low confidence (1)

src/connection/udp.rs:28

  • The new udpins: protocol is not registered in the select_protocol function, which means it cannot be used through the standard connect() API. The function should be updated to handle the "udpins:" prefix and route to the udpins() function, similar to how "udpin:", "udpout:", and "udpbcast:" are handled.
pub fn select_protocol<M: Message>(address: &str) -> io::Result<Box<dyn MavConnection<M>>> {
    let connection = if let Some(address) = address.strip_prefix("udpin:") {
        udpin(address)
    } else if let Some(address) = address.strip_prefix("udpout:") {
        udpout(address)
    } else if let Some(address) = address.strip_prefix("udpbcast:") {
        udpbcast(address)
    } else {
        Err(io::Error::new(
            io::ErrorKind::AddrNotAvailable,
            "Protocol unsupported",
        ))
    };

    Ok(Box::new(connection?))
}

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants