Exemplo n.º 1
0
func main() {
	_, err := flags.Parse(&opts)
	if err != nil {
		os.Exit(0)
	}
	if opts.Debug.TraceFile || opts.Debug.TraceIdx || opts.Debug.TraceNet || opts.Debug.LogSource {
		logger = log.New(os.Stderr, "", log.Lshortfile|log.Ldate|log.Ltime|log.Lmicroseconds)
	}
	if strings.HasPrefix(opts.ConfDir, "~/") {
		opts.ConfDir = strings.Replace(opts.ConfDir, "~", getHomeDir(), 1)
	}

	infoln("Version", Version)

	// Ensure that our home directory exists and that we have a certificate and key.

	ensureDir(opts.ConfDir, 0700)
	cert, err := loadCert(opts.ConfDir)
	if err != nil {
		newCertificate(opts.ConfDir)
		cert, err = loadCert(opts.ConfDir)
		fatalErr(err)
	}

	myID := string(certId(cert.Certificate[0]))
	infoln("My ID:", myID)

	if opts.Debug.Profiler != "" {
		go func() {
			err := http.ListenAndServe(opts.Debug.Profiler, nil)
			if err != nil {
				warnln(err)
			}
		}()
	}

	// The TLS configuration is used for both the listening socket and outgoing
	// connections.

	cfg := &tls.Config{
		ClientAuth:         tls.RequestClientCert,
		ServerName:         "syncthing",
		NextProtos:         []string{"bep/1.0"},
		InsecureSkipVerify: true,
		Certificates:       []tls.Certificate{cert},
	}

	// Load the configuration file, if it exists.

	cf, err := os.Open(path.Join(opts.ConfDir, confFileName))
	if err != nil {
		fatalln("No config file")
		config = ini.Config{}
	}
	config = ini.Parse(cf)
	cf.Close()

	var dir = config.Get("repository", "dir")

	// Create a map of desired node connections based on the configuration file
	// directives.

	for nodeID, addrs := range config.OptionMap("nodes") {
		addrs := strings.Fields(addrs)
		nodeAddrs[nodeID] = addrs
	}

	ensureDir(dir, -1)
	m := NewModel(dir)

	// Walk the repository and update the local model before establishing any
	// connections to other nodes.

	if !opts.Rehash {
		infoln("Loading index cache")
		loadIndex(m)
	}
	infoln("Populating repository index")
	updateLocalModel(m)

	// Routine to listen for incoming connections
	infoln("Listening for incoming connections")
	go listen(myID, opts.Listen, m, cfg)

	// Routine to connect out to configured nodes
	infoln("Attempting to connect to other nodes")
	go connect(myID, opts.Listen, nodeAddrs, m, cfg)

	// Routine to pull blocks from other nodes to synchronize the local
	// repository. Does not run when we are in read only (publish only) mode.
	if !opts.ReadOnly {
		infoln("Cleaning out incomplete synchronizations")
		CleanTempFiles(dir)
		okln("Ready to synchronize")
		m.Start()
	}

	// Periodically scan the repository and update the local model.
	// XXX: Should use some fsnotify mechanism.
	go func() {
		for {
			time.Sleep(opts.Advanced.ScanInterval)
			updateLocalModel(m)
		}
	}()

	select {}
}
Exemplo n.º 2
0
func main() {
	_, err := flags.Parse(&opts)
	if err != nil {
		if err, ok := err.(*flags.Error); ok {
			if err.Type == flags.ErrHelp {
				os.Exit(0)
			}
		}
		fatalln(err)
	}

	if opts.ShowVersion {
		fmt.Println(Version)
		os.Exit(0)
	}

	if len(os.Getenv("GOGC")) == 0 {
		debug.SetGCPercent(25)
	}

	if len(os.Getenv("GOMAXPROCS")) == 0 {
		runtime.GOMAXPROCS(runtime.NumCPU())
	}

	log.SetOutput(os.Stderr)
	logger = log.New(os.Stderr, "", log.Flags())
	if len(opts.Debug.TraceModel) > 0 || opts.Debug.LogSource {
		log.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds)
		logger.SetFlags(log.Lshortfile | log.Ldate | log.Ltime | log.Lmicroseconds)
	}
	opts.ConfDir = expandTilde(opts.ConfDir)

	infoln("Version", Version)

	// Ensure that our home directory exists and that we have a certificate and key.

	ensureDir(opts.ConfDir, 0700)
	cert, err := loadCert(opts.ConfDir)
	if err != nil {
		newCertificate(opts.ConfDir)
		cert, err = loadCert(opts.ConfDir)
		fatalErr(err)
	}

	myID = string(certId(cert.Certificate[0]))
	infoln("My ID:", myID)
	log.SetPrefix("[" + myID[0:5] + "] ")
	logger.SetPrefix("[" + myID[0:5] + "] ")

	if opts.Debug.Profiler != "" {
		go func() {
			err := http.ListenAndServe(opts.Debug.Profiler, nil)
			if err != nil {
				warnln(err)
			}
		}()
	}

	// The TLS configuration is used for both the listening socket and outgoing
	// connections.

	cfg := &tls.Config{
		Certificates:           []tls.Certificate{cert},
		NextProtos:             []string{"bep/1.0"},
		ServerName:             myID,
		ClientAuth:             tls.RequestClientCert,
		SessionTicketsDisabled: true,
		InsecureSkipVerify:     true,
		MinVersion:             tls.VersionTLS12,
	}

	// Load the configuration file, if it exists.

	cf, err := os.Open(path.Join(opts.ConfDir, confFileName))
	if err != nil {
		fatalln("No config file")
		config = ini.Config{}
	}
	config = ini.Parse(cf)
	cf.Close()

	var dir = expandTilde(config.Get("repository", "dir"))

	// Create a map of desired node connections based on the configuration file
	// directives.

	for nodeID, addrs := range config.OptionMap("nodes") {
		addrs := strings.Fields(addrs)
		nodeAddrs[nodeID] = addrs
	}

	ensureDir(dir, -1)
	m := model.NewModel(dir)
	for _, t := range opts.Debug.TraceModel {
		m.Trace(t)
	}
	if opts.Advanced.LimitRate > 0 {
		m.LimitRate(opts.Advanced.LimitRate)
	}

	// GUI
	if !opts.NoGUI && opts.GUIAddr != "" {
		host, port, err := net.SplitHostPort(opts.GUIAddr)
		if err != nil {
			warnf("Cannot start GUI on %q: %v", opts.GUIAddr, err)
		} else {
			if len(host) > 0 {
				infof("Starting web GUI on http://%s", opts.GUIAddr)
			} else {
				infof("Starting web GUI on port %s", port)
			}
			startGUI(opts.GUIAddr, m)
		}
	}

	// Walk the repository and update the local model before establishing any
	// connections to other nodes.

	if !opts.Rehash {
		infoln("Loading index cache")
		loadIndex(m)
	}
	infoln("Populating repository index")
	updateLocalModel(m)

	// Routine to listen for incoming connections
	infoln("Listening for incoming connections")
	go listen(myID, opts.Listen, m, cfg)

	// Routine to connect out to configured nodes
	infoln("Attempting to connect to other nodes")
	go connect(myID, opts.Listen, nodeAddrs, m, cfg)

	// Routine to pull blocks from other nodes to synchronize the local
	// repository. Does not run when we are in read only (publish only) mode.
	if !opts.ReadOnly {
		if opts.NoDelete {
			infoln("Deletes from peer nodes will be ignored")
		} else {
			infoln("Deletes from peer nodes are allowed")
		}
		okln("Ready to synchronize (read-write)")
		m.StartRW(!opts.NoDelete, opts.Advanced.RequestsInFlight)
	} else {
		okln("Ready to synchronize (read only; no external updates accepted)")
	}

	// Periodically scan the repository and update the local model.
	// XXX: Should use some fsnotify mechanism.
	go func() {
		for {
			time.Sleep(opts.Advanced.ScanInterval)
			if m.LocalAge() > opts.Advanced.ScanInterval.Seconds()/2 {
				updateLocalModel(m)
			}
		}
	}()

	if !opts.NoStats {
		// Periodically print statistics
		go printStatsLoop(m)
	}

	select {}
}