mirror of
https://github.com/jmcorgan/fips.git
synced 2026-09-14 00:45:08 +00:00
build: gate BLE on backend availability, and let an embedder install the radio
Two changes that are not themselves BLE code: the build gate that decides where the transport exists, and the node-level seam an application uses to hand it a radio. They are kept out of the BLE commits so that those stay purely about the transport. The BLE transport was compiled only on target_os = "linux", which conflates the transport with one of its backends. Nothing above the BleIo seam has a platform dependency, and the part that does is already selected separately. So the module gate becomes ble_available, defined as bluer_available or Android: the set of platforms with a concrete backend, deliberately not the set that could plausibly have Bluetooth. That distinction is the whole point. The mock arm was previously written as "anything that is not BlueZ", so widening the module gate alone would have handed a platform a transport that compiles, starts, reports itself Up and never peers, with no error anywhere to find it. The backend cascade is now explicitly three-way -- BlueZ, an embedder-supplied radio, and the in-memory double under cfg(test) only -- with a compile_error! for the remaining case. A compile_error! cannot fire in a test build, which is the build everybody runs, so a unit test asserts the same condition from the other side by reading cfg! values for the target rather than for the profile. Nothing about which backend runs changes on any platform that builds today. glibc-linux still gets BlueZ. macOS and Windows still have no BLE. Android is the only new platform and it gets a real backend rather than the mock. musl now has no BLE deliberately, where before the module compiled there and resolved to the mock; a musl node with BLE configured logs a warning and starts without the transport rather than running one that could never peer. The node side gains an optional BLE radio slot. It is built whether or not a radio has been installed, because the backend resolves the slot per operation, so an embedder that starts Bluetooth after the node is running is adopted in place. Arming twice returns the same slot rather than replacing it, since a slot may already hold a live radio a second call must not orphan, and the slot is per-node rather than a process global because a global collapses as soon as two nodes share a process.
This commit is contained in:
@@ -43,7 +43,22 @@ fn main() {
|
||||
println!("cargo:rustc-check-cfg=cfg(bluer_available)");
|
||||
let target_os = std::env::var("CARGO_CFG_TARGET_OS").unwrap_or_default();
|
||||
let target_env = std::env::var("CARGO_CFG_TARGET_ENV").unwrap_or_default();
|
||||
if target_os == "linux" && target_env != "musl" {
|
||||
let bluer_available = target_os == "linux" && target_env != "musl";
|
||||
if bluer_available {
|
||||
println!("cargo:rustc-cfg=bluer_available");
|
||||
}
|
||||
|
||||
// Whether the BLE transport is compiled at all.
|
||||
//
|
||||
// This is the set of platforms that have a concrete `BleIo` backend, not
|
||||
// the set that could plausibly have one. A platform listed here with no
|
||||
// backend behind it does not get "BLE, degraded" — it gets an in-memory
|
||||
// transport that starts, reports itself up and never peers, with no error
|
||||
// anywhere. Add a platform here only in the same change that adds its
|
||||
// backend; `transport::ble` carries a compile-time tripwire that refuses
|
||||
// a build where the two disagree.
|
||||
println!("cargo:rustc-check-cfg=cfg(ble_available)");
|
||||
if bluer_available || target_os == "android" {
|
||||
println!("cargo:rustc-cfg=ble_available");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -2474,7 +2474,7 @@ impl Node {
|
||||
}
|
||||
}
|
||||
} else if addr.transport == "ble" {
|
||||
#[cfg(bluer_available)]
|
||||
#[cfg(ble_available)]
|
||||
{
|
||||
match self.resolve_ble_addr(&addr.addr) {
|
||||
Ok(result) => result,
|
||||
@@ -2489,7 +2489,7 @@ impl Node {
|
||||
}
|
||||
}
|
||||
}
|
||||
#[cfg(not(bluer_available))]
|
||||
#[cfg(not(ble_available))]
|
||||
{
|
||||
debug!(transport = %addr.transport, "BLE transport not available on this build");
|
||||
continue;
|
||||
|
||||
+93
-1
@@ -541,6 +541,17 @@ pub struct Node {
|
||||
/// TUN interface name (for cleanup).
|
||||
tun_name: Option<String>,
|
||||
|
||||
/// Slot the embedder installs its BLE radio into, armed by
|
||||
/// [`Self::enable_app_owned_ble_radio`]. `None` unless armed.
|
||||
///
|
||||
/// Gated on the BLE transport existing *and* on its backend being the
|
||||
/// embedder-supplied one — the same condition
|
||||
/// `transport::ble::io_android` itself is compiled under, so the seam is
|
||||
/// absent on platforms whose radio is opened in process, and present in a
|
||||
/// test build so its contract is covered on an ordinary runner.
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
ble_radio: Option<Arc<crate::transport::ble::io_android::BleRadioSlot>>,
|
||||
|
||||
// === Index-Based Session Dispatch ===
|
||||
/// Allocator for session indices.
|
||||
index_allocator: IndexAllocator,
|
||||
@@ -833,6 +844,8 @@ impl Node {
|
||||
)),
|
||||
tun_state,
|
||||
tun_name: None,
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
ble_radio: None,
|
||||
index_allocator: IndexAllocator::new(),
|
||||
peers_by_index: HashMap::new(),
|
||||
pending_outbound: HashMap::new(),
|
||||
@@ -996,6 +1009,8 @@ impl Node {
|
||||
)),
|
||||
tun_state,
|
||||
tun_name: None,
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
ble_radio: None,
|
||||
index_allocator: IndexAllocator::new(),
|
||||
peers_by_index: HashMap::new(),
|
||||
pending_outbound: HashMap::new(),
|
||||
@@ -1189,6 +1204,33 @@ impl Node {
|
||||
}
|
||||
}
|
||||
|
||||
// Create BLE transport instances over an embedder-supplied radio.
|
||||
// Built whether or not a radio is installed yet: the backend resolves
|
||||
// the slot per operation, so one that arrives later is adopted in
|
||||
// place rather than needing the node rebuilt around it.
|
||||
#[cfg(all(target_os = "android", not(bluer_available), not(test)))]
|
||||
if let Some(slot) = self.ble_radio.clone() {
|
||||
let ble_instances: Vec<_> = self
|
||||
.config()
|
||||
.transports
|
||||
.ble
|
||||
.iter()
|
||||
.map(|(name, config)| (name.map(|s| s.to_string()), config.clone()))
|
||||
.collect();
|
||||
for (name, ble_config) in ble_instances {
|
||||
let transport_id = self.allocate_transport_id();
|
||||
let mut ble = crate::transport::ble::BleTransport::new(
|
||||
transport_id,
|
||||
name,
|
||||
ble_config,
|
||||
crate::transport::ble::io_android::AndroidIo::new(Arc::clone(&slot)),
|
||||
packet_tx.clone(),
|
||||
);
|
||||
ble.set_local_pubkey(self.identity().pubkey().serialize());
|
||||
transports.push(TransportHandle::Ble(ble));
|
||||
}
|
||||
}
|
||||
|
||||
transports
|
||||
}
|
||||
|
||||
@@ -1255,7 +1297,7 @@ impl Node {
|
||||
/// Resolve a BLE address string (`"adapter/AA:BB:CC:DD:EE:FF"`) to a
|
||||
/// (TransportId, TransportAddr) pair by finding the BLE transport
|
||||
/// instance matching the adapter name.
|
||||
#[cfg(bluer_available)]
|
||||
#[cfg(ble_available)]
|
||||
fn resolve_ble_addr(&self, addr_str: &str) -> Result<(TransportId, TransportAddr), NodeError> {
|
||||
let ta = TransportAddr::from_string(addr_str);
|
||||
let adapter = crate::transport::ble::addr::adapter_from_addr(&ta).ok_or_else(|| {
|
||||
@@ -3339,6 +3381,56 @@ impl Node {
|
||||
udp_fd_rx
|
||||
}
|
||||
|
||||
/// Set up an **app-owned BLE radio**: the embedder supplies the radio the
|
||||
/// BLE transport drives, because on this platform there is no
|
||||
/// Rust-reachable one to open. Call this after [`Node::new`] and
|
||||
/// **before** [`Self::start`] — the transport is built during `start`, and
|
||||
/// only a node armed by then has a slot to build it over.
|
||||
///
|
||||
/// Returns the slot. Installing, replacing and clearing a radio through it
|
||||
/// is safe at any time, from any thread, including long after the node is
|
||||
/// running:
|
||||
///
|
||||
/// ```no_run
|
||||
/// # async fn f(node: &mut fips::Node, radio: std::sync::Arc<dyn fips::transport::ble::io_android::AndroidRadio>)
|
||||
/// # -> Result<(), Box<dyn std::error::Error>> {
|
||||
/// let slot = node.enable_app_owned_ble_radio(); // after new(), before start()
|
||||
/// node.start().await?;
|
||||
/// // ...whenever the embedder's radio service comes up, and again each
|
||||
/// // time it restarts:
|
||||
/// slot.install(fips::transport::ble::io_android::AndroidBleBridge::new(radio));
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
///
|
||||
/// The lateness is the point rather than a convenience. The radio belongs
|
||||
/// to a service whose lifetime is not the node's: the user can turn it on
|
||||
/// after the mesh is already running, and off and on again, and each start
|
||||
/// typically produces a fresh radio. A node that had to be built around an
|
||||
/// existing radio would make that mean "tear the node down and rebuild
|
||||
/// it", dropping every peer, session and route for as long as
|
||||
/// re-handshaking takes. So the transport is built and started whether or
|
||||
/// not a radio is installed, and resolves the slot per operation: it
|
||||
/// listens and scans against whichever radio is there, dials fail while
|
||||
/// there is none, and everything recovers on its own when one appears.
|
||||
/// Streams already open keep the radio they were opened on rather than
|
||||
/// migrating.
|
||||
///
|
||||
/// Deliberately narrow, and shaped like the [`Self::enable_app_owned_tun`]
|
||||
/// seam it sits beside: one call, no callbacks, and no lifecycle contract
|
||||
/// beyond the slot outliving the node. Arming twice returns the same slot,
|
||||
/// so a second call cannot orphan a radio installed through the first. The
|
||||
/// seam does not exist on platforms whose BLE backend is opened in
|
||||
/// process, since there is nothing there for an embedder to supply.
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
pub fn enable_app_owned_ble_radio(
|
||||
&mut self,
|
||||
) -> Arc<crate::transport::ble::io_android::BleRadioSlot> {
|
||||
Arc::clone(self.ble_radio.get_or_insert_with(|| {
|
||||
Arc::new(crate::transport::ble::io_android::BleRadioSlot::new())
|
||||
}))
|
||||
}
|
||||
|
||||
/// Address the built-in `.fips` DNS responder is listening on, or `None`
|
||||
/// when it is not running (`dns.enabled = false`, the bind failed, or the
|
||||
/// node is stopped).
|
||||
|
||||
@@ -6,7 +6,7 @@ use crate::utils::index::SessionIndex;
|
||||
use std::time::Duration;
|
||||
|
||||
mod acl;
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
mod ble;
|
||||
mod bloom;
|
||||
mod bloom_poison;
|
||||
|
||||
@@ -3544,6 +3544,115 @@ fn app_owned_udp_fd_seam_second_arm_replaces_the_first() {
|
||||
);
|
||||
}
|
||||
|
||||
/// The app-owned BLE radio seam. The slot is live from the moment it is armed
|
||||
/// — before `start()`, which is when the transport that reads it gets built —
|
||||
/// and installing a radio through it is a slot operation, not a node one.
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
#[test]
|
||||
fn app_owned_ble_radio_seam_hands_out_a_live_slot_before_start() {
|
||||
use crate::transport::ble::io_android::{AndroidBleBridge, BleRadioSlot};
|
||||
|
||||
let mut node = make_node();
|
||||
let slot: std::sync::Arc<BleRadioSlot> = node.enable_app_owned_ble_radio();
|
||||
|
||||
assert!(
|
||||
!slot.is_installed(),
|
||||
"arming supplies the slot, not a radio to put in it",
|
||||
);
|
||||
|
||||
slot.install(AndroidBleBridge::new(std::sync::Arc::new(
|
||||
test_radio::TestRadio,
|
||||
)));
|
||||
assert!(slot.is_installed(), "the embedder installs whenever it can");
|
||||
|
||||
slot.clear();
|
||||
assert!(!slot.is_installed(), "and can take it away again");
|
||||
}
|
||||
|
||||
/// Arming twice returns the same slot, so a second call cannot orphan a radio
|
||||
/// installed through the first. This is where the seam deliberately differs
|
||||
/// from `enable_app_owned_udp_fd`, whose last arming wins: a channel can be
|
||||
/// replaced because nothing was delivered on it yet, while a slot may already
|
||||
/// be holding the embedder's live radio.
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
#[test]
|
||||
fn app_owned_ble_radio_seam_second_arm_returns_the_same_slot() {
|
||||
use crate::transport::ble::io_android::AndroidBleBridge;
|
||||
|
||||
let mut node = make_node();
|
||||
let first = node.enable_app_owned_ble_radio();
|
||||
first.install(AndroidBleBridge::new(std::sync::Arc::new(
|
||||
test_radio::TestRadio,
|
||||
)));
|
||||
|
||||
let second = node.enable_app_owned_ble_radio();
|
||||
|
||||
assert!(
|
||||
std::sync::Arc::ptr_eq(&first, &second),
|
||||
"re-arming must not hand back a different slot",
|
||||
);
|
||||
assert!(
|
||||
second.is_installed(),
|
||||
"the radio installed through the first handle is still there",
|
||||
);
|
||||
}
|
||||
|
||||
/// The slot is per-node state, which is the whole reason it is not a process
|
||||
/// global: two nodes in one process each drive their own radio.
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
#[test]
|
||||
fn app_owned_ble_radio_slots_are_per_node() {
|
||||
use crate::transport::ble::io_android::AndroidBleBridge;
|
||||
|
||||
let mut node_a = make_node();
|
||||
let mut node_b = make_node();
|
||||
let slot_a = node_a.enable_app_owned_ble_radio();
|
||||
let slot_b = node_b.enable_app_owned_ble_radio();
|
||||
|
||||
slot_a.install(AndroidBleBridge::new(std::sync::Arc::new(
|
||||
test_radio::TestRadio,
|
||||
)));
|
||||
|
||||
assert!(slot_a.is_installed());
|
||||
assert!(
|
||||
!slot_b.is_installed(),
|
||||
"node B's radio is node B's — no shared or global slot",
|
||||
);
|
||||
}
|
||||
|
||||
/// A node that never armed the seam has no slot to hand the transport, which
|
||||
/// is how a build with the embedder-supplied backend distinguishes "no radio
|
||||
/// yet" from "this embedder does not supply one at all".
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
#[test]
|
||||
fn app_owned_ble_radio_seam_is_absent_until_armed() {
|
||||
let node = make_node();
|
||||
assert!(node.ble_radio.is_none());
|
||||
}
|
||||
|
||||
#[cfg(all(ble_available, any(target_os = "android", test)))]
|
||||
mod test_radio {
|
||||
use crate::transport::ble::addr::BleAddr;
|
||||
use crate::transport::ble::io_android::AndroidRadio;
|
||||
|
||||
/// A radio that does nothing. These tests are about the seam handing one
|
||||
/// over, not about what it then does — that is covered where the backend
|
||||
/// lives.
|
||||
pub(super) struct TestRadio;
|
||||
|
||||
impl AndroidRadio for TestRadio {
|
||||
fn listen(&self) -> u16 {
|
||||
0
|
||||
}
|
||||
fn connect(&self, _connect_id: i64, _addr: &BleAddr, _psm: u16) {}
|
||||
fn start_advertising(&self, _psm: u16) {}
|
||||
fn stop_advertising(&self) {}
|
||||
fn start_scanning(&self) {}
|
||||
fn stop_scanning(&self) {}
|
||||
fn close_channel(&self, _ch_id: i64) {}
|
||||
}
|
||||
}
|
||||
|
||||
/// The embedder-facing DNS contract, end to end.
|
||||
///
|
||||
/// An embedder that owns the TUN fd (Android `VpnService`) has no system DNS
|
||||
|
||||
@@ -16,10 +16,13 @@
|
||||
//!
|
||||
//! ## Architecture
|
||||
//!
|
||||
//! Transport logic (pool, neighbor, lifecycle) is separated from the
|
||||
//! BlueZ/bluer stack via the `BleIo` trait. `BluerIo` provides the real
|
||||
//! implementation (behind `cfg(bluer_available)`); `MockBleIo` provides
|
||||
//! an in-memory test double for CI without hardware.
|
||||
//! Transport logic (pool, neighbor, lifecycle) is separated from any one
|
||||
//! Bluetooth stack via the `BleIo` trait. `BluerIo` drives BlueZ (behind
|
||||
//! `cfg(bluer_available)`), [`io_android::AndroidIo`] drives a radio the
|
||||
//! embedder supplies, and `MockBleIo` is an in-memory double for tests
|
||||
//! without hardware. Which one `DefaultBleTransport` resolves to is decided
|
||||
//! by the cascade below, and the whole module is compiled only on platforms
|
||||
//! that have one of them — see `ble_available` in `build.rs`.
|
||||
//!
|
||||
//! ## Connection Pool
|
||||
//!
|
||||
@@ -80,16 +83,41 @@ use tracing::{debug, info, trace, warn};
|
||||
/// dialled at when it advertises nothing.
|
||||
pub const DEFAULT_PSM: u16 = 0x0085;
|
||||
|
||||
/// Concrete BLE transport type for use in TransportHandle.
|
||||
/// Concrete BLE transport type for use in `TransportHandle`.
|
||||
///
|
||||
/// Production builds on glibc-linux use `BluerIo` (real BlueZ stack).
|
||||
/// Test builds, musl-linux, and non-Linux platforms use `MockBleIo`.
|
||||
/// Three arms, in priority order: an in-process BlueZ stack where one exists,
|
||||
/// otherwise a radio the embedder supplies, otherwise — and *only* in a test
|
||||
/// build — the in-memory double.
|
||||
///
|
||||
/// The mock arm is deliberately not written as "anything that is not BlueZ".
|
||||
/// That phrasing is what makes widening the module gate dangerous: a platform
|
||||
/// added to `ble_available` without a backend would silently land on an
|
||||
/// in-memory transport that compiles, starts, reports [`TransportState::Up`]
|
||||
/// and never peers, with nothing anywhere to say so. The tripwire below makes
|
||||
/// that state unrepresentable instead.
|
||||
#[cfg(all(bluer_available, not(test)))]
|
||||
pub type DefaultBleTransport = BleTransport<io_linux::BluerIo>;
|
||||
|
||||
#[cfg(any(not(bluer_available), test))]
|
||||
#[cfg(all(target_os = "android", not(bluer_available), not(test)))]
|
||||
pub type DefaultBleTransport = BleTransport<io_android::AndroidIo>;
|
||||
|
||||
#[cfg(test)]
|
||||
pub type DefaultBleTransport = BleTransport<io::MockBleIo>;
|
||||
|
||||
// The tripwire. This module is only compiled when `ble_available`, so
|
||||
// reaching here means a platform declared it has BLE while having no concrete
|
||||
// backend to provide it. It cannot fire today; it exists for whoever next
|
||||
// widens `ble_available`, and it fails the build rather than shipping a
|
||||
// transport that quietly never connects.
|
||||
#[cfg(all(not(test), not(bluer_available), not(target_os = "android")))]
|
||||
compile_error!(
|
||||
"this target is `ble_available` but has no concrete `BleIo` backend. \
|
||||
Add its backend and an arm to the `DefaultBleTransport` cascade in \
|
||||
src/transport/ble/mod.rs, or drop the target from `ble_available` in \
|
||||
build.rs. Falling back to the in-memory mock in a non-test build would \
|
||||
produce a BLE transport that starts, reports itself up, and never peers."
|
||||
);
|
||||
|
||||
// ============================================================================
|
||||
// BLE Transport
|
||||
// ============================================================================
|
||||
@@ -1708,6 +1736,29 @@ mod tests {
|
||||
assert!(p.position(&a(1)).is_none());
|
||||
}
|
||||
|
||||
/// The mock backend is a *test* backend. Any target that compiles this
|
||||
/// module must have a real one behind it, or a release build of it would
|
||||
/// ship a BLE transport that starts, reports itself up, and never peers.
|
||||
///
|
||||
/// The `compile_error!` above is what enforces that in a non-test build —
|
||||
/// and by construction it cannot fire in a test build, which is exactly
|
||||
/// the build everybody runs. This closes that gap: the `cfg!` values below
|
||||
/// are evaluated for the *target*, not for the test profile, so this
|
||||
/// asserts the same condition the tripwire does, from the one place a
|
||||
/// developer will actually see it.
|
||||
#[test]
|
||||
fn a_target_that_compiles_this_module_has_a_real_backend() {
|
||||
let has_concrete_backend = cfg!(bluer_available) || cfg!(target_os = "android");
|
||||
assert!(
|
||||
has_concrete_backend,
|
||||
"target {} is `ble_available` but has no concrete `BleIo` backend, \
|
||||
so a non-test build of it would select the in-memory mock. Add \
|
||||
its backend and an arm to the `DefaultBleTransport` cascade, or \
|
||||
drop it from `ble_available` in build.rs.",
|
||||
std::env::consts::OS,
|
||||
);
|
||||
}
|
||||
|
||||
/// Deterministic x-only pubkey for exchange tests.
|
||||
fn test_pubkey(seed: u8) -> [u8; 32] {
|
||||
let secp = Secp256k1::new();
|
||||
|
||||
+23
-23
@@ -15,10 +15,10 @@ pub mod udp;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
pub mod ethernet;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
pub mod ble;
|
||||
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
use ble::DefaultBleTransport;
|
||||
#[cfg(any(target_os = "linux", target_os = "macos"))]
|
||||
use ethernet::EthernetTransport;
|
||||
@@ -673,7 +673,7 @@ pub enum TransportHandle {
|
||||
/// Nym mixnet transport (via SOCKS5).
|
||||
Nym(NymTransport),
|
||||
/// BLE L2CAP transport.
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
Ble(DefaultBleTransport),
|
||||
/// In-process loopback transport (test harness only).
|
||||
#[cfg(test)]
|
||||
@@ -690,7 +690,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.start_async().await,
|
||||
TransportHandle::Tor(t) => t.start_async().await,
|
||||
TransportHandle::Nym(t) => t.start_async().await,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.start_async().await,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.start_async().await,
|
||||
@@ -706,7 +706,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.stop_async().await,
|
||||
TransportHandle::Tor(t) => t.stop_async().await,
|
||||
TransportHandle::Nym(t) => t.stop_async().await,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.stop_async().await,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.stop_async().await,
|
||||
@@ -722,7 +722,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.send_async(addr, data).await,
|
||||
TransportHandle::Tor(t) => t.send_async(addr, data).await,
|
||||
TransportHandle::Nym(t) => t.send_async(addr, data).await,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.send_async(addr, data).await,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.send_async(addr, data).await,
|
||||
@@ -738,7 +738,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.transport_id(),
|
||||
TransportHandle::Tor(t) => t.transport_id(),
|
||||
TransportHandle::Nym(t) => t.transport_id(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.transport_id(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.transport_id(),
|
||||
@@ -754,7 +754,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.name(),
|
||||
TransportHandle::Tor(t) => t.name(),
|
||||
TransportHandle::Nym(t) => t.name(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.name(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => None,
|
||||
@@ -770,7 +770,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.transport_type(),
|
||||
TransportHandle::Tor(t) => t.transport_type(),
|
||||
TransportHandle::Nym(t) => t.transport_type(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.transport_type(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.transport_type(),
|
||||
@@ -786,7 +786,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.state(),
|
||||
TransportHandle::Tor(t) => t.state(),
|
||||
TransportHandle::Nym(t) => t.state(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.state(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.state(),
|
||||
@@ -802,7 +802,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.mtu(),
|
||||
TransportHandle::Tor(t) => t.mtu(),
|
||||
TransportHandle::Nym(t) => t.mtu(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.mtu(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.mtu(),
|
||||
@@ -821,7 +821,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.link_mtu(addr),
|
||||
TransportHandle::Tor(t) => t.link_mtu(addr),
|
||||
TransportHandle::Nym(t) => t.link_mtu(addr),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.link_mtu(addr),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.link_mtu(addr),
|
||||
@@ -837,7 +837,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.local_addr(),
|
||||
TransportHandle::Tor(_) => None,
|
||||
TransportHandle::Nym(_) => None,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(_) => None,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => None,
|
||||
@@ -857,7 +857,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(_) => None,
|
||||
TransportHandle::Tor(_) => None,
|
||||
TransportHandle::Nym(_) => None,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(_) => None,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => None,
|
||||
@@ -873,7 +873,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(_) => None,
|
||||
TransportHandle::Tor(_) => None,
|
||||
TransportHandle::Nym(_) => None,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(_) => None,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => None,
|
||||
@@ -913,7 +913,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.discover(),
|
||||
TransportHandle::Tor(t) => t.discover(),
|
||||
TransportHandle::Nym(t) => t.discover(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.discover(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.discover(),
|
||||
@@ -929,7 +929,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.auto_connect(),
|
||||
TransportHandle::Tor(t) => t.auto_connect(),
|
||||
TransportHandle::Nym(t) => t.auto_connect(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.auto_connect(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.auto_connect(),
|
||||
@@ -945,7 +945,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.accept_connections(),
|
||||
TransportHandle::Tor(t) => t.accept_connections(),
|
||||
TransportHandle::Nym(t) => t.accept_connections(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.accept_connections(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(t) => t.accept_connections(),
|
||||
@@ -967,7 +967,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.connect_async(addr).await,
|
||||
TransportHandle::Tor(t) => t.connect_async(addr).await,
|
||||
TransportHandle::Nym(t) => t.connect_async(addr).await,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.connect_async(addr).await,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => Ok(()), // connectionless
|
||||
@@ -987,7 +987,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.connection_state_sync(addr),
|
||||
TransportHandle::Tor(t) => t.connection_state_sync(addr),
|
||||
TransportHandle::Nym(t) => t.connection_state_sync(addr),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.connection_state_sync(addr),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => ConnectionState::Connected,
|
||||
@@ -1006,7 +1006,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(t) => t.close_connection_async(addr).await,
|
||||
TransportHandle::Tor(t) => t.close_connection_async(addr).await,
|
||||
TransportHandle::Nym(t) => t.close_connection_async(addr).await,
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => t.close_connection_async(addr).await,
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => {} // connectionless no-op
|
||||
@@ -1031,7 +1031,7 @@ impl TransportHandle {
|
||||
TransportHandle::Tcp(_) => TransportCongestion::default(),
|
||||
TransportHandle::Tor(_) => TransportCongestion::default(),
|
||||
TransportHandle::Nym(_) => TransportCongestion::default(),
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(_) => TransportCongestion::default(),
|
||||
#[cfg(test)]
|
||||
TransportHandle::Loopback(_) => TransportCongestion::default(),
|
||||
@@ -1059,7 +1059,7 @@ impl TransportHandle {
|
||||
TransportHandle::Nym(t) => {
|
||||
serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
|
||||
}
|
||||
#[cfg(target_os = "linux")]
|
||||
#[cfg(ble_available)]
|
||||
TransportHandle::Ble(t) => {
|
||||
serde_json::to_value(t.stats().snapshot()).unwrap_or_default()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user