diff --git a/cmd/stfinddevice/main.go b/cmd/stfinddevice/main.go index 939a3c0f..c4ee8ddf 100644 --- a/cmd/stfinddevice/main.go +++ b/cmd/stfinddevice/main.go @@ -49,9 +49,8 @@ func main() { } type checkResult struct { - server string - direct []string - relays []discover.Relay + server string + addresses []string error } @@ -76,17 +75,14 @@ func checkServers(deviceID protocol.DeviceID, servers ...string) { if res.error != nil { fmt.Println(" " + res.error.Error()) } - for _, addr := range res.direct { + for _, addr := range res.addresses { fmt.Println(" address:", addr) } - for _, rel := range res.relays { - fmt.Printf(" relay: %s (%d ms)\n", rel.URL, rel.Latency) - } } } func checkServer(deviceID protocol.DeviceID, server string) checkResult { - disco, err := discover.NewGlobal(server, tls.Certificate{}, nil, nil) + disco, err := discover.NewGlobal(server, tls.Certificate{}, nil) if err != nil { return checkResult{error: err} } @@ -98,8 +94,8 @@ func checkServer(deviceID protocol.DeviceID, server string) checkResult { }) go func() { - direct, relays, err := disco.Lookup(deviceID) - res <- checkResult{direct: direct, relays: relays, error: err} + addresses, err := disco.Lookup(deviceID) + res <- checkResult{addresses: addresses, error: err} }() return <-res diff --git a/cmd/syncthing/gui.go b/cmd/syncthing/gui.go index 5fa63e10..3ae5537d 100644 --- a/cmd/syncthing/gui.go +++ b/cmd/syncthing/gui.go @@ -35,7 +35,6 @@ import ( "github.com/syncthing/syncthing/lib/model" "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/relay" "github.com/syncthing/syncthing/lib/stats" "github.com/syncthing/syncthing/lib/sync" "github.com/syncthing/syncthing/lib/tlsutil" @@ -51,21 +50,21 @@ var ( ) type apiService struct { - id protocol.DeviceID - cfg configIntf - httpsCertFile string - httpsKeyFile string - assetDir string - themes []string - model modelIntf - eventSub events.BufferedSubscription - discoverer discover.CachingMux - relayService relay.Service - fss *folderSummaryService - systemConfigMut sync.Mutex // serializes posts to /rest/system/config - stop chan struct{} // signals intentional stop - configChanged chan struct{} // signals intentional listener close due to config change - started chan struct{} // signals startup complete, for testing only + id protocol.DeviceID + cfg configIntf + httpsCertFile string + httpsKeyFile string + assetDir string + themes []string + model modelIntf + eventSub events.BufferedSubscription + discoverer discover.CachingMux + connectionsService connectionsIntf + fss *folderSummaryService + systemConfigMut sync.Mutex // serializes posts to /rest/system/config + stop chan struct{} // signals intentional stop + configChanged chan struct{} // signals intentional listener close due to config change + started chan struct{} // signals startup complete, for testing only listener net.Listener listenerMut sync.Mutex @@ -113,25 +112,30 @@ type configIntf interface { Folders() map[string]config.FolderConfiguration Devices() map[protocol.DeviceID]config.DeviceConfiguration Save() error + ListenAddresses() []string } -func newAPIService(id protocol.DeviceID, cfg configIntf, httpsCertFile, httpsKeyFile, assetDir string, m modelIntf, eventSub events.BufferedSubscription, discoverer discover.CachingMux, relayService relay.Service, errors, systemLog logger.Recorder) (*apiService, error) { +type connectionsIntf interface { + Status() map[string]interface{} +} + +func newAPIService(id protocol.DeviceID, cfg configIntf, httpsCertFile, httpsKeyFile, assetDir string, m modelIntf, eventSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService connectionsIntf, errors, systemLog logger.Recorder) (*apiService, error) { service := &apiService{ - id: id, - cfg: cfg, - httpsCertFile: httpsCertFile, - httpsKeyFile: httpsKeyFile, - assetDir: assetDir, - model: m, - eventSub: eventSub, - discoverer: discoverer, - relayService: relayService, - systemConfigMut: sync.NewMutex(), - stop: make(chan struct{}), - configChanged: make(chan struct{}), - listenerMut: sync.NewMutex(), - guiErrors: errors, - systemLog: systemLog, + id: id, + cfg: cfg, + httpsCertFile: httpsCertFile, + httpsKeyFile: httpsKeyFile, + assetDir: assetDir, + model: m, + eventSub: eventSub, + discoverer: discoverer, + connectionsService: connectionsService, + systemConfigMut: sync.NewMutex(), + stop: make(chan struct{}), + configChanged: make(chan struct{}), + listenerMut: sync.NewMutex(), + guiErrors: errors, + systemLog: systemLog, } seen := make(map[string]struct{}) @@ -825,18 +829,9 @@ func (s *apiService) getSystemStatus(w http.ResponseWriter, r *http.Request) { res["discoveryMethods"] = discoMethods res["discoveryErrors"] = discoErrors } - if s.relayService != nil { - res["relaysEnabled"] = true - relayClientStatus := make(map[string]bool) - relayClientLatency := make(map[string]int) - for _, relay := range s.relayService.Relays() { - latency, ok := s.relayService.RelayStatus(relay) - relayClientStatus[relay] = ok - relayClientLatency[relay] = int(latency / time.Millisecond) - } - res["relayClientStatus"] = relayClientStatus - res["relayClientLatency"] = relayClientLatency - } + + res["connectionServiceStatus"] = s.connectionsService.Status() + cpuUsageLock.RLock() var cpusum float64 for _, p := range cpuUsagePercent { diff --git a/cmd/syncthing/gui_test.go b/cmd/syncthing/gui_test.go index 45d545ca..e5ed2d07 100644 --- a/cmd/syncthing/gui_test.go +++ b/cmd/syncthing/gui_test.go @@ -462,13 +462,13 @@ func startHTTP(cfg *mockedConfig) (string, error) { assetDir := "../../gui" eventSub := new(mockedEventSub) discoverer := new(mockedCachingMux) - relayService := new(mockedRelayService) + connections := new(mockedConnections) errorLog := new(mockedLoggerRecorder) systemLog := new(mockedLoggerRecorder) // Instantiate the API service svc, err := newAPIService(protocol.LocalDeviceID, cfg, httpsCertFile, httpsKeyFile, assetDir, model, - eventSub, discoverer, relayService, errorLog, systemLog) + eventSub, discoverer, connections, errorLog, systemLog) if err != nil { return "", err } diff --git a/cmd/syncthing/main.go b/cmd/syncthing/main.go index 0d6dd6ff..a34a3924 100644 --- a/cmd/syncthing/main.go +++ b/cmd/syncthing/main.go @@ -17,7 +17,6 @@ import ( "net" "net/http" _ "net/http/pprof" - "net/url" "os" "os/signal" "path/filepath" @@ -38,19 +37,13 @@ import ( "github.com/syncthing/syncthing/lib/events" "github.com/syncthing/syncthing/lib/logger" "github.com/syncthing/syncthing/lib/model" - "github.com/syncthing/syncthing/lib/nat" "github.com/syncthing/syncthing/lib/osutil" "github.com/syncthing/syncthing/lib/protocol" - "github.com/syncthing/syncthing/lib/relay" "github.com/syncthing/syncthing/lib/symlinks" "github.com/syncthing/syncthing/lib/tlsutil" "github.com/syncthing/syncthing/lib/upgrade" "github.com/syncthing/syncthing/lib/util" - // Registers NAT service providers - _ "github.com/syncthing/syncthing/lib/pmp" - _ "github.com/syncthing/syncthing/lib/upnp" - "github.com/thejerf/suture" ) @@ -696,40 +689,6 @@ func syncthingMain(runtimeOptions RuntimeOptions) { mainService.Add(m) - // Start NAT service - var natService *nat.Service - var mappings []*nat.Mapping - if opts.NATEnabled { - natService = nat.NewService(myID, cfg) - for _, addrStr := range opts.ListenAddress { - uri, err := url.Parse(addrStr) - if err != nil { - l.Fatalf("Failed to parse listen address %s: %v", addrStr, err) - } - - if uri.Scheme == "tcp" || uri.Scheme == "tcp4" { - addr, err := net.ResolveTCPAddr(uri.Scheme, uri.Host) - if err != nil { - l.Fatalln("Bad listen address:", err) - } - if addr.Port == 0 { - l.Fatalf("Listen address %s: invalid port", uri) - } - - mappings = append(mappings, natService.NewMapping(nat.TCP, addr.IP, addr.Port)) - } - } - mainService.Add(natService) - } - - // Start relay management - - var relayService relay.Service - if opts.RelaysEnabled { - relayService = relay.NewService(cfg, tlsCfg) - mainService.Add(relayService) - } - // Start discovery cachedDiscovery := discover.NewCachingMux() @@ -737,13 +696,13 @@ func syncthingMain(runtimeOptions RuntimeOptions) { // Start connection management - connectionService := connections.NewConnectionService(cfg, myID, m, tlsCfg, cachedDiscovery, mappings, relayService, bepProtocolName, tlsDefaultCommonName, lans) - mainService.Add(connectionService) + connectionsService := connections.NewService(cfg, myID, m, tlsCfg, cachedDiscovery, bepProtocolName, tlsDefaultCommonName, lans) + mainService.Add(connectionsService) if cfg.Options().GlobalAnnEnabled { for _, srv := range cfg.GlobalDiscoveryServers() { l.Infoln("Using discovery server", srv) - gd, err := discover.NewGlobal(srv, cert, connectionService, relayService) + gd, err := discover.NewGlobal(srv, cert, connectionsService) if err != nil { l.Warnln("Global discovery:", err) continue @@ -758,14 +717,14 @@ func syncthingMain(runtimeOptions RuntimeOptions) { if cfg.Options().LocalAnnEnabled { // v4 broadcasts - bcd, err := discover.NewLocal(myID, fmt.Sprintf(":%d", cfg.Options().LocalAnnPort), connectionService, relayService) + bcd, err := discover.NewLocal(myID, fmt.Sprintf(":%d", cfg.Options().LocalAnnPort), connectionsService) if err != nil { l.Warnln("IPv4 local discovery:", err) } else { cachedDiscovery.Add(bcd, 0, 0, ipv4LocalDiscoveryPriority) } // v6 multicasts - mcd, err := discover.NewLocal(myID, cfg.Options().LocalAnnMCAddr, connectionService, relayService) + mcd, err := discover.NewLocal(myID, cfg.Options().LocalAnnMCAddr, connectionsService) if err != nil { l.Warnln("IPv6 local discovery:", err) } else { @@ -775,7 +734,7 @@ func syncthingMain(runtimeOptions RuntimeOptions) { // GUI - setupGUI(mainService, cfg, m, apiSub, cachedDiscovery, relayService, errors, systemLog, runtimeOptions) + setupGUI(mainService, cfg, m, apiSub, cachedDiscovery, connectionsService, errors, systemLog, runtimeOptions) if runtimeOptions.cpuProfile { f, err := os.Create(fmt.Sprintf("cpu-%d.pprof", os.Getpid())) @@ -957,7 +916,7 @@ func startAuditing(mainService *suture.Supervisor) { l.Infoln("Audit log in", auditFile) } -func setupGUI(mainService *suture.Supervisor, cfg *config.Wrapper, m *model.Model, apiSub events.BufferedSubscription, discoverer discover.CachingMux, relayService relay.Service, errors, systemLog logger.Recorder, runtimeOptions RuntimeOptions) { +func setupGUI(mainService *suture.Supervisor, cfg *config.Wrapper, m *model.Model, apiSub events.BufferedSubscription, discoverer discover.CachingMux, connectionsService *connections.Service, errors, systemLog logger.Recorder, runtimeOptions RuntimeOptions) { guiCfg := cfg.GUI() if !guiCfg.Enabled { @@ -968,7 +927,7 @@ func setupGUI(mainService *suture.Supervisor, cfg *config.Wrapper, m *model.Mode l.Warnln("Insecure admin access is enabled.") } - api, err := newAPIService(myID, cfg, locations[locHTTPSCertFile], locations[locHTTPSKeyFile], runtimeOptions.assetDir, m, apiSub, discoverer, relayService, errors, systemLog) + api, err := newAPIService(myID, cfg, locations[locHTTPSCertFile], locations[locHTTPSKeyFile], runtimeOptions.assetDir, m, apiSub, discoverer, connectionsService, errors, systemLog) if err != nil { l.Fatalln("Cannot start GUI:", err) } @@ -1017,7 +976,15 @@ func defaultConfig(myName string) config.Configuration { if err != nil { l.Fatalln("get free port (BEP):", err) } - newCfg.Options.ListenAddress = []string{fmt.Sprintf("tcp://0.0.0.0:%d", port)} + if port == 22000 { + newCfg.Options.ListenAddresses = []string{"default"} + } else { + newCfg.Options.ListenAddresses = []string{ + fmt.Sprintf("tcp://%s", net.JoinHostPort("0.0.0.0", strconv.Itoa(port))), + "dynamic+https://relays.syncthing.net/endpoint", + } + } + return newCfg } diff --git a/cmd/syncthing/mocked_config_test.go b/cmd/syncthing/mocked_config_test.go index c0bc6366..d4e734a7 100644 --- a/cmd/syncthing/mocked_config_test.go +++ b/cmd/syncthing/mocked_config_test.go @@ -19,6 +19,10 @@ func (c *mockedConfig) GUI() config.GUIConfiguration { return c.gui } +func (c *mockedConfig) ListenAddresses() []string { + return nil +} + func (c *mockedConfig) Raw() config.Configuration { return config.Configuration{} } diff --git a/cmd/syncthing/mocked_connections_test.go b/cmd/syncthing/mocked_connections_test.go new file mode 100644 index 00000000..b4b8ffe0 --- /dev/null +++ b/cmd/syncthing/mocked_connections_test.go @@ -0,0 +1,13 @@ +// Copyright (C) 2016 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 + +type mockedConnections struct{} + +func (m *mockedConnections) Status() map[string]interface{} { + return nil +} diff --git a/cmd/syncthing/mocked_discovery_test.go b/cmd/syncthing/mocked_discovery_test.go index 4d8b9190..8f8a977a 100644 --- a/cmd/syncthing/mocked_discovery_test.go +++ b/cmd/syncthing/mocked_discovery_test.go @@ -26,8 +26,8 @@ func (m *mockedCachingMux) Stop() { // from events.Finder -func (m *mockedCachingMux) Lookup(deviceID protocol.DeviceID) (direct []string, relays []discover.Relay, err error) { - return nil, nil, nil +func (m *mockedCachingMux) Lookup(deviceID protocol.DeviceID) (direct []string, err error) { + return nil, nil } func (m *mockedCachingMux) Error() error { diff --git a/cmd/syncthing/mocked_relay_test.go b/cmd/syncthing/mocked_relay_test.go deleted file mode 100644 index 211bfdbd..00000000 --- a/cmd/syncthing/mocked_relay_test.go +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright (C) 2016 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" - "time" -) - -type mockedRelayService struct{} - -// from suture.Service - -func (s *mockedRelayService) Serve() { - select {} -} - -func (s *mockedRelayService) Stop() { -} - -// from relay.Service - -func (s *mockedRelayService) Accept() *tls.Conn { - return nil -} - -func (s *mockedRelayService) Relays() []string { - return nil -} - -func (s *mockedRelayService) RelayStatus(uri string) (time.Duration, bool) { - return 0, false -} diff --git a/cmd/syncthing/usage_report.go b/cmd/syncthing/usage_report.go index bb20c9d2..fc64ddbd 100644 --- a/cmd/syncthing/usage_report.go +++ b/cmd/syncthing/usage_report.go @@ -16,6 +16,7 @@ import ( "net/http" "runtime" "sort" + "strings" "time" "github.com/syncthing/syncthing/lib/config" @@ -203,16 +204,16 @@ func reportData(cfg configIntf, m modelIntf) map[string]interface{} { } defaultRelayServers, otherRelayServers := 0, 0 - for _, addr := range cfg.Options().RelayServers { - switch addr { - case "dynamic+https://relays.syncthing.net/endpoint": + for _, addr := range cfg.ListenAddresses() { + switch { + case addr == "dynamic+https://relays.syncthing.net/endpoint": defaultRelayServers++ - default: + case strings.HasPrefix(addr, "relay://") || strings.HasPrefix(addr, "dynamic+http"): otherRelayServers++ } } res["relays"] = map[string]interface{}{ - "enabled": cfg.Options().RelaysEnabled, + "enabled": defaultRelayServers+otherAnnounceServers > 0, "defaultServers": defaultRelayServers, "otherServers": otherRelayServers, } diff --git a/cmd/syncthing/verboseservice.go b/cmd/syncthing/verboseservice.go index 1852920d..095b3211 100644 --- a/cmd/syncthing/verboseservice.go +++ b/cmd/syncthing/verboseservice.go @@ -8,7 +8,6 @@ package main import ( "fmt" - "strings" "github.com/syncthing/syncthing/lib/events" ) @@ -147,17 +146,12 @@ func (s *verboseService) formatEvent(ev events.Event) string { data := ev.Data.(map[string]string) device := data["device"] return fmt.Sprintf("Device %v was resumed", device) - case events.ExternalPortMappingChanged: + case events.ListenAddressesChanged: data := ev.Data.(map[string]interface{}) - protocol := data["protocol"] - local := data["local"] - added := data["added"] - removed := data["removed"] - return fmt.Sprintf("External port mapping changed; protocol: %s, local: %s, added: %s, removed: %s", protocol, local, added, removed) - case events.RelayStateChanged: - data := ev.Data.(map[string][]string) - newRelays := data["new"] - return fmt.Sprintf("Relay state changed; connected relay(s) are %s.", strings.Join(newRelays, ", ")) + address := data["address"] + lan := data["lan"] + wan := data["wan"] + return fmt.Sprintf("Listen address %s resolution has changed: lan addresses: %s wan addresses: %s", address, lan, wan) case events.LoginAttempt: data := ev.Data.(map[string]interface{}) username := data["username"].(string) diff --git a/gui/default/index.html b/gui/default/index.html index 33b7682c..d0793e03 100755 --- a/gui/default/index.html +++ b/gui/default/index.html @@ -430,6 +430,19 @@  CPU Utilization {{system.cpuPercent | alwaysNumber | natural:1}}% + +  Listeners + + + {{listenersTotal}}/{{listenersTotal}} + + + + {{listenersTotal-listenersFailed.length}}/{{listenersTotal}} + + + +  Discovery @@ -443,19 +456,6 @@ - -  Relays - - - {{relaysTotal}}/{{relaysTotal}} - - - - {{relaysTotal-relaysFailed.length}}/{{relaysTotal}} - - - -  Uptime {{system.uptime | duration:"m"}} @@ -503,13 +503,17 @@  Upload Rate {{connections[deviceCfg.deviceID].outbps | binary}}B/s ({{connections[deviceCfg.deviceID].outBytesTotal | binary}}B) - - - - Address - Relayed via - - {{deviceAddr(deviceCfg)}} + +  Address + + + {{deviceAddr(deviceCfg)}} + + + + +  Connection Type + {{connections[deviceCfg.deviceID].type}}  Compression diff --git a/gui/default/syncthing/core/syncthingController.js b/gui/default/syncthing/core/syncthingController.js index 07176b84..aeee056c 100755 --- a/gui/default/syncthing/core/syncthingController.js +++ b/gui/default/syncthing/core/syncthingController.js @@ -352,9 +352,8 @@ angular.module('syncthing.core') var hasConfig = !isEmptyObject($scope.config); $scope.config = config; - $scope.config.options._listenAddressStr = $scope.config.options.listenAddress.join(', '); + $scope.config.options._listenAddressesStr = $scope.config.options.listenAddresses.join(', '); $scope.config.options._globalAnnounceServersStr = $scope.config.options.globalAnnounceServers.join(', '); - $scope.config.options._relayServersStr = $scope.config.options.relayServers.join(', '); $scope.devices = $scope.config.devices; $scope.devices.forEach(function (deviceCfg) { @@ -390,6 +389,15 @@ angular.module('syncthing.core') $scope.myID = data.myID; $scope.system = data; + var listenersFailed = []; + for (var address in data.connectionServiceStatus) { + if (data.connectionServiceStatus[address].error) { + listenersFailed.push(address + ": " + data.connectionServiceStatus[address].error); + } + } + $scope.listenersFailed = listenersFailed; + $scope.listenersTotal = Object.keys(data.connectionServiceStatus).length; + $scope.discoveryTotal = data.discoveryMethods; var discoveryFailed = []; for (var disco in data.discoveryErrors) { @@ -398,18 +406,6 @@ angular.module('syncthing.core') } } $scope.discoveryFailed = discoveryFailed; - - var relaysFailed = []; - var relaysTotal = 0; - for (var relay in data.relayClientStatus) { - if (!data.relayClientStatus[relay]) { - relaysFailed.push(relay); - } - relaysTotal++; - } - $scope.relaysFailed = relaysFailed; - $scope.relaysTotal = relaysTotal; - console.log("refreshSystem", data); }).error($scope.emitHTTPError); } @@ -892,7 +888,7 @@ angular.module('syncthing.core') $scope.config.options = angular.copy($scope.tmpOptions); $scope.config.gui = angular.copy($scope.tmpGUI); - ['listenAddress', 'globalAnnounceServers', 'relayServers'].forEach(function (key) { + ['listenAddresses', 'globalAnnounceServers'].forEach(function (key) { $scope.config.options[key] = $scope.config.options["_" + key + "Str"].split(/[ ,]+/).map(function (x) { return x.trim(); }); diff --git a/gui/default/syncthing/settings/settingsModalView.html b/gui/default/syncthing/settings/settingsModalView.html index 3247805e..be66bc4e 100644 --- a/gui/default/syncthing/settings/settingsModalView.html +++ b/gui/default/syncthing/settings/settingsModalView.html @@ -15,8 +15,8 @@
- - + +
@@ -56,20 +56,6 @@
-
-
- -
-
- -
-
- - -
-