Преглед изворни кода

Use a socket per interface for v6 multicast (fixes #1563)

Jakob Borg пре 10 година
родитељ
комит
221f43e4bd
3 измењених фајлова са 73 додато и 53 уклоњено
  1. 1 1
      internal/beacon/broadcast.go
  2. 16 23
      internal/beacon/multicast.go
  3. 56 29
      internal/discover/discover.go

+ 1 - 1
internal/beacon/broadcast.go

@@ -16,7 +16,7 @@ type Broadcast struct {
 }
 
 func NewBroadcast(port int) (*Broadcast, error) {
-	conn, err := net.ListenUDP("udp", &net.UDPAddr{Port: port})
+	conn, err := net.ListenUDP("udp4", &net.UDPAddr{Port: port})
 	if err != nil {
 		return nil, err
 	}

+ 16 - 23
internal/beacon/multicast.go

@@ -11,22 +11,28 @@ import "net"
 type Multicast struct {
 	conn   *net.UDPConn
 	addr   *net.UDPAddr
+	intf   *net.Interface
 	inbox  chan []byte
 	outbox chan recv
 }
 
-func NewMulticast(addr string) (*Multicast, error) {
-	gaddr, err := net.ResolveUDPAddr("udp", addr)
+func NewMulticast(addr, ifname string) (*Multicast, error) {
+	gaddr, err := net.ResolveUDPAddr("udp6", addr)
 	if err != nil {
 		return nil, err
 	}
-	conn, err := net.ListenMulticastUDP("udp", nil, gaddr)
+	intf, err := net.InterfaceByName(ifname)
+	if err != nil {
+		return nil, err
+	}
+	conn, err := net.ListenMulticastUDP("udp6", intf, gaddr)
 	if err != nil {
 		return nil, err
 	}
 	b := &Multicast{
 		conn:   conn,
 		addr:   gaddr,
+		intf:   intf,
 		inbox:  make(chan []byte),
 		outbox: make(chan recv, 16),
 	}
@@ -47,27 +53,14 @@ func (b *Multicast) Recv() ([]byte, net.Addr) {
 }
 
 func (b *Multicast) writer() {
+	addr := *b.addr
+	addr.Zone = b.intf.Name
 	for bs := range b.inbox {
-		intfs, err := net.Interfaces()
-		if err != nil {
-			if debug {
-				l.Debugln("multicast interfaces:", err)
-			}
-			continue
-		}
-		for _, intf := range intfs {
-			if intf.Flags&net.FlagUp != 0 && intf.Flags&net.FlagMulticast != 0 {
-				addr := *b.addr
-				addr.Zone = intf.Name
-				_, err = b.conn.WriteTo(bs, &addr)
-				if err != nil {
-					if debug {
-						l.Debugln(err, "on write to", addr)
-					}
-				} else if debug {
-					l.Debugf("sent %d bytes to %s", len(bs), addr.String())
-				}
-			}
+		_, err := b.conn.WriteTo(bs, &addr)
+		if err != nil && debug {
+			l.Debugln(err, "on write to", addr)
+		} else if debug {
+			l.Debugf("sent %d bytes to %s", len(bs), addr.String())
 		}
 	}
 }

+ 56 - 29
internal/discover/discover.go

@@ -28,8 +28,7 @@ type Discoverer struct {
 	localBcastStart time.Time
 	cacheLifetime   time.Duration
 	negCacheCutoff  time.Duration
-	broadcastBeacon beacon.Interface
-	multicastBeacon beacon.Interface
+	beacons         []beacon.Interface
 	extPort         uint16
 	localBcastTick  <-chan time.Time
 	forcedBcastTick chan time.Time
@@ -65,38 +64,69 @@ func NewDiscoverer(id protocol.DeviceID, addresses []string) *Discoverer {
 
 func (d *Discoverer) StartLocal(localPort int, localMCAddr string) {
 	if localPort > 0 {
-		bb, err := beacon.NewBroadcast(localPort)
-		if err != nil {
-			if debug {
-				l.Debugln("discover: Start local v4:", err)
-			}
-			l.Infoln("Local discovery over IPv4 unavailable")
-		} else {
-			d.broadcastBeacon = bb
-			go d.recvAnnouncements(bb)
-		}
+		d.startLocalIPv4Broadcasts(localPort)
 	}
 
 	if len(localMCAddr) > 0 {
-		mb, err := beacon.NewMulticast(localMCAddr)
+		d.startLocalIPv6Multicasts(localMCAddr)
+	}
+
+	if len(d.beacons) == 0 {
+		l.Warnln("Local discovery unavailable")
+		return
+	}
+
+	d.localBcastTick = time.Tick(d.localBcastIntv)
+	d.forcedBcastTick = make(chan time.Time)
+	d.localBcastStart = time.Now()
+	go d.sendLocalAnnouncements()
+}
+
+func (d *Discoverer) startLocalIPv4Broadcasts(localPort int) {
+	bb, err := beacon.NewBroadcast(localPort)
+	if err != nil {
+		if debug {
+			l.Debugln("discover: Start local v4:", err)
+		}
+		l.Infoln("Local discovery over IPv4 unavailable")
+		return
+	}
+
+	d.beacons = append(d.beacons, bb)
+	go d.recvAnnouncements(bb)
+}
+
+func (d *Discoverer) startLocalIPv6Multicasts(localMCAddr string) {
+	intfs, err := net.Interfaces()
+	if err != nil {
+		if debug {
+			l.Debugln("discover: interfaces:", err)
+		}
+		l.Infoln("Local discovery over IPv6 unavailable")
+		return
+	}
+
+	v6Intfs := 0
+	for _, intf := range intfs {
+		if intf.Flags&net.FlagUp == 0 || intf.Flags&net.FlagMulticast == 0 {
+			continue
+		}
+
+		mb, err := beacon.NewMulticast(localMCAddr, intf.Name)
 		if err != nil {
 			if debug {
 				l.Debugln("discover: Start local v6:", err)
 			}
-			l.Infoln("Local discovery over IPv6 unavailable")
-		} else {
-			d.multicastBeacon = mb
-			go d.recvAnnouncements(mb)
+			continue
 		}
+
+		d.beacons = append(d.beacons, mb)
+		go d.recvAnnouncements(mb)
+		v6Intfs++
 	}
 
-	if d.broadcastBeacon == nil && d.multicastBeacon == nil {
-		l.Warnln("Local discovery unavailable")
-	} else {
-		d.localBcastTick = time.Tick(d.localBcastIntv)
-		d.forcedBcastTick = make(chan time.Time)
-		d.localBcastStart = time.Now()
-		go d.sendLocalAnnouncements()
+	if v6Intfs == 0 {
+		l.Infoln("Local discovery over IPv6 unavailable")
 	}
 }
 
@@ -288,11 +318,8 @@ func (d *Discoverer) sendLocalAnnouncements() {
 	msg := pkt.MustMarshalXDR()
 
 	for {
-		if d.multicastBeacon != nil {
-			d.multicastBeacon.Send(msg)
-		}
-		if d.broadcastBeacon != nil {
-			d.broadcastBeacon.Send(msg)
+		for _, b := range d.beacons {
+			b.Send(msg)
 		}
 
 		select {