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
This commit is contained in:
Jakob Borg 2017-11-17 09:12:35 +00:00 committed by Audrius Butkevicius
parent aecd7c64ce
commit 7ebf58f1bc
5 changed files with 51 additions and 17 deletions

View File

@ -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

View File

@ -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
}

View File

@ -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)
}
}

View File

@ -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:

View File

@ -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")
}
}