Expand description
hick-smoltcp
Runtime-agnostic mDNS / DNS-SD engine for bare metal — responder and querier
over smoltcp UDP, no_std + alloc, no OS and no async runtime required.
§Introduction
hick-smoltcp drives the Sans-I/O core (mdns-proto) over a smoltcp UDP
socket through a small UdpIo transport seam. It owns no executor and performs
no blocking: you pump it from your own poll loop alongside the smoltcp
Interface, and it tells you when to wake next. This is the shared engine the
hick-embassy driver builds on — but it is usable standalone with any smoltcp
stack.
no_std + alloc: the protocol state lives in slab-backed pools, so there is
no per-packet heap traffic on the hot path.
§Installation
[dependencies]
hick-smoltcp = "0.1"§Example
use hick_smoltcp::{DualStack, Engine};
use mdns_proto::{EndpointConfig, Name, ServiceRecords, ServiceSpec};
// The engine wires mdns-proto's alloc-tier state machines to any `UdpIo`. For
// smoltcp, use the family-aware `DualStack` over your v4 and/or v6 socket handles.
let mut engine = Engine::new(EndpointConfig::new(), rng);
let mut records = ServiceRecords::new(
Name::try_from_str("_http._tcp.local.")?,
Name::try_from_str("My Device._http._tcp.local.")?,
Name::try_from_str("mydevice.local.")?,
80,
120,
);
records.add_a(my_ipv4);
engine.register_service(ServiceSpec::new(records), now)?;
// Pump from your own loop, handing it a `DualStack` view of your sockets and a
// scratch buffer. The engine fans each multicast to BOTH groups, so `DualStack`
// routes by family (leave a family `None` for a single-stack node). `pump` returns
// the next instant the engine wants to be polled.
loop {
let mut io = DualStack::new(&mut sockets, Some(v4_handle), Some(v6_handle));
let next = engine.pump(now, &mut io, &mut scratch);
// ...advance the smoltcp interface (iface.poll(.., &mut sockets)), then sleep
// until `next` or RX-ready...
}§Feature flags
| Feature | Description |
|---|---|
atomic (default) | The native-atomic alloc tier: SmolStr names + Bytes rdata. Needs pointer-width atomics. |
no-atomic | For cores without native atomic CAS (Cortex-M0+ / thumbv6m / RP2040): swaps the refcounted Name / rdata onto portable-atomic’s Arc (clone via a critical-section impl your binary provides), keeping the alloc-backed pools. Build with --no-default-features --features no-atomic. |
tracing | Forward structured tracing events from mdns-proto (requires a std subscriber; a no-op on bare-metal without one). |
stats | Enable no_std-safe atomic counters; read a snapshot via engine.stats(). Implies atomic. |
defmt | Emit defmt log events — the idiomatic choice for bare-metal targets. |
§Observability
For bare-metal targets the recommended logging path is defmt combined with
stats:
hick-smoltcp = { version = "0.1", features = ["defmt", "stats"] }Enable defmt to have the engine emit structured log events through the
defmt framework at the level your firmware configures.
Enable stats and call engine.stats() to obtain a
hick_trace::stats::StatsSnapshot:
let snap = engine.stats();
// snap.packets_rx, snap.cache_size, etc.The tracing feature is available but is a no-op in bare-metal builds that
do not set up a tracing subscriber.
The metrics feature (bridging counters to the metrics facade) requires
std and is not available on bare-metal targets. Use stats + defmt
instead for observability on embedded.
§Design
no_std+alloc, panic-free hot path: slab-backed protocol pools, no per-packet allocation.UdpIotransport seam — a two-method, non-blocking trait (try_recv/try_send). The family-awareDualStackimplements it over smoltcp UDP sockets (routing each multicast to the socket of its own family); bring your own and the engine is transport-agnostic.- RFC 6762 §11 on-link gate — uses the received hop-limit (
== 255) when the transport surfaces it, else falls back to a source-subnet membership check. - RFC 6762 §10.1 goodbye — unregistering an announced service emits a TTL=0 goodbye, bursted a few times by the pump.
Pinned to a single smoltcp 0.13, unified with the version hick-embassy’s
embassy-net pulls in.
§The hick family
hick (facade) · mdns-proto (Sans-I/O core) · hick-udp (UDP) ·
hick-reactor (tokio / smol driver) · hick-compio (compio driver) ·
hick-smoltcp (this crate) · hick-embassy (embassy driver).
§License
hick-smoltcp is under the terms of both the MIT license and the Apache License
(Version 2.0).
See LICENSE-APACHE, LICENSE-MIT for details.
Copyright (c) 2025 Al Liu.
Re-exports§
pub use engine::Engine;pub use time::SmoltcpInstant;pub use udpio::RecvMeta;pub use udpio::SendError;pub use udpio::UdpIo;
Modules§
- constants
- mDNS multicast endpoints (RFC 6762 §3).
- engine
- The runtime-agnostic mDNS engine: a synchronous pump that drives the
mdns_proto::Endpoint(plus the per-service / per-query state machines it hands back) over aUdpIotransport. - time
- Bridge smoltcp’s monotonic clock to the
mdns_proto::Instanttrait. - udpio
- The
UdpIotransport seam between the engine and a concrete socket layer.