hick-reactor 0.2.0

Async mDNS driver layered on `mdns-proto` + `hick-udp`, runtime-agnostic via `agnostic-net` (tokio & smol).
Documentation

Runtime-agnostic async mDNS / DNS-SD — responder, querier, and DNS-SD discovery for tokio and smol.

Introduction

hick-reactor is an async mDNS driver: it wires the Sans-I/O core (mdns-proto) to multicast sockets (hick-udp) and runs the protocol on a spawned driver task. The task is generic over an agnostic-net Net implementation, so a single codebase serves both the tokio and smol runtimes.

mDNS (Multicast DNS) discovers services on the local link with no central DNS server. Note that many cloud and shared-infrastructure networks block multicast, so mDNS is best suited to office, home, or private networks.

For a batteries-included entry point, use the hick facade (it defaults to this driver). For the compio thread-per-core runtime, use hick-compio.

Installation

[dependencies]
hick-reactor = "0.6" # tokio by default

For smol instead of tokio:

[dependencies]
hick-reactor = { version = "0.6", default-features = false, features = ["smol"] }

Example

use hick_reactor::{
    Name, QuerySpec, ServerOptions, ServiceRecords, ServiceSpec, tokio, wire::ResourceType,
};

async fn run() -> Result<(), Box<dyn std::error::Error>> {
    // `tokio::server` / `smol::server` pin the runtime; the returned `Endpoint`
    // and its handles are otherwise the same.
    let endpoint = tokio::server(ServerOptions::default()).await?;

    // Advertise a service. Keep the handle alive to keep advertising; dropping it
    // withdraws the service (TTL=0 goodbye) and unregisters it.
    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("my-device.local.")?,
        80,
        120,
    );
    records.add_a([192, 168, 1, 10].into());
    let _service = endpoint.register_service(ServiceSpec::new(records)).await?;

    // Discover services of a type on the local link.
    let mut query = endpoint
        .start_query(QuerySpec::new(
            Name::try_from_str("_ipp._tcp.local.")?,
            ResourceType::Ptr,
        ))
        .await?;
    while let Some(event) = query.next().await {
        match event {
            hick_reactor::QueryEvent::Answer(answer) => println!("{answer:?}"),
            hick_reactor::QueryEvent::Terminal(_) => break,
        }
    }
    Ok(())
}

Feature flags

  • tokio (default)tokio runtime via agnostic-net.
  • smolsmol runtime.
  • tracing — forward structured tracing spans/events from the driver and the proto core.
  • stats — enable no_std-safe atomic counters; read a snapshot via endpoint.stats().
  • metrics — bridge counters to the metrics facade (Prometheus/StatsD). Implies stats.

Observability

tracing

Enable features = ["tracing"] and install a subscriber. The driver emits tracing events during socket I/O, protocol state transitions, and errors.

stats and metrics

Enable features = ["stats"] and call endpoint.stats() to obtain a hick_trace::stats::StatsSnapshot:

let snap = endpoint.stats();
println!("packets_rx={} queries_active={}", snap.packets_rx, snap.queries_active);

Enable features = ["metrics"] to additionally forward every counter/gauge update to the metrics facade automatically.

The hick family

hick (facade) · mdns-proto (Sans-I/O core) · hick-udp (UDP) · hick-reactor (this crate) · hick-compio (compio driver) · hick-smoltcp (smoltcp engine) · hick-embassy (embassy driver).

Pedigree

A port and refactor of HashiCorp's mdns; the wire format and protocol state machines are an independent, panic-free reimplementation.

License

hick-reactor 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.