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 }