Browse Source

Send announcements to all connected networks (fixes #56)

Jakob Borg 11 years ago
parent
commit
c6e396e8fb
1 changed files with 75 additions and 17 deletions
  1. 75 17
      discover/discover.go

+ 75 - 17
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
+
+	for errCounter < maxErrors {
+		for _, ipStr := range allBroadcasts() {
+			var addrStr = ipStr + ":21025"
 
-	pkt := AnnounceV2{AnnouncementMagicV2, d.MyID, []Address{{nil, 22000}}}
-	buf := pkt.MarshalXDR()
-	go d.writeAnnouncements(buf, remote4, d.BroadcastIntv)
+			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
+}