From c6e396e8fb5e1f5e9e7e0edd0183bda6723c844a Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sun, 23 Feb 2014 14:48:56 +0100 Subject: [PATCH] Send announcements to all connected networks (fixes #56) --- discover/discover.go | 92 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 17 deletions(-) diff --git a/discover/discover.go b/discover/discover.go index 6556ad87c..049eca89d 100644 --- a/discover/discover.go +++ b/discover/discover.go @@ -40,8 +40,8 @@ var ( const maxErrors = 30 func NewDiscoverer(id string, port int, extServer string) (*Discoverer, error) { - local4 := &net.UDPAddr{IP: net.IP{0, 0, 0, 0}, Port: AnnouncementPort} - conn, err := net.ListenUDP("udp4", local4) + local := &net.UDPAddr{IP: nil, Port: AnnouncementPort} + conn, err := net.ListenUDP("udp", local) if err != nil { return nil, err } @@ -60,39 +60,62 @@ func NewDiscoverer(id string, port int, extServer string) (*Discoverer, error) { go disc.recvAnnouncements() if disc.ListenPort > 0 { - disc.sendAnnouncements() + go disc.sendAnnouncements() } if len(disc.extServer) > 0 { - disc.sendExtAnnouncements() + go disc.sendExtAnnouncements() } return disc, nil } func (d *Discoverer) sendAnnouncements() { - remote4 := &net.UDPAddr{IP: net.IP{255, 255, 255, 255}, Port: AnnouncementPort} + var pkt = AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}} + var buf = pkt.MarshalXDR() + var errCounter = 0 + var err error - pkt := AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}} - buf := pkt.MarshalXDR() - go d.writeAnnouncements(buf, remote4, d.BroadcastIntv) + for errCounter < maxErrors { + for _, ipStr := range allBroadcasts() { + var addrStr = ipStr + ":21025" + + remote, err := net.ResolveUDPAddr("udp4", addrStr) + if err != nil { + log.Printf("discover/external: %v; no external announcements", err) + return + } + + if Debug { + fmt.Println("send announcement -> ", remote) + } + _, _, err = d.conn.WriteMsgUDP(buf, nil, remote) + if err != nil { + log.Println("discover/write: warning:", err) + errCounter++ + } else { + errCounter = 0 + } + } + time.Sleep(d.BroadcastIntv) + } + log.Println("discover/write: local: stopping due to too many errors:", err) } func (d *Discoverer) sendExtAnnouncements() { - extIP, err := net.ResolveUDPAddr("udp", d.extServer) + remote, err := net.ResolveUDPAddr("udp", d.extServer) if err != nil { log.Printf("discover/external: %v; no external announcements", err) return } - pkt := AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}} - buf := pkt.MarshalXDR() - go d.writeAnnouncements(buf, extIP, d.ExtBroadcastIntv) -} - -func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv time.Duration) { + var pkt = AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}} + var buf = pkt.MarshalXDR() var errCounter = 0 - var err error + for errCounter < maxErrors { + if Debug { + fmt.Println("send announcement -> ", remote) + } _, _, err = d.conn.WriteMsgUDP(buf, nil, remote) if err != nil { log.Println("discover/write: warning:", err) @@ -100,7 +123,7 @@ func (d *Discoverer) writeAnnouncements(buf []byte, remote *net.UDPAddr, intv ti } else { errCounter = 0 } - time.Sleep(intv) + time.Sleep(d.ExtBroadcastIntv) } log.Println("discover/write: %v: stopping due to too many errors:", remote, err) } @@ -251,3 +274,38 @@ func ipStr(ip []byte) string { } return strings.Join(ss, s) } + +func allBroadcasts() []string { + var bcasts = make(map[string]bool) + addrs, err := net.InterfaceAddrs() + if err != nil { + return nil + } + + for _, addr := range addrs { + switch { + case strings.HasPrefix(addr.String(), "127."): + // Ignore v4 localhost + + case strings.Contains(addr.String(), ":"): + // Ignore all v6, because we need link local multicast there which I haven't implemented + + default: + if in, ok := addr.(*net.IPNet); ok { + il := len(in.IP) - 1 + ml := len(in.Mask) - 1 + for i := range in.Mask { + in.IP[il-i] = in.IP[il-i] | ^in.Mask[ml-i] + } + parts := strings.Split(in.String(), "/") + bcasts[parts[0]] = true + } + } + } + + var l []string + for ip := range bcasts { + l = append(l, ip) + } + return l +}