// threadedHandleConn reads header data from a connection, then routes it to the // appropriate handler for further processing. func (g *Gateway) threadedHandleConn(conn modules.PeerConn) { defer conn.Close() var id rpcID if err := encoding.ReadObject(conn, &id, 8); err != nil { return } // call registered handler for this ID lockid := g.mu.RLock() fn, ok := g.handlers[id] g.mu.RUnlock(lockid) if !ok { g.log.Printf("WARN: incoming conn %v requested unknown RPC \"%v\"", conn.RemoteAddr(), id) return } // call fn err := fn(conn) // don't log benign errors if err == modules.ErrDuplicateTransactionSet || err == modules.ErrBlockKnown { err = nil } if err != nil { g.log.Printf("WARN: incoming RPC \"%v\" failed: %v", id, err) } }
// requestNodes is the calling end of the ShareNodes RPC. func (g *Gateway) requestNodes(conn modules.PeerConn) error { var nodes []modules.NetAddress if err := encoding.ReadObject(conn, &nodes, maxSharedNodes*maxAddrLength); err != nil { return err } g.log.Printf("INFO: %v sent us %v nodes", conn.RemoteAddr(), len(nodes)) id := g.mu.Lock() for _, node := range nodes { g.addNode(node) } g.save() g.mu.Unlock(id) return nil }
// shareNodes is the receiving end of the ShareNodes RPC. It writes up to 10 // randomly selected nodes to the caller. func (g *Gateway) shareNodes(conn modules.PeerConn) error { conn.SetDeadline(time.Now().Add(connStdDeadline)) // Assemble a list of nodes to send to the peer. var nodes []modules.NetAddress func() { g.mu.RLock() defer g.mu.RUnlock() // Create a random permutation of nodes from the gateway to iterate // through. gnodes := make([]modules.NetAddress, 0, len(g.nodes)) for node := range g.nodes { gnodes = append(gnodes, node) } perm, err := crypto.Perm(len(g.nodes)) if err != nil { g.log.Severe("Unable to get random permutation for sharing nodes") } // Iterate through the random permutation of nodes and select the // desirable ones. remoteNA := modules.NetAddress(conn.RemoteAddr().String()) for _, i := range perm { // Don't share local peers with remote peers. That means that if 'node' // is loopback, it will only be shared if the remote peer is also // loopback. And if 'node' is private, it will only be shared if the // remote peer is either the loopback or is also private. node := gnodes[i] if node.IsLoopback() && !remoteNA.IsLoopback() { continue } if node.IsLocal() && !remoteNA.IsLocal() { continue } nodes = append(nodes, node) if uint64(len(nodes)) == maxSharedNodes { break } } }() return encoding.WriteObject(conn, nodes) }
// threadedHandleConn reads header data from a connection, then routes it to the // appropriate handler for further processing. func (g *Gateway) threadedHandleConn(conn modules.PeerConn) { defer conn.Close() var id rpcID if err := encoding.ReadObject(conn, &id, 8); err != nil { g.log.Printf("WARN: could not read RPC identifier from incoming conn %v: %v", conn.RemoteAddr(), err) return } // call registered handler for this ID lockid := g.mu.RLock() fn, ok := g.handlers[id] g.mu.RUnlock(lockid) if !ok { g.log.Printf("WARN: incoming conn %v requested unknown RPC \"%v\"", conn.RemoteAddr(), id) return } if err := fn(conn); err != nil { g.log.Printf("WARN: incoming RPC \"%v\" failed: %v", id, err) } }
// relayBlock is an RPC that accepts a block from a peer. func (cs *ConsensusSet) relayBlock(conn modules.PeerConn) error { // Decode the block from the connection. var b types.Block err := encoding.ReadObject(conn, &b, types.BlockSizeLimit) if err != nil { return err } // Submit the block to the consensus set. err = cs.AcceptBlock(b) if err == errOrphan { // If the block is an orphan, try to find the parents. The block // received from the peer is discarded and will be downloaded again if // the parent is found. go cs.gateway.RPC(modules.NetAddress(conn.RemoteAddr().String()), "SendBlocks", cs.threadedReceiveBlocks) } if err != nil { return err } return nil }