github.com/n1ghtfa1l/go-vnt@v0.6.4-alpha.6/whisper/whisperv5/peer.go (about) 1 // Copyright 2016 The go-ethereum Authors 2 // This file is part of the go-ethereum library. 3 // 4 // The go-ethereum library is free software: you can redistribute it and/or modify 5 // it under the terms of the GNU Lesser General Public License as published by 6 // the Free Software Foundation, either version 3 of the License, or 7 // (at your option) any later version. 8 // 9 // The go-ethereum library is distributed in the hope that it will be useful, 10 // but WITHOUT ANY WARRANTY; without even the implied warranty of 11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 // GNU Lesser General Public License for more details. 13 // 14 // You should have received a copy of the GNU Lesser General Public License 15 // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. 16 17 package whisperv5 18 19 import ( 20 "fmt" 21 "time" 22 23 "github.com/vntchain/go-vnt/common" 24 "github.com/vntchain/go-vnt/log" 25 "github.com/vntchain/go-vnt/rlp" 26 "github.com/vntchain/go-vnt/vntp2p" 27 set "gopkg.in/fatih/set.v0" 28 29 libp2p "github.com/libp2p/go-libp2p-peer" 30 ) 31 32 // Peer represents a whisper protocol peer connection. 33 type Peer struct { 34 host *Whisper 35 peer *vntp2p.Peer 36 ws vntp2p.MsgReadWriter 37 trusted bool 38 39 known *set.Set // Messages already known by the peer to avoid wasting bandwidth 40 41 quit chan struct{} 42 } 43 44 // newPeer creates a new whisper peer object, but does not run the handshake itself. 45 func newPeer(host *Whisper, remote *vntp2p.Peer, rw vntp2p.MsgReadWriter) *Peer { 46 return &Peer{ 47 host: host, 48 peer: remote, 49 ws: rw, 50 trusted: false, 51 known: set.New(), 52 quit: make(chan struct{}), 53 } 54 } 55 56 // start initiates the peer updater, periodically broadcasting the whisper packets 57 // into the network. 58 func (peer *Peer) start() { 59 go peer.update() 60 log.Trace("start", "peer", peer.ID()) 61 } 62 63 // stop terminates the peer updater, stopping message forwarding to it. 64 func (peer *Peer) stop() { 65 close(peer.quit) 66 log.Trace("stop", "peer", peer.ID()) 67 } 68 69 // handshake sends the protocol initiation status message to the remote peer and 70 // verifies the remote status too. 71 func (peer *Peer) handshake() error { 72 // Send the handshake status message asynchronously 73 errc := make(chan error, 1) 74 go func() { 75 errc <- vntp2p.Send(peer.ws, ProtocolName, statusCode, ProtocolVersion) 76 }() 77 // Fetch the remote status packet and verify protocol match 78 packet, err := peer.ws.ReadMsg() 79 if err != nil { 80 return err 81 } 82 if packet.Body.Type != statusCode { 83 return fmt.Errorf("peer [%x] sent packet %x before status packet", peer.ID(), packet.Body.Type) 84 } 85 s := rlp.NewStream(packet.Body.Payload, uint64(packet.Body.PayloadSize)) 86 peerVersion, err := s.Uint() 87 if err != nil { 88 return fmt.Errorf("peer [%x] sent bad status message: %v", peer.ID(), err) 89 } 90 if peerVersion != ProtocolVersion { 91 return fmt.Errorf("peer [%x]: protocol version mismatch %d != %d", peer.ID(), peerVersion, ProtocolVersion) 92 } 93 // Wait until out own status is consumed too 94 if err := <-errc; err != nil { 95 return fmt.Errorf("peer [%x] failed to send status packet: %v", peer.ID(), err) 96 } 97 return nil 98 } 99 100 // update executes periodic operations on the peer, including message transmission 101 // and expiration. 102 func (peer *Peer) update() { 103 // Start the tickers for the updates 104 expire := time.NewTicker(expirationCycle) 105 transmit := time.NewTicker(transmissionCycle) 106 107 // Loop and transmit until termination is requested 108 for { 109 select { 110 case <-expire.C: 111 peer.expire() 112 113 case <-transmit.C: 114 if err := peer.broadcast(); err != nil { 115 log.Trace("broadcast failed", "reason", err, "peer", peer.ID()) 116 return 117 } 118 119 case <-peer.quit: 120 return 121 } 122 } 123 } 124 125 // mark marks an envelope known to the peer so that it won't be sent back. 126 func (peer *Peer) mark(envelope *Envelope) { 127 peer.known.Add(envelope.Hash()) 128 } 129 130 // marked checks if an envelope is already known to the remote peer. 131 func (peer *Peer) marked(envelope *Envelope) bool { 132 return peer.known.Has(envelope.Hash()) 133 } 134 135 // expire iterates over all the known envelopes in the host and removes all 136 // expired (unknown) ones from the known list. 137 func (peer *Peer) expire() { 138 unmark := make(map[common.Hash]struct{}) 139 peer.known.Each(func(v interface{}) bool { 140 if !peer.host.isEnvelopeCached(v.(common.Hash)) { 141 unmark[v.(common.Hash)] = struct{}{} 142 } 143 return true 144 }) 145 // Dump all known but no longer cached 146 for hash := range unmark { 147 peer.known.Remove(hash) 148 } 149 } 150 151 // broadcast iterates over the collection of envelopes and transmits yet unknown 152 // ones over the network. 153 func (peer *Peer) broadcast() error { 154 var cnt int 155 envelopes := peer.host.Envelopes() 156 for _, envelope := range envelopes { 157 if !peer.marked(envelope) { 158 err := vntp2p.Send(peer.ws, ProtocolName, messagesCode, envelope) 159 if err != nil { 160 return err 161 } else { 162 peer.mark(envelope) 163 cnt++ 164 } 165 } 166 } 167 if cnt > 0 { 168 log.Trace("broadcast", "num. messages", cnt) 169 } 170 return nil 171 } 172 173 func (peer *Peer) ID() libp2p.ID { 174 id := peer.peer.RemoteID() 175 return id 176 }