Archived
Large refactoring/feature commit
1. Change listen addresses to URIs 2. Break out connectionSvc to support listeners and dialers based on schema 3. Add relay announcement and lookups part of discovery service
This commit is contained in:
1 parent
50702eda94
commit
34c04babbe
18 files changed
+657
-321
No files matched your search
@@ -5,7 +5,7 @@ import (
|
||||
)
|
||||
|
||||
const (
|
||||
AssetsBuildDate = "Tue, 18 Aug 2015 11:29:36 GMT"
|
||||
AssetsBuildDate = "Wed, 19 Aug 2015 19:52:35 GMT"
|
||||
)
|
||||
|
||||
func Assets() map[string][]byte {
|
||||
@@ -50,7 +50,7 @@ func Assets() map[string][]byte {
|
||||
assets["assets/lang/lang-zh-TW.json"], _ = base64.StdEncoding.DecodeString("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 truncated
|
||||
assets["assets/lang/prettyprint.js"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/1xSUY7TMBD95xRWvrISuQASEiQsCxSVKpuF79nGm5g442hst9oijsNJuBgzdtSW/eq892bGb15zAFIWcNiRDuF5IYNBvVW/iseheFPU0Q5ABrB4XeyBiQYC2BW+O4DVuDdXvCq/rxzeSI8X6aT3I4NeM7jTNKdxbQWR1pMAZHCLgzV+TLC6qy+MKh/QBN2rjcGhd7Ns1rL5fgFcJ3x1e39hVMmFSRaeDNMfDa6NTySQ2GJGVfP+TKiyAYQeZGyMTH+KeL7eBCY+85EZ/pSjvwA/p71mPLlq0zK1caQlhvQri6zMfTVhjOwsjeIjM1tHRz0woWo3zX//WBEkkg8xJGuI/3Vtn9GRl6wW6dq5NaolVHWbCApxiGxGlTXBydibrO66F2quIenkqvYb662bkztVrlUSJYI2ep9t+4Pke9R9fjhIkF2kKcM4MXyYiFPP7aexarby748G07tSpL2sdD+ulQ7MUb6X36/+AQAA//8BAAD//5YJ/N+MAgAA")
|
||||
assets["assets/lang/valid-langs.js"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/yTMvQ6CMBTF8d2nIJ29j2CiEOOgUVNJHIxDgQqVppC2dPDpvacsv38/kpOUL5Kyprso14diV7xE04utaFVmz3/atSbfAtNpRlvgMnQq0ZCh44P7McBnqDpwh4UxkfliaZzoLLkWL64BWHRYnHGaI5Vy7b3m+onkDcVOSEzE/DIyv4Gq69r6Kd6bPwAAAP//AQAA//8bXi5E0gAAAA==")
|
||||
assets["index.html"], _ = base64.StdEncoding.DecodeString("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 truncated
|
||||
assets["index.html"], _ = base64.StdEncoding.DecodeString("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 truncated
|
||||
assets["modal.html"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/3RST0/cPhC9/z7F/HLogkQ2gDjRXaoWqVIlKiHBpceJPUlcHDuyJ9BtlO/eibNNYbUcEv97783Mm9lo8wzKYozbrPUaLVSoKQPG0jhNv7ZZfpGBq3NkDrlGxrxE9aSD77bZMAjVR4JPwKEnuIZVZGSjVjCOB6wn2pUeg06sL95bQneS2KcT+OY/gM3/eS5LUcCt73bB1A3Dye0pXJ5fXMFjQ/Cwc4ob42r43HPjQ1wn+Mx5bEyEB98HRcLXBF99aEHuYl/+JMXAHlhEmEIbwVfp8N3/NtYi3PelNWoWujOKXKQzeF7D5fp8Dd8qQFCS0sK6v4MXjOA8gzaRgyl7Jg0vhhsBSMzKWDqb5X74HhQ68CWjkcURIEPD3F0XRTvHX/tQF6JaSLxiKirPkyGHzcm1QevrZO3+fljNL7ZeXYPFUNNs5jG28o7J8f79GKIh6X4AtBR4/ufDMPW0j+O48ITZXL0lsmFLrwACiZ1ULYmaapsZCZ39ZVQoQya60+Wkuikm6GvuMCS9cfwXsGiulrQLyfv9Gkqvd8khDuiisr2m95n7/NIgZm91Ku9lVl4XLV1m74B3HW2z+bBwSnYgX66pwt5y2sc2gzT8MiStWZSP2PTGGTYtxcWWD66M3ccZliqyyHRzOyV8aNymmJM6Uu6y3W/2yx8AAAD//wEAAP//qvxG6f8DAAA=")
|
||||
assets["syncthing/app.js"], _ = base64.StdEncoding.DecodeString("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")
|
||||
assets["syncthing/core/aboutModalDirective.js"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/1SOMQ7CMAxF954im1upSnc6cQBG2ENqWktOglwHhFDvTgpSgT/+/yw/F8fMTmxIQ2asYX5ErxPF0fokCE1lSuxAgl7pVgB3TlkPaXAMrbnkQlOKpm7M842uEdQs8af4lLMKed0Z2EP7NymGKzvFo3BZN4NuNei+/06EdztpYNiul75amr56AQAA//8BAAD//xLf4CHFAAAA")
|
||||
@@ -85,7 +85,7 @@ func Assets() map[string][]byte {
|
||||
assets["syncthing/core/upgradingDialogView.html"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/1zOTarDMAwE4PXLKYQ2WSW5gO0zPCg9gHDcVODaxlIIJc3dm5b+QLfDN8yYSx4pAo8W5zJVGjlNCKKks1jkdMoI7HOySLXmpfNcfQzdXBCUNQaL69oe380WbqCVkkTSsG3omj9TnJFC6Zu7wzV5Pe8cWOCz2pvh4Rz88v8YSAIsxPoifb/j4hozPN+75g4AAP//AQAA///kaeW6xgAAAA==")
|
||||
assets["syncthing/core/validDeviceidDirective.js"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/5STQW/qMAzH73yKHJBS9Kr0Dnp6l7fjrtyzxG2jhbSznTI08d2XAAMGlDFfKtn+/23/ourQRK9RrTobPRSSNsFw60KjTIcgZxORQlmHYNgNqWHQ3tn/MDgDzspS1DEJXBdEMW2Z+5n42ElyIHDEcJbYJ99icpsLGZrnzoKX5be6d+F1fuZKpuuhFOBXpdDMSKUwjH52YZsj59W010iApGKg1tVcnKwGB+ul9hFuiXO4+jBPgXWcIDy9O8rfMUGOqhJrENR20dsgWewAaYZRwX5NAl7mTseba6iMacnFTYdtQkFwZ5/dM6gGuIjoX3Tq/SNkRYOp7GHAP2f/ypQ98VAUjQGiM1gI1N87+4tX7lOA2OFP3Q/eXut038jxD0P4xbw7rI/jRqvbsVe6mT38EEfu19pLv5PPdjHJxU8AAAD//wEAAP//7ceZ97ADAAA=")
|
||||
assets["syncthing/device/editDeviceModalDirective.js"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/1yOMQ+CMBCFd35Ft4OElF0mE1dH3Zv2hEuOYo4rxhj+uxUSor7xfe/uPRe7xE7sMIbEWML0jF57ip0NOJNHqAqTZQMJeqU5RzCQnlZ4HoNjqM0t5SMaoykr81rzHwlqkvhlbOakQl4PBo5Q/yDF4c5O8SKc6T6k2YY0f7VXwoftdWDYnyxtsVRt8QYAAP//AQAA//8AoJJL0wAAAA==")
|
||||
assets["syncthing/device/editDeviceModalView.html"], _ = base64.StdEncoding.DecodeString("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")
|
||||
assets["syncthing/device/editDeviceModalView.html"], _ = base64.StdEncoding.DecodeString("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")
|
||||
assets["syncthing/device/idqrModalDirective.js"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/1SOMQ7CMAxF954im1upSnc6cQBG2KPEtJbcFFynCKHenUClCP74/7P8XBwSO7HTHBJjDcszeh0pDjbgSh6hqUyODSToldaMULjLaQ6OoTXXlHGao6kb8/qSnwhqkvhT7OWiQl4PBo7Q/k2K042d4lk4r0Wh2xW68vBC+LCjTgzlfOurremrNwAAAP//AQAA///xwJawxwAAAA==")
|
||||
assets["syncthing/device/idqrModalView.html"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/zSQPXLCMBCFe59iZxug0PgCttPQ0OQOQlqbnegnSAsJo+jukQ00Gj3pvW/e7uCj1Q7Yjsj2mhCyaLnlpsIcEdjEMOI1mWgJQVgcjVjK7kh3NgQnS0F4ZqOFY9jBH0jSITstVCsoKMVuxk/taS8Xzs/c/nCoFcHptDTcgzKCcTG/7lMHMFi+tzedW5Mfcg7WQ2UPQr+ifAwxf+tWYJOmlaCEUyn+cTrWOvQtvVHYLxAWxfOI6xe+kc+EOrtovqCZlFxu/hw0O1z9OZl16P5jxY9vLPZTN/TbvqbuHwAA//8BAAD//2Nevvg4AQAA")
|
||||
assets["syncthing/device/module.js"], _ = base64.StdEncoding.DecodeString("H4sIAAAJbogA/0rMSy/NSSzSy81PKc1J1VAvrsxLLsnIzEvXS0kty0xOVddRiI7VtOYCAAAA//8BAAD//23b1z0oAAAA")
|
||||
|
||||
+43
-6
@@ -9,6 +9,7 @@ package config
|
||||
|
||||
import (
|
||||
"encoding/xml"
|
||||
"fmt"
|
||||
"io"
|
||||
"math/rand"
|
||||
"os"
|
||||
@@ -26,7 +27,7 @@ import (
|
||||
|
||||
const (
|
||||
OldestHandledVersion = 5
|
||||
CurrentVersion = 11
|
||||
CurrentVersion = 12
|
||||
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
||||
)
|
||||
|
||||
@@ -212,12 +213,13 @@ type FolderDeviceConfiguration struct {
|
||||
}
|
||||
|
||||
type OptionsConfiguration struct {
|
||||
ListenAddress []string `xml:"listenAddress" json:"listenAddress" default:"0.0.0.0:22000"`
|
||||
GlobalAnnServers []string `xml:"globalAnnounceServer" json:"globalAnnounceServers" json:"globalAnnounceServer" default:"udp4://announce.syncthing.net:22026, udp6://announce-v6.syncthing.net:22026"`
|
||||
ListenAddress []string `xml:"listenAddress" json:"listenAddress" default:"tcp://0.0.0.0:22000"`
|
||||
GlobalAnnServers []string `xml:"globalAnnounceServer" json:"globalAnnounceServers" json:"globalAnnounceServer" default:"udp4://announce.syncthing.net:22027, udp6://announce-v6.syncthing.net:22027"`
|
||||
GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" json:"globalAnnounceEnabled" default:"true"`
|
||||
LocalAnnEnabled bool `xml:"localAnnounceEnabled" json:"localAnnounceEnabled" default:"true"`
|
||||
LocalAnnPort int `xml:"localAnnouncePort" json:"localAnnouncePort" default:"21025"`
|
||||
LocalAnnMCAddr string `xml:"localAnnounceMCAddr" json:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
|
||||
RelayServers []string `xml:"relayServer" json:"relayServers" default:""`
|
||||
MaxSendKbps int `xml:"maxSendKbps" json:"maxSendKbps"`
|
||||
MaxRecvKbps int `xml:"maxRecvKbps" json:"maxRecvKbps"`
|
||||
ReconnectIntervalS int `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"`
|
||||
@@ -346,6 +348,9 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) {
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
|
||||
cfg.Options.GlobalAnnServers = uniqueStrings(cfg.Options.GlobalAnnServers)
|
||||
|
||||
if cfg.Version < OldestHandledVersion {
|
||||
l.Warnf("Configuration version %d is deprecated. Attempting best effort conversion, but please verify manually.", cfg.Version)
|
||||
}
|
||||
@@ -369,6 +374,9 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) {
|
||||
if cfg.Version == 10 {
|
||||
convertV10V11(cfg)
|
||||
}
|
||||
if cfg.Version == 11 {
|
||||
convertV11V12(cfg)
|
||||
}
|
||||
|
||||
// Hash old cleartext passwords
|
||||
if len(cfg.GUI.Password) > 0 && cfg.GUI.Password[0] != '$' {
|
||||
@@ -420,9 +428,6 @@ func (cfg *Configuration) prepare(myID protocol.DeviceID) {
|
||||
cfg.Options.ReconnectIntervalS = 5
|
||||
}
|
||||
|
||||
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
|
||||
cfg.Options.GlobalAnnServers = uniqueStrings(cfg.Options.GlobalAnnServers)
|
||||
|
||||
if cfg.GUI.APIKey == "" {
|
||||
cfg.GUI.APIKey = randomString(32)
|
||||
}
|
||||
@@ -467,6 +472,38 @@ func convertV10V11(cfg *Configuration) {
|
||||
cfg.Version = 11
|
||||
}
|
||||
|
||||
func convertV11V12(cfg *Configuration) {
|
||||
// Change listen address schema
|
||||
for i, addr := range cfg.Options.ListenAddress {
|
||||
if len(addr) > 0 && !strings.HasPrefix(addr, "tcp://") {
|
||||
cfg.Options.ListenAddress[i] = fmt.Sprintf("tcp://%s", addr)
|
||||
}
|
||||
}
|
||||
|
||||
for i, device := range cfg.Devices {
|
||||
for j, addr := range device.Addresses {
|
||||
if addr != "dynamic" && addr != "" {
|
||||
cfg.Devices[i].Addresses[j] = fmt.Sprintf("tcp://%s", addr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Use new discovery server
|
||||
for i, addr := range cfg.Options.GlobalAnnServers {
|
||||
if addr == "udp4://announce.syncthing.net:22026" {
|
||||
cfg.Options.GlobalAnnServers[i] = "udp4://announce.syncthing.net:22027"
|
||||
} else if addr == "udp6://announce-v6.syncthing.net:22026" {
|
||||
cfg.Options.GlobalAnnServers[i] = "udp6://announce-v6.syncthing.net:22027"
|
||||
} else if addr == "udp4://194.126.249.5:22026" {
|
||||
cfg.Options.GlobalAnnServers[i] = "udp4://194.126.249.5:22027"
|
||||
} else if addr == "udp6://[2001:470:28:4d6::5]:22026" {
|
||||
cfg.Options.GlobalAnnServers[i] = "udp6://[2001:470:28:4d6::5]:22027"
|
||||
}
|
||||
}
|
||||
|
||||
cfg.Version = 12
|
||||
}
|
||||
|
||||
func convertV9V10(cfg *Configuration) {
|
||||
// Enable auto normalization on existing folders.
|
||||
for i := range cfg.Folders {
|
||||
|
||||
+13
-12
@@ -31,8 +31,8 @@ func init() {
|
||||
|
||||
func TestDefaultValues(t *testing.T) {
|
||||
expected := OptionsConfiguration{
|
||||
ListenAddress: []string{"0.0.0.0:22000"},
|
||||
GlobalAnnServers: []string{"udp4://announce.syncthing.net:22026", "udp6://announce-v6.syncthing.net:22026"},
|
||||
ListenAddress: []string{"tcp://0.0.0.0:22000"},
|
||||
GlobalAnnServers: []string{"udp4://announce.syncthing.net:22027", "udp6://announce-v6.syncthing.net:22027"},
|
||||
GlobalAnnEnabled: true,
|
||||
LocalAnnEnabled: true,
|
||||
LocalAnnPort: 21025,
|
||||
@@ -100,13 +100,13 @@ func TestDeviceConfig(t *testing.T) {
|
||||
{
|
||||
DeviceID: device1,
|
||||
Name: "node one",
|
||||
Addresses: []string{"a"},
|
||||
Addresses: []string{"tcp://a"},
|
||||
Compression: protocol.CompressMetadata,
|
||||
},
|
||||
{
|
||||
DeviceID: device4,
|
||||
Name: "node two",
|
||||
Addresses: []string{"b"},
|
||||
Addresses: []string{"tcp://b"},
|
||||
Compression: protocol.CompressMetadata,
|
||||
},
|
||||
}
|
||||
@@ -142,12 +142,13 @@ func TestNoListenAddress(t *testing.T) {
|
||||
|
||||
func TestOverriddenValues(t *testing.T) {
|
||||
expected := OptionsConfiguration{
|
||||
ListenAddress: []string{":23000"},
|
||||
ListenAddress: []string{"tcp://:23000"},
|
||||
GlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"},
|
||||
GlobalAnnEnabled: false,
|
||||
LocalAnnEnabled: false,
|
||||
LocalAnnPort: 42123,
|
||||
LocalAnnMCAddr: "quux:3232",
|
||||
RelayServers: []string{"relay://123.123.123.123:1234", "relay://125.125.125.125:1255"},
|
||||
MaxSendKbps: 1234,
|
||||
MaxRecvKbps: 2341,
|
||||
ReconnectIntervalS: 6000,
|
||||
@@ -255,15 +256,15 @@ func TestDeviceAddressesStatic(t *testing.T) {
|
||||
expected := map[protocol.DeviceID]DeviceConfiguration{
|
||||
device1: {
|
||||
DeviceID: device1,
|
||||
Addresses: []string{"192.0.2.1", "192.0.2.2"},
|
||||
Addresses: []string{"tcp://192.0.2.1", "tcp://192.0.2.2"},
|
||||
},
|
||||
device2: {
|
||||
DeviceID: device2,
|
||||
Addresses: []string{"192.0.2.3:6070", "[2001:db8::42]:4242"},
|
||||
Addresses: []string{"tcp://192.0.2.3:6070", "tcp://[2001:db8::42]:4242"},
|
||||
},
|
||||
device3: {
|
||||
DeviceID: device3,
|
||||
Addresses: []string{"[2001:db8::44]:4444", "192.0.2.4:6090"},
|
||||
Addresses: []string{"tcp://[2001:db8::44]:4444", "tcp://192.0.2.4:6090"},
|
||||
},
|
||||
device4: {
|
||||
DeviceID: device4,
|
||||
@@ -330,12 +331,12 @@ func TestIssue1750(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if cfg.Options().ListenAddress[0] != ":23000" {
|
||||
t.Errorf("%q != %q", cfg.Options().ListenAddress[0], ":23000")
|
||||
if cfg.Options().ListenAddress[0] != "tcp://:23000" {
|
||||
t.Errorf("%q != %q", cfg.Options().ListenAddress[0], "tcp://:23000")
|
||||
}
|
||||
|
||||
if cfg.Options().ListenAddress[1] != ":23001" {
|
||||
t.Errorf("%q != %q", cfg.Options().ListenAddress[1], ":23001")
|
||||
if cfg.Options().ListenAddress[1] != "tcp://:23001" {
|
||||
t.Errorf("%q != %q", cfg.Options().ListenAddress[1], "tcp://:23001")
|
||||
}
|
||||
|
||||
if cfg.Options().GlobalAnnServers[0] != "udp4://syncthing.nym.se:22026" {
|
||||
|
||||
+2
@@ -7,6 +7,8 @@
|
||||
<localAnnounceEnabled>false</localAnnounceEnabled>
|
||||
<localAnnouncePort>42123</localAnnouncePort>
|
||||
<localAnnounceMCAddr>quux:3232</localAnnounceMCAddr>
|
||||
<relayServer>relay://123.123.123.123:1234</relayServer>
|
||||
<relayServer>relay://125.125.125.125:1255</relayServer>
|
||||
<parallelRequests>32</parallelRequests>
|
||||
<maxSendKbps>1234</maxSendKbps>
|
||||
<maxRecvKbps>2341</maxRecvKbps>
|
||||
|
||||
Vendored
+13
@@ -0,0 +1,13 @@
|
||||
<configuration version="12">
|
||||
<folder id="test" path="testdata" ro="true" ignorePerms="false" rescanIntervalS="600" autoNormalize="true">
|
||||
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR"></device>
|
||||
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2"></device>
|
||||
<minDiskFreePct>1</minDiskFreePct>
|
||||
</folder>
|
||||
<device id="AIR6LPZ-7K4PTTV-UXQSMUU-CPQ5YWH-OEDFIIQ-JUG777G-2YQXXR5-YD6AWQR" name="node one" compression="metadata">
|
||||
<address>tcp://a</address>
|
||||
</device>
|
||||
<device id="P56IOI7-MZJNU2Y-IQGDREY-DM2MGTI-MGL3BXN-PQ6W5BM-TBBZ4TJ-XZWICQ2" name="node two" compression="metadata">
|
||||
<address>tcp://b</address>
|
||||
</device>
|
||||
</configuration>
|
||||
@@ -43,7 +43,7 @@ func New(addr string, pkt *Announce) (Client, error) {
|
||||
}
|
||||
|
||||
type Client interface {
|
||||
Lookup(device protocol.DeviceID) []string
|
||||
Lookup(device protocol.DeviceID) (Announce, error)
|
||||
StatusOK() bool
|
||||
Address() string
|
||||
Stop()
|
||||
|
||||
+17
-11
@@ -37,10 +37,8 @@ func TestUDP4Success(t *testing.T) {
|
||||
Magic: AnnouncementMagic,
|
||||
This: Device{
|
||||
device[:],
|
||||
[]Address{{
|
||||
IP: net.IPv4(123, 123, 123, 123),
|
||||
Port: 1234,
|
||||
}},
|
||||
[]string{"tcp://123.123.123.123:1234"},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -101,7 +99,12 @@ func TestUDP4Success(t *testing.T) {
|
||||
wg := sync.NewWaitGroup()
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
addrs = client.Lookup(device)
|
||||
pkt, err := client.Lookup(device)
|
||||
if err == nil {
|
||||
for _, addr := range pkt.This.Addresses {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
@@ -117,7 +120,7 @@ func TestUDP4Success(t *testing.T) {
|
||||
// Wait for the lookup to arrive, verify that the number of answers is correct
|
||||
wg.Wait()
|
||||
|
||||
if len(addrs) != 1 || addrs[0] != "123.123.123.123:1234" {
|
||||
if len(addrs) != 1 || addrs[0] != "tcp://123.123.123.123:1234" {
|
||||
t.Fatal("Wrong number of answers")
|
||||
}
|
||||
|
||||
@@ -138,10 +141,8 @@ func TestUDP4Failure(t *testing.T) {
|
||||
Magic: AnnouncementMagic,
|
||||
This: Device{
|
||||
device[:],
|
||||
[]Address{{
|
||||
IP: net.IPv4(123, 123, 123, 123),
|
||||
Port: 1234,
|
||||
}},
|
||||
[]string{"tcp://123.123.123.123:1234"},
|
||||
nil,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -197,7 +198,12 @@ func TestUDP4Failure(t *testing.T) {
|
||||
wg := sync.NewWaitGroup()
|
||||
wg.Add(1)
|
||||
go func() {
|
||||
addrs = client.Lookup(device)
|
||||
pkt, err := client.Lookup(device)
|
||||
if err == nil {
|
||||
for _, addr := range pkt.This.Addresses {
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
}
|
||||
wg.Done()
|
||||
}()
|
||||
|
||||
|
||||
+16
-19
@@ -137,11 +137,13 @@ func (d *UDPClient) broadcast(pkt []byte) {
|
||||
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
res := d.Lookup(d.id)
|
||||
if debug {
|
||||
l.Debugf("discover %s: broadcast: Self-lookup returned: %v", d.url, res)
|
||||
pkt, err := d.Lookup(d.id)
|
||||
if err != nil && debug {
|
||||
l.Debugf("discover %s: broadcast: Self-lookup failed: %v", d.url, err)
|
||||
} else if debug {
|
||||
l.Debugf("discover %s: broadcast: Self-lookup returned: %v", d.url, pkt.This.Addresses)
|
||||
}
|
||||
ok = len(res) > 0
|
||||
ok = len(pkt.This.Addresses) > 0
|
||||
}
|
||||
|
||||
d.mut.Lock()
|
||||
@@ -157,13 +159,13 @@ func (d *UDPClient) broadcast(pkt []byte) {
|
||||
}
|
||||
}
|
||||
|
||||
func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
||||
func (d *UDPClient) Lookup(device protocol.DeviceID) (Announce, error) {
|
||||
extIP, err := net.ResolveUDPAddr(d.url.Scheme, d.url.Host)
|
||||
if err != nil {
|
||||
if debug {
|
||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||
}
|
||||
return nil
|
||||
return Announce{}, err
|
||||
}
|
||||
|
||||
conn, err := net.DialUDP(d.url.Scheme, d.listenAddress, extIP)
|
||||
@@ -171,7 +173,7 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
||||
if debug {
|
||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||
}
|
||||
return nil
|
||||
return Announce{}, err
|
||||
}
|
||||
defer conn.Close()
|
||||
|
||||
@@ -180,7 +182,7 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
||||
if debug {
|
||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||
}
|
||||
return nil
|
||||
return Announce{}, err
|
||||
}
|
||||
|
||||
buf := Query{QueryMagic, device[:]}.MustMarshalXDR()
|
||||
@@ -189,7 +191,7 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
||||
if debug {
|
||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||
}
|
||||
return nil
|
||||
return Announce{}, err
|
||||
}
|
||||
|
||||
buf = make([]byte, 2048)
|
||||
@@ -197,12 +199,12 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
||||
if err != nil {
|
||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||
// Expected if the server doesn't know about requested device ID
|
||||
return nil
|
||||
return Announce{}, err
|
||||
}
|
||||
if debug {
|
||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||
}
|
||||
return nil
|
||||
return Announce{}, err
|
||||
}
|
||||
|
||||
var pkt Announce
|
||||
@@ -211,18 +213,13 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
||||
if debug {
|
||||
l.Debugf("discover %s: Lookup(%s): %s\n%s", d.url, device, err, hex.Dump(buf[:n]))
|
||||
}
|
||||
return nil
|
||||
return Announce{}, err
|
||||
}
|
||||
|
||||
var addrs []string
|
||||
for _, a := range pkt.This.Addresses {
|
||||
deviceAddr := net.JoinHostPort(net.IP(a.IP).String(), strconv.Itoa(int(a.Port)))
|
||||
addrs = append(addrs, deviceAddr)
|
||||
}
|
||||
if debug {
|
||||
l.Debugf("discover %s: Lookup(%s) result: %v", d.url, device, addrs)
|
||||
l.Debugf("discover %s: Lookup(%s) result: %v relays: %v", d.url, device, pkt.This.Addresses, pkt.This.Relays)
|
||||
}
|
||||
return addrs
|
||||
return pkt, nil
|
||||
}
|
||||
|
||||
func (d *UDPClient) Stop() {
|
||||
|
||||
+199
-69
@@ -10,21 +10,25 @@ import (
|
||||
"bytes"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net"
|
||||
"net/url"
|
||||
"runtime"
|
||||
"strconv"
|
||||
"sort"
|
||||
"time"
|
||||
|
||||
"github.com/syncthing/protocol"
|
||||
"github.com/syncthing/syncthing/lib/beacon"
|
||||
"github.com/syncthing/syncthing/lib/events"
|
||||
"github.com/syncthing/syncthing/lib/osutil"
|
||||
"github.com/syncthing/syncthing/lib/sync"
|
||||
)
|
||||
|
||||
type Discoverer struct {
|
||||
myID protocol.DeviceID
|
||||
listenAddrs []string
|
||||
relays []Relay
|
||||
localBcastIntv time.Duration
|
||||
localBcastStart time.Time
|
||||
cacheLifetime time.Duration
|
||||
@@ -34,9 +38,10 @@ type Discoverer struct {
|
||||
localBcastTick <-chan time.Time
|
||||
forcedBcastTick chan time.Time
|
||||
|
||||
registryLock sync.RWMutex
|
||||
registry map[protocol.DeviceID][]CacheEntry
|
||||
lastLookup map[protocol.DeviceID]time.Time
|
||||
registryLock sync.RWMutex
|
||||
addressRegistry map[protocol.DeviceID][]CacheEntry
|
||||
relayRegistry map[protocol.DeviceID][]CacheEntry
|
||||
lastLookup map[protocol.DeviceID]time.Time
|
||||
|
||||
clients []Client
|
||||
mut sync.RWMutex
|
||||
@@ -51,17 +56,19 @@ var (
|
||||
ErrIncorrectMagic = errors.New("incorrect magic number")
|
||||
)
|
||||
|
||||
func NewDiscoverer(id protocol.DeviceID, addresses []string) *Discoverer {
|
||||
func NewDiscoverer(id protocol.DeviceID, addresses []string, relayAdresses []string) *Discoverer {
|
||||
return &Discoverer{
|
||||
myID: id,
|
||||
listenAddrs: addresses,
|
||||
localBcastIntv: 30 * time.Second,
|
||||
cacheLifetime: 5 * time.Minute,
|
||||
negCacheCutoff: 3 * time.Minute,
|
||||
registry: make(map[protocol.DeviceID][]CacheEntry),
|
||||
lastLookup: make(map[protocol.DeviceID]time.Time),
|
||||
registryLock: sync.NewRWMutex(),
|
||||
mut: sync.NewRWMutex(),
|
||||
myID: id,
|
||||
listenAddrs: addresses,
|
||||
relays: measureLatency(relayAdresses),
|
||||
localBcastIntv: 30 * time.Second,
|
||||
cacheLifetime: 5 * time.Minute,
|
||||
negCacheCutoff: 3 * time.Minute,
|
||||
addressRegistry: make(map[protocol.DeviceID][]CacheEntry),
|
||||
relayRegistry: make(map[protocol.DeviceID][]CacheEntry),
|
||||
lastLookup: make(map[protocol.DeviceID]time.Time),
|
||||
registryLock: sync.NewRWMutex(),
|
||||
mut: sync.NewRWMutex(),
|
||||
}
|
||||
}
|
||||
|
||||
@@ -184,75 +191,108 @@ func (d *Discoverer) ExtAnnounceOK() map[string]bool {
|
||||
return ret
|
||||
}
|
||||
|
||||
func (d *Discoverer) Lookup(device protocol.DeviceID) []string {
|
||||
// Lookup returns a list of addresses the device is available at, as well as
|
||||
// a list of relays the device is supposed to be available on sorted by the
|
||||
// sum of latencies between this device, and the device in question.
|
||||
func (d *Discoverer) Lookup(device protocol.DeviceID) ([]string, []string) {
|
||||
d.registryLock.RLock()
|
||||
cached := d.filterCached(d.registry[device])
|
||||
cachedAddresses := d.filterCached(d.addressRegistry[device])
|
||||
cachedRelays := d.filterCached(d.relayRegistry[device])
|
||||
lastLookup := d.lastLookup[device]
|
||||
d.registryLock.RUnlock()
|
||||
|
||||
d.mut.RLock()
|
||||
defer d.mut.RUnlock()
|
||||
|
||||
if len(cached) > 0 {
|
||||
relays := make([]string, len(cachedRelays))
|
||||
for i := range cachedRelays {
|
||||
relays[i] = cachedRelays[i].Address
|
||||
}
|
||||
|
||||
if len(cachedAddresses) > 0 {
|
||||
// There are cached address entries.
|
||||
addrs := make([]string, len(cached))
|
||||
for i := range cached {
|
||||
addrs[i] = cached[i].Address
|
||||
addrs := make([]string, len(cachedAddresses))
|
||||
for i := range cachedAddresses {
|
||||
addrs[i] = cachedAddresses[i].Address
|
||||
}
|
||||
return addrs
|
||||
return addrs, relays
|
||||
}
|
||||
|
||||
if time.Since(lastLookup) < d.negCacheCutoff {
|
||||
// We have recently tried to lookup this address and failed. Lets
|
||||
// chill for a while.
|
||||
return nil
|
||||
return nil, relays
|
||||
}
|
||||
|
||||
if len(d.clients) != 0 && time.Since(d.localBcastStart) > d.localBcastIntv {
|
||||
// Only perform external lookups if we have at least one external
|
||||
// server client and one local announcement interval has passed. This is
|
||||
// to avoid finding local peers on their remote address at startup.
|
||||
results := make(chan []string, len(d.clients))
|
||||
results := make(chan Announce, len(d.clients))
|
||||
wg := sync.NewWaitGroup()
|
||||
for _, client := range d.clients {
|
||||
wg.Add(1)
|
||||
go func(c Client) {
|
||||
defer wg.Done()
|
||||
results <- c.Lookup(device)
|
||||
ann, err := c.Lookup(device)
|
||||
if err == nil {
|
||||
results <- ann
|
||||
}
|
||||
|
||||
}(client)
|
||||
}
|
||||
|
||||
wg.Wait()
|
||||
close(results)
|
||||
|
||||
cached := []CacheEntry{}
|
||||
seen := make(map[string]struct{})
|
||||
cachedAddresses := []CacheEntry{}
|
||||
availableRelays := []Relay{}
|
||||
seenAddresses := make(map[string]struct{})
|
||||
seenRelays := make(map[string]struct{})
|
||||
now := time.Now()
|
||||
|
||||
var addrs []string
|
||||
for result := range results {
|
||||
for _, addr := range result {
|
||||
_, ok := seen[addr]
|
||||
for _, addr := range result.This.Addresses {
|
||||
_, ok := seenAddresses[addr]
|
||||
if !ok {
|
||||
cached = append(cached, CacheEntry{
|
||||
cachedAddresses = append(cachedAddresses, CacheEntry{
|
||||
Address: addr,
|
||||
Seen: now,
|
||||
})
|
||||
seen[addr] = struct{}{}
|
||||
seenAddresses[addr] = struct{}{}
|
||||
addrs = append(addrs, addr)
|
||||
}
|
||||
}
|
||||
|
||||
for _, relay := range result.This.Relays {
|
||||
_, ok := seenRelays[relay.Address]
|
||||
if !ok {
|
||||
availableRelays = append(availableRelays, relay)
|
||||
seenRelays[relay.Address] = struct{}{}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
relays = addressesSortedByLatency(availableRelays)
|
||||
cachedRelays := make([]CacheEntry, len(relays))
|
||||
for i := range relays {
|
||||
cachedRelays[i] = CacheEntry{
|
||||
Address: relays[i],
|
||||
Seen: now,
|
||||
}
|
||||
}
|
||||
|
||||
d.registryLock.Lock()
|
||||
d.registry[device] = cached
|
||||
d.addressRegistry[device] = cachedAddresses
|
||||
d.relayRegistry[device] = cachedRelays
|
||||
d.lastLookup[device] = time.Now()
|
||||
d.registryLock.Unlock()
|
||||
|
||||
return addrs
|
||||
return addrs, relays
|
||||
}
|
||||
|
||||
return nil
|
||||
return nil, relays
|
||||
}
|
||||
|
||||
func (d *Discoverer) Hint(device string, addrs []string) {
|
||||
@@ -267,8 +307,8 @@ func (d *Discoverer) Hint(device string, addrs []string) {
|
||||
|
||||
func (d *Discoverer) All() map[protocol.DeviceID][]CacheEntry {
|
||||
d.registryLock.RLock()
|
||||
devices := make(map[protocol.DeviceID][]CacheEntry, len(d.registry))
|
||||
for device, addrs := range d.registry {
|
||||
devices := make(map[protocol.DeviceID][]CacheEntry, len(d.addressRegistry))
|
||||
for device, addrs := range d.addressRegistry {
|
||||
addrsCopy := make([]CacheEntry, len(addrs))
|
||||
copy(addrsCopy, addrs)
|
||||
devices[device] = addrsCopy
|
||||
@@ -278,30 +318,38 @@ func (d *Discoverer) All() map[protocol.DeviceID][]CacheEntry {
|
||||
}
|
||||
|
||||
func (d *Discoverer) announcementPkt() *Announce {
|
||||
var addrs []Address
|
||||
var addrs []string
|
||||
if d.extPort != 0 {
|
||||
addrs = []Address{{Port: d.extPort}}
|
||||
addrs = []string{fmt.Sprintf("tcp://:%d", d.extPort)}
|
||||
} else {
|
||||
for _, astr := range d.listenAddrs {
|
||||
addr, err := net.ResolveTCPAddr("tcp", astr)
|
||||
for _, aurl := range d.listenAddrs {
|
||||
uri, err := url.Parse(aurl)
|
||||
if err != nil {
|
||||
l.Warnln("discover: %v: not announcing %s", err, astr)
|
||||
if debug {
|
||||
l.Debugf("discovery: failed to parse listen address %s: %s", aurl, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
addr, err := net.ResolveTCPAddr("tcp", uri.Host)
|
||||
if err != nil {
|
||||
l.Warnln("discover: %v: not announcing %s", err, aurl)
|
||||
continue
|
||||
} else if debug {
|
||||
l.Debugf("discover: resolved %s as %#v", astr, addr)
|
||||
l.Debugf("discover: resolved %s as %#v", aurl, uri.Host)
|
||||
}
|
||||
if len(addr.IP) == 0 || addr.IP.IsUnspecified() {
|
||||
addrs = append(addrs, Address{Port: uint16(addr.Port)})
|
||||
uri.Host = fmt.Sprintf(":%d", addr.Port)
|
||||
} else if bs := addr.IP.To4(); bs != nil {
|
||||
addrs = append(addrs, Address{IP: bs, Port: uint16(addr.Port)})
|
||||
uri.Host = fmt.Sprintf("%s:%d", bs.String(), addr.Port)
|
||||
} else if bs := addr.IP.To16(); bs != nil {
|
||||
addrs = append(addrs, Address{IP: bs, Port: uint16(addr.Port)})
|
||||
uri.Host = fmt.Sprintf("[%s]:%d", bs.String(), addr.Port)
|
||||
}
|
||||
addrs = append(addrs, uri.String())
|
||||
}
|
||||
}
|
||||
return &Announce{
|
||||
Magic: AnnouncementMagic,
|
||||
This: Device{d.myID[:], addrs},
|
||||
This: Device{d.myID[:], addrs, d.relays},
|
||||
}
|
||||
}
|
||||
|
||||
@@ -310,7 +358,7 @@ func (d *Discoverer) sendLocalAnnouncements() {
|
||||
|
||||
var pkt = Announce{
|
||||
Magic: AnnouncementMagic,
|
||||
This: Device{d.myID[:], addrs},
|
||||
This: Device{d.myID[:], addrs, d.relays},
|
||||
}
|
||||
msg := pkt.MustMarshalXDR()
|
||||
|
||||
@@ -363,19 +411,32 @@ func (d *Discoverer) registerDevice(addr net.Addr, device Device) bool {
|
||||
d.registryLock.Lock()
|
||||
defer d.registryLock.Unlock()
|
||||
|
||||
current := d.filterCached(d.registry[id])
|
||||
current := d.filterCached(d.addressRegistry[id])
|
||||
|
||||
orig := current
|
||||
|
||||
for _, a := range device.Addresses {
|
||||
var deviceAddr string
|
||||
if len(a.IP) > 0 {
|
||||
deviceAddr = net.JoinHostPort(net.IP(a.IP).String(), strconv.Itoa(int(a.Port)))
|
||||
} else if addr != nil {
|
||||
ua := addr.(*net.UDPAddr)
|
||||
ua.Port = int(a.Port)
|
||||
deviceAddr = ua.String()
|
||||
for _, deviceAddr := range device.Addresses {
|
||||
uri, err := url.Parse(deviceAddr)
|
||||
if err != nil {
|
||||
if debug {
|
||||
l.Debugf("discover: Failed to parse address %s: %s", deviceAddr, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
host, port, err := net.SplitHostPort(uri.Host)
|
||||
if err != nil {
|
||||
if debug {
|
||||
l.Debugf("discover: Failed to split address host %s: %s", deviceAddr, err)
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
if host == "" {
|
||||
uri.Host = net.JoinHostPort(addr.(*net.UDPAddr).IP.String(), port)
|
||||
deviceAddr = uri.String()
|
||||
}
|
||||
|
||||
for i := range current {
|
||||
if current[i].Address == deviceAddr {
|
||||
current[i].Seen = time.Now()
|
||||
@@ -393,7 +454,7 @@ func (d *Discoverer) registerDevice(addr net.Addr, device Device) bool {
|
||||
l.Debugf("discover: Caching %s addresses: %v", id, current)
|
||||
}
|
||||
|
||||
d.registry[id] = current
|
||||
d.addressRegistry[id] = current
|
||||
|
||||
if len(current) > len(orig) {
|
||||
addrs := make([]string, len(current))
|
||||
@@ -413,7 +474,7 @@ func (d *Discoverer) filterCached(c []CacheEntry) []CacheEntry {
|
||||
for i := 0; i < len(c); {
|
||||
if ago := time.Since(c[i].Seen); ago > d.cacheLifetime {
|
||||
if debug {
|
||||
l.Debugf("discover: Removing cached address %s - seen %v ago", c[i].Address, ago)
|
||||
l.Debugf("discover: Removing cached entry %s - seen %v ago", c[i].Address, ago)
|
||||
}
|
||||
c[i] = c[len(c)-1]
|
||||
c = c[:len(c)-1]
|
||||
@@ -424,30 +485,99 @@ func (d *Discoverer) filterCached(c []CacheEntry) []CacheEntry {
|
||||
return c
|
||||
}
|
||||
|
||||
func addrToAddr(addr *net.TCPAddr) Address {
|
||||
func addrToAddr(addr *net.TCPAddr) string {
|
||||
if len(addr.IP) == 0 || addr.IP.IsUnspecified() {
|
||||
return Address{Port: uint16(addr.Port)}
|
||||
return fmt.Sprintf(":%d", addr.Port)
|
||||
} else if bs := addr.IP.To4(); bs != nil {
|
||||
return Address{IP: bs, Port: uint16(addr.Port)}
|
||||
return fmt.Sprintf("%s:%d", bs.String(), addr.Port)
|
||||
} else if bs := addr.IP.To16(); bs != nil {
|
||||
return Address{IP: bs, Port: uint16(addr.Port)}
|
||||
return fmt.Sprintf("[%s]:%d", bs.String(), addr.Port)
|
||||
}
|
||||
return Address{}
|
||||
return ""
|
||||
}
|
||||
|
||||
func resolveAddrs(addrs []string) []Address {
|
||||
var raddrs []Address
|
||||
func resolveAddrs(addrs []string) []string {
|
||||
var raddrs []string
|
||||
for _, addrStr := range addrs {
|
||||
addrRes, err := net.ResolveTCPAddr("tcp", addrStr)
|
||||
uri, err := url.Parse(addrStr)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
addrRes, err := net.ResolveTCPAddr("tcp", uri.Host)
|
||||
if err != nil {
|
||||
continue
|
||||
}
|
||||
addr := addrToAddr(addrRes)
|
||||
if len(addr.IP) > 0 {
|
||||
raddrs = append(raddrs, addr)
|
||||
} else {
|
||||
raddrs = append(raddrs, Address{Port: addr.Port})
|
||||
if len(addr) > 0 {
|
||||
uri.Host = addr
|
||||
raddrs = append(raddrs, uri.String())
|
||||
}
|
||||
}
|
||||
return raddrs
|
||||
}
|
||||
|
||||
func measureLatency(relayAdresses []string) []Relay {
|
||||
relays := make([]Relay, 0, len(relayAdresses))
|
||||
for i, addr := range relayAdresses {
|
||||
relay := Relay{
|
||||
Address: addr,
|
||||
Latency: int32(time.Hour / time.Millisecond),
|
||||
}
|
||||
relays = append(relays, relay)
|
||||
|
||||
if latency, err := getLatencyForURL(addr); err == nil {
|
||||
if debug {
|
||||
l.Debugf("Relay %s latency %s", addr, latency)
|
||||
}
|
||||
relays[i].Latency = int32(latency / time.Millisecond)
|
||||
} else {
|
||||
l.Debugf("Failed to get relay %s latency %s", addr, err)
|
||||
}
|
||||
}
|
||||
return relays
|
||||
}
|
||||
|
||||
// addressesSortedByLatency adds local latency to the relay, and sorts them
|
||||
// by sum latency, and returns the addresses.
|
||||
func addressesSortedByLatency(input []Relay) []string {
|
||||
relays := make([]Relay, len(input))
|
||||
copy(relays, input)
|
||||
for i, relay := range relays {
|
||||
if latency, err := getLatencyForURL(relay.Address); err == nil {
|
||||
relays[i].Latency += int32(latency / time.Millisecond)
|
||||
} else {
|
||||
relays[i].Latency += int32(time.Hour / time.Millisecond)
|
||||
}
|
||||
}
|
||||
|
||||
sort.Sort(relayList(relays))
|
||||
|
||||
addresses := make([]string, 0, len(relays))
|
||||
for _, relay := range relays {
|
||||
addresses = append(addresses, relay.Address)
|
||||
}
|
||||
return addresses
|
||||
}
|
||||
|
||||
func getLatencyForURL(addr string) (time.Duration, error) {
|
||||
uri, err := url.Parse(addr)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return osutil.TCPPing(uri.Host)
|
||||
}
|
||||
|
||||
type relayList []Relay
|
||||
|
||||
func (l relayList) Len() int {
|
||||
return len(l)
|
||||
}
|
||||
|
||||
func (l relayList) Less(a, b int) bool {
|
||||
return l[a].Latency < l[b].Latency
|
||||
}
|
||||
|
||||
func (l relayList) Swap(a, b int) {
|
||||
l[a], l[b] = l[b], l[a]
|
||||
}
|
||||
@@ -18,15 +18,15 @@ import (
|
||||
type DummyClient struct {
|
||||
url *url.URL
|
||||
lookups []protocol.DeviceID
|
||||
lookupRet []string
|
||||
lookupRet Announce
|
||||
stops int
|
||||
statusRet bool
|
||||
statusChecks int
|
||||
}
|
||||
|
||||
func (c *DummyClient) Lookup(device protocol.DeviceID) []string {
|
||||
func (c *DummyClient) Lookup(device protocol.DeviceID) (Announce, error) {
|
||||
c.lookups = append(c.lookups, device)
|
||||
return c.lookupRet
|
||||
return c.lookupRet, nil
|
||||
}
|
||||
|
||||
func (c *DummyClient) StatusOK() bool {
|
||||
@@ -45,17 +45,41 @@ func (c *DummyClient) Address() string {
|
||||
func TestGlobalDiscovery(t *testing.T) {
|
||||
c1 := &DummyClient{
|
||||
statusRet: false,
|
||||
lookupRet: []string{"test.com:1234"},
|
||||
lookupRet: Announce{
|
||||
Magic: AnnouncementMagic,
|
||||
This: Device{
|
||||
ID: protocol.LocalDeviceID[:],
|
||||
Addresses: []string{"test.com:1234"},
|
||||
Relays: nil,
|
||||
},
|
||||
Extra: nil,
|
||||
},
|
||||
}
|
||||
|
||||
c2 := &DummyClient{
|
||||
statusRet: true,
|
||||
lookupRet: []string{},
|
||||
lookupRet: Announce{
|
||||
Magic: AnnouncementMagic,
|
||||
This: Device{
|
||||
ID: protocol.LocalDeviceID[:],
|
||||
Addresses: nil,
|
||||
Relays: nil,
|
||||
},
|
||||
Extra: nil,
|
||||
},
|
||||
}
|
||||
|
||||
c3 := &DummyClient{
|
||||
statusRet: true,
|
||||
lookupRet: []string{"best.com:2345"},
|
||||
lookupRet: Announce{
|
||||
Magic: AnnouncementMagic,
|
||||
This: Device{
|
||||
ID: protocol.LocalDeviceID[:],
|
||||
Addresses: []string{"best.com:2345"},
|
||||
Relays: nil,
|
||||
},
|
||||
Extra: nil,
|
||||
},
|
||||
}
|
||||
|
||||
clients := []*DummyClient{c1, c2}
|
||||
@@ -72,7 +96,7 @@ func TestGlobalDiscovery(t *testing.T) {
|
||||
return c3, nil
|
||||
})
|
||||
|
||||
d := NewDiscoverer(device, []string{})
|
||||
d := NewDiscoverer(device, []string{}, nil)
|
||||
d.localBcastStart = time.Time{}
|
||||
servers := []string{
|
||||
"test1://123.123.123.123:1234",
|
||||
@@ -93,7 +117,7 @@ func TestGlobalDiscovery(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
addrs := d.Lookup(device)
|
||||
addrs, _ := d.Lookup(device)
|
||||
if len(addrs) != 2 {
|
||||
t.Fatal("Wrong number of addresses", addrs)
|
||||
}
|
||||
@@ -117,7 +141,7 @@ func TestGlobalDiscovery(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
addrs = d.Lookup(device)
|
||||
addrs, _ = d.Lookup(device)
|
||||
if len(addrs) != 2 {
|
||||
t.Fatal("Wrong number of addresses", addrs)
|
||||
}
|
||||
|
||||
@@ -10,8 +10,8 @@
|
||||
package discover
|
||||
|
||||
const (
|
||||
AnnouncementMagic = 0x9D79BC39
|
||||
QueryMagic = 0x2CA856F5
|
||||
AnnouncementMagic = 0x9D79BC40
|
||||
QueryMagic = 0x2CA856F6
|
||||
)
|
||||
|
||||
type Query struct {
|
||||
@@ -25,12 +25,13 @@ type Announce struct {
|
||||
Extra []Device // max:16
|
||||
}
|
||||
|
||||
type Device struct {
|
||||
ID []byte // max:32
|
||||
Addresses []Address // max:16
|
||||
type Relay struct {
|
||||
Address string // max:256
|
||||
Latency int32
|
||||
}
|
||||
|
||||
type Address struct {
|
||||
IP []byte // max:16
|
||||
Port uint16
|
||||
type Device struct {
|
||||
ID []byte // max:32
|
||||
Addresses []string // max:16
|
||||
Relays []Relay // max:16
|
||||
}
|
||||
+106
-79
@@ -187,6 +187,80 @@ func (o *Announce) DecodeXDRFrom(xr *xdr.Reader) error {
|
||||
|
||||
/*
|
||||
|
||||
Relay Structure:
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length of Address |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
/ /
|
||||
\ Address (variable length) \
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Latency |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
struct Relay {
|
||||
string Address<256>;
|
||||
int Latency;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
func (o Relay) EncodeXDR(w io.Writer) (int, error) {
|
||||
var xw = xdr.NewWriter(w)
|
||||
return o.EncodeXDRInto(xw)
|
||||
}
|
||||
|
||||
func (o Relay) MarshalXDR() ([]byte, error) {
|
||||
return o.AppendXDR(make([]byte, 0, 128))
|
||||
}
|
||||
|
||||
func (o Relay) MustMarshalXDR() []byte {
|
||||
bs, err := o.MarshalXDR()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func (o Relay) AppendXDR(bs []byte) ([]byte, error) {
|
||||
var aw = xdr.AppendWriter(bs)
|
||||
var xw = xdr.NewWriter(&aw)
|
||||
_, err := o.EncodeXDRInto(xw)
|
||||
return []byte(aw), err
|
||||
}
|
||||
|
||||
func (o Relay) EncodeXDRInto(xw *xdr.Writer) (int, error) {
|
||||
if l := len(o.Address); l > 256 {
|
||||
return xw.Tot(), xdr.ElementSizeExceeded("Address", l, 256)
|
||||
}
|
||||
xw.WriteString(o.Address)
|
||||
xw.WriteUint32(uint32(o.Latency))
|
||||
return xw.Tot(), xw.Error()
|
||||
}
|
||||
|
||||
func (o *Relay) DecodeXDR(r io.Reader) error {
|
||||
xr := xdr.NewReader(r)
|
||||
return o.DecodeXDRFrom(xr)
|
||||
}
|
||||
|
||||
func (o *Relay) UnmarshalXDR(bs []byte) error {
|
||||
var br = bytes.NewReader(bs)
|
||||
var xr = xdr.NewReader(br)
|
||||
return o.DecodeXDRFrom(xr)
|
||||
}
|
||||
|
||||
func (o *Relay) DecodeXDRFrom(xr *xdr.Reader) error {
|
||||
o.Address = xr.ReadStringMax(256)
|
||||
o.Latency = int32(xr.ReadUint32())
|
||||
return xr.Error()
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Device Structure:
|
||||
|
||||
0 1 2 3
|
||||
@@ -200,15 +274,24 @@ Device Structure:
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Number of Addresses |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length of Addresses |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
/ /
|
||||
\ Zero or more Address Structures \
|
||||
\ Addresses (variable length) \
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Number of Relays |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
/ /
|
||||
\ Zero or more Relay Structures \
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
struct Device {
|
||||
opaque ID<32>;
|
||||
Address Addresses<16>;
|
||||
string Addresses<16>;
|
||||
Relay Relays<16>;
|
||||
}
|
||||
|
||||
*/
|
||||
@@ -247,7 +330,14 @@ func (o Device) EncodeXDRInto(xw *xdr.Writer) (int, error) {
|
||||
}
|
||||
xw.WriteUint32(uint32(len(o.Addresses)))
|
||||
for i := range o.Addresses {
|
||||
_, err := o.Addresses[i].EncodeXDRInto(xw)
|
||||
xw.WriteString(o.Addresses[i])
|
||||
}
|
||||
if l := len(o.Relays); l > 16 {
|
||||
return xw.Tot(), xdr.ElementSizeExceeded("Relays", l, 16)
|
||||
}
|
||||
xw.WriteUint32(uint32(len(o.Relays)))
|
||||
for i := range o.Relays {
|
||||
_, err := o.Relays[i].EncodeXDRInto(xw)
|
||||
if err != nil {
|
||||
return xw.Tot(), err
|
||||
}
|
||||
@@ -275,83 +365,20 @@ func (o *Device) DecodeXDRFrom(xr *xdr.Reader) error {
|
||||
if _AddressesSize > 16 {
|
||||
return xdr.ElementSizeExceeded("Addresses", _AddressesSize, 16)
|
||||
}
|
||||
o.Addresses = make([]Address, _AddressesSize)
|
||||
o.Addresses = make([]string, _AddressesSize)
|
||||
for i := range o.Addresses {
|
||||
(&o.Addresses[i]).DecodeXDRFrom(xr)
|
||||
o.Addresses[i] = xr.ReadString()
|
||||
}
|
||||
_RelaysSize := int(xr.ReadUint32())
|
||||
if _RelaysSize < 0 {
|
||||
return xdr.ElementSizeExceeded("Relays", _RelaysSize, 16)
|
||||
}
|
||||
if _RelaysSize > 16 {
|
||||
return xdr.ElementSizeExceeded("Relays", _RelaysSize, 16)
|
||||
}
|
||||
o.Relays = make([]Relay, _RelaysSize)
|
||||
for i := range o.Relays {
|
||||
(&o.Relays[i]).DecodeXDRFrom(xr)
|
||||
}
|
||||
return xr.Error()
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
Address Structure:
|
||||
|
||||
0 1 2 3
|
||||
0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| Length of IP |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
/ /
|
||||
\ IP (variable length) \
|
||||
/ /
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
| 0x0000 | Port |
|
||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||
|
||||
|
||||
struct Address {
|
||||
opaque IP<16>;
|
||||
unsigned int Port;
|
||||
}
|
||||
|
||||
*/
|
||||
|
||||
func (o Address) EncodeXDR(w io.Writer) (int, error) {
|
||||
var xw = xdr.NewWriter(w)
|
||||
return o.EncodeXDRInto(xw)
|
||||
}
|
||||
|
||||
func (o Address) MarshalXDR() ([]byte, error) {
|
||||
return o.AppendXDR(make([]byte, 0, 128))
|
||||
}
|
||||
|
||||
func (o Address) MustMarshalXDR() []byte {
|
||||
bs, err := o.MarshalXDR()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
return bs
|
||||
}
|
||||
|
||||
func (o Address) AppendXDR(bs []byte) ([]byte, error) {
|
||||
var aw = xdr.AppendWriter(bs)
|
||||
var xw = xdr.NewWriter(&aw)
|
||||
_, err := o.EncodeXDRInto(xw)
|
||||
return []byte(aw), err
|
||||
}
|
||||
|
||||
func (o Address) EncodeXDRInto(xw *xdr.Writer) (int, error) {
|
||||
if l := len(o.IP); l > 16 {
|
||||
return xw.Tot(), xdr.ElementSizeExceeded("IP", l, 16)
|
||||
}
|
||||
xw.WriteBytes(o.IP)
|
||||
xw.WriteUint16(o.Port)
|
||||
return xw.Tot(), xw.Error()
|
||||
}
|
||||
|
||||
func (o *Address) DecodeXDR(r io.Reader) error {
|
||||
xr := xdr.NewReader(r)
|
||||
return o.DecodeXDRFrom(xr)
|
||||
}
|
||||
|
||||
func (o *Address) UnmarshalXDR(bs []byte) error {
|
||||
var br = bytes.NewReader(bs)
|
||||
var xr = xdr.NewReader(br)
|
||||
return o.DecodeXDRFrom(xr)
|
||||
}
|
||||
|
||||
func (o *Address) DecodeXDRFrom(xr *xdr.Reader) error {
|
||||
o.IP = xr.ReadBytesMax(16)
|
||||
o.Port = xr.ReadUint16()
|
||||
return xr.Error()
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
// Copyright (C) 2015 The Syncthing Authors.
|
||||
//
|
||||
// This Source Code Form is subject to the terms of the Mozilla Public
|
||||
// License, v. 2.0. If a copy of the MPL was not distributed with this file,
|
||||
// You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
package osutil
|
||||
|
||||
import (
|
||||
"net"
|
||||
"time"
|
||||
)
|
||||
|
||||
// TCPPing returns the duration required to establish a TCP connection
|
||||
// to the given host. ICMP packets require root priviledges, hence why we use
|
||||
// tcp.
|
||||
func TCPPing(address string) (time.Duration, error) {
|
||||
dialer := net.Dialer{
|
||||
Deadline: time.Now().Add(time.Second),
|
||||
}
|
||||
start := time.Now()
|
||||
conn, err := dialer.Dial("tcp", address)
|
||||
if conn != nil {
|
||||
conn.Close()
|
||||
}
|
||||
return time.Since(start), err
|
||||
}
|
||||
Reference in new issue
Block a user