Avahi provides three programming APIs for integration of mDNS/DNS-SD features into your progams:
- avahi-core: an API for embedding a complete mDNS/DNS-SD stack into your software. This is intended for developers of embedded ampliances only. We dissuade from using this API in normal desktop applications since it is not a good idea to run multiple mDNS stacks simultaneously on the same host.
- the D-Bus API: an extensive D-Bus interface for browsing and registering mDNS/DNS-SD services using avahi-daemon. We recommend to use this API for software written in any language but C. (i.e. Python)
- avahi-client: a simplifying C wrapper around the D-Bus API. We recommend to use this API in C or C++ progams. The D-Bus internals are hidden completely.
All three APIs are very similar, however avahi-core is the most powerful.
In addition to the three APIs described above Avahi supports two compatibility libraries:
- avahi-compat-libdns_sd: the original Bonjour API as documented in the header file "dns_sd.h" by Apple Computer, Inc.
- avahi-compat-howl: the HOWL API as released with HOWL 0.9.8 by Porchdog Software.
Please note that these compatibility layers are incomplete and generally a waste of resources. We strongly encourage everyone to use our native APIs for newly written programs and to port older programs to avahi-client!
Some notes on the Avahi error handling:
- Error codes are negative integers and defined as AVAHI_ERR_xx
- If a function returns some kind of non-negative integer value on success, a failure is indicated by returning the error code directly.
- If a function returns a pointer of some kind on success, a failure is indicated by returning NULL
- The last error number may be retrieved by calling avahi_client_errno()
- Just like the libc errno variable the Avahi errno is NOT reset to AVAHI_OK if a function call succeeds.
- You may convert a numeric error code into a human readable string using avahi_strerror()
- The constructor function avahi_client_new() returns the error code in a call-by-reference argument
Avahi uses a simple event loop abstraction laye. A table AvahiPoll
which contains function pointers for user defined timeout and I/O condition event source implementations needs to be passed to avahi_client_new()
. An adapter for this abstraction layer is available for the GLib main loop in the object AvahiGLibPoll. A simple stand-alone implementation is available under the name AvahiSimplePoll. An adpater for the Qt main loop is available from avahi_qt_poll_get()
- Subscribe to server state changes. Pass a callback function pointer to avahi_client_new(). It will be called whenever the server state changes.
- Only register your services when the server is in state AVAHI_SERVER_RUNNING. If you register your services in other server states they might not be accessible since the local host name is not established.
- Remove your services when the server enters AVAHI_SERVER_COLLISION or AVAHI_SERVER_REGISTERING state. Your services may no be reachable anymore since the local host name is no longer established or is currently in the process of being established.
- When registering services, use the following algorithm:
- Subscribe to entry group state changes.
- If the entry group enters AVAHI_ENTRY_GROUP_COLLISION state the services of the entry group are automatically removed from the server. You may immediately add your services back to the entry group (but with new names, perhaps using avahi_alternative_service_name()) and commit again. Please do not free the entry group and create a new one. This would inhibit some traffic limiting algorithms in mDNS.
- When you need to modify your services (i.e. change the TXT data or the port number), use the AVAHI_PUBLISH_UPDATE flag. Please do not free the entry group and create a new one. This would inhibit some traffic limiting algorithms in mDNS. When changing just the TXT data avahi_entry_group_update_txt() is a shortcut for AVAHI_PUBLISH_UPDATE. Please note that you cannot use AVAHI_PUBLISH_UPDATE when changing the service name! Renaming a DNS-SD service is identical to deleting and creating a new one, and that's exactly what you should do in that case. First call avahi_entry_group_reset() to remove it and than readd it normally.
- For normal applications you need to call avahi_service_browser_new() for the service type you want to browse for. Use avahi_client_resolve_service() to acquire service data for a a service name.
- You can use avahi_domain_browser_new() to get a list of announced browsing domains. Please note that not all domains whith services on the LAN are mandatorily announced.
- Network monitor software may use avahi_service_type_browser_new() to browse for the list of available service types on the LAN. This API should NOT be used in normal software since it increases traffic immensly. In addition not all DNS-SD implementations announce their services in away that they can be found with avahi_server_type_browser_new().
- There is no need to subscribe to server state changes.
With Avahi it is possible to write client applications that can deal with Avahi daemon restarts. To accomplish that make sure to pass AVAHI_CLIENT_NO_FAIL to avahi_client_new()
's flags parameter. That way avahi_client_new()
will succeed even when the daemon is not running. In that case the object will enter AVAHI_CLIENT_CONNECTING state. As soon as the daemon becomes available the object will enter one of the AVAHI_CLIENT_S_xxx states. Make sure to not create browsers or entry groups before the client object has entered one of those states. As usual you will be informed about state changes with the callback function supplied to avahi_client_new()
. If the client is forced to disconnect from the server it will enter AVAHI_CLIENT_FAILURE state with avahi_client_errno()
== AVAHI_ERR_DISCONNECTED. Free the AvahiClient object in that case and reconnect to the server anew - again with passing AVAHI_CLIENT_NO_FAIL to avahi_client_new()
We encourage to implement this in all software where service discovery is not an integral part of application. e.g. use it in all kinds of background daemons, but not in software like iChat compatible IM software.
For now AVAHI_CLIENT_NO_FAIL cannot deal with D-Bus daemon restarts.
Due to the introduction of wide-area DNS-SD the correct handling of domains becomes more important for Avahi enabled applications. All applications that offer the user a list of services discovered with Avahi should offer some kind of editable drop down box where the user can either enter his own domain or select one of those offered by AvahiDomainBrowser. The default domain to browse should be the one returned by avahi_client_get_domain_name()
. The list of domains returned by AvahiDomainBrowser is assembled by the browsing domains configured in the daemon's configuration file, the domains announced inside the default domain, the domains set with the environment variable $AVAHI_BROWSE_DOMAINS (colon-seperated) on the client side and the domains set in the XDG configuration file ~/.config/avahi/browse-domains on the client side (seperated by newlines). File managers offering some kind of "Network Neighborhood" folder should show the entries of the default domain right inside that and offer subfolders for the browsing domains returned by AvahiDomainBrowser.