Replace DNS-SD dependency with built-in mDNS responder, and Add multi-platform CI build verification#523
Replace DNS-SD dependency with built-in mDNS responder, and Add multi-platform CI build verification#523kgbook wants to merge 10 commits into
Conversation
- Linux (ubuntu-latest): CMake + GStreamer + OpenSSL + libplist + DBus - macOS (macos-latest): Homebrew dependencies - Windows (windows-latest): MSYS2 + MinGW toolchain Triggered on push and PR to master/main branches
GitHub Actions ubuntu-latest requires sudo for package installation
|
replacing avahi is a major change. can you describe where the mdnsd.c code came from? Did you adapt it from somewhere? it would have needed a lot of testing if written from scratch. I could not find this code in Juho V's "shareplay" code, but the header says:
|
|
My mistake, I originally implemented this in dnssd.c, then split it into mdnsd.c later. I forgot to update the copyright information after copying. I have fixed it to use kgbook's copyright. Tested OK on Debian 13, and Apple M1 iMac. |
|
I also wrote a short article about this mDNS discovery work here: The article includes UML diagrams and packet capture analysis, which provide more background on the implementation and debugging process. It is written in Chinese, but Google Translate should be enough to read it. I hope it can provide some useful background and help. |
|
Can you move your PR to the new uxplay mdnsd branch? thanks for your work on this! |
|
OK, A new PR #524 |
|
Hi @kgbook we are reviewing this. (sorry for delay).
we are looking at initially moving the previous dnssd.[c,h] into a lib/dnssd-service directory, (The "service" could later be removed as deprecated.) |
|
I think the better architectural choice is to remove mDNS code from uxplay entirely. Let uxplay write to a file with the txt records it wants and let a seconday process deal with mDNS. this reduces the technical debt in uxplay and allows others to choose the implementation they would like - whether that is avahi, a future android api, etc. ("files" can be unix sockets too) Also, has this PR been tested running in conjunction with a system is also using avahi? |
You're right that IPv6 support was dropped in this PR. The original Avahi-based implementation had IPv6 support (v1.66 changelog: "Fix IPV6 support"). The new mdnsd.c currently only supports IPv4 multicast (224.0.0.251). Adding IPv6 support requires:
I will add IPv6 support in a follow-up PR. |
Your suggestion has merit, but separate process introduces significant tradeoffs for the embedded scenarios I care about: I'm also developing APlay — an AirPlay receiver focused on ARM/RISC-V devices, targeting Android, ARM Linux, HarmonyOS, and RTOS platforms. These targets make the case for embedded mDNS even stronger:
For APlay's target platforms (especially RTOS), a standalone mDNS daemon simply isn't available, and spawning one adds integration burden. The current embedded approach — zero external dependencies, single-process lifecycle, minimal footprint — is the right default for these scenarios. |
Also, an extra mDNS helper process requires extra permission set |
I think this is an upside, as it stands avahi-daemon (or mdnsreponder on macos (and windows??)) is the only process that needs to be allowed to access multicast on 5353. there is already a generic "dns_sd.h" interface, why not provide a header-only implementation of your proposed changes so that you can have all your criteria (single process, deployment, error handling, etc.) while minimizing the maintenance burden (no other uxplay code needs to change at all, simply a compile time flag |
|
A new branch dnssd2 has been created that will use the internal mdns code if compiled with and otherwise use the unchanged uxplay with dnssd support. Please use this for testing or PR's The README changes, and uxplay.service changes are not included yet. |
Hi @fduncanhI |
|
@kgbook thanks for the ipv6. Your work has been refactored a bit in the new branch work_dnssd which include both the avahi/bonjour dnssd and yours. https://github.com/FDH2/UxPlay/tree/work_dnssd compile with "cmake -DUSE_MDNSD=1" to get your version. The README changes and uxplay.service are not yet included, as well as the github/workflows. To make changes, clone work_dnssd and submit a PR to it. |
|
@kgbook An IPv4 connection is opened first, then replaced with an IPv6 connection... |
mdnsd previously appended both A and AAAA host records to responses sent on both IPv4 and IPv6 sockets. That behavior is only appropriate when the responder treats the physical interface as one dual-stack mDNS interface. The built-in responder uses separate IPv4 and IPv6 sockets, so treat them as RFC 6762 logical interfaces: emit A records for IPv4 responses and AAAA records for IPv6 responses. This matches the observed Avahi AirPlay behavior more closely and avoids clients learning cross-family host addresses from one response and opening replacement TCP connections. Also keep the AAAA answer count tied to the IPv6 address record that is actually emitted.
|
@kgbook EDIT: yes, they fix the IPv4/IPv6 double connection reported earlier. good job! |
|
The mdnsd code seems to work well , except on macOS, where the announcement is not visible to clients. If you are not able to test for yourself on macOS, can you perhaps add some tests in the code., that might detect failure to publish the announcement? Or give some suggestions about where such a problem might occur? (since this is UDP, its obviously not easy to detect this.) |
|
we have resolved the issue on macOS finally using Claude. It was a fight between the native mdns_responder on macOS which "owns" mac_hostname.local and mdnsd.c. Will code the fix and test it. Immediately mdnsd.c sends an announcement, the native macOS dns-responder thinks "that address belongs to me, no-one else can use it", and sends a new announcement to cancel the mdnsd.c announcement. |
Summary
The previous implementation depended on
avahi-daemonfor DNS-SD/mDNS service discovery and advertisement. While this works well on typical Linux desktop/server environments,avahi-daemonis relatively heavy for embedded targets and introduces extra runtime dependencies, daemon management, and deployment complexity.This is especially problematic for cross-platform support, particularly on Android, where running and managing an external Avahi daemon is not practical and may conflict with the platform’s permission and service model.
This PR rewrites the mDNS responder internally, removing the dependency on Avahi/DNS-SD while keeping the required service discovery and advertisement behavior.
Triggered on push and PR to master/main branches.
Motivation
avahi-daemonChanges
Validation
The rewritten mDNS responder has been tested and verified successfully, including service discovery and response behavior.