Skip to main content

Crate hick_reactor

Crate hick_reactor 

Source
Expand description

hick-reactor

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

github LoC Build codecov

docs.rs crates.io crates.io license

§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.

Modules§

config
Configuration types. Configuration types passed to Endpoint/Service/Query constructors.
event
Event types between Endpoint, Service, and Query. Event types flowing between Endpoint, Service, and Query.
proto_error
Cross-cutting error types. Cross-cutting error types and their shared detail-struct payloads.
smolsmol
Per-runtime adapter for the smol runtime.
tokiotokio
Per-runtime adapter for the tokio runtime.
wire
mDNS wire format — panic-free parser and encoder. mDNS wire format — panic-free, no_alloc-capable parser and encoder.

Structs§

CollectedAnswer
One collected answer record for a Query.
Endpoint
Handle to a running mDNS endpoint.
EndpointConfig
Configuration for an Endpoint.
Lookup
A running DNS-SD lookup.
Name
Owned, canonical DNS name (lowercased on construction).
Query
Handle to an in-flight query.
QueryHandle
Opaque identifier for an in-flight query.
QueryParam
Parameters for a Lookup / browse.
QuerySpec
Spec for starting a query.
ServerOptions
Build-time configuration for an mDNS Endpoint.
Service
Handle to a registered service.
ServiceEntry
A resolved DNS-SD service instance.
ServiceHandle
Opaque identifier for a registered service.
ServiceRecords
Records advertised by a single registered service.
ServiceRenamed
Detail payload for ServiceUpdate::Renamed.
ServiceSpec
Spec for registering a service.

Enums§

CancelError
Errors raised by Query::cancel and Service::unregister.
QueryEvent
Per-answer event surfaced on the Query stream.
RegisterError
Errors raised by Endpoint::register_service.
ServerError
Errors raised while constructing or running an Endpoint.
ServiceUpdate
App-level events emitted by Service::poll().
StartQueryError
Errors raised by Endpoint::start_query.