Documentation ¶
Overview ¶
Package avahi provides a fairly complete CGo binding for Avahi client.
Avahi is the standard implementation of Multicast DNS and DNS-SD for Linux, and likely for some BSD systems as well. This technology is essential for automatic network configuration, service discovery on local networks, and driverless printing and scanning. It also can be useful for the peer services discovery in a cloud.
Package philosophy ¶
The Avahi API wrapper, provided by this package, attempts to be as close to the original Avahi C API and as transparent, as possible. However, the following differences still exist:
- Events are reported via channels, not via callbacks, as in C
- AvahiPoll object is not exposed and handled internally
- Workaround for Avahi localhost handling bug is provided (for details, see "Loopback interface handling and localhost" section above).
A bit of theory (Multicast DNS and DNS-SD essentials) ¶
Avahi API is much simpler to understand when reader knows the basics of the Multicast DNS and DNS-SD protocols.
DNS is a kind of a distributed key-value database. In classical (unicast) DNS, records are maintained by the hierarchy of servers, while in the MDNS each participating host maintains its own records by itself and responds when somebody asks, usually using multicast UDP as transport.
In the case of classical DNS, clients perform database queries by contacting DNS servers. In contrast, with multicast DNS, clients send their queries to all other hosts in the vicinity using UDP multicast (e.g., "Hey! I need an IP address for the 'example.local' hostname. Who knows the answer?"). The hosts then respond by their own. To speed things up, when a new host connects to the network, it announces its resource records (RRs) to all interested parties and attempts to notify others of its removal just before it disconnects. Clients can capture and cache this information, eliminating the need for a slow network query each time this information is requires.
Each entry in the DNS database (called the Resource Record, RR) is identified by the search key, which consist of:
- record name
- record class
- record type
The record name always looks like domain name, i.e., it is a string that consists from the dot-separated labels. The "example.com" name consists of two labels: "example" and "com".
This syntax is used even for names, which are not domains by themselves. For example, "1.0.0.127.in-addr.arpa" is the IP address "127.0.0.1", written using a DNS name syntax (please notice the reverse order of labels), and "_http._tcp.local" is the collective name of all HTTP servers running over TCP on a local network.
To distinguish between normal domains and pseudo-domains, a number of special top-level domains have been reserved for this purpose, like "in-addr.arpa" for IP addresses
DNS defines many classes, but the only class relevant to multicast DNS is IN, which stands for "Internet." That's all there is to it.
Record type is more important, as many record types are being used. We will not attempt to list them all, the most important for as are the following:
A - these records contains one or more IPv4 addresses AAAA - these records contains one or more IPv6 addresses PTR - the pointer record. They point to some other domain name SRV - service descriptor TXT - contains a lot of additional information, represented as a list of key=value textual pairs.
Once we have a record name and type, we can query a record value. Interpretation of this value depends on a record type.
Now lets manually discover all IPP printers in our local network. We will use the small utility, mcdig, which allows to manually perform the Multicast DNS queries.
First of all, lets list all services on a network around. This is a query of the "_services._dns-sd._udp.local" records of type PTR, and mcdig will return the following answer (shortened):
$ mcdig _services._dns-sd._udp.local ptr ;; ANSWER SECTION: _services._dns-sd._udp.local. 4500 IN PTR _http._tcp.local. _services._dns-sd._udp.local. 4500 IN PTR _https._tcp.local. _services._dns-sd._udp.local. 4500 IN PTR _ipp._tcp.local. _services._dns-sd._udp.local. 4500 IN PTR _ipps._tcp.local. _services._dns-sd._udp.local. 4500 IN PTR _printer._tcp.local.
This is the same list as avahi-browse -a returns, and programmatically it can be obtained, using the ServiceTypeBrowser object.
Please notice, the "_services._dns-sd._udp.<domain>" is a reserved name for this purpose and <domain> is usually "local"; this top-level domain name is reserved for this purpose.
Now we see that somebody in our network provide the "_http._tcp.local." service (IPP printing), "_http._tcp.local." service (HTTP server) and so on. In a typical network there will be many services and they will duplicate in the answer.
Now, we are only interested in the IPP printers, so:
$ mcdig _ipp._tcp.local. ptr ;; ANSWER SECTION: _ipp._tcp.local. 4500 IN PTR Kyocera\ ECOSYS\ M2040dn._ipp._tcp.local.
Now we have a so called service instance name, "Kyocera ECOSYS M2040dn". Please notice, unlike classical DNS, MDNS labels may contain spaces (and virtually any valid UTF-8 characters), but although these labels looks like human-readable names, they are network-unique (which is enforced by the protocol) and can be used to unambiguously identify the device.
The same list will be returned by the avahi-browse _ipp._tcp command (please notice, the .local suffix is implied here) or using the ServiceBrowser object.
Now we need to know a bit more about the device, so the next two queries are:
$ mcdig Kyocera\ ECOSYS\ M2040dn._ipp._tcp.local. srv Kyocera\ ECOSYS\ M2040dn._ipp._tcp.local. 120 IN SRV 0 0 631 KM7B6A91.local. $ mcdig Kyocera\ ECOSYS\ M2040dn._ipp._tcp.local. txt Kyocera\ ECOSYS\ M2040dn._ipp._tcp.local. 4500 IN TXT "txtvers=1" "pdl=image/pwg-raster,..." ...
It brings us the following information:
SRV record contains a hostname (which is not the same as the instance name, and often is not as friendly and human-readable) and IP port (631, the third parameter in the SRV RR)
TXT record contains a lot of "key=value" pairs which describe many characteristics of device.
And the final step is to obtain device's IP addresses. Here we need the hostname, obtained at the previous steps:
$ mcdig KM7B6A91.local. a KM7B6A91.local. 120 IN A 192.168.1.102 $ mcdig KM7B6A91.local. aaaa KM7B6A91.local. 120 IN AAAA fe80::217:c8ff:fe7b:6a91
The response is really huge and significantly shortened here. The TXT record is omitted at all, as it really large.
So the whole picture looks as following:
INPUT: "_ipp._tcp.local." (the service type) | --> Query PTR record | --> "Kyocera ECOSYS M2040dn._ipp._tcp.local." (the instance name) | |-> Query SRC record | | | |-> 631 (TCP port) | | | --> "KM7B6A91.local." (the hostname) | | | |-> Query A record | | | | | --> 192.168.1.102 (IPv4 address) | | | --> Query AAAA record | | | --> fe80::217:c8ff:fe7b:6a91 (IPv6 address) | -> Query TXT record | --> A lot of key=value pairs (device description)
So a lot of work indeed!
The same information can be obtained programmatically, using the ServiceResolver object, and the service resolver actually perform all these steps under the hood.
And finally, we can lookup IP address by hostname and hostname by IP address:
$ mcdig KM7B6A91.local. a ;; ANSWER SECTION: KM7B6A91.local. 120 IN A 192.168.1.102 $ mcdig 102.1.168.192.in-addr.arpa ptr ;; ANSWER SECTION: 102.1.168.192.in-addr.arpa. 120 IN PTR KM7B6A91.local.
It corresponds to avahi commands "avahi-resolve-host-name KM7B6A91.local" and "avahi-resolve-address 192.168.1.102".
The HostNameResolver and AddressResolver objects provide the similar functionality in a form of API.
Key objects ¶
The key objects exposed by this package are:
- Client represents a client connection to the avahi-daemon
- Assortment of browsers: DomainBrowser, RecordBrowser, ServiceBrowser, ServiceTypeBrowser
- Assortment of resolvers: AddressResolver, HostNameResolver, ServiceResolver
- EntryGroup, which implements Avahi publishing API.
These objects have 1:1 relations to the corresponding avahi objects (i.e., Client represents AvahiClient, DomainBrowser represennts AvahiDomainBrowser and so on).
These objects are explicitly created with appropriate constructor functions (e.g., NewClient, NewDomainBrowser, NewServiceResolver and so on).
All these objects report their state change and discovered information using provided channel (use Chan() method to obtain the channel). There is also a context.Context-aware Get() methods which can be used to wait for the next event.
As these objects own some resources, such as DBus connection to the avahi-daemon, which is not automatically released when objects are garbage-collected, this is important to call appropriate Close method, when object is not longer in use.
Once object is closed, the sending side of its event channel is closed too, which effectively unblocks all users waiting for events.
Client ¶
The Client represents a client connection to the avahi-daemon. Client is the required parameter for creation of Browsers and Resolvers and "owns" these objects.
Client has a state and this state can change dynamically. Changes in the Client state reported as a series of [ClientEVENT] events, reported via the Client.Chan channel or Client.Get convenience wrapper.
The Client itself can survive avahi-daemon (and DBus server) failure and restart. If it happens, ClientStateFailure event will be reported, followed by ClientStateConnecting and finally ClientStateRunning, when client connection will be recovered. However, all Browsers, Resolvers and EntryGroup-s owned by the Client will fail (with BrowserFailure/ResolverFailure/EntryGroupStateFailure events) and will not be restarted automatically. If it happens, application needs to close and re-create these objects.
The Client manages underlying AvahiPoll object (Avahi event loop) automatically and doesn't expose it via its interface.
Browsers ¶
Browser constantly monitors the network for newly discovered or removed objects of the specified type and report discovered information as a series of events, delivered via provided channel.
More technically, browser monitors the network for reception of the MDNS messages of the browser-specific type and reports these messages as browser events.
There are 5 types of browser events, represented as values of the BrowserEvent integer type:
- BrowserNew - new object was discovered on a network
- BrowserRemove - the object was removed from the network
- BrowserCacheExhausted - one-time hint event, that notifies the user that all entries from the avahi-daemon cache have been sent
- BrowserAllForNow - one-time hint event, that notifies the user that more events are are unlikely to be shown in the near feature
- BrowserFailure - browsing failed and needs to be restarted
Avahi documentation doesn't explain in detail, when BrowserAllForNow is generated, but generally, it is generated after an one-second interval from the reception of MDNS message of related type has been expired.
Each browser has a constructor function (e.g., NewDomainBrowser) and three methods:
- Chan, which returns the event channel
- Get, the convenience wrapper which waits for the next event and can be canceled using context.Context parameter
- Close, which closes the browser.
This is important to call Close method when browser is not longer in use.
Resolvers ¶
Resolver performs a series of appropriate MDNS queries to resolve supplied parameters into the requested information, depending on Resolver type (e.g,, ServiceResolver will resolve service name into hostname, IP address:port and TXT record).
Like Browsers, Resolvers return discovered information as a series of resolver events.
There are 2 types of resolver events, represented by integer value of the ResolverEvent type:
- ResolverFound - new portion of required information received from the network
- ResolverFailure - resolving failed and needs to be restarted
Please notice a single query may return multiple ResolverFound events. For example, if target has multiple IP addresses, each address will be reported via separate event.
Unlike the Browser, the Resolver does not provide any indication of which event is considered "last" in the sequence. Technically, there is no definitive "last" event, as a continuously running Resolver will generate a ResolverFound event each time the service data changes. However, if we simply need to connect to a discovered service, we must eventually stop waiting. A reasonable approach would be to wait for a meaningful duration (for example, 1 second) after the last event in the sequence arrives.
EntryGroup ¶
EntryGroup implements Avahi publishing API. This is, essentially, a collection of resource entries which can be published "atomically", i.e., either the whole group is published or not.
Records can be added to the EntryGroup using EntryGroup.AddService, EntryGroup.AddAddress and EntryGroup.AddRecord methods. Existing services can be modified, using the EntryGroup.AddServiceSubtype and EntryGroup.UpdateServiceTxt methods. Once group is configured, application must call EntryGroup.Commit for changes to take effect.
When records are added, even before Commit, Avahi performs some basic checking of the group consistency, and if consistency is violated or added records contains invalid data, the appropriate call will fail with suitable error code.
When publishing services, there is no way to set service IP address explicitly. Instead, Avahi deduces appropriate IP address, based on the network interface being used and available addresses assigned to that interface.
Like other objects, EntryGroup maintains a dynamic state and reports its state changes using EntryGroupEvent which can be received either via the channel, returned by EntryGroup.Chan or via the EntryGroup.Get convenience wrapper.
As the protocol requires, EntryGroup implies a conflict checking, so this process takes some time. As result of this process, the EntryGroup will eventually come into the either EntryGroupStateEstablished or EntryGroupStateCollision state.
Unfortunately, in a case of collision there is no detailed reporting, which entry has caused a collision. So it is not recommended to mix unrelated entries in the same group.
IP4 vs IP6 ¶
When new Browser or Resolver is created, the 3rd parameter of constructor function specified a transport protocol, used for queries.
Some Resolver constructors have a second parameter of the Protocol type, the "addrproto" parameter. This parameter specifies which kind of addresses, IP4 or IP6, we are interested in output (technically, which kind of address records, A or AAAA, are queried).
If you create a Browser, using ProtocolUnspec transport protocol, it will report both IP4 and IP6 RRs and report them as separate events.
A new Resolver, created with ProtocolUnspec transport protocol will use IP6 as its transport protocol, as if ProtocolIP6 was specified.
If "addrproto" is specified as ProtocolUnspec, Resolver will always query for addresses that match the transport protocol.
It can be summarized by the following table:
proto addrproto transport query for ProtocolIP4 ProtocolIP4 IP4 IP4 ProtocolIP4 ProtocolIP6 IP4 IP6 ProtocolIP4 ProtocolUnspec IP4 IP4 ProtocolIP6 ProtocolIP4 IP6 IP4 ProtocolIP6 ProtocolIP6 IP6 IP6 ProtocolIP6 ProtocolUnspec IP6 IP6 ProtocolUnspec ProtocolIP4 IP6 IP4 ProtocolUnspec ProtocolIP6 IP6 IP6 ProtocolUnspec ProtocolUnspec IP6 IP6
By default the Avahi daemon publishes both IP4 and IP6 addresses when queried over IP4, but only IP6 addresses, when queried over IP6. This default can be changed using 'publish-aaaa-on-ipv4' and 'publish-a-on-ipv6' in 'avahi-daemon.conf').
Other servers (especially DNS-SD servers found on devices, like printers or scanners) may have a different, sometimes surprising, behavior.
So it makes sense to perform queries of all four transport/address combinations and merge results.
Loopback interface handling and localhost ¶
As loopback network interface doesn't support multicasting, Avahi just emulates the appropriate functionality.
Loopback support is essentially for implementing the IPP over USB protocol, and ipp-usb daemon actively uses it. It allows the many modern printers and scanners to work seamlessly under the Linux OS.
Unfortunately, loopback support is broken in Avahi. This is a long story, but in short:
- Services, published at the loopback address (127.0.0.1 or ::1) are erroneously reported by AvahiServiceResolver as being published at the real hostname and domain, instead of "localhost.localdomain"
- AvahiAddressResolver also resolves these addresses using real hostname and domain
- AvahiHostNameResolver doesn't resolve neither "localhost" nor "localhost.localdomain".
This library provides a workaround, but it needs to be explicitly enabled, using the ClientLoopbackWorkarounds flag:
clnt, err := NewClient(ClientLoopbackWorkarounds)
If this flag is in use, the following changes will occur:
- ServiceResolver and AddressResolver will return "localhost.localdomain" for the loopback addresses
- HostNameResolver will resolve "localhost" and "localhost.localdomain" as either 127.0.0.1 or ::1, depending on a value of the proto parameter for the NewHostNameResolver call. Please notice that if proto is ProtocolUnspec, NewHostNameResolver will use by default ProtocolIP6, to be consistent with other Avahi API (see section "IP4 vs IP6" for details).
IP addresses ¶
This package uniformly uses netip.Addr to represent addresses. Unlike net.Addr, this format is compact, convenient and comparable.
When addresses are received from Avahi (for example, as a part of ServiceResolverEvent), the following rules apply:
- IPv4 addresses are represented as 4-byte netip.Addr, not as 16-byte IP6-mapped IP4 addresses.
- Link-local IPv6 addresses come with zone. For zone, numerical, not symbolic, format is used (i.e., fe80::1ff:fe23:4567:890a%3, not fe80::1ff:fe23:4567:890a%eth2)
When address is sent from application to Avahi, the following rules apply:
- Both genuine IP4 and IP6-mapped IP4 addresses are equally accepted
- For IP6 addresses, zone is ignored
The Poller ¶
Poller is the helper object that allows to simplify the event loop when working with many instances of Browsers and Resolvers (the typical case for Avahi programming).
Poller is not a part of the native Avahi API and added here for convenience.
Poller allows to "connect" many event sources to the single object and use it's Poller.Poll methods to gather events from all the connected objects.
See project's README.md for the usage example.
Index ¶
- func DNSDecodeA(rdata []byte) netip.Addr
- func DNSDecodeAAAA(rdata []byte) netip.Addr
- func DNSDecodeTXT(rdata []byte) []string
- func DomainEqual(d1, d2 string) bool
- func DomainFrom(labels []string) string
- func DomainNormalize(d string) string
- func DomainServiceNameJoin(instance, svctype, domain string) string
- func DomainServiceNameSplit(nm string) (instance, svctype, domain string)
- func DomainSlice(d string) []string
- func DomainToLower(d string) string
- func DomainToUpper(d string) string
- type AddressResolver
- type AddressResolverEvent
- type BrowserEvent
- type Client
- func (clnt *Client) Chan() <-chan *ClientEvent
- func (clnt *Client) Close()
- func (clnt *Client) Get(ctx context.Context) (*ClientEvent, error)
- func (clnt *Client) GetDomainName() string
- func (clnt *Client) GetHostFQDN() string
- func (clnt *Client) GetHostName() string
- func (clnt *Client) GetVersionString() string
- type ClientEvent
- type ClientFlags
- type ClientState
- type DNSClass
- type DNSType
- type DomainBrowser
- type DomainBrowserEvent
- type DomainBrowserType
- type EntryGroup
- func (egrp *EntryGroup) AddAddress(rec *EntryGroupAddress, flags PublishFlags) error
- func (egrp *EntryGroup) AddRecord(rec *EntryGroupRecord, flags PublishFlags) error
- func (egrp *EntryGroup) AddService(svc *EntryGroupService, flags PublishFlags) error
- func (egrp *EntryGroup) AddServiceSubtype(svcid *EntryGroupServiceIdent, subtype string, flags PublishFlags) error
- func (egrp *EntryGroup) Chan() <-chan *EntryGroupEvent
- func (egrp *EntryGroup) Close()
- func (egrp *EntryGroup) Commit() error
- func (egrp *EntryGroup) Get(ctx context.Context) (*EntryGroupEvent, error)
- func (egrp *EntryGroup) IsEmpty() bool
- func (egrp *EntryGroup) Reset() error
- func (egrp *EntryGroup) UpdateServiceTxt(svcid *EntryGroupServiceIdent, txt []string, flags PublishFlags) error
- type EntryGroupAddress
- type EntryGroupEvent
- type EntryGroupRecord
- type EntryGroupService
- type EntryGroupServiceIdent
- type EntryGroupState
- type ErrCode
- type HostNameResolver
- type HostNameResolverEvent
- type IfIndex
- type LookupFlags
- type LookupResultFlags
- type Poller
- func (p *Poller) AddAddressResolver(resolver *AddressResolver)
- func (p *Poller) AddClient(clnt *Client)
- func (p *Poller) AddDomainBrowser(browser *DomainBrowser)
- func (p *Poller) AddHostNameResolver(resolver *HostNameResolver)
- func (p *Poller) AddRecordBrowser(browser *RecordBrowser)
- func (p *Poller) AddServiceBrowser(browser *ServiceBrowser)
- func (p *Poller) AddServiceResolver(resolver *ServiceResolver)
- func (p *Poller) AddServiceTypeBrowser(browser *ServiceTypeBrowser)
- func (p *Poller) Poll(ctx context.Context) (any, error)
- type Protocol
- type PublishFlags
- type RecordBrowser
- type RecordBrowserEvent
- type ResolverEvent
- type ServiceBrowser
- type ServiceBrowserEvent
- type ServiceResolver
- type ServiceResolverEvent
- type ServiceTypeBrowser
- type ServiceTypeBrowserEvent
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func DNSDecodeA ¶
DNSDecodeA decodes A type resource record.
It returns a real IPv4 (not IPv6-encoded IPv4) address.
RecordBrowserEvent.RData can be used as input. Errors reported by returning zero netip.Addr
func DNSDecodeAAAA ¶
DNSDecodeAAAA decodes AAAA type resource record.
RecordBrowserEvent.RData can be used as input. Errors reported by returning zero netip.Addr
func DNSDecodeTXT ¶
DNSDecodeTXT decodes TXT type resource record.
RecordBrowserEvent.RData can be used as input. Errors reported by returning nil slice.
func DomainEqual ¶
DomainEqual reports if two domain names are equal.
Note, invalid domain names are never equal to anything else, including itself.
func DomainFrom ¶
DomainFrom makes escaped domain name string from a sequence of unescaped labels:
["Ex.Ample", "com"] -> "Ex\.Ample.com"
Note, this function is not guaranteed to escape labels exactly as Avahi does, but output is anyway correct.
func DomainNormalize ¶
DomainNormalize normalizes the domain name by removing unneeded escaping.
In a case of error it returns empty string.
func DomainServiceNameJoin ¶
DomainServiceNameJoin merges two parts of the full service name (instance name, service type and domain name) into the full service name.
- instance MUST be unescaped label
- svctype and domain MUST be escaped domain names
- instance and svctype MUST NOT be empty
In a case of error it returns empty strings. Strong validation of input strings is not performed here.
func DomainServiceNameSplit ¶
DomainServiceNameSplit splits service name into instance, service type and domain components:
"Kyocera ECOSYS M2040dn._ipp._tcp.local" --> --> ["Kyocera ECOSYS M2040dn", "_ipp._tcp", "local"]
In a case of error it returns empty strings
func DomainSlice ¶
DomainSlice splits escaped domain name into a sequence of unescaped labels:
"Ex\.Ample.com" -> ["Ex.Ample", "com"]
In a case of error it returns nil.
func DomainToLower ¶
DomainToLower converts domain name to upper case.
It only touches ASCII uppercase letters "a" to "z", leaving all other bytes untouched.
See RFC6762, 16. Multicast DNS Character Set for details.
func DomainToUpper ¶
DomainToUpper converts domain name to upper case.
It only touches ASCII lowercase letters "a" to "z", leaving all other bytes untouched.
See RFC6762, 16. Multicast DNS Character Set for details.
Types ¶
type AddressResolver ¶
type AddressResolver struct {
// contains filtered or unexported fields
}
AddressResolver resolves hostname by IP address.
func NewAddressResolver ¶
func NewAddressResolver( clnt *Client, ifidx IfIndex, proto Protocol, addr netip.Addr, flags LookupFlags) (*AddressResolver, error)
NewAddressResolver creates a new AddressResolver.
AddressResolver resolves hostname by provided IP address. Roughly speaking, it does the work similar to gethostbyaddr using MDNS. Resolved information is reported via channel returned by the AddressResolver.Chan.
Function parameters:
- clnt is the pointer to Client
- ifidx is the network interface index. Use IfIndexUnspec to specify all interfaces.
- proto is the IP4/IP6 protocol, used as transport for queries. If set to ProtocolUnspec, both protocols will be used.
- addr is the IP address for which hostname discovery is performed.
- flags provide some lookup options. See LookupFlags for details.
AddressResolver must be closed after use with the AddressResolver.Close function call.
func (*AddressResolver) Chan ¶
func (resolver *AddressResolver) Chan() <-chan *AddressResolverEvent
Chan returns channel where [AddressResolverEvent]s are sent.
func (*AddressResolver) Close ¶
func (resolver *AddressResolver) Close()
Close closes the AddressResolver and releases allocated resources. It closes the event channel, effectively unblocking pending readers.
Note, double close is safe.
func (*AddressResolver) Get ¶
func (resolver *AddressResolver) Get(ctx context.Context) ( *AddressResolverEvent, error)
Get waits for the next AddressResolverEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if AddressResolver was closed
type AddressResolverEvent ¶
type AddressResolverEvent struct { Event ResolverEvent // Event code IfIdx IfIndex // Network interface index Proto Protocol // Network protocol Err ErrCode // In a case of ResolverFailure Flags LookupResultFlags // Lookup flags Addr netip.Addr // IP address (mirrored) Hostname string // Hostname (resolved) }
AddressResolverEvent represents events, generated by the AddressResolver.
type BrowserEvent ¶
type BrowserEvent int
BrowserEvent is the CGo representation of AvahiBrowserEvent.
const ( // New object discovered on the network. BrowserNew BrowserEvent = C.AVAHI_BROWSER_NEW // The object has been removed from the network. BrowserRemove BrowserEvent = C.AVAHI_BROWSER_REMOVE // One-time event, to notify the user that all entries from // the cache have been sent. BrowserCacheExhausted BrowserEvent = C.AVAHI_BROWSER_CACHE_EXHAUSTED // One-time event, to hint the user that more records // are unlikely to be shown in the near feature. BrowserAllForNow BrowserEvent = C.AVAHI_BROWSER_ALL_FOR_NOW // Browsing failed with a error. BrowserFailure BrowserEvent = C.AVAHI_BROWSER_FAILURE )
BrowserEvent values:
func (BrowserEvent) String ¶
func (e BrowserEvent) String() string
String returns a name of BrowserEvent
type Client ¶
type Client struct {
// contains filtered or unexported fields
}
Client represents a client connection to the Avahi daemon.
Client may change its state dynamically. ClientState changes reported as a series of ClientEvent via the channel returned by the Client.Chan call.
When Client is not in use anymore, it must be closed using the Client.Close call to free associated resources. Closing the client closes its event notifications channel, effectively unblocking pending readers.
func (*Client) Chan ¶
func (clnt *Client) Chan() <-chan *ClientEvent
Chan returns a channel where ClientState change events are delivered.
Client.Close closes the sending side of this channel, effectively unblocking pending receivers.
func (*Client) Close ¶
func (clnt *Client) Close()
Close closes a Client.
Note, double close is safe.
func (*Client) Get ¶
func (clnt *Client) Get(ctx context.Context) (*ClientEvent, error)
Get waits for the next ClientEvent.
It returns:
- event, nil - on success
- nil, error - if context is canceled
- nil, nil - if Client was closed
func (*Client) GetDomainName ¶
GetDomainName returns domain name (e.g., "local")
func (*Client) GetHostFQDN ¶
GetHostFQDN returns FQDN host name (e.g., "name.local")
func (*Client) GetHostName ¶
GetHostName returns host name (e.g., "name")
func (*Client) GetVersionString ¶
GetVersionString returns avahi-daemon version string
type ClientEvent ¶
type ClientEvent struct { State ClientState // New client state Err ErrCode // Only for ClientStateFailure }
ClientEvent represents events, generated by the Client.
type ClientFlags ¶
type ClientFlags int
ClientFlags modify certain aspects of the Client behavior.
const ( // Loopback handling in Avahi is broken. In particular: // - AvahiServiceResolver and AvahiAddressResolver // return real host name and domain for loopback addresses // - AvahiHostNameResolver doesn't resolve neither // "localhost" nor "localhost.localdomain". // // Among other things, it breaks IPP over USB support. This // protocol uses Avahi for local service discovery and has // a strong requirement to use "localhost" as a hostname // when working with local services. // // If Client is created with this flag, the following // workarounds are enabled: // - Host name and domain returned by ServiceResolver and // AddressResolver for the loopback addresses (127.0.0.1 // and ::1) are forced to be localhost.localdomain // - HostNameResolver resolves "localhost" and // "localhost.localdomain" as 127.0.0.1. ClientLoopbackWorkarounds ClientFlags = 1 << iota )
ClientFlags bits:
type ClientState ¶
type ClientState int
ClientState represents a Client state.
const ( // Avahi server is being registering host RRs on a network ClientStateRegistering ClientState = C.AVAHI_CLIENT_S_REGISTERING // Ahavi server is up and running ClientStateRunning ClientState = C.AVAHI_CLIENT_S_RUNNING // Avahi server was not able to register host RRs due to collision // with some another host. // // Administrator needs to update the host name to avoid the // collision. ClientStateCollision ClientState = C.AVAHI_CLIENT_S_COLLISION // Avahi server failure. ClientStateFailure ClientState = C.AVAHI_CLIENT_FAILURE // Avahi Client is trying to connect the server. ClientStateConnecting ClientState = C.AVAHI_CLIENT_CONNECTING )
ClientState values:
func (ClientState) String ¶
func (state ClientState) String() string
String returns name of the ClientState.
type DNSClass ¶
type DNSClass int
DNSClass represents a DNS record class. See RFC1035, 3.2.4. for details.
const (
DNSClassIN DNSClass = 1
)
DNSClass values:
type DNSType ¶
type DNSType int
DNSType represents a DNS record type.
For details, see:
- RFC1035, 3.2.2. - common record types
- RFC2782 - SRV record
- RFC3596 - AAAA record
const ( DNSTypeA DNSType = 1 // IP4 host address DNSTypeNS DNSType = 2 // An authoritative name server DNSTypeCNAME DNSType = 5 // The canonical name for an alias DNSTypeSOA DNSType = 6 // SOA record DNSTypePTR DNSType = 12 // A domain name pointer DNSTypeHINFO DNSType = 13 // Host information DNSTypeMX DNSType = 15 // Mail exchange DNSTypeTXT DNSType = 16 // Text strings DNSTypeAAAA DNSType = 28 // IP6 host address (RFC3596) DNSTypeSRV DNSType = 33 // Service record (RFC2782) )
DNSType values
type DomainBrowser ¶
type DomainBrowser struct {
// contains filtered or unexported fields
}
DomainBrowser performs discovery of browsing and registration domains. See NewDomainBrowser and RFC6763, 11 for details.
func NewDomainBrowser ¶
func NewDomainBrowser( clnt *Client, ifidx IfIndex, proto Protocol, domain string, btype DomainBrowserType, flags LookupFlags) (*DomainBrowser, error)
NewDomainBrowser creates a new DomainBrowser.
DomainBrowser constantly monitors the network for the available browsing/registration domains reports discovered information as a series of DomainBrowserEvent events via channel returned by the DomainBrowser.Chan
Avahi documentation doesn't give a lot of explanation about purpose of this functionality, but RFC6763, 11 gives some technical for details. In short, DomainBrowser performs DNS PTR queries in the following special domains:
DomainBrowserBrowse: b._dns-sd._udp.<domain>. DomainBrowserBrowseDefault: db._dns-sd._udp.<domain>. DomainBrowserRegister: r._dns-sd._udp.<domain>. DomainBrowserRegisterDefault: dr._dns-sd._udp.<domain>. DomainBrowserLegacy: lb._dns-sd._udp.<domain>.
According to RFC6763, the <domain> is usually "local", (meaning "perform the query using link-local multicast") or it may be learned through some other mechanism, such as the DHCP "Domain" option (option code 15) RFC2132.
So network administrator can configure some MDNS responder located in the local network to provide this information for applications.
In fact, this mechanism seems to be rarely used in practice and provided here just for consistency.
Function parameters:
- clnt is the pointer to Client
- ifidx is the network interface index. Use IfIndexUnspec to monitor all interfaces.
- proto is the IP4/IP6 protocol, used as transport for queries. If set to ProtocolUnspec, both protocols will be used.
- domain is domain where domains are looked. If set to "", the default domain is used, which depends on a avahi-daemon configuration and usually is ".local"
- btype specified a type of domains being browses. See DomainBrowserType for details.
- flags provide some lookup options. See LookupFlags for details.
DomainBrowser must be closed after use with the DomainBrowser.Close function call.
func (*DomainBrowser) Chan ¶
func (browser *DomainBrowser) Chan() <-chan *DomainBrowserEvent
Chan returns channel where [DomainBrowserEvent]s are sent.
func (*DomainBrowser) Close ¶
func (browser *DomainBrowser) Close()
Close closes the DomainBrowser and releases allocated resources. It closes the event channel, effectively unblocking pending readers.
Note, double close is safe.
func (*DomainBrowser) Get ¶
func (browser *DomainBrowser) Get(ctx context.Context) (*DomainBrowserEvent, error)
Get waits for the next DomainBrowserEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if DomainBrowser was closed
type DomainBrowserEvent ¶
type DomainBrowserEvent struct { Event BrowserEvent // Event code IfIdx IfIndex // Network interface index Proto Protocol // Network protocol Err ErrCode // In a case of BrowserFailure Flags LookupResultFlags // Lookup flags Domain string // Domain name }
DomainBrowserEvent represents events, generated by the DomainBrowser.
type DomainBrowserType ¶
type DomainBrowserType int
DomainBrowserType specifies a type of domain to browse for.
const ( // Request list of available browsing domains. DomainBrowserBrowse DomainBrowserType = C.AVAHI_DOMAIN_BROWSER_BROWSE // Request the default browsing domain. DomainBrowserBrowseDefault DomainBrowserType = C.AVAHI_DOMAIN_BROWSER_BROWSE_DEFAULT // Request list of available registering domains. DomainBrowserRegister DomainBrowserType = C.AVAHI_DOMAIN_BROWSER_REGISTER // Request the default registering domains. DomainBrowserRegisterDefault DomainBrowserType = C.AVAHI_DOMAIN_BROWSER_REGISTER_DEFAULT // Request for "legacy browsing" domains. See RFC6763, 11 for details. DomainBrowserLegacy DomainBrowserType = C.AVAHI_DOMAIN_BROWSER_BROWSE_LEGACY )
DomainBrowserType values:
type EntryGroup ¶
type EntryGroup struct {
// contains filtered or unexported fields
}
EntryGroup represents a group of RR records published via avahi-daemon.
All entries in the group are published or updated atomically.
func NewEntryGroup ¶
func NewEntryGroup(clnt *Client) (*EntryGroup, error)
NewEntryGroup creates a new EntryGroup.
func (*EntryGroup) AddAddress ¶
func (egrp *EntryGroup) AddAddress( rec *EntryGroupAddress, flags PublishFlags) error
AddAddress adds host/address pair.
func (*EntryGroup) AddRecord ¶
func (egrp *EntryGroup) AddRecord( rec *EntryGroupRecord, flags PublishFlags) error
AddRecord adds a raw DNS record
func (*EntryGroup) AddService ¶
func (egrp *EntryGroup) AddService( svc *EntryGroupService, flags PublishFlags) error
AddService adds a service registration
func (*EntryGroup) AddServiceSubtype ¶
func (egrp *EntryGroup) AddServiceSubtype( svcid *EntryGroupServiceIdent, subtype string, flags PublishFlags) error
AddServiceSubtype adds subtype for the existent service.
func (*EntryGroup) Chan ¶
func (egrp *EntryGroup) Chan() <-chan *EntryGroupEvent
Chan returns channel where [EntryGroupEvent]s are sent.
func (*EntryGroup) Close ¶
func (egrp *EntryGroup) Close()
Close closed the EntryGroup.
Note, double close is safe
func (*EntryGroup) Commit ¶
func (egrp *EntryGroup) Commit() error
Commit changes to the EntryGroup.
func (*EntryGroup) Get ¶
func (egrp *EntryGroup) Get(ctx context.Context) (*EntryGroupEvent, error)
Get waits for the next EntryGroupEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if EntryGroup was closed
func (*EntryGroup) IsEmpty ¶
func (egrp *EntryGroup) IsEmpty() bool
IsEmpty reports if EntryGroup is empty.
func (*EntryGroup) Reset ¶
func (egrp *EntryGroup) Reset() error
Reset (purge) the EntryGroup. This takes effect immediately (without commit).
func (*EntryGroup) UpdateServiceTxt ¶
func (egrp *EntryGroup) UpdateServiceTxt( svcid *EntryGroupServiceIdent, txt []string, flags PublishFlags) error
UpdateServiceTxt updates TXT record for the existent service.
type EntryGroupAddress ¶
type EntryGroupAddress struct { IfIdx IfIndex // Network interface index Proto Protocol // Publishing network protocol Hostname string // Host name (use "" for default) Addr netip.Addr // IP address }
EntryGroupAddress represents a host address registration.
type EntryGroupEvent ¶
type EntryGroupEvent struct { State EntryGroupState // Entry group state Err ErrCode // In a case of EntryGroupStateFailure }
EntryGroupEvent represents an EntryGroup state change event.
type EntryGroupRecord ¶
type EntryGroupRecord struct { IfIdx IfIndex // Network interface index Proto Protocol // Publishing network protocol Name string // Record name RClass DNSClass // Record DNS class RType DNSType // Record DNS type TTL time.Duration // DNS TTL, rounded to seconds and must fit int32 RData []byte // Record data }
EntryGroupRecord represents a raw DNS record that can be added to the EntryGroup.
type EntryGroupService ¶
type EntryGroupService struct { IfIdx IfIndex // Network interface index Proto Protocol // Publishing network protocol InstanceName string // Service instance name SvcType string // Service type Domain string // Service domain (use "" for default) Hostname string // Host name (use "" for default) Port int // IP port Txt []string // TXT record ("key=value"...) }
EntryGroupService represents a service registration.
type EntryGroupServiceIdent ¶
type EntryGroupServiceIdent struct { IfIdx IfIndex // Network interface index Proto Protocol // Publishing network protocol InstanceName string // Service instance name SvcType string // Service type Domain string // Service domain (use "" for default) }
EntryGroupServiceIdent contains common set of parameters that identify a service in EntryGroup.
Please notice, services are identified by the DNS record name, which is EntryGroupServiceIdent.InstanceName, but all other parameters must match. In another words, you can't have two distinct entries in the EntryGroup with the same InstanceName and difference in other parameters (in particular, you can't define per-interface or per-protocol distinct entries).
type EntryGroupState ¶
type EntryGroupState int
EntryGroupState represents an EntryGroup state.
const ( // The group has not yet been committed EntryGroupStateUncommited EntryGroupState = C.AVAHI_ENTRY_GROUP_UNCOMMITED // The group is currently being registered EntryGroupStateRegistering EntryGroupState = C.AVAHI_ENTRY_GROUP_REGISTERING // The group has been successfully established EntryGroupStateEstablished EntryGroupState = C.AVAHI_ENTRY_GROUP_ESTABLISHED // A name collision for one of entries in the group has been detected. // The entries has been withdrawn. EntryGroupStateCollision EntryGroupState = C.AVAHI_ENTRY_GROUP_COLLISION // Some kind of failure has been detected, the entries has been withdrawn. EntryGroupStateFailure EntryGroupState = C.AVAHI_ENTRY_GROUP_FAILURE )
EntryGroupState values:
func (EntryGroupState) String ¶
func (state EntryGroupState) String() string
String returns a name of the EntryGroupState.
type ErrCode ¶
type ErrCode int
ErrCode represents an Avahi error code
const ( // No error NoError ErrCode = C.AVAHI_OK // Generic error code ErrFailure ErrCode = C.AVAHI_ERR_FAILURE // Object was in a bad state ErrBadState ErrCode = C.AVAHI_ERR_BAD_STATE // Invalid host name ErrInvalidHostName ErrCode = C.AVAHI_ERR_INVALID_HOST_NAME // Invalid domain name ErrInvalidDomainName ErrCode = C.AVAHI_ERR_INVALID_DOMAIN_NAME // No suitable network protocol available ErrNoNetwork ErrCode = C.AVAHI_ERR_NO_NETWORK // Invalid DNS TTL ErrInvalidTTL ErrCode = C.AVAHI_ERR_INVALID_TTL // RR key is pattern ErrIsPattern ErrCode = C.AVAHI_ERR_IS_PATTERN // Name collision ErrCollision ErrCode = C.AVAHI_ERR_COLLISION // Invalid RR ErrInvalidRecord ErrCode = C.AVAHI_ERR_INVALID_RECORD // Invalid service name ErrInvalidServiceName ErrCode = C.AVAHI_ERR_INVALID_SERVICE_NAME // Invalid service type ErrInvalidServiceType ErrCode = C.AVAHI_ERR_INVALID_SERVICE_TYPE // Invalid port number ErrInvalidPort ErrCode = C.AVAHI_ERR_INVALID_PORT // Invalid key ErrInvalidKey ErrCode = C.AVAHI_ERR_INVALID_KEY // Invalid address ErrInvalidAddress ErrCode = C.AVAHI_ERR_INVALID_ADDRESS // Timeout reached ErrTimeout ErrCode = C.AVAHI_ERR_TIMEOUT // Too many clients ErrTooManyClients ErrCode = C.AVAHI_ERR_TOO_MANY_CLIENTS // Too many objects ErrTooManyObjects ErrCode = C.AVAHI_ERR_TOO_MANY_OBJECTS // Too many entries ErrTooManyEntries ErrCode = C.AVAHI_ERR_TOO_MANY_ENTRIES // OS error ErrOS ErrCode = C.AVAHI_ERR_OS // Access denied ErrAccessDenied ErrCode = C.AVAHI_ERR_ACCESS_DENIED // Invalid operation ErrInvalidOperation ErrCode = C.AVAHI_ERR_INVALID_OPERATION // An unexpected D-Bus error occurred ErrDbusError ErrCode = C.AVAHI_ERR_DBUS_ERROR // Daemon connection failed ErrDisconnected ErrCode = C.AVAHI_ERR_DISCONNECTED // Memory exhausted ErrNoMemory ErrCode = C.AVAHI_ERR_NO_MEMORY // The object passed to this function was invalid ErrInvalidObject ErrCode = C.AVAHI_ERR_INVALID_OBJECT // Daemon not running ErrNoDaemon ErrCode = C.AVAHI_ERR_NO_DAEMON // Invalid interface ErrInvalidInterface ErrCode = C.AVAHI_ERR_INVALID_INTERFACE // Invalid protocol ErrInvalidProtocol ErrCode = C.AVAHI_ERR_INVALID_PROTOCOL // Invalid flags ErrInvalidFlags ErrCode = C.AVAHI_ERR_INVALID_FLAGS // Not found ErrNotFound ErrCode = C.AVAHI_ERR_NOT_FOUND // Configuration error ErrInvalidConfig ErrCode = C.AVAHI_ERR_INVALID_CONFIG // Verson mismatch ErrVersionMismatch ErrCode = C.AVAHI_ERR_VERSION_MISMATCH // Invalid service subtype ErrInvalidServiceSubtype ErrCode = C.AVAHI_ERR_INVALID_SERVICE_SUBTYPE // Invalid packet ErrInvalidPacket ErrCode = C.AVAHI_ERR_INVALID_PACKET // Invlaid DNS return code ErrInvalidDNSError ErrCode = C.AVAHI_ERR_INVALID_DNS_ERROR // DNS Error: Form error ErrDNSFormerr ErrCode = C.AVAHI_ERR_DNS_FORMERR // DNS Error: Server Failure ErrDNSSERVFAIL ErrCode = C.AVAHI_ERR_DNS_SERVFAIL // DNS Error: No such domain ErrDNSNXDOMAIN ErrCode = C.AVAHI_ERR_DNS_NXDOMAIN // DNS Error: Not implemented ErrDNSNotimp ErrCode = C.AVAHI_ERR_DNS_NOTIMP // DNS Error: Operation refused ErrDNSREFUSED ErrCode = C.AVAHI_ERR_DNS_REFUSED // DNS Error: YXDOMAIN ErrDNSYXDOMAIN ErrCode = C.AVAHI_ERR_DNS_YXDOMAIN // DNS Error: YXRRSET ErrDNSYXRRSET ErrCode = C.AVAHI_ERR_DNS_YXRRSET // DNS Error: NXRRSET ErrDNSNXRRSET ErrCode = C.AVAHI_ERR_DNS_NXRRSET // DNS Error: Not authorized ErrDNSNOTAUTH ErrCode = C.AVAHI_ERR_DNS_NOTAUTH // DNS Error: NOTZONE ErrDNSNOTZONE ErrCode = C.AVAHI_ERR_DNS_NOTZONE // Invalid RDATA ErrInvalidRDATA ErrCode = C.AVAHI_ERR_INVALID_RDATA // Invalid DNS class ErrInvalidDNSClass ErrCode = C.AVAHI_ERR_INVALID_DNS_CLASS // Invalid DNS type ErrInvalidDNSType ErrCode = C.AVAHI_ERR_INVALID_DNS_TYPE // Not supported ErrNotSupported ErrCode = C.AVAHI_ERR_NOT_SUPPORTED // Operation not permitted ErrNotPermitted ErrCode = C.AVAHI_ERR_NOT_PERMITTED // Invalid argument ErrInvalidArgument ErrCode = C.AVAHI_ERR_INVALID_ARGUMENT // Is empty ErrIsEmpty ErrCode = C.AVAHI_ERR_IS_EMPTY // The requested operation is invalid because it is redundant ErrNoChange ErrCode = C.AVAHI_ERR_NO_CHANGE )
Error codes:
type HostNameResolver ¶
type HostNameResolver struct {
// contains filtered or unexported fields
}
HostNameResolver resolves hostname by IP address.
func NewHostNameResolver ¶
func NewHostNameResolver( clnt *Client, ifidx IfIndex, proto Protocol, hostname string, addrproto Protocol, flags LookupFlags) (*HostNameResolver, error)
NewHostNameResolver creates a new HostNameResolver.
HostNameResolver resolves IP addresses by provided hostname. Roughly speaking, it does the work similar to gethostbyname using MDNS. Resolved information is reported via channel returned by the HostNameResolver.Chan.
This is important to understand the proper usage of the "proto" and "addrproto" parameters and difference between them. Please read the "IP4 vs IP6" section of the package Overview for technical details.
Function parameters:
- clnt is the pointer to Client
- ifidx is the network interface index. Use IfIndexUnspec to specify all interfaces.
- proto is the IP4/IP6 protocol, used as transport for queries. If set to ProtocolUnspec, both protocols will be used.
- hostname is the name of the host to lookup for
- flags provide some lookup options. See LookupFlags for details.
HostNameResolver must be closed after use with the HostNameResolver.Close function call.
func (*HostNameResolver) Chan ¶
func (resolver *HostNameResolver) Chan() <-chan *HostNameResolverEvent
Chan returns channel where [HostNameResolverEvent]s are sent.
func (*HostNameResolver) Close ¶
func (resolver *HostNameResolver) Close()
Close closes the HostNameResolver and releases allocated resources. It closes the event channel, effectively unblocking pending readers.
Note, double close is safe
func (*HostNameResolver) Get ¶
func (resolver *HostNameResolver) Get(ctx context.Context) ( *HostNameResolverEvent, error)
Get waits for the next HostNameResolverEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if HostNameResolver was closed
type HostNameResolverEvent ¶
type HostNameResolverEvent struct { Event ResolverEvent // Event code IfIdx IfIndex // Network interface index Proto Protocol // Network protocol Err ErrCode // In a case of ResolverFailure Flags LookupResultFlags // Lookup flags Hostname string // Hostname (mirrored) Addr netip.Addr // IP address (resolved) }
HostNameResolverEvent represents events, generated by the HostNameResolver.
type IfIndex ¶
type IfIndex int
IfIndex specifies network interface index
const (
IfIndexUnspec IfIndex = C.AVAHI_PROTO_UNSPEC
)
IfIndex values:
func Loopback ¶
Loopback returns index of the loopback network interface.
This function may fail, if net.Interfaces fails or there is no loopback interface in the response.
As this function is extremely unlikely to fail, you may consider using MustLoopback instead.
func MustLoopback ¶
func MustLoopback() IfIndex
MustLoopback returns index of the loopback network interface.
This is convenience wrapper around the Loopback function. If Loopback function fails, MustLoopback panics instead of returning the error.
type LookupFlags ¶
type LookupFlags int
LookupFlags provides some options for lookup functions
const ( // Force lookup via wide area DNS LookupUseWideArea LookupFlags = C.AVAHI_LOOKUP_USE_WIDE_AREA // Force lookup via multicast DNS LookupUseMulticast LookupFlags = C.AVAHI_LOOKUP_USE_MULTICAST // When doing service resolving, don't lookup TXT record LookupNoTXT LookupFlags = C.AVAHI_LOOKUP_NO_TXT // When doing service resolving, don't lookup A/AAAA records LookupNoAddress LookupFlags = C.AVAHI_LOOKUP_NO_ADDRESS )
LookupFlags values.
Please notice, LookupUseWideArea and LookupUseMulticast are mutually exclusive. Each of these flags forces the particular lookup methods, so if both are set, no valid lookup methods remains. The following simple table summarize usage of these flags:
Flags combination Meaning 0 WAN + Multicast LookupUseWideArea WAN only LookupUseMulticast mDNS only LookupUseWideArea | LookupUseMulticast Invalid
LookupNoTXT and LookupNoAddress are only meaningful for creating ServiceResolver with the NewServiceResolver function. Using them for any other purpose may result in ErrInvalidFlags error.
func (LookupFlags) String ¶
func (flags LookupFlags) String() string
String returns LookupFlags as string, for debugging
type LookupResultFlags ¶
type LookupResultFlags int
LookupResultFlags provides some additional information about lookup response.
const ( // This response originates from the cache LookupResultCached LookupResultFlags = C.AVAHI_LOOKUP_RESULT_CACHED // This response originates from wide area DNS LookupResultWideArea LookupResultFlags = C.AVAHI_LOOKUP_RESULT_WIDE_AREA // This response originates from multicast DNS LookupResultMulticast LookupResultFlags = C.AVAHI_LOOKUP_RESULT_MULTICAST // This record/service resides on and was announced by the local host. // Only available in service and record browsers and only on // BrowserNew event. LookupResultLocal LookupResultFlags = C.AVAHI_LOOKUP_RESULT_LOCAL // This service belongs to the same local client as the browser object. // Only for service browsers and only on BrowserNew event. LookupResultOurOwn LookupResultFlags = C.AVAHI_LOOKUP_RESULT_OUR_OWN // The returned data was defined statically by server configuration. LookupResultStatic LookupResultFlags = C.AVAHI_LOOKUP_RESULT_STATIC )
LookupResultFlags bits:
func (LookupResultFlags) String ¶
func (flags LookupResultFlags) String() string
String returns LookupResultFlags as string, for debugging
type Poller ¶
type Poller struct {
// contains filtered or unexported fields
}
Poller is the convenience object, that implements a centralized events reception from multiple sources.
Multiple Event sources (Client, Browsers, Resolvers and EntryGroup) can be added to the Poller. Poller combines their events flows together and makes it available via single Poller.Poll API call.
func (*Poller) AddAddressResolver ¶
func (p *Poller) AddAddressResolver(resolver *AddressResolver)
AddAddressResolver adds AddressResolver as the event source.
func (*Poller) AddDomainBrowser ¶
func (p *Poller) AddDomainBrowser(browser *DomainBrowser)
AddDomainBrowser adds DomainBrowser as the event source.
func (*Poller) AddHostNameResolver ¶
func (p *Poller) AddHostNameResolver(resolver *HostNameResolver)
AddHostNameResolver adds HostNameResolver as the event source.
func (*Poller) AddRecordBrowser ¶
func (p *Poller) AddRecordBrowser(browser *RecordBrowser)
AddRecordBrowser adds RecordBrowser as the event source.
func (*Poller) AddServiceBrowser ¶
func (p *Poller) AddServiceBrowser(browser *ServiceBrowser)
AddServiceBrowser adds ServiceBrowser as the event source.
func (*Poller) AddServiceResolver ¶
func (p *Poller) AddServiceResolver(resolver *ServiceResolver)
AddServiceResolver adds ServiceResolver as the event source.
func (*Poller) AddServiceTypeBrowser ¶
func (p *Poller) AddServiceTypeBrowser(browser *ServiceTypeBrowser)
AddServiceTypeBrowser adds ServiceTypeBrowser as the event source.
func (*Poller) Poll ¶
Poll waits for the next event from any of registered sources.
It returns:
- nil, error - if context is canceled
- event, nil - if event is available
The returned event is one of the following:
- *ClientEvent
- *DomainBrowserEvent
- *RecordBrowserEvent
- *ServiceBrowserEvent
- *ServiceTypeBrowserEvent
- *AddressResolverEvent
- *HostNameResolverEvent
- *ServiceResolverEvent
If source is added while Poll is active, it may or may not affect the pending Poll, no guarantees are provided here except for safety guarantees.
Events, received from the same source, are never reordered between each other, but events from different sources may be reordered.
Adding the same source to the multiple Pollers has roughly the same effect as reading the same channel from multiple goroutines and generally not recommended.
type Protocol ¶
type Protocol int
Protocol specifies IP4/IP6 protocol
const ( ProtocolIP4 Protocol = C.AVAHI_PROTO_INET ProtocolIP6 Protocol = C.AVAHI_PROTO_INET6 ProtocolUnspec Protocol = C.AVAHI_PROTO_UNSPEC )
Protocol values:
type PublishFlags ¶
type PublishFlags int
PublishFlags represents flags for publishing functions
const ( // RRset is intended to be unique PublishUnique PublishFlags = C.AVAHI_PUBLISH_UNIQUE // Though the RRset is intended to be unique no probes shall be sent PublishNoProbe PublishFlags = C.AVAHI_PUBLISH_NO_PROBE // Do not announce this RR to other hosts PublishNoAnnounce PublishFlags = C.AVAHI_PUBLISH_NO_ANNOUNCE // Allow multiple local records of this type PublishAllowMultiple PublishFlags = C.AVAHI_PUBLISH_ALLOW_MULTIPLE )
PublishFlags for raw records:
const ( // Don't create a reverse (PTR) entry PublishNoReverse PublishFlags = C.AVAHI_PUBLISH_NO_REVERSE // Do not implicitly add the local service cookie to TXT data PublishNoCookie PublishFlags = C.AVAHI_PUBLISH_NO_COOKIE )
PublishFlags for address records:
const ( // Update existing records instead of adding new ones PublishUpdate PublishFlags = C.AVAHI_PUBLISH_UPDATE // Register the record using wide area DNS (i.e. unicast DNS update) PublishUseWideArea PublishFlags = C.AVAHI_PUBLISH_USE_WIDE_AREA // Register the record using multicast DNS PublishUseMulticast PublishFlags = C.AVAHI_PUBLISH_USE_MULTICAST )
Other PublishFlags:
func (PublishFlags) String ¶
func (flags PublishFlags) String() string
String returns PublishFlags as string, for debugging
type RecordBrowser ¶
type RecordBrowser struct {
// contains filtered or unexported fields
}
RecordBrowser is the generic browser for resource records of the specified name, class and type.
func NewRecordBrowser ¶
func NewRecordBrowser( clnt *Client, ifidx IfIndex, proto Protocol, name string, dnsclass DNSClass, dnstype DNSType, flags LookupFlags) (*RecordBrowser, error)
NewRecordBrowser creates a new RecordBrowser.
RecordBrowser is the generic browser for RRs of the specified name, class and type. It uses RecordBrowserEvent to report discovered information as via channel returned by the RecordBrowser.Chan
Function parameters:
- clnt is the pointer to Client
- ifidx is the network interface index. Use IfIndexUnspec to monitor all interfaces.
- proto is the IP4/IP6 protocol, used as transport for queries. If set to ProtocolUnspec, both protocols will be used.
- name is the RR name to look for
- dnsclass is the DNS class to look for (most likely, DNSClassIN)
- dnstype is the DNS record type.
- flags provide some lookup options. See LookupFlags for details.
RecordBrowser must be closed after use with the RecordBrowser.Close function call.
func (*RecordBrowser) Chan ¶
func (browser *RecordBrowser) Chan() <-chan *RecordBrowserEvent
Chan returns channel where [RecordBrowserEvent]s are sent.
func (*RecordBrowser) Close ¶
func (browser *RecordBrowser) Close()
Close closes the RecordBrowser and releases allocated resources. It closes the event channel, effectively unblocking pending readers.
Note, double close is safe.
func (*RecordBrowser) Get ¶
func (browser *RecordBrowser) Get(ctx context.Context) (*RecordBrowserEvent, error)
Get waits for the next RecordBrowserEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if RecordBrowser was closed
type RecordBrowserEvent ¶
type RecordBrowserEvent struct { Event BrowserEvent // Event code IfIdx IfIndex // Network interface index Proto Protocol // Network protocol Err ErrCode // In a case of BrowserFailure Flags LookupResultFlags // Lookup flags Name string // Record name RClass DNSClass // Record DNS class RType DNSType // Record DNS type RData []byte // Record data }
RecordBrowserEvent represents events, generated by the RecordBrowser.
type ResolverEvent ¶
type ResolverEvent int
ResolverEvent is the CGo representation of the AvahiResolverEvent.
const ( // Successful resolving ResolverFound ResolverEvent = C.AVAHI_RESOLVER_FOUND // Resolving failed due to some reason. ResolverFailure ResolverEvent = C.AVAHI_RESOLVER_FAILURE )
ResolverEvent values:
func (ResolverEvent) String ¶
func (e ResolverEvent) String() string
String returns a name of ResolverEvent
type ServiceBrowser ¶
type ServiceBrowser struct {
// contains filtered or unexported fields
}
ServiceBrowser reports available services of the specified type.
Service type is a string that looks like "_http._tcp", "_ipp._tcp" and so on.
func NewServiceBrowser ¶
func NewServiceBrowser( clnt *Client, ifidx IfIndex, proto Protocol, svctype, domain string, flags LookupFlags) (*ServiceBrowser, error)
NewServiceBrowser creates a new ServiceBrowser.
ServiceBrowser constantly monitors the network for the available services of specified type and reports discovered information as a series of ServiceBrowserEvent events via channel returned by the ServiceBrowser.Chan
Technically speaking, ServiceBrowser monitors network for the PTR records with the name <svctype>.<domain>, with domain defaulted to "local". I.e., if requested svctype is the "_http._tcp" and domain is "", it will look for the PTR records with name "_http._tcp.local.".
Function parameters:
- clnt is the pointer to Client
- ifidx is the network interface index. Use IfIndexUnspec to monitor all interfaces.
- proto is the IP4/IP6 protocol, used as transport for queries. If set to ProtocolUnspec, both protocols will be used.
- svctype is the service type we are looking for (e.g., "_http._tcp")
- domain is domain where service is looked. If set to "", the default domain is used, which depends on a avahi-daemon configuration and usually is ".local"
- flags provide some lookup options. See LookupFlags for details.
ServiceBrowser must be closed after use with the ServiceBrowser.Close function call.
func (*ServiceBrowser) Chan ¶
func (browser *ServiceBrowser) Chan() <-chan *ServiceBrowserEvent
Chan returns channel where [ServiceBrowserEvent]s are sent.
func (*ServiceBrowser) Close ¶
func (browser *ServiceBrowser) Close()
Close closes the ServiceBrowser and releases allocated resources. It closes the event channel, effectively unblocking pending readers.
Note, double close is safe.
func (*ServiceBrowser) Get ¶
func (browser *ServiceBrowser) Get(ctx context.Context) (*ServiceBrowserEvent, error)
Get waits for the next ServiceBrowserEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if ServiceBrowser was closed
type ServiceBrowserEvent ¶
type ServiceBrowserEvent struct { Event BrowserEvent // Event code IfIdx IfIndex // Network interface index Proto Protocol // Network protocol Err ErrCode // In a case of BrowserFailure Flags LookupResultFlags // Lookup flags InstanceName string // Service instance name SvcType string // Service type Domain string // Service domain }
ServiceBrowserEvent represents events, generated by the ServiceBrowser.
type ServiceResolver ¶
type ServiceResolver struct {
// contains filtered or unexported fields
}
ServiceResolver resolves hostname, IP address and TXT record of the discovered services.
func NewServiceResolver ¶
func NewServiceResolver( clnt *Client, ifidx IfIndex, proto Protocol, instname, svctype, domain string, addrproto Protocol, flags LookupFlags) (*ServiceResolver, error)
NewServiceResolver creates a new ServiceResolver.
ServiceResolver resolves hostname, IP address and TXT record of the services, previously discovered by the ServiceBrowser by service instance name ([ServiceBrowserEvent.InstanceName]). Resolved information is reported via channel returned by the ServiceResolver.Chan.
If IP address and/or TXT record is not needed, resolving of these parameters may be suppressed, using LookupNoAddress/LookupNoTXT LookupFlags.
Please notice, it is a common practice to register a service with a zero port value as a "placeholder" for missed service. For example, printers always register the "_printer._tcp" service to reserve the service name, but if LPD protocol is actually not supported, it will be registered with zero port.
This is important to understand the proper usage of the "proto" and "addrproto" parameters and difference between them. Please read the "IP4 vs IP6" section of the package Overview for technical details.
Function parameters:
- clnt is the pointer to Client
- ifidx is the network interface index. Use IfIndexUnspec to specify all interfaces.
- proto is the IP4/IP6 protocol, used as transport for queries. If set to ProtocolUnspec, both protocols will be used.
- instname is the service instance name, as reported by [ServiceBrowserEvent.InstanceName]
- svctype is the service type we are looking for (e.g., "_http._tcp")
- domain is domain where service is looked. If set to "", the default domain is used, which depends on a avahi-daemon configuration and usually is ".local"
- addrproto specifies a protocol family of IP addresses we are interested in. See explanation above for details.
- flags provide some lookup options. See LookupFlags for details.
ServiceResolver must be closed after use with the ServiceResolver.Close function call.
func (*ServiceResolver) Chan ¶
func (resolver *ServiceResolver) Chan() <-chan *ServiceResolverEvent
Chan returns channel where [ServiceResolverEvent]s are sent.
func (*ServiceResolver) Close ¶
func (resolver *ServiceResolver) Close()
Close closes the ServiceResolver and releases allocated resources. It closes the event channel, effectively unblocking pending readers.
func (*ServiceResolver) Get ¶
func (resolver *ServiceResolver) Get(ctx context.Context) ( *ServiceResolverEvent, error)
Get waits for the next ServiceResolverEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if ServiceResolver was closed
type ServiceResolverEvent ¶
type ServiceResolverEvent struct { Event ResolverEvent // Event code IfIdx IfIndex // Network interface index Proto Protocol // Network protocol Err ErrCode // In a case of ResolverFailure Flags LookupResultFlags // Lookup flags InstanceName string // Service instance name (mirrored) SvcType string // Service type (mirrored) Domain string // Service domain (mirrored) Hostname string // Service hostname (resolved) Port uint16 // Service IP port (resolved) Addr netip.Addr // Service IP address (resolved) Txt []string // TXT record ("key=value"...) (resolved) }
ServiceResolverEvent represents events, generated by the ServiceResolver.
Notes:
- Addr is not available, if NewServiceResolver is called with the LookupNoAddress flag
- Txt is not available, if NewServiceResolver is called with the LookupNoTXT flag
- Port is always available, but may be 0, which indicates, that service doesn't actually process responses and exists as a service instance name placeholder only.
func (*ServiceResolverEvent) FQDN ¶
func (evnt *ServiceResolverEvent) FQDN() string
FQDN returns a Fully Qualified Domain Name by joining Hostname and Domain.
type ServiceTypeBrowser ¶
type ServiceTypeBrowser struct {
// contains filtered or unexported fields
}
ServiceTypeBrowser reports available service types across the network.
If you a looking for services of the particular type, probably you need to use ServiceBrowser instead.
func NewServiceTypeBrowser ¶
func NewServiceTypeBrowser( clnt *Client, ifidx IfIndex, proto Protocol, domain string, flags LookupFlags) (*ServiceTypeBrowser, error)
NewServiceTypeBrowser creates a new ServiceTypeBrowser.
ServiceTypeBrowser constantly monitors the network for available service types and reports discovered information as a series of ServiceTypeBrowserEvent events via channel returned by the ServiceTypeBrowser.Chan.
Technically speaking, NewServiceTypeBrowser monitors network for the PTR records with the name _services._dns-sd._udp.<domain>, with the domain defaulted to "local", which yields a list of all available services on the network. See RFC6763, 9 for details.
Function parameters:
- clnt is the pointer to Client
- ifidx is the network interface index. Use IfIndexUnspec to monitor all interfaces.
- proto is the IP4/IP6 protocol, used as transport for queries. If set to ProtocolUnspec, both protocols will be used.
- domain is domain where service is looked. If set to "", the default domain is used, which depends on a avahi-daemon configuration and usually is ".local"
- flags provide some lookup options. See LookupFlags for details.
ServiceTypeBrowser must be closed after use with the ServiceTypeBrowser.Close function call.
func (*ServiceTypeBrowser) Chan ¶
func (browser *ServiceTypeBrowser) Chan() <-chan *ServiceTypeBrowserEvent
Chan returns channel where [ServiceTypeBrowserEvent]s are sent.
func (*ServiceTypeBrowser) Close ¶
func (browser *ServiceTypeBrowser) Close()
Close closes the ServiceTypeBrowser and releases allocated resources. It closes the event channel, effectively unblocking pending readers.
Note, double close is safe.
func (*ServiceTypeBrowser) Get ¶
func (browser *ServiceTypeBrowser) Get(ctx context.Context) ( *ServiceTypeBrowserEvent, error)
Get waits for the next ServiceTypeBrowserEvent.
It returns:
- event, nil - if event available
- nil, error - if context is canceled
- nil, nil - if ServiceTypeBrowser was closed
type ServiceTypeBrowserEvent ¶
type ServiceTypeBrowserEvent struct { Event BrowserEvent // Event code IfIdx IfIndex // Network interface index Proto Protocol // Network protocol Err ErrCode // In a case of BrowserFailure Flags LookupResultFlags // Lookup flags SvcType string // Service type Domain string // Service domain }
ServiceTypeBrowserEvent represents events, generated by the ServiceTypeBrowser.
Source Files ¶
- addressresolver.go
- browserevent.go
- client.go
- clientstate.go
- closer.go
- dns.go
- doc.go
- domain.go
- domainbrowser.go
- entrygroup.go
- entrygroupstate.go
- err.go
- eventqueue.go
- glue.go
- hostnameresolver.go
- ifindex.go
- localhost.go
- lookupflags.go
- loopback.go
- poller.go
- protocol.go
- publishiflags.go
- recordbrowser.go
- resolverevent.go
- servicebrowser.go
- serviceresolver.go
- servicetypebrowser.go