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

Fix discovery in the absence of listen addresses (fixes #4418)

This makes it OK to not have any listeners working. Specifically,

- We don't complain about an empty listener address
- We don't complain about not having anything to announce to global
  discovery servers
- We don't send local discovery packets when there is nothing to
  announce.

The last point also fixes a thing where the list of addresses for local
discovery was set at startup time and never refreshed.

GitHub-Pull-Request: https://github.com/syncthing/syncthing/pull/4517
Jakob Borg пре 8 година
родитељ
комит
7ebf58f1bc
5 измењених фајлова са 51 додато и 17 уклоњено
  1. 7 0
      lib/connections/service.go
  2. 4 2
      lib/discover/global.go
  3. 1 1
      lib/discover/global_test.go
  4. 28 10
      lib/discover/local.go
  5. 11 4
      lib/discover/local_test.go

+ 7 - 0
lib/connections/service.go

@@ -504,6 +504,13 @@ func (s *Service) CommitConfiguration(from, to config.Configuration) bool {
 	s.listenersMut.Lock()
 	seen := make(map[string]struct{})
 	for _, addr := range config.Wrap("", to).ListenAddresses() {
+		if addr == "" {
+			// We can get an empty address if there is an empty listener
+			// element in the config, indicating no listeners should be
+			// used. This is not an error.
+			continue
+		}
+
 		if _, ok := s.listeners[addr]; ok {
 			seen[addr] = struct{}{}
 			continue

+ 4 - 2
lib/discover/global.go

@@ -208,8 +208,10 @@ func (c *globalClient) sendAnnouncement(timer *time.Timer) {
 	}
 
 	if len(ann.Addresses) == 0 {
-		c.setError(errors.New("nothing to announce"))
-		l.Debugln("Nothing to announce")
+		// There are legitimate cases for not having anything to announce,
+		// yet still using global discovery for lookups. Do not error out
+		// here.
+		c.setError(nil)
 		timer.Reset(announceErrorRetryInterval)
 		return
 	}

+ 1 - 1
lib/discover/global_test.go

@@ -214,7 +214,7 @@ func TestGlobalAnnounce(t *testing.T) {
 	}
 
 	if !strings.Contains(string(s.announce), "tcp://0.0.0.0:22000") {
-		t.Errorf("announce missing addresses address: %s", s.announce)
+		t.Errorf("announce missing address: %q", s.announce)
 	}
 }
 

+ 28 - 10
lib/discover/local.go

@@ -112,24 +112,42 @@ func (c *localClient) Error() error {
 	return c.beacon.Error()
 }
 
-func (c *localClient) announcementPkt() Announce {
-	return Announce{
-		ID:         c.myID,
-		Addresses:  c.addrList.AllAddresses(),
-		InstanceID: rand.Int63(),
+// announcementPkt appends the local discovery packet to send to msg. Returns
+// true if the packet should be sent, false if there is nothing useful to
+// send.
+func (c *localClient) announcementPkt(instanceID int64, msg []byte) ([]byte, bool) {
+	addrs := c.addrList.AllAddresses()
+	if len(addrs) == 0 {
+		// Nothing to announce
+		return msg, false
 	}
-}
 
-func (c *localClient) sendLocalAnnouncements() {
-	msg := make([]byte, 4)
+	if cap(msg) >= 4 {
+		msg = msg[:4]
+	} else {
+		msg = make([]byte, 4)
+	}
 	binary.BigEndian.PutUint32(msg, Magic)
 
-	var pkt = c.announcementPkt()
+	pkt := Announce{
+		ID:         c.myID,
+		Addresses:  addrs,
+		InstanceID: instanceID,
+	}
 	bs, _ := pkt.Marshal()
 	msg = append(msg, bs...)
 
+	return msg, true
+}
+
+func (c *localClient) sendLocalAnnouncements() {
+	var msg []byte
+	var ok bool
+	instanceID := rand.Int63()
 	for {
-		c.beacon.Send(msg)
+		if msg, ok = c.announcementPkt(instanceID, msg[:0]); ok {
+			c.beacon.Send(msg)
+		}
 
 		select {
 		case <-c.localBcastTick:

+ 11 - 4
lib/discover/local_test.go

@@ -7,13 +7,14 @@
 package discover
 
 import (
+	"bytes"
 	"net"
 	"testing"
 
 	"github.com/syncthing/syncthing/lib/protocol"
 )
 
-func TestRandomLocalInstanceID(t *testing.T) {
+func TestLocalInstanceID(t *testing.T) {
 	c, err := NewLocal(protocol.LocalDeviceID, ":0", &fakeAddressLister{})
 	if err != nil {
 		t.Fatal(err)
@@ -23,9 +24,15 @@ func TestRandomLocalInstanceID(t *testing.T) {
 
 	lc := c.(*localClient)
 
-	p0 := lc.announcementPkt()
-	p1 := lc.announcementPkt()
-	if p0.InstanceID == p1.InstanceID {
+	p0, ok := lc.announcementPkt(1, nil)
+	if !ok {
+		t.Fatal("unexpectedly not ok")
+	}
+	p1, ok := lc.announcementPkt(2, nil)
+	if !ok {
+		t.Fatal("unexpectedly not ok")
+	}
+	if bytes.Equal(p0, p1) {
 		t.Error("each generated packet should have a new instance id")
 	}
 }