Mono.Zeroconf

Mono.Zeroconf is a cross platform Zero Configuration Networking library for Mono and .NET. It provides a unified API for performing the most common zeroconf operations on a variety of platforms and subsystems: all the operating systems supported by Mono and both the Avahi and Bonjour/mDNSResponder transports.

By using Mono.Zeroconf developers can use a single API that will work regardless of the underlying implementation that a particular operating system uses.

Developers can publish services that will be exposed to other computers on the network and also query the local machines on the network for services that could have been exposed.

Table of contents

What's Included

Most developers will make use of:

  • A base namespace, Mono.Zeroconf. This is the namespace that applications and libraries should use to use zeroconf networking.
  • A command line tool, mzclient. This tool can be used to query/browse and publish services from the command line.

In addition, some backend-specific namespaces exist:

  • A provider namespace Mono.Zeroconf.Providers. This namespace can be used to implement new zeroconf providers. Most applications and libraries will never need to use this namespace.
  • A provider for mDNSResponder (Bonjour). This provider works on Windows, Mac OS X, and Linux.
  • A provider for Avahi. This provider is preferred on Linux over mDNSResponder. Most Linux distributions ship Avahi these days.

It is important to note that Mono.Zeroconf abstracts away the differences between providers (mDNSResponder/Avahi). Because of this, some of the more detailed, seldom used features of each provider stack are not exposed through Mono.Zeroconf. If you require such specificity from a zeroconf stack, you probably need to use that provider's API directly. Mono.Zeroconf is not for you.


Where to get it

Mono.Zeroconf is available in both source and binary tarball/zip form as "upstream" sources. It is maintained separately from Mono itself, but will be included as a module in the Mono release suite soon.

Sources and Windows Binaries

Currently the releases are being managed by the Banshee Project, but will soon be moved to the same location as all other Mono sources.

Note: Windows users must install Apple's Bonjour before using Mono.Zeroconf.

Linux Packages

Packages for many Linux distributions are available through the Mono project in the openSUSE Build Service. Subscribe to any of the repositories below to obtain the latest Mono suite releases, including the latest Mono.Zeroconf:

Git

Mono.Zeroconf can be checked out from Mono's github repo:

git clone https://github.com/mono/Mono.Zeroconf.git

Documentation

Things a developer should know

API Stability

Mono.Zeroconf has been around for a few years, but has gone largely unnoticed outside a few specific projects (namely, Banshee). The project started specifically to target mDNSResponder. Later, support for other providers was added. The primary Mono.Zeroconf API however caters more towards mDNSResponder, though the Avahi implementation is full featured.

While Mono.Zeroconf is functionally complete and stable, the API is currently subject to change. However, it is not expected to change much, if at all.

When Mono.Zeroconf 1.0 is released, the API will be frozen. This should happen fairly soon.

API coverage of Zeroconf operations

Today Mono.Zeroconf provides an easy to use API that covers the most common operations for Zeroconf networking (Browsing, Publishing, full TXT record support). It works either against Avahi (via the avahi-sharp bindings) or Bonjour on Linux, Windows, and Mac.

It should be noted that Mono.Zeroconf does not support many of the more advanced Zeroconf features that Avahi in particular exposes. It is an intersection of the most common operations supported by both Bonjour and Avahi.

If your application needs advanced Zeroconf features, you most likely will care about the Zeroconf provider that you actually use. Therefore, we do not expect the functionality of Mono.Zeroconf to expand much and the current API is considered stable and complete. We may however add domain enumeration support in the future if it becomes a requested feature.

Compatibility with .NET

Mono.Zeroconf references only System and System.Web assemblies. Therefore, it both builds and runs equally as well on Mono and .NET.

Mono.Zeroconf works out of the box on Windows against Bonjour on both Mono and .NET. All Mono.Zeroconf binaries, compiled either with Mono on Linux or Windows, or on Windows with .NET work on any operating system that runs either Mono or .NET and at least Bonjour.

The Avahi provider works on any platform that provides both a working Avahi daemon and the avahi-sharp bindings. The Bonjour provider works on Linux, Windows, and Mac.

Implementation Details

All Mono.Zeroconf operations are asynchronous. As such, events are how Mono.Zeroconf communicates with applications. Ensure you connect to any necessary events before starting a Zeroconf operation.

Bad Example (never do this)

ServiceBrowser browser = new ServiceBrowser ();
browser.Browse ();              // Note the order of these two operations
browser.ServiceAdded += ... ;

Good Example (always do this)

ServiceBrowser browser = new ServiceBrowser ();
browser.ServiceAdded += ... ;   // Note the order of these two operations
browser.Browse ();

Known Workarounds

There is a bug in older Mono.Zeroconf releases (0.8.0 and older) that makes it difficult to register services whose port lies outside the range of the Int16 data type.

The Mono.Zeroconf API defines Port as:

short IRegisterService.Port { get; set; }

If you need to use a port value that is greater than Int16.MaxValue, you can do the following:

service.Port = unchecked ((short)my_ushort_port_value);

Mono.Zeroconf version 0.9.0 addresses this by adding the following API (the existing Port property cannot be changed for API stability reasons):

ushort IRegisterService.UPort { get; set; }

Since both UInt16 and Int16 are of the same size, the unchecked cast is legal, and internally the high value port will be passed bit-for-bit to the underlying Zeroconf provider.

Bug Reports and Support

If you run into any issues with Mono.Zeroconf or would like help getting started, the usual Mono support channels including IRC or an appropriate mailing list.

Additionally, if you think you have found a bug in Mono.Zeroconf, please feel free to file it in Mono's Bugzilla.

How to use it

First, it should be noted that mzclient is a simple command line tool that consumes all APIs in the Mono.Zeroconf namespace. This means that mzclient's source code is an excellent, easy to follow, example of how to use Mono.Zeroconf.

Listen for and resolve services

The following example illustrates how to browse for services available on the network:

using Mono.Zeroconf;
...
ServiceBrowser browser = new ServiceBrowser ();
 
//
// Configure the code that will be called back when the information
// becomes available
//
browser.ServiceAdded += delegate (object o, ServiceBrowseEventArgs args) {
    Console.WriteLine ("Found Service: {0}", args.Service.Name);
    args.Service.Resolved += delegate (object o, ServiceResolvedEventArgs args) {
        IResolvableService s = (IResolvableService)args.Service;
        Console.WriteLine ("Resolved Service: {0} - {1}:{2} ({3} TXT record entries)", 
            s.FullName, s.HostEntry.AddressList[0], s.Port, s.TxtRecord.Count);
    };
    args.Service.Resolve ();
};
 
// 
// Trigger the request
//
browser.Browse ("_daap._tcp", "local");

Publish a service

using Mono.Zeroconf;
...
RegisterService service = new RegisterService ();
service.Name = "Aaron's DAAP Share";
service.RegType = "_daap._tcp";
service.ReplyDomain = "local.";
service.Port = 3689;
 
// TxtRecords are optional
TxtRecord txt_record = new TxtRecord ();
txt_record.Add ("Password", "false");
service.TxtRecord = txt_record;
 
service.Register ();


Providers

Mono.Zeroconf supports the concept of providers. The core Mono.Zeroconf API is provided by the Mono.Zeroconf.dll assembly which is simply a wrapper layer around interfaces that provider assemblies must implement. This core assembly does not actually perform any Zeroconf operations itself.

Provider assemblies (such as Mono.Zeroconf.Providers.Bonjour.dll) implement the Mono.Zeroconf API and actually perform the underlying Zeroconf operations described by the API.

Providers are essentially plugins to Mono.Zeroconf and are resolved at runtime in a number of ways (in the following order):

  • Scan for assemblies in the paths specified by the MONO_ZEROCONF_PROVIDERS environment variable. Multiple paths may be specified, separated by the standard ':' character.
  • Scan for assemblies in the same directory as the entry assembly.
  • Scan for assemblies in the Global Assembly Cache (GAC).

It is very important to note that the provider factory will perform the following call against all of the directories resolved in the above three steps in order to locate assemblies which may contain a provider:

Directory.GetFiles (directory, "Mono.Zeroconf.Providers.*.dll")

Therefore, in order for a provider assembly to be loaded it must satisfy the naming convention Mono.Zeroconf.Providers.*.dll. This is to reduce the overhead of loading unnecessary assemblies.

Also, each provider assembly must provide the assembly level attribute, Mono.Zeroconf.Providers.ZeroconfProviderAttribute, which informs the provider factory which type in the assembly contains the actual provider implementation details. For example:

[assembly:Mono.Zeroconf.Providers.ZeroconfProvider (
    typeof (Mono.Zeroconf.Providers.Avahi.ZeroconfProvider))]
 
namespace Mono.Zeroconf.Providers.Avahi
{
    public class ZeroconfProvider : IZeroconfProvider
    {
        // Implement IZeroconfProvider
    }
}

Finally, when an assembly is loaded by the provider factory and it contains the ZeroconfProvider type as outlined above, the type will be instantiated and its Initialize method will be executed. The first provider to not throw an exception in this method will be used as the provider throughout the lifetime of the process.

Future

Mono.Zeroconf includes support for both mDNSResponder and Avahi, though it is possible to write new providers for Mono.Zeroconf, which are just plugins to the Mono.Zeroconf system.

At this time however, we consider Mono.Zeroconf to be API stable and mostly feature complete. The only feature we may consider adding is support for domain enumeration.