github.com/avence12/go-ethereum@v1.5.10-0.20170320123548-1dfd65f6d047/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/ethereum/go-ethereum/common" 24 "github.com/ethereum/go-ethereum/log" 25 "github.com/ethereum/go-ethereum/p2p" 26 "github.com/ethereum/go-ethereum/rlp" 27 set "gopkg.in/fatih/set.v0" 28 ) 29 30 // peer represents a whisper protocol peer connection. 31 type Peer struct { 32 host *Whisper 33 peer *p2p.Peer 34 ws p2p.MsgReadWriter 35 trusted bool 36 37 known *set.Set // Messages already known by the peer to avoid wasting bandwidth 38 39 quit chan struct{} 40 } 41 42 // newPeer creates a new whisper peer object, but does not run the handshake itself. 43 func newPeer(host *Whisper, remote *p2p.Peer, rw p2p.MsgReadWriter) *Peer { 44 return &Peer{ 45 host: host, 46 peer: remote, 47 ws: rw, 48 trusted: false, 49 known: set.New(), 50 quit: make(chan struct{}), 51 } 52 } 53 54 // start initiates the peer updater, periodically broadcasting the whisper packets 55 // into the network. 56 func (p *Peer) start() { 57 go p.update() 58 log.Debug(fmt.Sprintf("%v: whisper started", p.peer)) 59 } 60 61 // stop terminates the peer updater, stopping message forwarding to it. 62 func (p *Peer) stop() { 63 close(p.quit) 64 log.Debug(fmt.Sprintf("%v: whisper stopped", p.peer)) 65 } 66 67 // handshake sends the protocol initiation status message to the remote peer and 68 // verifies the remote status too. 69 func (p *Peer) handshake() error { 70 // Send the handshake status message asynchronously 71 errc := make(chan error, 1) 72 go func() { 73 errc <- p2p.Send(p.ws, statusCode, ProtocolVersion) 74 }() 75 // Fetch the remote status packet and verify protocol match 76 packet, err := p.ws.ReadMsg() 77 if err != nil { 78 return err 79 } 80 if packet.Code != statusCode { 81 return fmt.Errorf("peer sent %x before status packet", packet.Code) 82 } 83 s := rlp.NewStream(packet.Payload, uint64(packet.Size)) 84 peerVersion, err := s.Uint() 85 if err != nil { 86 return fmt.Errorf("bad status message: %v", err) 87 } 88 if peerVersion != ProtocolVersion { 89 return fmt.Errorf("protocol version mismatch %d != %d", peerVersion, ProtocolVersion) 90 } 91 // Wait until out own status is consumed too 92 if err := <-errc; err != nil { 93 return fmt.Errorf("failed to send status packet: %v", err) 94 } 95 return nil 96 } 97 98 // update executes periodic operations on the peer, including message transmission 99 // and expiration. 100 func (p *Peer) update() { 101 // Start the tickers for the updates 102 expire := time.NewTicker(expirationCycle) 103 transmit := time.NewTicker(transmissionCycle) 104 105 // Loop and transmit until termination is requested 106 for { 107 select { 108 case <-expire.C: 109 p.expire() 110 111 case <-transmit.C: 112 if err := p.broadcast(); err != nil { 113 log.Info(fmt.Sprintf("%v: broadcast failed: %v", p.peer, err)) 114 return 115 } 116 117 case <-p.quit: 118 return 119 } 120 } 121 } 122 123 // mark marks an envelope known to the peer so that it won't be sent back. 124 func (peer *Peer) mark(envelope *Envelope) { 125 peer.known.Add(envelope.Hash()) 126 } 127 128 // marked checks if an envelope is already known to the remote peer. 129 func (peer *Peer) marked(envelope *Envelope) bool { 130 return peer.known.Has(envelope.Hash()) 131 } 132 133 // expire iterates over all the known envelopes in the host and removes all 134 // expired (unknown) ones from the known list. 135 func (peer *Peer) expire() { 136 unmark := make(map[common.Hash]struct{}) 137 peer.known.Each(func(v interface{}) bool { 138 if !peer.host.isEnvelopeCached(v.(common.Hash)) { 139 unmark[v.(common.Hash)] = struct{}{} 140 } 141 return true 142 }) 143 // Dump all known but no longer cached 144 for hash := range unmark { 145 peer.known.Remove(hash) 146 } 147 } 148 149 // broadcast iterates over the collection of envelopes and transmits yet unknown 150 // ones over the network. 151 func (p *Peer) broadcast() error { 152 // Fetch the envelopes and collect the unknown ones 153 envelopes := p.host.Envelopes() 154 transmit := make([]*Envelope, 0, len(envelopes)) 155 for _, envelope := range envelopes { 156 if !p.marked(envelope) { 157 transmit = append(transmit, envelope) 158 p.mark(envelope) 159 } 160 } 161 if len(transmit) == 0 { 162 return nil 163 } 164 // Transmit the unknown batch (potentially empty) 165 if err := p2p.Send(p.ws, messagesCode, transmit); err != nil { 166 return err 167 } 168 log.Trace(fmt.Sprint(p.peer, "broadcasted", len(transmit), "message(s)")) 169 return nil 170 } 171 172 func (p *Peer) ID() []byte { 173 id := p.peer.ID() 174 return id[:] 175 }