Skip to content
Snippets Groups Projects
autopeering.go 4.66 KiB
Newer Older
package autopeering

import (
	"encoding/base64"
	"fmt"
capossele's avatar
capossele committed
	"io/ioutil"
	"net"
capossele's avatar
capossele committed
	"net/http"
	"strconv"
capossele's avatar
capossele committed
	"time"

	"github.com/iotaledger/autopeering-sim/discover"
	"github.com/iotaledger/autopeering-sim/logger"
	"github.com/iotaledger/autopeering-sim/peer"
capossele's avatar
capossele committed
	"github.com/iotaledger/autopeering-sim/peer/service"
	"github.com/iotaledger/autopeering-sim/selection"
	"github.com/iotaledger/autopeering-sim/server"
	"github.com/iotaledger/autopeering-sim/transport"
capossele's avatar
capossele committed
	"github.com/iotaledger/goshimmer/plugins/autopeering/local"
capossele's avatar
capossele committed
	"github.com/iotaledger/goshimmer/plugins/gossip"
	"github.com/iotaledger/hive.go/parameter"
capossele's avatar
capossele committed
	"go.uber.org/zap"
	debugLevel = "debug"
	close      = make(chan struct{}, 1)
	srv        *server.Server
	Discovery  *discover.Protocol
	Selection  *selection.Protocol
)

const defaultZLC = `{
	"level": "info",
	"development": false,
capossele's avatar
capossele committed
	"outputPaths": ["stdout"],
	"errorOutputPaths": ["stderr"],
	"encoding": "console",
	"encoderConfig": {
	  "timeKey": "ts",
	  "levelKey": "level",
	  "nameKey": "logger",
	  "callerKey": "caller",
	  "messageKey": "msg",
	  "stacktraceKey": "stacktrace",
	  "lineEnding": "",
	  "levelEncoder": "",
	  "timeEncoder": "iso8601",
	  "durationEncoder": "",
	  "callerEncoder": ""
	}
  }`

capossele's avatar
capossele committed
var (
	db       peer.DB
	trans    *transport.TransportConn
	zLogger  *zap.SugaredLogger
	handlers []server.Handler
	conn     *net.UDPConn
)
capossele's avatar
capossele committed

capossele's avatar
capossele committed
func configureAP() {
	host := parameter.NodeConfig.GetString(CFG_ADDRESS)
capossele's avatar
capossele committed
	localhost := host
	apPort := strconv.Itoa(parameter.NodeConfig.GetInt(CFG_PORT))
	gossipPort := strconv.Itoa(parameter.NodeConfig.GetInt(gossip.GOSSIP_PORT))
	if host == "0.0.0.0" {
		host = getMyIP()
	}
capossele's avatar
capossele committed

capossele's avatar
capossele committed
	listenAddr := host + ":" + apPort
	gossipAddr := host + ":" + gossipPort
capossele's avatar
capossele committed
	zLogger = logger.NewLogger(defaultZLC, debugLevel)
capossele's avatar
capossele committed

capossele's avatar
capossele committed
	addr, err := net.ResolveUDPAddr("udp", localhost+":"+apPort)
	if err != nil {
		log.Fatalf("ResolveUDPAddr: %v", err)
	}
capossele's avatar
capossele committed
	conn, err = net.ListenUDP("udp", addr)
	if err != nil {
		log.Fatalf("ListenUDP: %v", err)
	}

	masterPeers := []*peer.Peer{}
	master, err := parseEntryNodes()
	if err != nil {
capossele's avatar
capossele committed
		log.Fatalf("Ignoring entry nodes: %v\n", err)
	} else if master != nil {
		masterPeers = master
	}

	// use the UDP connection for transport
capossele's avatar
capossele committed
	trans = transport.Conn(conn, func(network, address string) (net.Addr, error) { return net.ResolveUDPAddr(network, address) })

	// create a new local node
capossele's avatar
capossele committed
	db = peer.NewPersistentDB(zLogger.Named("db"))

capossele's avatar
capossele committed
	local.INSTANCE, err = peer.NewLocal("udp", listenAddr, db)
	if err != nil {
		log.Fatalf("ListenUDP: %v", err)
	}
capossele's avatar
capossele committed

	// add a service for the gossip
capossele's avatar
capossele committed
	if parameter.NodeConfig.GetBool(CFG_SELECTION) {
		local.INSTANCE.UpdateService(service.GossipKey, "tcp", gossipAddr)
	}
capossele's avatar
capossele committed
	Discovery = discover.New(local.INSTANCE, discover.Config{
capossele's avatar
capossele committed
		Log:         zLogger.Named("disc"),
		MasterPeers: masterPeers,
	})
capossele's avatar
capossele committed
	handlers = append([]server.Handler{}, Discovery)
capossele's avatar
capossele committed

	if parameter.NodeConfig.GetBool(CFG_SELECTION) {
		Selection = selection.New(local.INSTANCE, Discovery, selection.Config{
capossele's avatar
capossele committed
			Log: zLogger.Named("sel"),
capossele's avatar
capossele committed
			Param: &selection.Parameters{
capossele's avatar
capossele committed
				SaltLifetime:    selection.DefaultSaltLifetime,
				RequiredService: []service.Key{service.GossipKey},
capossele's avatar
capossele committed
			},
		})
		handlers = append(handlers, Selection)
	}
capossele's avatar
capossele committed
func start() {
	// start a server doing discovery and peering
capossele's avatar
capossele committed
	srv = server.Listen(local.INSTANCE, trans, zLogger.Named("srv"), handlers...)

	// start the discovery on that connection
	Discovery.Start(srv)

	// start the peering on that connection
capossele's avatar
capossele committed
	if parameter.NodeConfig.GetBool(CFG_SELECTION) {
		Selection.Start(srv)
		defer Selection.Close()
	}
capossele's avatar
capossele committed
	id := base64.StdEncoding.EncodeToString(local.INSTANCE.PublicKey())
capossele's avatar
capossele committed
	zLogger.Info("Discovery protocol started: ID=" + id + ", address=" + srv.LocalAddr())

	defer func() {
		_ = zLogger.Sync() // ignore the returned error
		trans.Close()
		db.Close()
		conn.Close()
		srv.Close()
		Discovery.Close()
	}()
capossele's avatar
capossele committed
	// Only for debug
capossele's avatar
capossele committed
	go func() {
		for t := range time.NewTicker(2 * time.Second).C {
			_ = t
capossele's avatar
capossele committed
			printReport(zLogger)
capossele's avatar
capossele committed
func getMyIP() string {
	url := "https://api.ipify.org?format=text"
	resp, err := http.Get(url)
	if err != nil {
		return ""
	}
	defer resp.Body.Close()
	ip, err := ioutil.ReadAll(resp.Body)
	if err != nil {
		return ""
	}
	return fmt.Sprintf("%s", ip)
}
capossele's avatar
capossele committed

capossele's avatar
capossele committed
// used only for debugging puropose
capossele's avatar
capossele committed
func printReport(log *zap.SugaredLogger) {
	if Discovery == nil || Selection == nil {
		return
	}
	knownPeers := Discovery.GetVerifiedPeers()
capossele's avatar
capossele committed
	incoming := []*peer.Peer{}
	outgoing := []*peer.Peer{}
	if Selection != nil {
		incoming = Selection.GetIncomingNeighbors()
		outgoing = Selection.GetOutgoingNeighbors()
	}
capossele's avatar
capossele committed
	log.Info("Known peers:", len(knownPeers))
capossele's avatar
capossele committed
	log.Info("Chosen:", len(outgoing))
	log.Info("Accepted:", len(incoming))
}