func Run()

in bootstrap.go [41:201]


func Run(ec *config.Extended, opts ...Option) {
	var (
		gl  config.Global
		err error
	)

	bl, err := zap.NewProduction()
	if err != nil {
		coreLog.Fatal(err)
	}
	bootstrapLogger := &log.Logger{
		Logger:    bl,
		PIDPath:   "",
		RemovePID: util.RemovePID,
	}

	util.PrintBanner()

	gl.CLI = config.ParseCliArgs(bootstrapLogger, d.ArachneService, d.ArachneVersion)
	apply(&gl, opts...)
	gl.App, err = config.Get(gl.CLI, ec, bootstrapLogger)
	if err != nil {
		bootstrapLogger.Error("error reading the configuration file",
			zap.String("file", *gl.CLI.ConfigFile),
			zap.Error(err))
		os.Exit(1)
	}

	logger, err := log.CreateLogger(gl.App.Logging, gl.App.PIDPath, util.RemovePID)
	if err != nil {
		bootstrapLogger.Fatal("unable to initialize Arachne Logger", zap.Error(err))
		os.Exit(1)
	}

	// Channel to be informed if Unix signal has been received.
	sigC := make(chan struct{}, 1)
	util.UnixSignals(sigC, logger)

	// Check if another Arachne process is already running.
	// Pass bootstrapLogger so that the arachne PID file is not removed.
	if err := util.CheckPID(gl.App.PIDPath, bootstrapLogger); err != nil {
		os.Exit(1)
	}

	sr, err := gl.App.Metrics.NewReporter(logger.Logger)
	if err != nil {
		logger.Error("error initializing stats", zap.Error(err))
	}

	// Hold raw socket connection for IPv4 packets
	var connIPv4 *ip.Conn

	logger.Info("Starting up arachne")

	for {
		var (
			err                 error
			currentDSCP         ip.DSCPValue
			dnsWg               sync.WaitGroup
			finishedCycleUpload sync.WaitGroup
		)

		// Channels to tell goroutines to terminate
		killC := new(util.KillChannels)

		// If Orchestrator mode enabled, fetch JSON configuration file, otherwise try
		// to retrieve default local file
		err = config.FetchRemoteList(&gl, d.MaxNumRemoteTargets, d.MaxNumSrcTCPPorts,
			d.MinBatchInterval, d.HTTPResponseHeaderTimeout, d.OrchestratorRESTConf, sigC, logger)
		if err != nil {
			break
		}
		logger.Debug("Global JSON configuration", zap.Any("configuration", gl.RemoteConfig))

		if len(gl.Remotes) == 0 {
			logger.Debug("No targets to be echoed have been specified")
			apply(&gl, ReceiverOnlyMode(true))
		}

		configRefresh := time.NewTicker(gl.RemoteConfig.PollOrchestratorInterval.Success)

		if gl.RemoteConfig.ResolveDNS && !*gl.CLI.ReceiverOnlyMode {
			// Refresh DNS resolutions
			dnsRefresh := time.NewTicker(d.DNSRefreshInterval)
			dnsWg.Add(1)
			killC.DNSRefresh = make(chan struct{})
			config.ResolveDNSTargets(gl.Remotes, gl.RemoteConfig, dnsRefresh, &dnsWg,
				killC.DNSRefresh, logger)
			dnsWg.Wait()
			logger.Debug("Remotes after DNS resolution include",
				zap.Int("count", len(gl.Remotes)),
				zap.Any("remotes", gl.Remotes))
		}

		// Channels for Collector to receive Probes and Responses from.
		sentC := make(chan tcp.Message, d.ChannelOutBufferSize)
		rcvdC := make(chan tcp.Message, d.ChannelInBufferSize)

		// Connection for IPv4 packets
		if connIPv4 == nil {
			connIPv4 = ip.NewConn(
				d.AfInet,
				gl.RemoteConfig.TargetTCPPort,
				gl.RemoteConfig.InterfaceName,
				gl.RemoteConfig.SrcAddress,
				logger)
		}

		// Actual echoing is a percentage of the total configured batch cycle duration.
		realBatchInterval := time.Duration(float32(gl.RemoteConfig.BatchInterval) *
			d.BatchIntervalEchoingPerc)
		uploadBatchInterval := time.Duration(float32(gl.RemoteConfig.BatchInterval) *
			d.BatchIntervalUploadStats)
		batchEndCycle := time.NewTicker(uploadBatchInterval)
		completeCycleUpload := make(chan bool, 1)

		if !*gl.CLI.SenderOnlyMode && !*gl.CLI.ReceiverOnlyMode {
			// Start gathering and reporting results.
			killC.Collector = make(chan struct{})
			collector.Run(&gl, sentC, rcvdC, gl.Remotes, &currentDSCP, sr, completeCycleUpload,
				&finishedCycleUpload, killC.Collector, logger)
		}

		if !*gl.CLI.SenderOnlyMode {
			// Listen for responses or probes from other IPv4 arachne agents.
			killC.Receiver = make(chan struct{})
			err = tcp.Receiver(connIPv4, sentC, rcvdC, killC.Receiver, logger)
			if err != nil {
				logger.Fatal("IPv4 receiver failed to start", zap.Error(err))
			}
			logger.Debug("IPv4 receiver now ready...")
			//TODO IPv6 receiver
		}

		if !*gl.CLI.ReceiverOnlyMode {
			logger.Debug("Echoing...")
			// Start echoing all targets.
			killC.Echo = make(chan struct{})
			tcp.EchoTargets(gl.Remotes, connIPv4, gl.RemoteConfig.TargetTCPPort,
				gl.RemoteConfig.SrcTCPPortRange, gl.RemoteConfig.QoSEnabled, &currentDSCP,
				realBatchInterval, batchEndCycle, sentC, *gl.CLI.SenderOnlyMode,
				completeCycleUpload, &finishedCycleUpload, killC.Echo, logger)
		}

		select {
		case <-configRefresh.C:
			util.CleanUpRefresh(killC, *gl.CLI.ReceiverOnlyMode,
				*gl.CLI.SenderOnlyMode, gl.RemoteConfig.ResolveDNS)
			log.ResetLogFiles(gl.App.Logging.OutputPaths, d.LogFileSizeMaxMB, d.LogFileSizeKeepKB, logger)
			logger.Info("Refreshing target list file, if needed")
			configRefresh.Stop()
		case <-sigC:
			logger.Debug("Received SIG")
			configRefresh.Stop()
			util.CleanUpAll(killC, *gl.CLI.ReceiverOnlyMode, *gl.CLI.SenderOnlyMode,
				gl.RemoteConfig.ResolveDNS, connIPv4, gl.App.PIDPath, sr, logger)
			logger.Info("Exiting")
			os.Exit(0)
		}
	}
}