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:
@@ -21,11 +21,11 @@ func main() {
|
|||||||
|
|
||||||
var server string
|
var server string
|
||||||
|
|
||||||
flag.StringVar(&server, "server", "udp4://announce.syncthing.net:22026", "Announce server")
|
flag.StringVar(&server, "server", "udp4://announce.syncthing.net:22027", "Announce server")
|
||||||
flag.Parse()
|
flag.Parse()
|
||||||
|
|
||||||
if len(flag.Args()) != 1 || server == "" {
|
if len(flag.Args()) != 1 || server == "" {
|
||||||
log.Printf("Usage: %s [-server=\"udp4://announce.syncthing.net:22026\"] <device>", os.Args[0])
|
log.Printf("Usage: %s [-server=\"udp4://announce.syncthing.net:22027\"] <device>", os.Args[0])
|
||||||
os.Exit(64)
|
os.Exit(64)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -35,9 +35,13 @@ func main() {
|
|||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
discoverer := discover.NewDiscoverer(protocol.LocalDeviceID, nil)
|
discoverer := discover.NewDiscoverer(protocol.LocalDeviceID, nil, nil)
|
||||||
discoverer.StartGlobal([]string{server}, 1)
|
discoverer.StartGlobal([]string{server}, 1)
|
||||||
for _, addr := range discoverer.Lookup(id) {
|
addresses, relays := discoverer.Lookup(id)
|
||||||
log.Println(addr)
|
for _, addr := range addresses {
|
||||||
|
log.Println("address:", addr)
|
||||||
|
}
|
||||||
|
for _, addr := range relays {
|
||||||
|
log.Println("relay:", addr)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
"strings"
|
"net/url"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
@@ -21,6 +21,14 @@ import (
|
|||||||
"github.com/thejerf/suture"
|
"github.com/thejerf/suture"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
type DialerFactory func(*url.URL, *tls.Config) (*tls.Conn, error)
|
||||||
|
type ListenerFactory func(*url.URL, *tls.Config, chan<- *tls.Conn)
|
||||||
|
|
||||||
|
var (
|
||||||
|
dialers = make(map[string]DialerFactory, 0)
|
||||||
|
listeners = make(map[string]ListenerFactory, 0)
|
||||||
|
)
|
||||||
|
|
||||||
// The connection service listens on TLS and dials configured unconnected
|
// The connection service listens on TLS and dials configured unconnected
|
||||||
// devices. Successful connections are handed to the model.
|
// devices. Successful connections are handed to the model.
|
||||||
type connectionSvc struct {
|
type connectionSvc struct {
|
||||||
@@ -51,9 +59,9 @@ func newConnectionSvc(cfg *config.Wrapper, myID protocol.DeviceID, model *model.
|
|||||||
//
|
//
|
||||||
// +-----------------+
|
// +-----------------+
|
||||||
// Incoming | +---------------+-+ +-----------------+
|
// Incoming | +---------------+-+ +-----------------+
|
||||||
// Connections | | | | | Outgoing
|
// Connections | | | | |
|
||||||
// -------------->| | svc.listen | | | Connections
|
// -------------->| | listener | | | Outgoing connections via dialers
|
||||||
// | | (1 per listen | | svc.connect |-------------->
|
// | | (1 per listen | | svc.connect |----------------------------------->
|
||||||
// | | address) | | |
|
// | | address) | | |
|
||||||
// +-+ | | |
|
// +-+ | | |
|
||||||
// +-----------------+ +-----------------+
|
// +-----------------+ +-----------------+
|
||||||
@@ -79,11 +87,25 @@ func newConnectionSvc(cfg *config.Wrapper, myID protocol.DeviceID, model *model.
|
|||||||
|
|
||||||
svc.Add(serviceFunc(svc.connect))
|
svc.Add(serviceFunc(svc.connect))
|
||||||
for _, addr := range svc.cfg.Options().ListenAddress {
|
for _, addr := range svc.cfg.Options().ListenAddress {
|
||||||
addr := addr
|
uri, err := url.Parse(addr)
|
||||||
listener := serviceFunc(func() {
|
if err != nil {
|
||||||
svc.listen(addr)
|
l.Infoln("Failed to parse listen address:", addr, err)
|
||||||
})
|
continue
|
||||||
svc.Add(listener)
|
}
|
||||||
|
|
||||||
|
listener, ok := listeners[uri.Scheme]
|
||||||
|
if !ok {
|
||||||
|
l.Infoln("Unknown listen address scheme:", uri.String())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if debugNet {
|
||||||
|
l.Debugln("listening on", uri.String())
|
||||||
|
}
|
||||||
|
|
||||||
|
svc.Add(serviceFunc(func() {
|
||||||
|
listener(uri, svc.tlsCfg, svc.conns)
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
svc.Add(serviceFunc(svc.handle))
|
svc.Add(serviceFunc(svc.handle))
|
||||||
|
|
||||||
@@ -197,46 +219,6 @@ next:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (s *connectionSvc) listen(addr string) {
|
|
||||||
if debugNet {
|
|
||||||
l.Debugln("listening on", addr)
|
|
||||||
}
|
|
||||||
|
|
||||||
tcaddr, err := net.ResolveTCPAddr("tcp", addr)
|
|
||||||
if err != nil {
|
|
||||||
l.Fatalln("listen (BEP):", err)
|
|
||||||
}
|
|
||||||
listener, err := net.ListenTCP("tcp", tcaddr)
|
|
||||||
if err != nil {
|
|
||||||
l.Fatalln("listen (BEP):", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
for {
|
|
||||||
conn, err := listener.Accept()
|
|
||||||
if err != nil {
|
|
||||||
l.Warnln("Accepting connection:", err)
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
if debugNet {
|
|
||||||
l.Debugln("connect from", conn.RemoteAddr())
|
|
||||||
}
|
|
||||||
|
|
||||||
tcpConn := conn.(*net.TCPConn)
|
|
||||||
s.setTCPOptions(tcpConn)
|
|
||||||
|
|
||||||
tc := tls.Server(conn, s.tlsCfg)
|
|
||||||
err = tc.Handshake()
|
|
||||||
if err != nil {
|
|
||||||
l.Infoln("TLS handshake:", err)
|
|
||||||
tc.Close()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
s.conns <- tc
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *connectionSvc) connect() {
|
func (s *connectionSvc) connect() {
|
||||||
delay := time.Second
|
delay := time.Second
|
||||||
for {
|
for {
|
||||||
@@ -254,7 +236,7 @@ func (s *connectionSvc) connect() {
|
|||||||
for _, addr := range deviceCfg.Addresses {
|
for _, addr := range deviceCfg.Addresses {
|
||||||
if addr == "dynamic" {
|
if addr == "dynamic" {
|
||||||
if discoverer != nil {
|
if discoverer != nil {
|
||||||
t := discoverer.Lookup(deviceID)
|
t, _ := discoverer.Lookup(deviceID)
|
||||||
if len(t) == 0 {
|
if len(t) == 0 {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
@@ -266,45 +248,30 @@ func (s *connectionSvc) connect() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for _, addr := range addrs {
|
for _, addr := range addrs {
|
||||||
host, port, err := net.SplitHostPort(addr)
|
uri, err := url.Parse(addr)
|
||||||
if err != nil && strings.HasPrefix(err.Error(), "missing port") {
|
if err != nil {
|
||||||
// addr is on the form "1.2.3.4"
|
l.Infoln("Failed to parse connection url:", addr, err)
|
||||||
addr = net.JoinHostPort(addr, "22000")
|
continue
|
||||||
} else if err == nil && port == "" {
|
|
||||||
// addr is on the form "1.2.3.4:"
|
|
||||||
addr = net.JoinHostPort(host, "22000")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
dialer, ok := dialers[uri.Scheme]
|
||||||
|
if !ok {
|
||||||
|
l.Infoln("Unknown address schema", uri.String())
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
if debugNet {
|
if debugNet {
|
||||||
l.Debugln("dial", deviceCfg.DeviceID, addr)
|
l.Debugln("dial", deviceCfg.DeviceID, uri.String())
|
||||||
}
|
}
|
||||||
|
conn, err := dialer(uri, s.tlsCfg)
|
||||||
raddr, err := net.ResolveTCPAddr("tcp", addr)
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if debugNet {
|
if debugNet {
|
||||||
l.Debugln(err)
|
l.Debugln("dial failed", deviceCfg.DeviceID, uri.String(), err)
|
||||||
}
|
}
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
conn, err := net.DialTCP("tcp", nil, raddr)
|
s.conns <- conn
|
||||||
if err != nil {
|
|
||||||
if debugNet {
|
|
||||||
l.Debugln(err)
|
|
||||||
}
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
s.setTCPOptions(conn)
|
|
||||||
|
|
||||||
tc := tls.Client(conn, s.tlsCfg)
|
|
||||||
err = tc.Handshake()
|
|
||||||
if err != nil {
|
|
||||||
l.Infoln("TLS handshake:", err)
|
|
||||||
tc.Close()
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
s.conns <- tc
|
|
||||||
continue nextDevice
|
continue nextDevice
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -317,22 +284,6 @@ func (s *connectionSvc) connect() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (*connectionSvc) setTCPOptions(conn *net.TCPConn) {
|
|
||||||
var err error
|
|
||||||
if err = conn.SetLinger(0); err != nil {
|
|
||||||
l.Infoln(err)
|
|
||||||
}
|
|
||||||
if err = conn.SetNoDelay(false); err != nil {
|
|
||||||
l.Infoln(err)
|
|
||||||
}
|
|
||||||
if err = conn.SetKeepAlivePeriod(60 * time.Second); err != nil {
|
|
||||||
l.Infoln(err)
|
|
||||||
}
|
|
||||||
if err = conn.SetKeepAlive(true); err != nil {
|
|
||||||
l.Infoln(err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func (s *connectionSvc) shouldLimit(addr net.Addr) bool {
|
func (s *connectionSvc) shouldLimit(addr net.Addr) bool {
|
||||||
if s.cfg.Options().LimitBandwidthInLan {
|
if s.cfg.Options().LimitBandwidthInLan {
|
||||||
return true
|
return true
|
||||||
@@ -370,3 +321,19 @@ func (s *connectionSvc) CommitConfiguration(from, to config.Configuration) bool
|
|||||||
|
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func setTCPOptions(conn *net.TCPConn) {
|
||||||
|
var err error
|
||||||
|
if err = conn.SetLinger(0); err != nil {
|
||||||
|
l.Infoln(err)
|
||||||
|
}
|
||||||
|
if err = conn.SetNoDelay(false); err != nil {
|
||||||
|
l.Infoln(err)
|
||||||
|
}
|
||||||
|
if err = conn.SetKeepAlivePeriod(60 * time.Second); err != nil {
|
||||||
|
l.Infoln(err)
|
||||||
|
}
|
||||||
|
if err = conn.SetKeepAlive(true); err != nil {
|
||||||
|
l.Infoln(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
95
cmd/syncthing/connections_tcp.go
Normal file
95
cmd/syncthing/connections_tcp.go
Normal file
@@ -0,0 +1,95 @@
|
|||||||
|
// 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 main
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"net"
|
||||||
|
"net/url"
|
||||||
|
"strings"
|
||||||
|
)
|
||||||
|
|
||||||
|
func init() {
|
||||||
|
dialers["tcp"] = tcpDialer
|
||||||
|
listeners["tcp"] = tcpListener
|
||||||
|
}
|
||||||
|
|
||||||
|
func tcpDialer(uri *url.URL, tlsCfg *tls.Config) (*tls.Conn, error) {
|
||||||
|
host, port, err := net.SplitHostPort(uri.Host)
|
||||||
|
if err != nil && strings.HasPrefix(err.Error(), "missing port") {
|
||||||
|
// addr is on the form "1.2.3.4"
|
||||||
|
uri.Host = net.JoinHostPort(uri.Host, "22000")
|
||||||
|
} else if err == nil && port == "" {
|
||||||
|
// addr is on the form "1.2.3.4:"
|
||||||
|
uri.Host = net.JoinHostPort(host, "22000")
|
||||||
|
}
|
||||||
|
|
||||||
|
raddr, err := net.ResolveTCPAddr("tcp", uri.Host)
|
||||||
|
if err != nil {
|
||||||
|
if debugNet {
|
||||||
|
l.Debugln(err)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
conn, err := net.DialTCP("tcp", nil, raddr)
|
||||||
|
if err != nil {
|
||||||
|
if debugNet {
|
||||||
|
l.Debugln(err)
|
||||||
|
}
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
setTCPOptions(conn)
|
||||||
|
|
||||||
|
tc := tls.Client(conn, tlsCfg)
|
||||||
|
err = tc.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
tc.Close()
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return tc, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func tcpListener(uri *url.URL, tlsCfg *tls.Config, conns chan<- *tls.Conn) {
|
||||||
|
tcaddr, err := net.ResolveTCPAddr("tcp", uri.Host)
|
||||||
|
if err != nil {
|
||||||
|
l.Fatalln("listen (BEP/tcp):", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
listener, err := net.ListenTCP("tcp", tcaddr)
|
||||||
|
if err != nil {
|
||||||
|
l.Fatalln("listen (BEP/tcp):", err)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for {
|
||||||
|
conn, err := listener.Accept()
|
||||||
|
if err != nil {
|
||||||
|
l.Warnln("Accepting connection (BEP/tcp):", err)
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
if debugNet {
|
||||||
|
l.Debugln("connect from", conn.RemoteAddr())
|
||||||
|
}
|
||||||
|
|
||||||
|
tcpConn := conn.(*net.TCPConn)
|
||||||
|
setTCPOptions(tcpConn)
|
||||||
|
|
||||||
|
tc := tls.Server(conn, tlsCfg)
|
||||||
|
err = tc.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
l.Infoln("TLS handshake (BEP/tcp):", err)
|
||||||
|
tc.Close()
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
|
||||||
|
conns <- tc
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -658,7 +658,12 @@ func syncthingMain() {
|
|||||||
|
|
||||||
// The default port we announce, possibly modified by setupUPnP next.
|
// The default port we announce, possibly modified by setupUPnP next.
|
||||||
|
|
||||||
addr, err := net.ResolveTCPAddr("tcp", opts.ListenAddress[0])
|
uri, err := url.Parse(opts.ListenAddress[0])
|
||||||
|
if err != nil {
|
||||||
|
l.Fatalf("Failed to parse listen address %s: %v", opts.ListenAddress[0], err)
|
||||||
|
}
|
||||||
|
|
||||||
|
addr, err := net.ResolveTCPAddr("tcp", uri.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
l.Fatalln("Bad listen address:", err)
|
l.Fatalln("Bad listen address:", err)
|
||||||
}
|
}
|
||||||
@@ -902,7 +907,7 @@ func shutdown() {
|
|||||||
|
|
||||||
func discovery(extPort int) *discover.Discoverer {
|
func discovery(extPort int) *discover.Discoverer {
|
||||||
opts := cfg.Options()
|
opts := cfg.Options()
|
||||||
disc := discover.NewDiscoverer(myID, opts.ListenAddress)
|
disc := discover.NewDiscoverer(myID, opts.ListenAddress, opts.RelayServers)
|
||||||
|
|
||||||
if opts.LocalAnnEnabled {
|
if opts.LocalAnnEnabled {
|
||||||
l.Infoln("Starting local discovery announcements")
|
l.Infoln("Starting local discovery announcements")
|
||||||
|
|||||||
@@ -32,7 +32,7 @@
|
|||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label translate for="addresses">Addresses</label>
|
<label translate for="addresses">Addresses</label>
|
||||||
<input ng-disabled="currentDevice.deviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice._addressesStr"></input>
|
<input ng-disabled="currentDevice.deviceID == myID" id="addresses" class="form-control" type="text" ng-model="currentDevice._addressesStr"></input>
|
||||||
<p translate class="help-block">Enter comma separated "ip:port" addresses or "dynamic" to perform automatic discovery of the address.</p>
|
<p translate class="help-block">Enter comma separated ("tcp://ip:port", "tcp://host:port") addresses or "dynamic" to perform automatic discovery of the address.</p>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group">
|
<div class="form-group">
|
||||||
<label translate>Compression</label>
|
<label translate>Compression</label>
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
@@ -9,6 +9,7 @@ package config
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"encoding/xml"
|
"encoding/xml"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"math/rand"
|
"math/rand"
|
||||||
"os"
|
"os"
|
||||||
@@ -26,7 +27,7 @@ import (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
OldestHandledVersion = 5
|
OldestHandledVersion = 5
|
||||||
CurrentVersion = 11
|
CurrentVersion = 12
|
||||||
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
MaxRescanIntervalS = 365 * 24 * 60 * 60
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -212,12 +213,13 @@ type FolderDeviceConfiguration struct {
|
|||||||
}
|
}
|
||||||
|
|
||||||
type OptionsConfiguration struct {
|
type OptionsConfiguration struct {
|
||||||
ListenAddress []string `xml:"listenAddress" json:"listenAddress" default:"0.0.0.0:22000"`
|
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:22026, udp6://announce-v6.syncthing.net:22026"`
|
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"`
|
GlobalAnnEnabled bool `xml:"globalAnnounceEnabled" json:"globalAnnounceEnabled" default:"true"`
|
||||||
LocalAnnEnabled bool `xml:"localAnnounceEnabled" json:"localAnnounceEnabled" default:"true"`
|
LocalAnnEnabled bool `xml:"localAnnounceEnabled" json:"localAnnounceEnabled" default:"true"`
|
||||||
LocalAnnPort int `xml:"localAnnouncePort" json:"localAnnouncePort" default:"21025"`
|
LocalAnnPort int `xml:"localAnnouncePort" json:"localAnnouncePort" default:"21025"`
|
||||||
LocalAnnMCAddr string `xml:"localAnnounceMCAddr" json:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
|
LocalAnnMCAddr string `xml:"localAnnounceMCAddr" json:"localAnnounceMCAddr" default:"[ff32::5222]:21026"`
|
||||||
|
RelayServers []string `xml:"relayServer" json:"relayServers" default:""`
|
||||||
MaxSendKbps int `xml:"maxSendKbps" json:"maxSendKbps"`
|
MaxSendKbps int `xml:"maxSendKbps" json:"maxSendKbps"`
|
||||||
MaxRecvKbps int `xml:"maxRecvKbps" json:"maxRecvKbps"`
|
MaxRecvKbps int `xml:"maxRecvKbps" json:"maxRecvKbps"`
|
||||||
ReconnectIntervalS int `xml:"reconnectionIntervalS" json:"reconnectionIntervalS" default:"60"`
|
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 {
|
if cfg.Version < OldestHandledVersion {
|
||||||
l.Warnf("Configuration version %d is deprecated. Attempting best effort conversion, but please verify manually.", cfg.Version)
|
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 {
|
if cfg.Version == 10 {
|
||||||
convertV10V11(cfg)
|
convertV10V11(cfg)
|
||||||
}
|
}
|
||||||
|
if cfg.Version == 11 {
|
||||||
|
convertV11V12(cfg)
|
||||||
|
}
|
||||||
|
|
||||||
// Hash old cleartext passwords
|
// Hash old cleartext passwords
|
||||||
if len(cfg.GUI.Password) > 0 && cfg.GUI.Password[0] != '$' {
|
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.ReconnectIntervalS = 5
|
||||||
}
|
}
|
||||||
|
|
||||||
cfg.Options.ListenAddress = uniqueStrings(cfg.Options.ListenAddress)
|
|
||||||
cfg.Options.GlobalAnnServers = uniqueStrings(cfg.Options.GlobalAnnServers)
|
|
||||||
|
|
||||||
if cfg.GUI.APIKey == "" {
|
if cfg.GUI.APIKey == "" {
|
||||||
cfg.GUI.APIKey = randomString(32)
|
cfg.GUI.APIKey = randomString(32)
|
||||||
}
|
}
|
||||||
@@ -467,6 +472,38 @@ func convertV10V11(cfg *Configuration) {
|
|||||||
cfg.Version = 11
|
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) {
|
func convertV9V10(cfg *Configuration) {
|
||||||
// Enable auto normalization on existing folders.
|
// Enable auto normalization on existing folders.
|
||||||
for i := range cfg.Folders {
|
for i := range cfg.Folders {
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ func init() {
|
|||||||
|
|
||||||
func TestDefaultValues(t *testing.T) {
|
func TestDefaultValues(t *testing.T) {
|
||||||
expected := OptionsConfiguration{
|
expected := OptionsConfiguration{
|
||||||
ListenAddress: []string{"0.0.0.0:22000"},
|
ListenAddress: []string{"tcp://0.0.0.0:22000"},
|
||||||
GlobalAnnServers: []string{"udp4://announce.syncthing.net:22026", "udp6://announce-v6.syncthing.net:22026"},
|
GlobalAnnServers: []string{"udp4://announce.syncthing.net:22027", "udp6://announce-v6.syncthing.net:22027"},
|
||||||
GlobalAnnEnabled: true,
|
GlobalAnnEnabled: true,
|
||||||
LocalAnnEnabled: true,
|
LocalAnnEnabled: true,
|
||||||
LocalAnnPort: 21025,
|
LocalAnnPort: 21025,
|
||||||
@@ -100,13 +100,13 @@ func TestDeviceConfig(t *testing.T) {
|
|||||||
{
|
{
|
||||||
DeviceID: device1,
|
DeviceID: device1,
|
||||||
Name: "node one",
|
Name: "node one",
|
||||||
Addresses: []string{"a"},
|
Addresses: []string{"tcp://a"},
|
||||||
Compression: protocol.CompressMetadata,
|
Compression: protocol.CompressMetadata,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
DeviceID: device4,
|
DeviceID: device4,
|
||||||
Name: "node two",
|
Name: "node two",
|
||||||
Addresses: []string{"b"},
|
Addresses: []string{"tcp://b"},
|
||||||
Compression: protocol.CompressMetadata,
|
Compression: protocol.CompressMetadata,
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
@@ -142,12 +142,13 @@ func TestNoListenAddress(t *testing.T) {
|
|||||||
|
|
||||||
func TestOverriddenValues(t *testing.T) {
|
func TestOverriddenValues(t *testing.T) {
|
||||||
expected := OptionsConfiguration{
|
expected := OptionsConfiguration{
|
||||||
ListenAddress: []string{":23000"},
|
ListenAddress: []string{"tcp://:23000"},
|
||||||
GlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"},
|
GlobalAnnServers: []string{"udp4://syncthing.nym.se:22026"},
|
||||||
GlobalAnnEnabled: false,
|
GlobalAnnEnabled: false,
|
||||||
LocalAnnEnabled: false,
|
LocalAnnEnabled: false,
|
||||||
LocalAnnPort: 42123,
|
LocalAnnPort: 42123,
|
||||||
LocalAnnMCAddr: "quux:3232",
|
LocalAnnMCAddr: "quux:3232",
|
||||||
|
RelayServers: []string{"relay://123.123.123.123:1234", "relay://125.125.125.125:1255"},
|
||||||
MaxSendKbps: 1234,
|
MaxSendKbps: 1234,
|
||||||
MaxRecvKbps: 2341,
|
MaxRecvKbps: 2341,
|
||||||
ReconnectIntervalS: 6000,
|
ReconnectIntervalS: 6000,
|
||||||
@@ -255,15 +256,15 @@ func TestDeviceAddressesStatic(t *testing.T) {
|
|||||||
expected := map[protocol.DeviceID]DeviceConfiguration{
|
expected := map[protocol.DeviceID]DeviceConfiguration{
|
||||||
device1: {
|
device1: {
|
||||||
DeviceID: 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: {
|
device2: {
|
||||||
DeviceID: 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: {
|
device3: {
|
||||||
DeviceID: 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: {
|
device4: {
|
||||||
DeviceID: device4,
|
DeviceID: device4,
|
||||||
@@ -330,12 +331,12 @@ func TestIssue1750(t *testing.T) {
|
|||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Options().ListenAddress[0] != ":23000" {
|
if cfg.Options().ListenAddress[0] != "tcp://:23000" {
|
||||||
t.Errorf("%q != %q", cfg.Options().ListenAddress[0], ":23000")
|
t.Errorf("%q != %q", cfg.Options().ListenAddress[0], "tcp://:23000")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Options().ListenAddress[1] != ":23001" {
|
if cfg.Options().ListenAddress[1] != "tcp://:23001" {
|
||||||
t.Errorf("%q != %q", cfg.Options().ListenAddress[1], ":23001")
|
t.Errorf("%q != %q", cfg.Options().ListenAddress[1], "tcp://:23001")
|
||||||
}
|
}
|
||||||
|
|
||||||
if cfg.Options().GlobalAnnServers[0] != "udp4://syncthing.nym.se:22026" {
|
if cfg.Options().GlobalAnnServers[0] != "udp4://syncthing.nym.se:22026" {
|
||||||
|
|||||||
2
lib/config/testdata/overridenvalues.xml
vendored
2
lib/config/testdata/overridenvalues.xml
vendored
@@ -7,6 +7,8 @@
|
|||||||
<localAnnounceEnabled>false</localAnnounceEnabled>
|
<localAnnounceEnabled>false</localAnnounceEnabled>
|
||||||
<localAnnouncePort>42123</localAnnouncePort>
|
<localAnnouncePort>42123</localAnnouncePort>
|
||||||
<localAnnounceMCAddr>quux:3232</localAnnounceMCAddr>
|
<localAnnounceMCAddr>quux:3232</localAnnounceMCAddr>
|
||||||
|
<relayServer>relay://123.123.123.123:1234</relayServer>
|
||||||
|
<relayServer>relay://125.125.125.125:1255</relayServer>
|
||||||
<parallelRequests>32</parallelRequests>
|
<parallelRequests>32</parallelRequests>
|
||||||
<maxSendKbps>1234</maxSendKbps>
|
<maxSendKbps>1234</maxSendKbps>
|
||||||
<maxRecvKbps>2341</maxRecvKbps>
|
<maxRecvKbps>2341</maxRecvKbps>
|
||||||
|
|||||||
13
lib/config/testdata/v12.xml
vendored
Normal file
13
lib/config/testdata/v12.xml
vendored
Normal file
@@ -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 {
|
type Client interface {
|
||||||
Lookup(device protocol.DeviceID) []string
|
Lookup(device protocol.DeviceID) (Announce, error)
|
||||||
StatusOK() bool
|
StatusOK() bool
|
||||||
Address() string
|
Address() string
|
||||||
Stop()
|
Stop()
|
||||||
|
|||||||
@@ -37,10 +37,8 @@ func TestUDP4Success(t *testing.T) {
|
|||||||
Magic: AnnouncementMagic,
|
Magic: AnnouncementMagic,
|
||||||
This: Device{
|
This: Device{
|
||||||
device[:],
|
device[:],
|
||||||
[]Address{{
|
[]string{"tcp://123.123.123.123:1234"},
|
||||||
IP: net.IPv4(123, 123, 123, 123),
|
nil,
|
||||||
Port: 1234,
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -101,7 +99,12 @@ func TestUDP4Success(t *testing.T) {
|
|||||||
wg := sync.NewWaitGroup()
|
wg := sync.NewWaitGroup()
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
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()
|
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
|
// Wait for the lookup to arrive, verify that the number of answers is correct
|
||||||
wg.Wait()
|
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")
|
t.Fatal("Wrong number of answers")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,10 +141,8 @@ func TestUDP4Failure(t *testing.T) {
|
|||||||
Magic: AnnouncementMagic,
|
Magic: AnnouncementMagic,
|
||||||
This: Device{
|
This: Device{
|
||||||
device[:],
|
device[:],
|
||||||
[]Address{{
|
[]string{"tcp://123.123.123.123:1234"},
|
||||||
IP: net.IPv4(123, 123, 123, 123),
|
nil,
|
||||||
Port: 1234,
|
|
||||||
}},
|
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -197,7 +198,12 @@ func TestUDP4Failure(t *testing.T) {
|
|||||||
wg := sync.NewWaitGroup()
|
wg := sync.NewWaitGroup()
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func() {
|
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()
|
wg.Done()
|
||||||
}()
|
}()
|
||||||
|
|
||||||
|
|||||||
@@ -137,11 +137,13 @@ func (d *UDPClient) broadcast(pkt []byte) {
|
|||||||
|
|
||||||
time.Sleep(1 * time.Second)
|
time.Sleep(1 * time.Second)
|
||||||
|
|
||||||
res := d.Lookup(d.id)
|
pkt, err := d.Lookup(d.id)
|
||||||
if debug {
|
if err != nil && debug {
|
||||||
l.Debugf("discover %s: broadcast: Self-lookup returned: %v", d.url, res)
|
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()
|
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)
|
extIP, err := net.ResolveUDPAddr(d.url.Scheme, d.url.Host)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
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)
|
conn, err := net.DialUDP(d.url.Scheme, d.listenAddress, extIP)
|
||||||
@@ -171,7 +173,7 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
|||||||
if debug {
|
if debug {
|
||||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||||
}
|
}
|
||||||
return nil
|
return Announce{}, err
|
||||||
}
|
}
|
||||||
defer conn.Close()
|
defer conn.Close()
|
||||||
|
|
||||||
@@ -180,7 +182,7 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
|||||||
if debug {
|
if debug {
|
||||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||||
}
|
}
|
||||||
return nil
|
return Announce{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf := Query{QueryMagic, device[:]}.MustMarshalXDR()
|
buf := Query{QueryMagic, device[:]}.MustMarshalXDR()
|
||||||
@@ -189,7 +191,7 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
|||||||
if debug {
|
if debug {
|
||||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||||
}
|
}
|
||||||
return nil
|
return Announce{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
buf = make([]byte, 2048)
|
buf = make([]byte, 2048)
|
||||||
@@ -197,12 +199,12 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
if err, ok := err.(net.Error); ok && err.Timeout() {
|
if err, ok := err.(net.Error); ok && err.Timeout() {
|
||||||
// Expected if the server doesn't know about requested device ID
|
// Expected if the server doesn't know about requested device ID
|
||||||
return nil
|
return Announce{}, err
|
||||||
}
|
}
|
||||||
if debug {
|
if debug {
|
||||||
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
l.Debugf("discover %s: Lookup(%s): %s", d.url, device, err)
|
||||||
}
|
}
|
||||||
return nil
|
return Announce{}, err
|
||||||
}
|
}
|
||||||
|
|
||||||
var pkt Announce
|
var pkt Announce
|
||||||
@@ -211,18 +213,13 @@ func (d *UDPClient) Lookup(device protocol.DeviceID) []string {
|
|||||||
if debug {
|
if debug {
|
||||||
l.Debugf("discover %s: Lookup(%s): %s\n%s", d.url, device, err, hex.Dump(buf[:n]))
|
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 {
|
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() {
|
func (d *UDPClient) Stop() {
|
||||||
|
|||||||
@@ -10,21 +10,25 @@ import (
|
|||||||
"bytes"
|
"bytes"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"errors"
|
"errors"
|
||||||
|
"fmt"
|
||||||
"io"
|
"io"
|
||||||
"net"
|
"net"
|
||||||
|
"net/url"
|
||||||
"runtime"
|
"runtime"
|
||||||
"strconv"
|
"sort"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/syncthing/protocol"
|
"github.com/syncthing/protocol"
|
||||||
"github.com/syncthing/syncthing/lib/beacon"
|
"github.com/syncthing/syncthing/lib/beacon"
|
||||||
"github.com/syncthing/syncthing/lib/events"
|
"github.com/syncthing/syncthing/lib/events"
|
||||||
|
"github.com/syncthing/syncthing/lib/osutil"
|
||||||
"github.com/syncthing/syncthing/lib/sync"
|
"github.com/syncthing/syncthing/lib/sync"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Discoverer struct {
|
type Discoverer struct {
|
||||||
myID protocol.DeviceID
|
myID protocol.DeviceID
|
||||||
listenAddrs []string
|
listenAddrs []string
|
||||||
|
relays []Relay
|
||||||
localBcastIntv time.Duration
|
localBcastIntv time.Duration
|
||||||
localBcastStart time.Time
|
localBcastStart time.Time
|
||||||
cacheLifetime time.Duration
|
cacheLifetime time.Duration
|
||||||
@@ -34,9 +38,10 @@ type Discoverer struct {
|
|||||||
localBcastTick <-chan time.Time
|
localBcastTick <-chan time.Time
|
||||||
forcedBcastTick chan time.Time
|
forcedBcastTick chan time.Time
|
||||||
|
|
||||||
registryLock sync.RWMutex
|
registryLock sync.RWMutex
|
||||||
registry map[protocol.DeviceID][]CacheEntry
|
addressRegistry map[protocol.DeviceID][]CacheEntry
|
||||||
lastLookup map[protocol.DeviceID]time.Time
|
relayRegistry map[protocol.DeviceID][]CacheEntry
|
||||||
|
lastLookup map[protocol.DeviceID]time.Time
|
||||||
|
|
||||||
clients []Client
|
clients []Client
|
||||||
mut sync.RWMutex
|
mut sync.RWMutex
|
||||||
@@ -51,17 +56,19 @@ var (
|
|||||||
ErrIncorrectMagic = errors.New("incorrect magic number")
|
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{
|
return &Discoverer{
|
||||||
myID: id,
|
myID: id,
|
||||||
listenAddrs: addresses,
|
listenAddrs: addresses,
|
||||||
localBcastIntv: 30 * time.Second,
|
relays: measureLatency(relayAdresses),
|
||||||
cacheLifetime: 5 * time.Minute,
|
localBcastIntv: 30 * time.Second,
|
||||||
negCacheCutoff: 3 * time.Minute,
|
cacheLifetime: 5 * time.Minute,
|
||||||
registry: make(map[protocol.DeviceID][]CacheEntry),
|
negCacheCutoff: 3 * time.Minute,
|
||||||
lastLookup: make(map[protocol.DeviceID]time.Time),
|
addressRegistry: make(map[protocol.DeviceID][]CacheEntry),
|
||||||
registryLock: sync.NewRWMutex(),
|
relayRegistry: make(map[protocol.DeviceID][]CacheEntry),
|
||||||
mut: sync.NewRWMutex(),
|
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
|
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()
|
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]
|
lastLookup := d.lastLookup[device]
|
||||||
d.registryLock.RUnlock()
|
d.registryLock.RUnlock()
|
||||||
|
|
||||||
d.mut.RLock()
|
d.mut.RLock()
|
||||||
defer d.mut.RUnlock()
|
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.
|
// There are cached address entries.
|
||||||
addrs := make([]string, len(cached))
|
addrs := make([]string, len(cachedAddresses))
|
||||||
for i := range cached {
|
for i := range cachedAddresses {
|
||||||
addrs[i] = cached[i].Address
|
addrs[i] = cachedAddresses[i].Address
|
||||||
}
|
}
|
||||||
return addrs
|
return addrs, relays
|
||||||
}
|
}
|
||||||
|
|
||||||
if time.Since(lastLookup) < d.negCacheCutoff {
|
if time.Since(lastLookup) < d.negCacheCutoff {
|
||||||
// We have recently tried to lookup this address and failed. Lets
|
// We have recently tried to lookup this address and failed. Lets
|
||||||
// chill for a while.
|
// chill for a while.
|
||||||
return nil
|
return nil, relays
|
||||||
}
|
}
|
||||||
|
|
||||||
if len(d.clients) != 0 && time.Since(d.localBcastStart) > d.localBcastIntv {
|
if len(d.clients) != 0 && time.Since(d.localBcastStart) > d.localBcastIntv {
|
||||||
// Only perform external lookups if we have at least one external
|
// Only perform external lookups if we have at least one external
|
||||||
// server client and one local announcement interval has passed. This is
|
// server client and one local announcement interval has passed. This is
|
||||||
// to avoid finding local peers on their remote address at startup.
|
// 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()
|
wg := sync.NewWaitGroup()
|
||||||
for _, client := range d.clients {
|
for _, client := range d.clients {
|
||||||
wg.Add(1)
|
wg.Add(1)
|
||||||
go func(c Client) {
|
go func(c Client) {
|
||||||
defer wg.Done()
|
defer wg.Done()
|
||||||
results <- c.Lookup(device)
|
ann, err := c.Lookup(device)
|
||||||
|
if err == nil {
|
||||||
|
results <- ann
|
||||||
|
}
|
||||||
|
|
||||||
}(client)
|
}(client)
|
||||||
}
|
}
|
||||||
|
|
||||||
wg.Wait()
|
wg.Wait()
|
||||||
close(results)
|
close(results)
|
||||||
|
|
||||||
cached := []CacheEntry{}
|
cachedAddresses := []CacheEntry{}
|
||||||
seen := make(map[string]struct{})
|
availableRelays := []Relay{}
|
||||||
|
seenAddresses := make(map[string]struct{})
|
||||||
|
seenRelays := make(map[string]struct{})
|
||||||
now := time.Now()
|
now := time.Now()
|
||||||
|
|
||||||
var addrs []string
|
var addrs []string
|
||||||
for result := range results {
|
for result := range results {
|
||||||
for _, addr := range result {
|
for _, addr := range result.This.Addresses {
|
||||||
_, ok := seen[addr]
|
_, ok := seenAddresses[addr]
|
||||||
if !ok {
|
if !ok {
|
||||||
cached = append(cached, CacheEntry{
|
cachedAddresses = append(cachedAddresses, CacheEntry{
|
||||||
Address: addr,
|
Address: addr,
|
||||||
Seen: now,
|
Seen: now,
|
||||||
})
|
})
|
||||||
seen[addr] = struct{}{}
|
seenAddresses[addr] = struct{}{}
|
||||||
addrs = append(addrs, addr)
|
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.registryLock.Lock()
|
||||||
d.registry[device] = cached
|
d.addressRegistry[device] = cachedAddresses
|
||||||
|
d.relayRegistry[device] = cachedRelays
|
||||||
d.lastLookup[device] = time.Now()
|
d.lastLookup[device] = time.Now()
|
||||||
d.registryLock.Unlock()
|
d.registryLock.Unlock()
|
||||||
|
|
||||||
return addrs
|
return addrs, relays
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil, relays
|
||||||
}
|
}
|
||||||
|
|
||||||
func (d *Discoverer) Hint(device string, addrs []string) {
|
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 {
|
func (d *Discoverer) All() map[protocol.DeviceID][]CacheEntry {
|
||||||
d.registryLock.RLock()
|
d.registryLock.RLock()
|
||||||
devices := make(map[protocol.DeviceID][]CacheEntry, len(d.registry))
|
devices := make(map[protocol.DeviceID][]CacheEntry, len(d.addressRegistry))
|
||||||
for device, addrs := range d.registry {
|
for device, addrs := range d.addressRegistry {
|
||||||
addrsCopy := make([]CacheEntry, len(addrs))
|
addrsCopy := make([]CacheEntry, len(addrs))
|
||||||
copy(addrsCopy, addrs)
|
copy(addrsCopy, addrs)
|
||||||
devices[device] = addrsCopy
|
devices[device] = addrsCopy
|
||||||
@@ -278,30 +318,38 @@ func (d *Discoverer) All() map[protocol.DeviceID][]CacheEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (d *Discoverer) announcementPkt() *Announce {
|
func (d *Discoverer) announcementPkt() *Announce {
|
||||||
var addrs []Address
|
var addrs []string
|
||||||
if d.extPort != 0 {
|
if d.extPort != 0 {
|
||||||
addrs = []Address{{Port: d.extPort}}
|
addrs = []string{fmt.Sprintf("tcp://:%d", d.extPort)}
|
||||||
} else {
|
} else {
|
||||||
for _, astr := range d.listenAddrs {
|
for _, aurl := range d.listenAddrs {
|
||||||
addr, err := net.ResolveTCPAddr("tcp", astr)
|
uri, err := url.Parse(aurl)
|
||||||
if err != nil {
|
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
|
continue
|
||||||
} else if debug {
|
} 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() {
|
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 {
|
} 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 {
|
} 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{
|
return &Announce{
|
||||||
Magic: AnnouncementMagic,
|
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{
|
var pkt = Announce{
|
||||||
Magic: AnnouncementMagic,
|
Magic: AnnouncementMagic,
|
||||||
This: Device{d.myID[:], addrs},
|
This: Device{d.myID[:], addrs, d.relays},
|
||||||
}
|
}
|
||||||
msg := pkt.MustMarshalXDR()
|
msg := pkt.MustMarshalXDR()
|
||||||
|
|
||||||
@@ -363,19 +411,32 @@ func (d *Discoverer) registerDevice(addr net.Addr, device Device) bool {
|
|||||||
d.registryLock.Lock()
|
d.registryLock.Lock()
|
||||||
defer d.registryLock.Unlock()
|
defer d.registryLock.Unlock()
|
||||||
|
|
||||||
current := d.filterCached(d.registry[id])
|
current := d.filterCached(d.addressRegistry[id])
|
||||||
|
|
||||||
orig := current
|
orig := current
|
||||||
|
|
||||||
for _, a := range device.Addresses {
|
for _, deviceAddr := range device.Addresses {
|
||||||
var deviceAddr string
|
uri, err := url.Parse(deviceAddr)
|
||||||
if len(a.IP) > 0 {
|
if err != nil {
|
||||||
deviceAddr = net.JoinHostPort(net.IP(a.IP).String(), strconv.Itoa(int(a.Port)))
|
if debug {
|
||||||
} else if addr != nil {
|
l.Debugf("discover: Failed to parse address %s: %s", deviceAddr, err)
|
||||||
ua := addr.(*net.UDPAddr)
|
}
|
||||||
ua.Port = int(a.Port)
|
continue
|
||||||
deviceAddr = ua.String()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
for i := range current {
|
||||||
if current[i].Address == deviceAddr {
|
if current[i].Address == deviceAddr {
|
||||||
current[i].Seen = time.Now()
|
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)
|
l.Debugf("discover: Caching %s addresses: %v", id, current)
|
||||||
}
|
}
|
||||||
|
|
||||||
d.registry[id] = current
|
d.addressRegistry[id] = current
|
||||||
|
|
||||||
if len(current) > len(orig) {
|
if len(current) > len(orig) {
|
||||||
addrs := make([]string, len(current))
|
addrs := make([]string, len(current))
|
||||||
@@ -413,7 +474,7 @@ func (d *Discoverer) filterCached(c []CacheEntry) []CacheEntry {
|
|||||||
for i := 0; i < len(c); {
|
for i := 0; i < len(c); {
|
||||||
if ago := time.Since(c[i].Seen); ago > d.cacheLifetime {
|
if ago := time.Since(c[i].Seen); ago > d.cacheLifetime {
|
||||||
if debug {
|
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[i] = c[len(c)-1]
|
||||||
c = c[:len(c)-1]
|
c = c[:len(c)-1]
|
||||||
@@ -424,30 +485,99 @@ func (d *Discoverer) filterCached(c []CacheEntry) []CacheEntry {
|
|||||||
return c
|
return c
|
||||||
}
|
}
|
||||||
|
|
||||||
func addrToAddr(addr *net.TCPAddr) Address {
|
func addrToAddr(addr *net.TCPAddr) string {
|
||||||
if len(addr.IP) == 0 || addr.IP.IsUnspecified() {
|
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 {
|
} 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 {
|
} 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 {
|
func resolveAddrs(addrs []string) []string {
|
||||||
var raddrs []Address
|
var raddrs []string
|
||||||
for _, addrStr := range addrs {
|
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 {
|
if err != nil {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
addr := addrToAddr(addrRes)
|
addr := addrToAddr(addrRes)
|
||||||
if len(addr.IP) > 0 {
|
if len(addr) > 0 {
|
||||||
raddrs = append(raddrs, addr)
|
uri.Host = addr
|
||||||
} else {
|
raddrs = append(raddrs, uri.String())
|
||||||
raddrs = append(raddrs, Address{Port: addr.Port})
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return raddrs
|
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 {
|
type DummyClient struct {
|
||||||
url *url.URL
|
url *url.URL
|
||||||
lookups []protocol.DeviceID
|
lookups []protocol.DeviceID
|
||||||
lookupRet []string
|
lookupRet Announce
|
||||||
stops int
|
stops int
|
||||||
statusRet bool
|
statusRet bool
|
||||||
statusChecks int
|
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)
|
c.lookups = append(c.lookups, device)
|
||||||
return c.lookupRet
|
return c.lookupRet, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *DummyClient) StatusOK() bool {
|
func (c *DummyClient) StatusOK() bool {
|
||||||
@@ -45,17 +45,41 @@ func (c *DummyClient) Address() string {
|
|||||||
func TestGlobalDiscovery(t *testing.T) {
|
func TestGlobalDiscovery(t *testing.T) {
|
||||||
c1 := &DummyClient{
|
c1 := &DummyClient{
|
||||||
statusRet: false,
|
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{
|
c2 := &DummyClient{
|
||||||
statusRet: true,
|
statusRet: true,
|
||||||
lookupRet: []string{},
|
lookupRet: Announce{
|
||||||
|
Magic: AnnouncementMagic,
|
||||||
|
This: Device{
|
||||||
|
ID: protocol.LocalDeviceID[:],
|
||||||
|
Addresses: nil,
|
||||||
|
Relays: nil,
|
||||||
|
},
|
||||||
|
Extra: nil,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
c3 := &DummyClient{
|
c3 := &DummyClient{
|
||||||
statusRet: true,
|
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}
|
clients := []*DummyClient{c1, c2}
|
||||||
@@ -72,7 +96,7 @@ func TestGlobalDiscovery(t *testing.T) {
|
|||||||
return c3, nil
|
return c3, nil
|
||||||
})
|
})
|
||||||
|
|
||||||
d := NewDiscoverer(device, []string{})
|
d := NewDiscoverer(device, []string{}, nil)
|
||||||
d.localBcastStart = time.Time{}
|
d.localBcastStart = time.Time{}
|
||||||
servers := []string{
|
servers := []string{
|
||||||
"test1://123.123.123.123:1234",
|
"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 {
|
if len(addrs) != 2 {
|
||||||
t.Fatal("Wrong number of addresses", addrs)
|
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 {
|
if len(addrs) != 2 {
|
||||||
t.Fatal("Wrong number of addresses", addrs)
|
t.Fatal("Wrong number of addresses", addrs)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,8 +10,8 @@
|
|||||||
package discover
|
package discover
|
||||||
|
|
||||||
const (
|
const (
|
||||||
AnnouncementMagic = 0x9D79BC39
|
AnnouncementMagic = 0x9D79BC40
|
||||||
QueryMagic = 0x2CA856F5
|
QueryMagic = 0x2CA856F6
|
||||||
)
|
)
|
||||||
|
|
||||||
type Query struct {
|
type Query struct {
|
||||||
@@ -25,12 +25,13 @@ type Announce struct {
|
|||||||
Extra []Device // max:16
|
Extra []Device // max:16
|
||||||
}
|
}
|
||||||
|
|
||||||
type Device struct {
|
type Relay struct {
|
||||||
ID []byte // max:32
|
Address string // max:256
|
||||||
Addresses []Address // max:16
|
Latency int32
|
||||||
}
|
}
|
||||||
|
|
||||||
type Address struct {
|
type Device struct {
|
||||||
IP []byte // max:16
|
ID []byte // max:32
|
||||||
Port uint16
|
Addresses []string // max:16
|
||||||
|
Relays []Relay // max:16
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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:
|
Device Structure:
|
||||||
|
|
||||||
0 1 2 3
|
0 1 2 3
|
||||||
@@ -200,15 +274,24 @@ Device Structure:
|
|||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
| Number of Addresses |
|
| Number of Addresses |
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| Length of Addresses |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
/ /
|
/ /
|
||||||
\ Zero or more Address Structures \
|
\ Addresses (variable length) \
|
||||||
|
/ /
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
| Number of Relays |
|
||||||
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
/ /
|
||||||
|
\ Zero or more Relay Structures \
|
||||||
/ /
|
/ /
|
||||||
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+
|
||||||
|
|
||||||
|
|
||||||
struct Device {
|
struct Device {
|
||||||
opaque ID<32>;
|
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)))
|
xw.WriteUint32(uint32(len(o.Addresses)))
|
||||||
for i := range 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 {
|
if err != nil {
|
||||||
return xw.Tot(), err
|
return xw.Tot(), err
|
||||||
}
|
}
|
||||||
@@ -275,83 +365,20 @@ func (o *Device) DecodeXDRFrom(xr *xdr.Reader) error {
|
|||||||
if _AddressesSize > 16 {
|
if _AddressesSize > 16 {
|
||||||
return xdr.ElementSizeExceeded("Addresses", _AddressesSize, 16)
|
return xdr.ElementSizeExceeded("Addresses", _AddressesSize, 16)
|
||||||
}
|
}
|
||||||
o.Addresses = make([]Address, _AddressesSize)
|
o.Addresses = make([]string, _AddressesSize)
|
||||||
for i := range o.Addresses {
|
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()
|
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()
|
|
||||||
}
|
|
||||||
|
|||||||
27
lib/osutil/ping.go
Normal file
27
lib/osutil/ping.go
Normal file
@@ -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