Current section
Files
Jump to
Current section
Files
README.md
# Madness
Madness queries mDNS and publishes DNS-SD services from Elixir. Queries support
IPv4 and IPv6 and return records as a lazy stream or process messages.
Publishing delegates to Avahi or Apple's mDNSResponder daemon.
## Installation
Add Madness to `mix.exs`:
```elixir
def deps do
[
{:madness, "~> 0.5.0"}
]
end
```
Publishing through Avahi uses the required `rebus` dependency included by
Madness. Publishing on one specific interface also requires the optional
[`inertial`](https://hex.pm/packages/inertial) package:
```elixir
{:inertial, "~> 2.2"}
```
## Querying
`request/2` returns a stream by default:
```elixir
records =
Madness.request({"_http._tcp.local", :ptr})
|> Enum.to_list()
```
Multiple questions can share one query:
```elixir
Madness.request([
{"mydevice.local", :a},
{"mydevice.local", :aaaa}
])
|> Enum.to_list()
```
For an OTP process, use message mode:
```elixir
{:ok, ref} = Madness.request({"_http._tcp.local", :ptr}, into: :self)
receive do
{^ref, %Madness.Record{} = record} -> IO.inspect(record)
{^ref, :done} -> :ok
end
```
Responses include Answer and Additional records. Use
`record.metadata.section` to distinguish them. Non-PTR queries can finish once
all questions are answered, including by an NSEC negative answer. PTR queries
wait for the configured timeout because more responders may reply.
Common options are `timeout: 5_000`, `family: :any | :inet | :inet6`,
`interface: :any | name | index`, and `unicast_response: true | false`. See
`Madness.request/2` for the complete API.
## Publishing
Publish a service and keep the returned handle:
```elixir
{:ok, publication} =
Madness.publish(
name: "Web",
type: "_http._tcp",
port: 4000,
txt: %{"path" => "/"}
)
:ok = Madness.unpublish(publication)
```
The publication follows the lifetime of its owner process and is withdrawn
automatically when that process exits. Pass `owner:` when a short-lived setup
process publishes for a long-lived server. Monitor `publication.pid` if the
service should be republished after a daemon restart or another terminal
publication failure.
Publishing uses `config :madness, backend: :auto` by default. Automatic
selection probes Avahi and then mDNSResponder, settling on the first reachable
daemon. You can configure `:avahi`, `:mdns_responder`, a custom
`Madness.Responder` module, or `false`. The native responder is not implemented.
Avahi supports `interface:` and `family:` scopes. mDNSResponder supports
`interface:` but cannot restrict an advertisement to one address family;
Madness returns an error rather than widening a requested scope. An
interface-scoped publication requires `inertial` and terminates if the bound
interface disappears or can no longer be observed.
See `Madness.publish/2` and `Madness.Service` for service fields, lifecycle
notifications, subtypes, and validation rules.
## Development
Run the normal checks with:
```sh
mix precommit
```
The unit suite uses in-process daemon fakes. With Docker available,
`mix test.avahi` runs the Avahi integration suite against a real daemon.
## License
MIT