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 }