Adding ability to set multicast query interface
This commit is contained in:
parent
dab97f2090
commit
9215784091
72
client.go
72
client.go
@ -1,6 +1,8 @@
|
|||||||
package mdns
|
package mdns
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"code.google.com/p/go.net/ipv4"
|
||||||
|
"code.google.com/p/go.net/ipv6"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/miekg/dns"
|
"github.com/miekg/dns"
|
||||||
"log"
|
"log"
|
||||||
@ -26,11 +28,30 @@ func (s *ServiceEntry) complete() bool {
|
|||||||
return s.Addr != nil && s.Port != 0 && s.hasTXT
|
return s.Addr != nil && s.Port != 0 && s.hasTXT
|
||||||
}
|
}
|
||||||
|
|
||||||
// LookupDomain looks up a given service, in a domain, waiting at most
|
// QueryParam is used to customize how a Lookup is performed
|
||||||
|
type QueryParam struct {
|
||||||
|
Service string // Service to lookup
|
||||||
|
Domain string // Lookup domain, default "local"
|
||||||
|
Timeout time.Duration // Lookup timeout, default 1 second
|
||||||
|
Interface *net.Interface // Multicast interface to use
|
||||||
|
Entries chan<- *ServiceEntry // Entries Channel
|
||||||
|
}
|
||||||
|
|
||||||
|
// DefaultParams is used to return a default set of QueryParam's
|
||||||
|
func DefaultParams(service string) *QueryParam {
|
||||||
|
return &QueryParam{
|
||||||
|
Service: service,
|
||||||
|
Domain: "local",
|
||||||
|
Timeout: time.Second,
|
||||||
|
Entries: make(chan *ServiceEntry),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Query looks up a given service, in a domain, waiting at most
|
||||||
// for a timeout before finishing the query. The results are streamed
|
// for a timeout before finishing the query. The results are streamed
|
||||||
// to a channel. Sends will not block, so clients should make sure to
|
// to a channel. Sends will not block, so clients should make sure to
|
||||||
// either read or buffer.
|
// either read or buffer.
|
||||||
func LookupDomain(service, domain string, timeout time.Duration, entries chan<- *ServiceEntry) error {
|
func Query(params *QueryParam) error {
|
||||||
// Create a new client
|
// Create a new client
|
||||||
client, err := newClient()
|
client, err := newClient()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -38,17 +59,27 @@ func LookupDomain(service, domain string, timeout time.Duration, entries chan<-
|
|||||||
}
|
}
|
||||||
defer client.Close()
|
defer client.Close()
|
||||||
|
|
||||||
// Create the query name
|
// Set the multicast interface
|
||||||
serviceAddr := fmt.Sprintf("%s.%s.", trimDot(service), trimDot(domain))
|
if params.Interface != nil {
|
||||||
|
if err := client.setInterface(params.Interface); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ensure a timeout
|
||||||
|
if params.Timeout == 0 {
|
||||||
|
params.Timeout = time.Second
|
||||||
|
}
|
||||||
|
|
||||||
// Run the query
|
// Run the query
|
||||||
return client.query(serviceAddr, timeout, entries)
|
return client.query(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lookup is the same as LookupDomain, however it only searches in the "local"
|
// Lookup is the same as Query, however it uses all the default parameters
|
||||||
// domain, and uses a one second lookup timeout.
|
|
||||||
func Lookup(service string, entries chan<- *ServiceEntry) error {
|
func Lookup(service string, entries chan<- *ServiceEntry) error {
|
||||||
return LookupDomain(service, "local", time.Second, entries)
|
params := DefaultParams(service)
|
||||||
|
params.Entries = entries
|
||||||
|
return Query(params)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Client provides a query interface that can be used to
|
// Client provides a query interface that can be used to
|
||||||
@ -107,8 +138,25 @@ func (c *client) Close() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// setInterface is used to set the query interface, uses sytem
|
||||||
|
// default if not provided
|
||||||
|
func (c *client) setInterface(iface *net.Interface) error {
|
||||||
|
p := ipv4.NewPacketConn(c.ipv4List)
|
||||||
|
if err := p.SetMulticastInterface(iface); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
p2 := ipv6.NewPacketConn(c.ipv6List)
|
||||||
|
if err := p2.SetMulticastInterface(iface); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
// query is used to perform a lookup and stream results
|
// query is used to perform a lookup and stream results
|
||||||
func (c *client) query(service string, timeout time.Duration, entries chan<- *ServiceEntry) error {
|
func (c *client) query(params *QueryParam) error {
|
||||||
|
// Create the service name
|
||||||
|
serviceAddr := fmt.Sprintf("%s.%s.", trimDot(params.Service), trimDot(params.Domain))
|
||||||
|
|
||||||
// Start listening for response packets
|
// Start listening for response packets
|
||||||
msgCh := make(chan *dns.Msg, 32)
|
msgCh := make(chan *dns.Msg, 32)
|
||||||
go c.recv(c.ipv4List, msgCh)
|
go c.recv(c.ipv4List, msgCh)
|
||||||
@ -116,7 +164,7 @@ func (c *client) query(service string, timeout time.Duration, entries chan<- *Se
|
|||||||
|
|
||||||
// Send the query
|
// Send the query
|
||||||
m := new(dns.Msg)
|
m := new(dns.Msg)
|
||||||
m.SetQuestion(service, dns.TypeANY)
|
m.SetQuestion(serviceAddr, dns.TypeANY)
|
||||||
if err := c.sendQuery(m); err != nil {
|
if err := c.sendQuery(m); err != nil {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
@ -125,7 +173,7 @@ func (c *client) query(service string, timeout time.Duration, entries chan<- *Se
|
|||||||
inprogress := make(map[string]*ServiceEntry)
|
inprogress := make(map[string]*ServiceEntry)
|
||||||
|
|
||||||
// Listen until we reach the timeout
|
// Listen until we reach the timeout
|
||||||
finish := time.After(timeout)
|
finish := time.After(params.Timeout)
|
||||||
for {
|
for {
|
||||||
select {
|
select {
|
||||||
case resp := <-msgCh:
|
case resp := <-msgCh:
|
||||||
@ -163,7 +211,7 @@ func (c *client) query(service string, timeout time.Duration, entries chan<- *Se
|
|||||||
if inp.complete() && !inp.sent {
|
if inp.complete() && !inp.sent {
|
||||||
inp.sent = true
|
inp.sent = true
|
||||||
select {
|
select {
|
||||||
case entries <- inp:
|
case params.Entries <- inp:
|
||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -8,7 +8,7 @@ import (
|
|||||||
|
|
||||||
func TestServer_StartStop(t *testing.T) {
|
func TestServer_StartStop(t *testing.T) {
|
||||||
s := makeService(t)
|
s := makeService(t)
|
||||||
serv, err := NewServer(&Config{s})
|
serv, err := NewServer(&Config{Zone: s})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
@ -19,7 +19,7 @@ func TestServer_Lookup(t *testing.T) {
|
|||||||
s := makeService(t)
|
s := makeService(t)
|
||||||
s.Service = "_foobar._tcp"
|
s.Service = "_foobar._tcp"
|
||||||
s.Init()
|
s.Init()
|
||||||
serv, err := NewServer(&Config{s})
|
serv, err := NewServer(&Config{Zone: s})
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
@ -49,7 +49,13 @@ func TestServer_Lookup(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}()
|
}()
|
||||||
|
|
||||||
err = LookupDomain("_foobar._tcp", "local", 50*time.Millisecond, entries)
|
params := &QueryParam{
|
||||||
|
Service: "_foobar._tcp",
|
||||||
|
Domain: "local",
|
||||||
|
Timeout: 50 * time.Millisecond,
|
||||||
|
Entries: entries,
|
||||||
|
}
|
||||||
|
err = Query(params)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatalf("err: %v", err)
|
t.Fatalf("err: %v", err)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user