From 156314a8027dfb718923b4717aabfa2eb70b1443 Mon Sep 17 00:00:00 2001 From: Michael Bridgen Date: Wed, 22 Oct 2014 13:22:50 +0100 Subject: [PATCH] Complete multicast requests on first response This is the simplest thing that works, is consistent with what happens if there's a local answer, and avoids having all multicast requests last 250ms or more. Since we're no longer waiting *at least* the timeout period, I've bumped the multicast response timeout up to half a second. There was also a bug whereby the query would be entered into the inflight map even if the socket write had failed (and the channel had been closed). --- server/mdns_client.go | 13 ++++++++----- server/server.go | 3 +-- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/server/mdns_client.go b/server/mdns_client.go index 26c23bbe..f5d5d672 100644 --- a/server/mdns_client.go +++ b/server/mdns_client.go @@ -14,9 +14,9 @@ const ( mdnsPort = 5353 // mDNS assigned port // We wait this long to hear responses from other mDNS servers on the network. // TODO: introduce caching so we don't have to wait this long on every call. - mDNSTimeout = 250 * time.Millisecond + mDNSTimeout = 500 * time.Millisecond MaxDuration = time.Duration(math.MaxInt64) - ChannelSize = 16 + MailboxSize = 16 ) var ( @@ -88,7 +88,7 @@ func (c *MDNSClient) Start(ifi *net.Interface) error { c.server = &dns.Server{Listener: nil, PacketConn: multicast, Handler: dns.HandlerFunc(handleMDNS)} go c.server.ActivateAndServe() - queryChan := make(chan *MDNSInteraction, ChannelSize) + queryChan := make(chan *MDNSInteraction, MailboxSize) c.queryChan = queryChan go c.queryLoop(queryChan) @@ -216,13 +216,13 @@ func (c *MDNSClient) handleSendQuery(q mDNSQueryInfo) { name: q.name, id: m.Id, } - c.inflight[q.name] = query _, err = c.conn.WriteTo(buf, c.addr) if err != nil { q.responseCh <- &ResponseA{Err: err} close(q.responseCh) return } + c.inflight[q.name] = query } info := &responseInfo{ ch: q.responseCh, @@ -237,10 +237,13 @@ func (c *MDNSClient) handleResponse(r *dns.Msg) { for _, answer := range r.Answer { switch rr := answer.(type) { case *dns.A: - if query, found := c.inflight[rr.Hdr.Name]; found { + name := rr.Hdr.Name + if query, found := c.inflight[name]; found { for _, resp := range query.responseInfos { resp.ch <- &ResponseA{Name: rr.Hdr.Name, Addr: rr.A} + close(resp.ch) } + delete(c.inflight, name) } else { // We've received a response that didn't match a query // Do we want to cache it? diff --git a/server/server.go b/server/server.go index ba5f8cb0..e4a338c2 100644 --- a/server/server.go +++ b/server/server.go @@ -41,10 +41,9 @@ func queryHandler(zone Zone, mdnsClient *MDNSClient) dns.HandlerFunc { } else { Debug.Printf("Failed lookup for %s; sending mDNS query", q.Name) // We don't know the answer; see if someone else does - channel := make(chan *ResponseA, ChannelSize) + channel := make(chan *ResponseA) replies := make([]net.IP, 0) go func() { - // Loop terminates when channel is closed by MDNSClient on timeout for resp := range channel { Debug.Printf("Got address response %s to query %s addr %s", resp.Name, q.Name, resp.Addr) replies = append(replies, resp.Addr)