github.com/aergoio/aergo@v1.3.1/p2p/transport/networktransport.go (about)

     1  /*
     2   * @file
     3   * @copyright defined in aergo/LICENSE.txt
     4   */
     5  
     6  package transport
     7  
     8  import (
     9  	"context"
    10  	"fmt"
    11  	network2 "github.com/aergoio/aergo/internal/network"
    12  	"github.com/aergoio/aergo/types"
    13  	core "github.com/libp2p/go-libp2p-core"
    14  	"github.com/libp2p/go-libp2p-core/network"
    15  	"sync"
    16  	"time"
    17  
    18  	"github.com/aergoio/aergo-lib/log"
    19  	"github.com/aergoio/aergo/p2p/p2pcommon"
    20  	"github.com/aergoio/aergo/p2p/p2pkey"
    21  	"github.com/aergoio/aergo/p2p/p2putil"
    22  	"github.com/libp2p/go-libp2p-core/crypto"
    23  	"github.com/libp2p/go-libp2p-peerstore/pstoremem"
    24  
    25  	cfg "github.com/aergoio/aergo/config"
    26  	"github.com/libp2p/go-libp2p"
    27  	pstore "github.com/libp2p/go-libp2p-peerstore"
    28  	ma "github.com/multiformats/go-multiaddr"
    29  )
    30  
    31  /**
    32   * networkTransport connect to and listen from other nodes.
    33   * It implements  Component interface
    34   */
    35  type networkTransport struct {
    36  	core.Host
    37  	privateKey crypto.PrivKey
    38  
    39  	selfMeta    p2pcommon.PeerMeta
    40  	bindAddress string
    41  	bindPort    uint32
    42  
    43  	// hostInited is
    44  	hostInited *sync.WaitGroup
    45  
    46  	conf   *cfg.P2PConfig
    47  	logger *log.Logger
    48  }
    49  
    50  var _ p2pcommon.NetworkTransport = (*networkTransport)(nil)
    51  
    52  func (sl *networkTransport) SelfMeta() p2pcommon.PeerMeta {
    53  	return sl.selfMeta
    54  }
    55  
    56  func NewNetworkTransport(conf *cfg.P2PConfig, logger *log.Logger, internalService p2pcommon.InternalService) *networkTransport {
    57  	nt := &networkTransport{
    58  		conf:   conf,
    59  		logger: logger,
    60  
    61  		hostInited: &sync.WaitGroup{},
    62  	}
    63  	nt.initNT(internalService)
    64  
    65  	return nt
    66  }
    67  
    68  func (sl *networkTransport) initNT(internalService p2pcommon.InternalService) {
    69  	// check Key and address
    70  	sl.privateKey = p2pkey.NodePrivKey()
    71  	sl.selfMeta = internalService.SelfMeta()
    72  	// init address and port
    73  	// if not set, it look up ip addresses of machine and choose suitable one (but not so smart) and default port 7845
    74  	sl.initServiceBindAddress()
    75  
    76  	sl.hostInited.Add(1)
    77  
    78  	// set meta info
    79  	// TODO more survey libp2p NAT configuration
    80  }
    81  
    82  func (sl *networkTransport) initServiceBindAddress() {
    83  	bindAddr := sl.conf.NPBindAddr
    84  	// if bindAddress or bindPort is not set, it will be same as NetProtocolAddr or NetProtocolPort
    85  	if len(sl.conf.NPBindAddr) > 0 {
    86  		_, err := network2.GetSingleIPAddress(bindAddr)
    87  		if err != nil {
    88  			panic("invalid NPBindAddr " + sl.conf.NPBindAddr)
    89  		}
    90  		// check address connectivity
    91  		sl.bindAddress = bindAddr
    92  	} else {
    93  		// bind address and port will be overridden if configuration is specified
    94  		sl.bindAddress = sl.selfMeta.IPAddress
    95  	}
    96  	if sl.conf.NPBindPort > 0 {
    97  		sl.bindPort = uint32(sl.conf.NPBindPort)
    98  	} else {
    99  		sl.bindPort = sl.selfMeta.Port
   100  	}
   101  
   102  }
   103  
   104  func (sl *networkTransport) Start() error {
   105  	sl.logger.Debug().Msg("Starting network transport")
   106  	sl.startListener()
   107  	sl.hostInited.Done()
   108  	return nil
   109  }
   110  
   111  func (sl *networkTransport) AddStreamHandler(pid core.ProtocolID, handler network.StreamHandler) {
   112  	sl.hostInited.Wait()
   113  	sl.SetStreamHandler(pid, handler)
   114  }
   115  
   116  // GetOrCreateStream try to connect and handshake to remote peer. it can be called after peermanager is inited.
   117  // It return true if peer is added or return false if failed to add peer or more suitable connection already exists.
   118  func (sl *networkTransport) GetOrCreateStreamWithTTL(meta p2pcommon.PeerMeta, ttl time.Duration, protocolIDs ...core.ProtocolID) (core.Stream, error) {
   119  	var peerAddr, err = p2putil.PeerMetaToMultiAddr(meta)
   120  	if err != nil {
   121  		sl.logger.Warn().Err(err).Str("addr", meta.IPAddress).Msg("invalid NPAddPeer address")
   122  		return nil, fmt.Errorf("invalid IP address %s:%d", meta.IPAddress, meta.Port)
   123  	}
   124  	var peerID = meta.ID
   125  	sl.Peerstore().AddAddr(peerID, peerAddr, ttl)
   126  	ctx := context.Background()
   127  	s, err := sl.NewStream(ctx, meta.ID, protocolIDs...)
   128  	if err != nil {
   129  		sl.logger.Info().Err(err).Str("addr", meta.IPAddress).Str(p2putil.LogPeerID, p2putil.ShortForm(meta.ID)).Str("p2p_proto", p2putil.ProtocolIDsToString(protocolIDs)).Msg("Error while get stream")
   130  		return nil, err
   131  	}
   132  	return s, nil
   133  }
   134  
   135  func (sl *networkTransport) GetOrCreateStream(meta p2pcommon.PeerMeta, protocolIDs ...core.ProtocolID) (core.Stream, error) {
   136  	return sl.GetOrCreateStreamWithTTL(meta, getTTL(meta), protocolIDs...)
   137  }
   138  
   139  func (sl *networkTransport) FindPeer(peerID types.PeerID) bool {
   140  	found := false
   141  	for _, existingPeerID := range sl.Peerstore().Peers() {
   142  		if existingPeerID == peerID {
   143  			found = true
   144  			break
   145  		}
   146  	}
   147  	return found
   148  }
   149  
   150  // ClosePeerConnection find and Close Peer connection
   151  // It return true if peer is found
   152  func (sl *networkTransport) ClosePeerConnection(peerID types.PeerID) bool {
   153  	// also disconnect connection
   154  	for _, existingPeerID := range sl.Peerstore().Peers() {
   155  		if existingPeerID == peerID {
   156  			sl.Network().ClosePeer(peerID)
   157  			return true
   158  		}
   159  	}
   160  	return false
   161  }
   162  
   163  //
   164  //func (sl *networkTransport) Peerstore() pstore.Peerstore {
   165  //	return sl.Host.Peerstore()
   166  //}
   167  
   168  func (sl *networkTransport) startListener() {
   169  	var err error
   170  	listens := make([]ma.Multiaddr, 0, 2)
   171  	ipAddr, err := network2.GetSingleIPAddress(sl.bindAddress)
   172  	if err != nil {
   173  		panic("Can't establish listening address: " + err.Error())
   174  	}
   175  	listen, err := types.ToMultiAddr(ipAddr, sl.bindPort)
   176  	if err != nil {
   177  		panic("Can't establish listening address: " + err.Error())
   178  	}
   179  	listens = append(listens, listen)
   180  
   181  	peerStore := pstore.NewPeerstore(pstoremem.NewKeyBook(), pstoremem.NewAddrBook(), pstoremem.NewProtoBook(),pstoremem.NewPeerMetadata())
   182  
   183  	newHost, err := libp2p.New(context.Background(), libp2p.Identity(sl.privateKey), libp2p.Peerstore(peerStore), libp2p.ListenAddrs(listens...))
   184  	if err != nil {
   185  		sl.logger.Fatal().Err(err).Str("addr", listen.String()).Msg("Couldn't listen from")
   186  		panic(err.Error())
   187  	}
   188  	sl.Host = newHost
   189  	sl.logger.Info().Str(p2putil.LogFullID, sl.ID().Pretty()).Str(p2putil.LogPeerID, p2putil.ShortForm(sl.ID())).Str("addr[0]", listens[0].String()).Msg("Set self node's pid, and listening for connections")
   190  }
   191  
   192  func (sl *networkTransport) Stop() error {
   193  	return sl.Host.Close()
   194  }
   195  
   196  func (sl *networkTransport) GetAddressesOfPeer(peerID types.PeerID) []string {
   197  	addrs := sl.Peerstore().Addrs(peerID)
   198  	addrStrs := make([]string, len(addrs))
   199  	for i, addr := range addrs {
   200  		addrStrs[i] = addr.String()
   201  	}
   202  	return addrStrs
   203  }
   204  
   205  // TTL return node's ttl
   206  func getTTL(m p2pcommon.PeerMeta) time.Duration {
   207  	if m.Designated {
   208  		return p2pcommon.DesignatedNodeTTL
   209  	}
   210  	return p2pcommon.DefaultNodeTTL
   211  }