From 77addfa698c1e07c695d3e9f87ea6587da0a1db1 Mon Sep 17 00:00:00 2001 From: Stephen Waits Date: Tue, 7 Apr 2026 17:04:38 -0600 Subject: [PATCH] fix: connect() no longer falls through from mux to USB serial MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit When a mux socket file exists, connect(None, timeout) and try_connect() now commit to the mux — returning an error if unreachable instead of silently falling through to USB serial. This prevents a race condition where a client could steal the serial port from the mux during reconnect. Callers with explicit port = Some(...) are unaffected. --- CHANGELOG.md | 11 +++++++++++ Cargo.lock | 2 +- Cargo.toml | 2 +- src/connect.rs | 47 ++++++++++++++++------------------------------- 4 files changed, 29 insertions(+), 33 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index e05efc6..5fe6661 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 0.2.1 — 2026-04-07 + +### Fixed + +- **`connect()` no longer falls through from mux to USB serial.** If a mux + socket file exists, `connect(None, timeout)` and `try_connect(timeout)` now + commit to the mux and return an error if the mux is unreachable — instead of + silently bypassing it and grabbing the USB port directly. This prevents a + race condition where a client could steal the serial port from the mux during + reconnect. Callers with explicit `port = Some(...)` are unaffected. + ## 0.2.0 — 2026-04-07 ### Features diff --git a/Cargo.lock b/Cargo.lock index f7f9e15..ca586f9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -44,7 +44,7 @@ checksum = "773648b94d0e5d620f64f280777445740e61fe701025087ec8b57f45c791888b" [[package]] name = "donglora-client" -version = "0.2.0" +version = "0.2.1" dependencies = [ "anyhow", "serialport", diff --git a/Cargo.toml b/Cargo.toml index 16622f6..30f201e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "donglora-client" -version = "0.2.0" +version = "0.2.1" edition = "2024" rust-version = "1.85" authors = ["Stephen Waits "] diff --git a/src/connect.rs b/src/connect.rs index 36828b8..18b4cde 100644 --- a/src/connect.rs +++ b/src/connect.rs @@ -100,26 +100,19 @@ pub fn connect(port: Option<&str>, timeout: Duration) -> anyhow::Result { - debug!("connected to mux socket at {path}"); - let mut client = Client::new(AnyTransport::Mux(transport)); - if client.validate().is_ok() { - return Ok(client); - } - debug!("mux at {path} did not validate, falling back to USB"); - } - Err(_) => { - // Stale socket or connection refused — fall through - debug!("mux socket at {path} not reachable, falling back to USB"); - } - } + debug!("mux socket found at {path} — connecting via mux only"); + let transport = MuxTransport::unix(&path, timeout)?; + let mut client = Client::new(AnyTransport::Mux(transport)); + client.validate()?; + return Ok(client); } - // Direct USB serial — auto-detect or wait + // Direct USB serial — only reached when no mux socket exists at all let port_path = discovery::find_port().unwrap_or_else(discovery::wait_for_device); debug!("opening serial port {port_path}"); let transport = SerialTransport::open(&port_path, timeout)?; @@ -183,25 +176,17 @@ pub fn try_connect(timeout: Duration) -> anyhow::Result> { return Ok(client); } - // Try Unix socket mux + // Try Unix socket mux — commit to it if socket exists (same rationale as connect()) #[cfg(unix)] if let Some(path) = find_mux_socket() { - match MuxTransport::unix(&path, timeout) { - Ok(transport) => { - debug!("connected to mux socket at {path}"); - let mut client = Client::new(AnyTransport::Mux(transport)); - if client.validate().is_ok() { - return Ok(client); - } - debug!("mux socket at {path} did not validate, falling back to USB"); - } - Err(_) => { - debug!("mux socket at {path} not reachable, falling back to USB"); - } - } + debug!("mux socket found at {path} — connecting via mux only"); + let transport = MuxTransport::unix(&path, timeout)?; + let mut client = Client::new(AnyTransport::Mux(transport)); + client.validate()?; + return Ok(client); } - // Direct USB serial — single non-blocking scan + // Direct USB serial — single non-blocking scan (only when no mux socket exists) let port_path = discovery::find_port().ok_or_else(|| anyhow::anyhow!("no DongLoRa device found (no mux, no USB device)"))?; debug!("opening serial port {port_path}");