hick-smoltcp 0.2.0

Runtime-agnostic mDNS / DNS-SD engine over smoltcp: the `mdns-proto` Sans-I/O core wired to smoltcp UDP. `no_std` + `alloc`.
Documentation

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.
  • UdpIo transport seam — a two-method, non-blocking trait (try_recv / try_send). The family-aware DualStack implements 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.