main.go 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910
  1. // Copyright (C) 2014 Jakob Borg and Contributors (see the CONTRIBUTORS file).
  2. // All rights reserved. Use of this source code is governed by an MIT-style
  3. // license that can be found in the LICENSE file.
  4. package main
  5. import (
  6. "crypto/sha1"
  7. "crypto/tls"
  8. "flag"
  9. "fmt"
  10. "io"
  11. "log"
  12. "math/rand"
  13. "net"
  14. "net/http"
  15. _ "net/http/pprof"
  16. "os"
  17. "os/exec"
  18. "path/filepath"
  19. "regexp"
  20. "runtime"
  21. "runtime/debug"
  22. "runtime/pprof"
  23. "strconv"
  24. "strings"
  25. "time"
  26. "github.com/calmh/syncthing/config"
  27. "github.com/calmh/syncthing/discover"
  28. "github.com/calmh/syncthing/events"
  29. "github.com/calmh/syncthing/logger"
  30. "github.com/calmh/syncthing/model"
  31. "github.com/calmh/syncthing/osutil"
  32. "github.com/calmh/syncthing/protocol"
  33. "github.com/calmh/syncthing/upnp"
  34. "github.com/juju/ratelimit"
  35. "github.com/syndtr/goleveldb/leveldb"
  36. )
  37. var (
  38. Version = "unknown-dev"
  39. BuildEnv = "default"
  40. BuildStamp = "0"
  41. BuildDate time.Time
  42. BuildHost = "unknown"
  43. BuildUser = "unknown"
  44. LongVersion string
  45. )
  46. var l = logger.DefaultLogger
  47. func init() {
  48. if Version != "unknown-dev" {
  49. // If not a generic dev build, version string should come from git describe
  50. exp := regexp.MustCompile(`^v\d+\.\d+\.\d+(-\d+-g[0-9a-f]+)?(-dirty)?$`)
  51. if !exp.MatchString(Version) {
  52. l.Fatalf("Invalid version string %q;\n\tdoes not match regexp %v", Version, exp)
  53. }
  54. }
  55. stamp, _ := strconv.Atoi(BuildStamp)
  56. BuildDate = time.Unix(int64(stamp), 0)
  57. date := BuildDate.UTC().Format("2006-01-02 15:04:05 MST")
  58. LongVersion = fmt.Sprintf("syncthing %s (%s %s-%s %s) %s@%s %s", Version, runtime.Version(), runtime.GOOS, runtime.GOARCH, BuildEnv, BuildUser, BuildHost, date)
  59. if os.Getenv("STTRACE") != "" {
  60. logFlags = log.Ltime | log.Ldate | log.Lmicroseconds | log.Lshortfile
  61. }
  62. }
  63. var (
  64. cfg config.Configuration
  65. myID protocol.NodeID
  66. confDir string
  67. logFlags int = log.Ltime
  68. rateBucket *ratelimit.Bucket
  69. stop = make(chan bool)
  70. discoverer *discover.Discoverer
  71. )
  72. const (
  73. usage = "syncthing [options]"
  74. extraUsage = `The value for the -logflags option is a sum of the following:
  75. 1 Date
  76. 2 Time
  77. 4 Microsecond time
  78. 8 Long filename
  79. 16 Short filename
  80. I.e. to prefix each log line with date and time, set -logflags=3 (1 + 2 from
  81. above). The value 0 is used to disable all of the above. The default is to
  82. show time only (2).
  83. The following enviroment variables are interpreted by syncthing:
  84. STNORESTART Do not attempt to restart when requested to, instead just exit.
  85. Set this variable when running under a service manager such as
  86. runit, launchd, etc.
  87. STPROFILER Set to a listen address such as "127.0.0.1:9090" to start the
  88. profiler with HTTP access.
  89. STTRACE A comma separated string of facilities to trace. The valid
  90. facility strings:
  91. - "beacon" (the beacon package)
  92. - "discover" (the discover package)
  93. - "files" (the files package)
  94. - "net" (the main package; connections & network messages)
  95. - "model" (the model package)
  96. - "scanner" (the scanner package)
  97. - "upnp" (the upnp package)
  98. - "xdr" (the xdr package)
  99. - "all" (all of the above)
  100. STCPUPROFILE Write CPU profile to the specified file.
  101. STGUIASSETS Directory to load GUI assets from. Overrides compiled in assets.
  102. STDEADLOCKTIMEOUT Alter deadlock detection timeout (seconds; default 1200).`
  103. )
  104. func init() {
  105. rand.Seed(time.Now().UnixNano())
  106. }
  107. func main() {
  108. var reset bool
  109. var showVersion bool
  110. var doUpgrade bool
  111. flag.StringVar(&confDir, "home", getDefaultConfDir(), "Set configuration directory")
  112. flag.BoolVar(&reset, "reset", false, "Prepare to resync from cluster")
  113. flag.BoolVar(&showVersion, "version", false, "Show version")
  114. flag.BoolVar(&doUpgrade, "upgrade", false, "Perform upgrade")
  115. flag.IntVar(&logFlags, "logflags", logFlags, "Set log flags")
  116. flag.Usage = usageFor(flag.CommandLine, usage, extraUsage)
  117. flag.Parse()
  118. if showVersion {
  119. fmt.Println(LongVersion)
  120. return
  121. }
  122. l.SetFlags(logFlags)
  123. if doUpgrade {
  124. err := upgrade()
  125. if err != nil {
  126. l.Fatalln(err)
  127. }
  128. return
  129. }
  130. if len(os.Getenv("GOGC")) == 0 {
  131. debug.SetGCPercent(25)
  132. }
  133. if len(os.Getenv("GOMAXPROCS")) == 0 {
  134. runtime.GOMAXPROCS(runtime.NumCPU())
  135. }
  136. confDir = expandTilde(confDir)
  137. if _, err := os.Stat(confDir); err != nil && confDir == getDefaultConfDir() {
  138. // We are supposed to use the default configuration directory. It
  139. // doesn't exist. In the past our default has been ~/.syncthing, so if
  140. // that directory exists we move it to the new default location and
  141. // continue. We don't much care if this fails at this point, we will
  142. // be checking that later.
  143. var oldDefault string
  144. if runtime.GOOS == "windows" {
  145. oldDefault = filepath.Join(os.Getenv("AppData"), "Syncthing")
  146. } else {
  147. oldDefault = expandTilde("~/.syncthing")
  148. }
  149. if _, err := os.Stat(oldDefault); err == nil {
  150. os.MkdirAll(filepath.Dir(confDir), 0700)
  151. if err := os.Rename(oldDefault, confDir); err == nil {
  152. l.Infoln("Moved config dir", oldDefault, "to", confDir)
  153. }
  154. }
  155. }
  156. // Ensure that our home directory exists and that we have a certificate and key.
  157. ensureDir(confDir, 0700)
  158. cert, err := loadCert(confDir, "")
  159. if err != nil {
  160. newCertificate(confDir, "")
  161. cert, err = loadCert(confDir, "")
  162. l.FatalErr(err)
  163. }
  164. myID = protocol.NewNodeID(cert.Certificate[0])
  165. l.SetPrefix(fmt.Sprintf("[%s] ", myID.String()[:5]))
  166. l.Infoln(LongVersion)
  167. l.Infoln("My ID:", myID)
  168. // Prepare to be able to save configuration
  169. cfgFile := filepath.Join(confDir, "config.xml")
  170. go saveConfigLoop(cfgFile)
  171. // Load the configuration file, if it exists.
  172. // If it does not, create a template.
  173. cf, err := os.Open(cfgFile)
  174. if err == nil {
  175. // Read config.xml
  176. cfg, err = config.Load(cf, myID)
  177. if err != nil {
  178. l.Fatalln(err)
  179. }
  180. cf.Close()
  181. } else {
  182. l.Infoln("No config file; starting with empty defaults")
  183. name, _ := os.Hostname()
  184. defaultRepo := filepath.Join(getHomeDir(), "Sync")
  185. ensureDir(defaultRepo, 0755)
  186. cfg, err = config.Load(nil, myID)
  187. cfg.Repositories = []config.RepositoryConfiguration{
  188. {
  189. ID: "default",
  190. Directory: defaultRepo,
  191. Nodes: []config.NodeConfiguration{{NodeID: myID}},
  192. },
  193. }
  194. cfg.Nodes = []config.NodeConfiguration{
  195. {
  196. NodeID: myID,
  197. Addresses: []string{"dynamic"},
  198. Name: name,
  199. },
  200. }
  201. port, err := getFreePort("127.0.0.1", 8080)
  202. l.FatalErr(err)
  203. cfg.GUI.Address = fmt.Sprintf("127.0.0.1:%d", port)
  204. port, err = getFreePort("0.0.0.0", 22000)
  205. l.FatalErr(err)
  206. cfg.Options.ListenAddress = []string{fmt.Sprintf("0.0.0.0:%d", port)}
  207. saveConfig()
  208. l.Infof("Edit %s to taste or use the GUI\n", cfgFile)
  209. }
  210. if reset {
  211. resetRepositories()
  212. return
  213. }
  214. if profiler := os.Getenv("STPROFILER"); len(profiler) > 0 {
  215. go func() {
  216. l.Debugln("Starting profiler on", profiler)
  217. runtime.SetBlockProfileRate(1)
  218. err := http.ListenAndServe(profiler, nil)
  219. if err != nil {
  220. l.Fatalln(err)
  221. }
  222. }()
  223. }
  224. if len(os.Getenv("STRESTART")) > 0 {
  225. waitForParentExit()
  226. }
  227. // The TLS configuration is used for both the listening socket and outgoing
  228. // connections.
  229. tlsCfg := &tls.Config{
  230. Certificates: []tls.Certificate{cert},
  231. NextProtos: []string{"bep/1.0"},
  232. ServerName: myID.String(),
  233. ClientAuth: tls.RequestClientCert,
  234. SessionTicketsDisabled: true,
  235. InsecureSkipVerify: true,
  236. MinVersion: tls.VersionTLS12,
  237. }
  238. // If the write rate should be limited, set up a rate limiter for it.
  239. // This will be used on connections created in the connect and listen routines.
  240. if cfg.Options.MaxSendKbps > 0 {
  241. rateBucket = ratelimit.NewBucketWithRate(float64(1000*cfg.Options.MaxSendKbps), int64(5*1000*cfg.Options.MaxSendKbps))
  242. }
  243. removeLegacyIndexes()
  244. db, err := leveldb.OpenFile(filepath.Join(confDir, "index"), nil)
  245. if err != nil {
  246. l.Fatalln("leveldb.OpenFile():", err)
  247. }
  248. m := model.NewModel(confDir, &cfg, "syncthing", Version, db)
  249. nextRepo:
  250. for i, repo := range cfg.Repositories {
  251. if repo.Invalid != "" {
  252. continue
  253. }
  254. repo.Directory = expandTilde(repo.Directory)
  255. // Safety check. If the cached index contains files but the repository
  256. // doesn't exist, we have a problem. We would assume that all files
  257. // have been deleted which might not be the case, so abort instead.
  258. id := fmt.Sprintf("%x", sha1.Sum([]byte(repo.Directory)))
  259. idxFile := filepath.Join(confDir, id+".idx.gz")
  260. if _, err := os.Stat(idxFile); err == nil {
  261. if fi, err := os.Stat(repo.Directory); err != nil || !fi.IsDir() {
  262. cfg.Repositories[i].Invalid = "repo directory missing"
  263. continue nextRepo
  264. }
  265. }
  266. ensureDir(repo.Directory, -1)
  267. m.AddRepo(repo)
  268. }
  269. // GUI
  270. if cfg.GUI.Enabled && cfg.GUI.Address != "" {
  271. addr, err := net.ResolveTCPAddr("tcp", cfg.GUI.Address)
  272. if err != nil {
  273. l.Fatalf("Cannot start GUI on %q: %v", cfg.GUI.Address, err)
  274. } else {
  275. var hostOpen, hostShow string
  276. switch {
  277. case addr.IP == nil:
  278. hostOpen = "localhost"
  279. hostShow = "0.0.0.0"
  280. case addr.IP.IsUnspecified():
  281. hostOpen = "localhost"
  282. hostShow = addr.IP.String()
  283. default:
  284. hostOpen = addr.IP.String()
  285. hostShow = hostOpen
  286. }
  287. var proto = "http"
  288. if cfg.GUI.UseTLS {
  289. proto = "https"
  290. }
  291. l.Infof("Starting web GUI on %s://%s:%d/", proto, hostShow, addr.Port)
  292. err := startGUI(cfg.GUI, os.Getenv("STGUIASSETS"), m)
  293. if err != nil {
  294. l.Fatalln("Cannot start GUI:", err)
  295. }
  296. if cfg.Options.StartBrowser && len(os.Getenv("STRESTART")) == 0 {
  297. openURL(fmt.Sprintf("%s://%s:%d", proto, hostOpen, addr.Port))
  298. }
  299. }
  300. }
  301. // Walk the repository and update the local model before establishing any
  302. // connections to other nodes.
  303. m.CleanRepos()
  304. l.Infoln("Performing initial repository scan")
  305. m.ScanRepos()
  306. // Remove all .idx* files that don't belong to an active repo.
  307. validIndexes := make(map[string]bool)
  308. for _, repo := range cfg.Repositories {
  309. dir := expandTilde(repo.Directory)
  310. id := fmt.Sprintf("%x", sha1.Sum([]byte(dir)))
  311. validIndexes[id] = true
  312. }
  313. allIndexes, err := filepath.Glob(filepath.Join(confDir, "*.idx*"))
  314. if err == nil {
  315. for _, idx := range allIndexes {
  316. bn := filepath.Base(idx)
  317. fs := strings.Split(bn, ".")
  318. if len(fs) > 1 {
  319. if _, ok := validIndexes[fs[0]]; !ok {
  320. l.Infoln("Removing old index", bn)
  321. os.Remove(idx)
  322. }
  323. }
  324. }
  325. }
  326. // UPnP
  327. var externalPort = 0
  328. if cfg.Options.UPnPEnabled {
  329. // We seed the random number generator with the node ID to get a
  330. // repeatable sequence of random external ports.
  331. externalPort = setupUPnP(rand.NewSource(certSeed(cert.Certificate[0])))
  332. }
  333. // Routine to connect out to configured nodes
  334. discoverer = discovery(externalPort)
  335. go listenConnect(myID, m, tlsCfg)
  336. for _, repo := range cfg.Repositories {
  337. if repo.Invalid != "" {
  338. continue
  339. }
  340. // Routine to pull blocks from other nodes to synchronize the local
  341. // repository. Does not run when we are in read only (publish only) mode.
  342. if repo.ReadOnly {
  343. l.Okf("Ready to synchronize %s (read only; no external updates accepted)", repo.ID)
  344. m.StartRepoRO(repo.ID)
  345. } else {
  346. l.Okf("Ready to synchronize %s (read-write)", repo.ID)
  347. m.StartRepoRW(repo.ID, cfg.Options.ParallelRequests)
  348. }
  349. }
  350. if cpuprof := os.Getenv("STCPUPROFILE"); len(cpuprof) > 0 {
  351. f, err := os.Create(cpuprof)
  352. if err != nil {
  353. log.Fatal(err)
  354. }
  355. pprof.StartCPUProfile(f)
  356. defer pprof.StopCPUProfile()
  357. }
  358. for _, node := range cfg.Nodes {
  359. if len(node.Name) > 0 {
  360. l.Infof("Node %s is %q at %v", node.NodeID, node.Name, node.Addresses)
  361. }
  362. }
  363. if cfg.Options.URAccepted > 0 && cfg.Options.URAccepted < usageReportVersion {
  364. l.Infoln("Anonymous usage report has changed; revoking acceptance")
  365. cfg.Options.URAccepted = 0
  366. }
  367. if cfg.Options.URAccepted >= usageReportVersion {
  368. go usageReportingLoop(m)
  369. go func() {
  370. time.Sleep(10 * time.Minute)
  371. err := sendUsageReport(m)
  372. if err != nil {
  373. l.Infoln("Usage report:", err)
  374. }
  375. }()
  376. }
  377. events.Default.Log(events.StartupComplete, nil)
  378. go generateEvents()
  379. <-stop
  380. l.Okln("Exiting")
  381. }
  382. func generateEvents() {
  383. for {
  384. time.Sleep(300 * time.Second)
  385. events.Default.Log(events.Ping, nil)
  386. }
  387. }
  388. func waitForParentExit() {
  389. l.Infoln("Waiting for parent to exit...")
  390. // Wait for the listen address to become free, indicating that the parent has exited.
  391. for {
  392. ln, err := net.Listen("tcp", cfg.Options.ListenAddress[0])
  393. if err == nil {
  394. ln.Close()
  395. break
  396. }
  397. time.Sleep(250 * time.Millisecond)
  398. }
  399. l.Okln("Continuing")
  400. }
  401. func setupUPnP(r rand.Source) int {
  402. var externalPort = 0
  403. if len(cfg.Options.ListenAddress) == 1 {
  404. _, portStr, err := net.SplitHostPort(cfg.Options.ListenAddress[0])
  405. if err != nil {
  406. l.Warnln(err)
  407. } else {
  408. // Set up incoming port forwarding, if necessary and possible
  409. port, _ := strconv.Atoi(portStr)
  410. igd, err := upnp.Discover()
  411. if err == nil {
  412. for i := 0; i < 10; i++ {
  413. r := 1024 + int(r.Int63()%(65535-1024))
  414. err := igd.AddPortMapping(upnp.TCP, r, port, "syncthing", 0)
  415. if err == nil {
  416. externalPort = r
  417. l.Infoln("Created UPnP port mapping - external port", externalPort)
  418. break
  419. }
  420. }
  421. if externalPort == 0 {
  422. l.Warnln("Failed to create UPnP port mapping")
  423. }
  424. } else {
  425. l.Infof("No UPnP gateway detected")
  426. if debugNet {
  427. l.Debugf("UPnP: %v", err)
  428. }
  429. }
  430. }
  431. } else {
  432. l.Warnln("Multiple listening addresses; not attempting UPnP port mapping")
  433. }
  434. return externalPort
  435. }
  436. func resetRepositories() {
  437. suffix := fmt.Sprintf(".syncthing-reset-%d", time.Now().UnixNano())
  438. for _, repo := range cfg.Repositories {
  439. if _, err := os.Stat(repo.Directory); err == nil {
  440. l.Infof("Reset: Moving %s -> %s", repo.Directory, repo.Directory+suffix)
  441. os.Rename(repo.Directory, repo.Directory+suffix)
  442. }
  443. }
  444. idx := filepath.Join(confDir, "index")
  445. os.RemoveAll(idx)
  446. }
  447. func removeLegacyIndexes() {
  448. pat := filepath.Join(confDir, "*.idx.gz*")
  449. idxs, err := filepath.Glob(pat)
  450. if err == nil {
  451. for _, idx := range idxs {
  452. l.Infof("Reset: Removing %s", idx)
  453. os.Remove(idx)
  454. }
  455. }
  456. }
  457. func restart() {
  458. l.Infoln("Restarting")
  459. if os.Getenv("SMF_FMRI") != "" || os.Getenv("STNORESTART") != "" {
  460. // Solaris SMF
  461. l.Infoln("Service manager detected; exit instead of restart")
  462. stop <- true
  463. return
  464. }
  465. env := os.Environ()
  466. if len(os.Getenv("STRESTART")) == 0 {
  467. env = append(env, "STRESTART=1")
  468. }
  469. pgm, err := exec.LookPath(os.Args[0])
  470. if err != nil {
  471. l.Warnln(err)
  472. return
  473. }
  474. proc, err := os.StartProcess(pgm, os.Args, &os.ProcAttr{
  475. Env: env,
  476. Files: []*os.File{os.Stdin, os.Stdout, os.Stderr},
  477. })
  478. if err != nil {
  479. l.Fatalln(err)
  480. }
  481. proc.Release()
  482. stop <- true
  483. }
  484. func shutdown() {
  485. stop <- true
  486. }
  487. var saveConfigCh = make(chan struct{})
  488. func saveConfigLoop(cfgFile string) {
  489. for _ = range saveConfigCh {
  490. fd, err := os.Create(cfgFile + ".tmp")
  491. if err != nil {
  492. l.Warnln(err)
  493. continue
  494. }
  495. err = config.Save(fd, cfg)
  496. if err != nil {
  497. l.Warnln(err)
  498. fd.Close()
  499. continue
  500. }
  501. err = fd.Close()
  502. if err != nil {
  503. l.Warnln(err)
  504. continue
  505. }
  506. err = osutil.Rename(cfgFile+".tmp", cfgFile)
  507. if err != nil {
  508. l.Warnln(err)
  509. }
  510. }
  511. }
  512. func saveConfig() {
  513. saveConfigCh <- struct{}{}
  514. }
  515. func listenConnect(myID protocol.NodeID, m *model.Model, tlsCfg *tls.Config) {
  516. var conns = make(chan *tls.Conn)
  517. // Listen
  518. for _, addr := range cfg.Options.ListenAddress {
  519. go listenTLS(conns, addr, tlsCfg)
  520. }
  521. // Connect
  522. go dialTLS(m, conns, tlsCfg)
  523. next:
  524. for conn := range conns {
  525. certs := conn.ConnectionState().PeerCertificates
  526. if cl := len(certs); cl != 1 {
  527. l.Infof("Got peer certificate list of length %d != 1 from %s; protocol error", cl, conn.RemoteAddr())
  528. conn.Close()
  529. continue
  530. }
  531. remoteID := protocol.NewNodeID(certs[0].Raw)
  532. if remoteID == myID {
  533. l.Infof("Connected to myself (%s) - should not happen", remoteID)
  534. conn.Close()
  535. continue
  536. }
  537. if m.ConnectedTo(remoteID) {
  538. l.Infof("Connected to already connected node (%s)", remoteID)
  539. conn.Close()
  540. continue
  541. }
  542. for _, nodeCfg := range cfg.Nodes {
  543. if nodeCfg.NodeID == remoteID {
  544. var wr io.Writer = conn
  545. if rateBucket != nil {
  546. wr = &limitedWriter{conn, rateBucket}
  547. }
  548. name := fmt.Sprintf("%s-%s", conn.LocalAddr(), conn.RemoteAddr())
  549. protoConn := protocol.NewConnection(remoteID, conn, wr, m, name)
  550. l.Infof("Established secure connection to %s at %s", remoteID, name)
  551. if debugNet {
  552. l.Debugf("cipher suite %04X", conn.ConnectionState().CipherSuite)
  553. }
  554. events.Default.Log(events.NodeConnected, map[string]string{
  555. "id": remoteID.String(),
  556. "addr": conn.RemoteAddr().String(),
  557. })
  558. m.AddConnection(conn, protoConn)
  559. continue next
  560. }
  561. }
  562. l.Infof("Connection from %s with unknown node ID %s; ignoring", conn.RemoteAddr(), remoteID)
  563. conn.Close()
  564. }
  565. }
  566. func listenTLS(conns chan *tls.Conn, addr string, tlsCfg *tls.Config) {
  567. if debugNet {
  568. l.Debugln("listening on", addr)
  569. }
  570. tcaddr, err := net.ResolveTCPAddr("tcp", addr)
  571. l.FatalErr(err)
  572. listener, err := net.ListenTCP("tcp", tcaddr)
  573. l.FatalErr(err)
  574. for {
  575. conn, err := listener.Accept()
  576. if err != nil {
  577. l.Warnln(err)
  578. continue
  579. }
  580. if debugNet {
  581. l.Debugln("connect from", conn.RemoteAddr())
  582. }
  583. tcpConn := conn.(*net.TCPConn)
  584. setTCPOptions(tcpConn)
  585. tc := tls.Server(conn, tlsCfg)
  586. err = tc.Handshake()
  587. if err != nil {
  588. l.Warnln(err)
  589. tc.Close()
  590. continue
  591. }
  592. conns <- tc
  593. }
  594. }
  595. func dialTLS(m *model.Model, conns chan *tls.Conn, tlsCfg *tls.Config) {
  596. var delay time.Duration = 1 * time.Second
  597. for {
  598. nextNode:
  599. for _, nodeCfg := range cfg.Nodes {
  600. if nodeCfg.NodeID == myID {
  601. continue
  602. }
  603. if m.ConnectedTo(nodeCfg.NodeID) {
  604. continue
  605. }
  606. var addrs []string
  607. for _, addr := range nodeCfg.Addresses {
  608. if addr == "dynamic" {
  609. if discoverer != nil {
  610. t := discoverer.Lookup(nodeCfg.NodeID)
  611. if len(t) == 0 {
  612. continue
  613. }
  614. addrs = append(addrs, t...)
  615. }
  616. } else {
  617. addrs = append(addrs, addr)
  618. }
  619. }
  620. for _, addr := range addrs {
  621. host, port, err := net.SplitHostPort(addr)
  622. if err != nil && strings.HasPrefix(err.Error(), "missing port") {
  623. // addr is on the form "1.2.3.4"
  624. addr = net.JoinHostPort(addr, "22000")
  625. } else if err == nil && port == "" {
  626. // addr is on the form "1.2.3.4:"
  627. addr = net.JoinHostPort(host, "22000")
  628. }
  629. if debugNet {
  630. l.Debugln("dial", nodeCfg.NodeID, addr)
  631. }
  632. raddr, err := net.ResolveTCPAddr("tcp", addr)
  633. if err != nil {
  634. if debugNet {
  635. l.Debugln(err)
  636. }
  637. continue
  638. }
  639. conn, err := net.DialTCP("tcp", nil, raddr)
  640. if err != nil {
  641. if debugNet {
  642. l.Debugln(err)
  643. }
  644. continue
  645. }
  646. setTCPOptions(conn)
  647. tc := tls.Client(conn, tlsCfg)
  648. err = tc.Handshake()
  649. if err != nil {
  650. l.Warnln(err)
  651. tc.Close()
  652. continue
  653. }
  654. conns <- tc
  655. continue nextNode
  656. }
  657. }
  658. time.Sleep(delay)
  659. delay *= 2
  660. if maxD := time.Duration(cfg.Options.ReconnectIntervalS) * time.Second; delay > maxD {
  661. delay = maxD
  662. }
  663. }
  664. }
  665. func setTCPOptions(conn *net.TCPConn) {
  666. var err error
  667. if err = conn.SetLinger(0); err != nil {
  668. l.Infoln(err)
  669. }
  670. if err = conn.SetNoDelay(false); err != nil {
  671. l.Infoln(err)
  672. }
  673. if err = conn.SetKeepAlivePeriod(60 * time.Second); err != nil {
  674. l.Infoln(err)
  675. }
  676. if err = conn.SetKeepAlive(true); err != nil {
  677. l.Infoln(err)
  678. }
  679. }
  680. func discovery(extPort int) *discover.Discoverer {
  681. disc, err := discover.NewDiscoverer(myID, cfg.Options.ListenAddress, cfg.Options.LocalAnnPort)
  682. if err != nil {
  683. l.Warnf("No discovery possible (%v)", err)
  684. return nil
  685. }
  686. if cfg.Options.LocalAnnEnabled {
  687. l.Infoln("Sending local discovery announcements")
  688. disc.StartLocal()
  689. }
  690. if cfg.Options.GlobalAnnEnabled {
  691. l.Infoln("Sending global discovery announcements")
  692. disc.StartGlobal(cfg.Options.GlobalAnnServer, uint16(extPort))
  693. }
  694. return disc
  695. }
  696. func ensureDir(dir string, mode int) {
  697. fi, err := os.Stat(dir)
  698. if os.IsNotExist(err) {
  699. err := os.MkdirAll(dir, 0700)
  700. l.FatalErr(err)
  701. } else if mode >= 0 && err == nil && int(fi.Mode()&0777) != mode {
  702. err := os.Chmod(dir, os.FileMode(mode))
  703. l.FatalErr(err)
  704. }
  705. }
  706. func getDefaultConfDir() string {
  707. switch runtime.GOOS {
  708. case "windows":
  709. return filepath.Join(os.Getenv("LocalAppData"), "Syncthing")
  710. case "darwin":
  711. return expandTilde("~/Library/Application Support/Syncthing")
  712. default:
  713. if xdgCfg := os.Getenv("XDG_CONFIG_HOME"); xdgCfg != "" {
  714. return filepath.Join(xdgCfg, "syncthing")
  715. } else {
  716. return expandTilde("~/.config/syncthing")
  717. }
  718. }
  719. }
  720. func expandTilde(p string) string {
  721. if p == "~" {
  722. return getHomeDir()
  723. }
  724. p = filepath.FromSlash(p)
  725. if !strings.HasPrefix(p, fmt.Sprintf("~%c", os.PathSeparator)) {
  726. return p
  727. }
  728. return filepath.Join(getHomeDir(), p[2:])
  729. }
  730. func getHomeDir() string {
  731. var home string
  732. switch runtime.GOOS {
  733. case "windows":
  734. home = filepath.Join(os.Getenv("HomeDrive"), os.Getenv("HomePath"))
  735. if home == "" {
  736. home = os.Getenv("UserProfile")
  737. }
  738. default:
  739. home = os.Getenv("HOME")
  740. }
  741. if home == "" {
  742. l.Fatalln("No home directory found - set $HOME (or the platform equivalent).")
  743. }
  744. return home
  745. }
  746. // getFreePort returns a free TCP port fort listening on. The ports given are
  747. // tried in succession and the first to succeed is returned. If none succeed,
  748. // a random high port is returned.
  749. func getFreePort(host string, ports ...int) (int, error) {
  750. for _, port := range ports {
  751. c, err := net.Listen("tcp", fmt.Sprintf("%s:%d", host, port))
  752. if err == nil {
  753. c.Close()
  754. return port, nil
  755. }
  756. }
  757. c, err := net.Listen("tcp", host+":0")
  758. if err != nil {
  759. return 0, err
  760. }
  761. addr := c.Addr().String()
  762. c.Close()
  763. _, portstr, err := net.SplitHostPort(addr)
  764. if err != nil {
  765. return 0, err
  766. }
  767. port, err := strconv.Atoi(portstr)
  768. if err != nil {
  769. return 0, err
  770. }
  771. return port, nil
  772. }