github.com/igggame/nebulas-go@v2.1.0+incompatible/net/node.go (about)

     1  // Copyright (C) 2017 go-nebulas authors
     2  //
     3  // This file is part of the go-nebulas library.
     4  //
     5  // the go-nebulas library is free software: you can redistribute it and/or modify
     6  // it under the terms of the GNU General Public License as published by
     7  // the Free Software Foundation, either version 3 of the License, or
     8  // (at your option) any later version.
     9  //
    10  // the go-nebulas library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    13  // GNU General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU General Public License
    16  // along with the go-nebulas library.  If not, see <http://www.gnu.org/licenses/>.
    17  //
    18  
    19  package net
    20  
    21  import (
    22  	"context"
    23  
    24  	"errors"
    25  	"fmt"
    26  	"net"
    27  
    28  	crypto "github.com/libp2p/go-libp2p-crypto"
    29  	libnet "github.com/libp2p/go-libp2p-net"
    30  	"github.com/libp2p/go-libp2p-peer"
    31  	swarm "github.com/libp2p/go-libp2p-swarm"
    32  	"github.com/libp2p/go-libp2p/p2p/host/basic"
    33  	multiaddr "github.com/multiformats/go-multiaddr"
    34  	"github.com/nebulasio/go-nebulas/util/logging"
    35  	"github.com/sirupsen/logrus"
    36  )
    37  
    38  const letterBytes = "0123456789ABCDEF0123456789ABCDE10123456789ABCDEF0123456789ABCDEF"
    39  
    40  const (
    41  	letterIdxBits = 6                    // 6 bits to represent a letter index
    42  	letterIdxMask = 1<<letterIdxBits - 1 // All 1-bits, as many as letterIdxBits
    43  	letterIdxMax  = 63 / letterIdxBits   // # of letter indices fitting in 63 bits
    44  )
    45  
    46  // Error types
    47  var (
    48  	ErrPeerIsNotConnected = errors.New("peer is not connected")
    49  )
    50  
    51  // Node the node can be used as both the client and the server
    52  type Node struct {
    53  	synchronizing bool
    54  	quitCh        chan bool
    55  	netService    *NebService
    56  	config        *Config
    57  	context       context.Context
    58  	id            peer.ID
    59  	networkKey    crypto.PrivKey
    60  	network       *swarm.Network
    61  	host          *basichost.BasicHost
    62  	streamManager *StreamManager
    63  	routeTable    *RouteTable
    64  }
    65  
    66  // NewNode return new Node according to the config.
    67  func NewNode(config *Config) (*Node, error) {
    68  	// check Listen port.
    69  	if err := checkPortAvailable(config.Listen); err != nil {
    70  		logging.CLog().WithFields(logrus.Fields{
    71  			"err":    err,
    72  			"listen": config.Listen,
    73  		}).Error("Failed to check port.")
    74  		return nil, err
    75  	}
    76  
    77  	node := &Node{
    78  		quitCh:        make(chan bool, 10),
    79  		config:        config,
    80  		context:       context.Background(),
    81  		streamManager: NewStreamManager(config),
    82  		synchronizing: false,
    83  	}
    84  
    85  	initP2PNetworkKey(config, node)
    86  	initP2PRouteTable(config, node)
    87  
    88  	if err := initP2PSwarmNetwork(config, node); err != nil {
    89  		return nil, err
    90  	}
    91  
    92  	return node, nil
    93  }
    94  
    95  // Start host & route table discovery
    96  func (node *Node) Start() error {
    97  	logging.CLog().Info("Starting NebService Node...")
    98  
    99  	node.streamManager.Start()
   100  
   101  	if err := node.startHost(); err != nil {
   102  		return err
   103  	}
   104  
   105  	node.routeTable.Start()
   106  
   107  	logging.CLog().WithFields(logrus.Fields{
   108  		"id":                node.ID(),
   109  		"listening address": node.host.Addrs(),
   110  	}).Info("Started NebService Node.")
   111  
   112  	return nil
   113  }
   114  
   115  // Stop stop a node.
   116  func (node *Node) Stop() {
   117  	logging.CLog().WithFields(logrus.Fields{
   118  		"id":                node.ID(),
   119  		"listening address": node.host.Addrs(),
   120  	}).Info("Stopping NebService Node...")
   121  
   122  	node.routeTable.Stop()
   123  	node.stopHost()
   124  	node.streamManager.Stop()
   125  }
   126  
   127  func (node *Node) startHost() error {
   128  	// add nat manager
   129  	options := &basichost.HostOpts{}
   130  	options.NATManager = basichost.NewNATManager(node.network)
   131  	host, err := basichost.NewHost(node.context, node.network, options)
   132  	if err != nil {
   133  		logging.CLog().WithFields(logrus.Fields{
   134  			"err":            err,
   135  			"listen address": node.config.Listen,
   136  		}).Error("Failed to start node.")
   137  		return err
   138  	}
   139  
   140  	host.SetStreamHandler(NebProtocolID, node.onStreamConnected)
   141  	node.host = host
   142  
   143  	return nil
   144  }
   145  
   146  func (node *Node) stopHost() {
   147  	node.network.Close()
   148  
   149  	if node.host == nil {
   150  		return
   151  	}
   152  
   153  	node.host.Close()
   154  }
   155  
   156  // Config return node config.
   157  func (node *Node) Config() *Config {
   158  	return node.config
   159  }
   160  
   161  // SetNebService set netService
   162  func (node *Node) SetNebService(ns *NebService) {
   163  	node.netService = ns
   164  }
   165  
   166  // ID return node ID.
   167  func (node *Node) ID() string {
   168  	return node.id.Pretty()
   169  }
   170  
   171  // IsSynchronizing return node synchronizing
   172  func (node *Node) IsSynchronizing() bool {
   173  	return node.synchronizing
   174  }
   175  
   176  // SetSynchronizing set node synchronizing.
   177  func (node *Node) SetSynchronizing(synchronizing bool) {
   178  	node.synchronizing = synchronizing
   179  }
   180  
   181  // PeersCount return stream count.
   182  func (node *Node) PeersCount() int32 {
   183  	return node.streamManager.Count()
   184  }
   185  
   186  // RouteTable return route table.
   187  func (node *Node) RouteTable() *RouteTable {
   188  	return node.routeTable
   189  }
   190  
   191  func initP2PNetworkKey(config *Config, node *Node) {
   192  	// init p2p network key.
   193  	networkKey, err := LoadNetworkKeyFromFileOrCreateNew(config.PrivateKeyPath)
   194  	if err != nil {
   195  		logging.CLog().WithFields(logrus.Fields{
   196  			"err":        err,
   197  			"NetworkKey": config.PrivateKeyPath,
   198  		}).Warn("Failed to load network private key from file.")
   199  	}
   200  
   201  	node.networkKey = networkKey
   202  	node.id, err = peer.IDFromPublicKey(networkKey.GetPublic())
   203  	if err != nil {
   204  		logging.CLog().WithFields(logrus.Fields{
   205  			"err":        err,
   206  			"NetworkKey": config.PrivateKeyPath,
   207  		}).Warn("Failed to generate ID from network key file.")
   208  	}
   209  }
   210  
   211  func initP2PRouteTable(config *Config, node *Node) error {
   212  	// init p2p route table.
   213  	node.routeTable = NewRouteTable(config, node)
   214  	return nil
   215  }
   216  
   217  func initP2PSwarmNetwork(config *Config, node *Node) error {
   218  	// init p2p multiaddr and swarm network.
   219  	multiaddrs := make([]multiaddr.Multiaddr, len(config.Listen))
   220  	for idx, v := range node.config.Listen {
   221  		tcpAddr, err := net.ResolveTCPAddr("tcp", v)
   222  		if err != nil {
   223  			logging.CLog().WithFields(logrus.Fields{
   224  				"err":    err,
   225  				"listen": v,
   226  			}).Error("Failed to bind node socket.")
   227  			return err
   228  		}
   229  
   230  		addr, err := multiaddr.NewMultiaddr(
   231  			fmt.Sprintf(
   232  				"/ip4/%s/tcp/%d",
   233  				tcpAddr.IP,
   234  				tcpAddr.Port,
   235  			),
   236  		)
   237  		if err != nil {
   238  			logging.CLog().WithFields(logrus.Fields{
   239  				"err":    err,
   240  				"listen": v,
   241  			}).Error("Failed to bind node socket.")
   242  			return err
   243  		}
   244  
   245  		multiaddrs[idx] = addr
   246  	}
   247  
   248  	network, err := swarm.NewNetwork(
   249  		node.context,
   250  		multiaddrs,
   251  		node.id,
   252  		node.routeTable.peerStore,
   253  		nil, // TODO: @robin integrate metrics.Reporter.
   254  	)
   255  	if err != nil {
   256  		logging.CLog().WithFields(logrus.Fields{
   257  			"err":            err,
   258  			"listen address": config.Listen,
   259  			"node.id":        node.id.Pretty(),
   260  		}).Error("Failed to create swarm network.")
   261  		return err
   262  	}
   263  	node.network = network
   264  	return nil
   265  }
   266  
   267  func (node *Node) onStreamConnected(s libnet.Stream) {
   268  	node.streamManager.Add(s, node)
   269  }
   270  
   271  // SendMessageToPeer send message to a peer.
   272  func (node *Node) SendMessageToPeer(messageName string, data []byte, priority int, peerID string) error {
   273  	stream := node.streamManager.FindByPeerID(peerID)
   274  	if stream == nil {
   275  		logging.VLog().WithFields(logrus.Fields{
   276  			"pid": peerID,
   277  			"err": ErrPeerIsNotConnected,
   278  		}).Debug("Failed to locate peer's stream")
   279  		return ErrPeerIsNotConnected
   280  	}
   281  
   282  	return stream.SendMessage(messageName, data, priority)
   283  }
   284  
   285  // BroadcastMessage broadcast message.
   286  func (node *Node) BroadcastMessage(messageName string, data Serializable, priority int) {
   287  	// node can not broadcast or relay message if it is in synchronizing.
   288  	if node.synchronizing {
   289  		return
   290  	}
   291  
   292  	node.streamManager.BroadcastMessage(messageName, data, priority)
   293  }
   294  
   295  // RelayMessage relay message.
   296  func (node *Node) RelayMessage(messageName string, data Serializable, priority int) {
   297  	// node can not broadcast or relay message if it is in synchronizing.
   298  	if node.synchronizing {
   299  		return
   300  	}
   301  
   302  	node.streamManager.RelayMessage(messageName, data, priority)
   303  }