This article describes the Bonjour operations of service publication, browsing, and resolution that underlay the three network service API layers, and the API layers themselves. You should read this article if you want to write an application or tool that publishes or discovers network services.
Architectural Overview
Publication
Discovery
Resolution
The network services architecture in Bonjour includes an easy-to-use mechanism for publishing, discovering, and using IP-based services. Bonjour supports three fundamental operations, each of which is a necessary part of zero-configuration network services:
Publication (advertising a service)
Discovery (browsing for available services)
Resolution (translating service names to addresses and port numbers for use)
These operations are discussed in detail in the following sections.
To publish a service, an application or device must register the service with a Multicast DNS responder, either through a high-level API or by communicating directly with the responder (mDNSResponder in Mac OS X v10.2 and later). Using Mac OS X v10.4 also supports storing records on conventional DNS servers as well, using Dynamic DNS Update.
When a service is registered, three related DNS records are created: a service (SRV) record, a pointer (PTR) record, and a text (TXT) record. The TXT record contains additional data needed to resolve or use the service, although it is also often empty.
The SRV record maps the name of the service instance to the information needed by a client to actually use the service. Clients then store the service name as a persistent way to access the service, and perform a DNS query for the host name and port number when it’s time to connect. This additional level of indirection provides for two important features. First, the service is identified by a human-readable name instead of a domain name and port number. Second, clients can access the service even if its port number, IP address, or host name changes, as long as the service name remains the same.
The SRV record contains two pieces of information to identify a service:
Host name
Port number
The host name is the domain name where the service can currently be found. The reason a host name is given instead of a single IP address is that it could be a multi-homed host with more than one IP address, or it could have IPv6 addresses as well as IPv4 addresses, and so on. Identifying the host by name allows all these cases to be handled gracefully.
The port number identifies the UDP or TCP port for the service.
SRV records are named according to the following convention:
<Instance Name>.<Service Type>.<Domain>
<Instance Name>
, the name of a service instance, can be any UTF-8-encoded Unicode string, and is intended to be human readable.
<Service Type>
is a standard IP protocol name, preceded by an underscore, followed by the host-to-host transport protocol (TCP or UDP), also preceded by an underscore. For example, a Trivial FTP service running over UDP would have a service type of _tftp._udp
, and an IPP printing service running over TCP would register under the _ipp._tcp
service type. The list of official protocol names is maintained on http://www.dns-sd.org—see “Bonjour and Domain Names” for more information.
<Domain>
is a standard DNS domain. This may be a specific domain, such as apple.com.
, or the generic suffix local.
for a service accessible only on the local link.
Here is an example of the SRV record for a print spooler named PrintsAlot
running on TCP port 515
:
PrintsAlot._printer._tcp.local. 120 IN SRV 0 0 515 blackhawk.local.
This record would be created on the Multicast DNS responder of a printer called blackhawk.local.
on the local link. (The initial 120
represents the time-to-live—TTL—value which is used for caching.)
For more information about domain, service, and instance names, see “Bonjour and Domain Names.”
PTR records enable service discovery by mapping the type of the service to a list of names of specific instances of that type of service. This record adds yet another layer of indirection so services can be found just by looking up PTR records labeled with the service type.
The record contains just one piece of information, the name of the service (which is the same as the name of the SRV record). PTR records are accordingly named just like SRV records but without the instance name:
<Service Type>.<Domain>
Here is an example of a PTR record for a print spooler named PrintsAlot
:
_printer._tcp.local. 28800 PTR PrintsAlot._printer._tcp.local.
The TXT record has the same name as the corresponding SRV record, and can contain a small amount of additional information about the service instance, typically no more than 100–200 bytes at most. This record may also be empty. For example, a network game could advertise the name of the map being used in a multiplayer game, and a chat program could advertise the availability of the user (for example, idle, away, or available). If you need to transmit larger amounts of data, the host should establish a connection with the client and send the data directly.
Historically, this record has been used for multiple services running on the same port at the same IP address, for example multiple print queues running on the same print server. In this case additional information in the TXT record can be used to identify the intended print queue, as shown in this example:
Service name | Type | IP address | Port | Queue name (from TXT record) |
---|---|---|---|---|
|
|
|
|
|
|
|
|
|
|
This kind of practice was necessary because service types have historically been associated with well known ports. Designers of new Bonjour protocols are encouraged to run each instance of their service on a different dynamically allocated port number, instead of trying to run them all on the same well known port number and using extra information to specify which instance the client is trying to talk to.
The nature and format of the data in the TXT record are specific to each type of service, so each new service type needs to also define the format of data for its associated TXT record (if any), and publish this format as part of the protocol specification.
For a concrete example, consider a hypothetical device that shares music over a local network—an IP-enabled jukebox. Suppose that its transport protocol is TCP and its application protocol goes by the name music
. When someone plugs the device into an Ethernet hub, a number of things happen, as shown in Figure 1.
In step 1, the device randomly selects the link-local IP address 169.254.150.84
, randomly selected from the IPv4 link-local range 169.254.0.0
with a subnet mask of 255.255.0.0
, and announces it to the network. Because no devices respond to the announcement, the device takes the address as its own. In step 2, it starts up its own Multicast DNS responder, requests the host name eds-musicbox.local.
, verifies its availability, and takes the name as its own. Next, in step 3, the device starts up a music sharing service on TCP port 1010
. Finally, in step 4, it publishes the service, of type _music._tcp
, under the name Ed’s Party Mix
, in the local.
domain, first making sure that no service exists under the same name. This creates a SRV record named Ed’s Party Mix._music._tcp.local.
pointing to eds-musicbox.local.
on TCP port 1010
, and a PTR record named _music._tcp.local.
, pointing to the Ed’s Party Mix._music._tcp.local.
service.
If the requested IP address is unavailable, a host should assign itself a new one. If the domain name or service name are unavailable, a device without an interface should find a new name. Application software encountering this situation should present a user interface informing the user that the name is unavailable, and allow them to choose a different one.
Service discovery makes use of the DNS records registered during service publication to find all named instances of a particular type of service. To do this, an application performs a query for PTR records matching a service type, such as _http._tcp
, usually through a higher-level API. The Multicast DNS responders running on each device return PTR records with service instance names.
Figure 2 illustrates a client application browsing for music sharing services. In step 1, the client application issues a query for services of type _music._tcp
in the
local.
domain to the standard multicast address 224.0.0.251
. Every Multicast DNS responder on the network hears the request, but only the music sharing device responds with a PTR record (step 2). The resulting PTR record holds the service instance name,
Ed's Party Mix._music._tcp.local.
in this case.
Service discovery typically takes place only once in a while—for example, when a user first selects a printer. This operation saves the service instance name, the intended stable identifier for any given instance of a service. Port numbers, IP addresses, and even host names can change from day to day, but a user should not need to reselect a printer every time this happens. Accordingly, resolution from a service name to socket information does not happen until the service is actually used.
To resolve a service, an application performs a DNS lookup for a SRV record with the name of the service. The Multicast DNS responder responds with the SRV record containing the current information.
Figure 3 illustrates service resolution in the music sharing example. The resolution process begins with a DNS query to the multicast address 224.0.0.251
asking for the Ed’s Party Mix._music._tcp.local.
SRV record (step 1). In step 2, this query returns the service’s host name and port number (eds-musicbox.local.
, 1010
). In step 3, the client sends out a multicast request for the IP address. In step 4, this request resolves to the IP address 169.254.150.84
. Then the client can use the IP address and port number to connect to the service. This process takes place each time the service is used, thereby always finding the service’s most current address and port number.
© 2006 Apple Computer, Inc. All Rights Reserved. (Last updated: 2006-05-23)