You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

258 lines
6.2 KiB

9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
prevent nil addr Error: ``` Error: runtime error: invalid memoryaddress or nil pointer dereference\nStack: goroutine 549 [running]:\nruntime/debug.Stack(0x0, 0x0, 0x0)\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x80\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection)._recover(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:173 +0x53\npanic(0xbe1500, 0xc820012080)\n\t/usr/local/go/src/runtime/panic.go:443 +0x4e9\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Valid(0x0, 0x0)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:125 +0x1c\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Routable(0x0, 0xc8217bb740)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:117 +0x25\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).addAddress(0xc820108380, 0x0, 0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:524 +0x45\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).AddAddress(0xc820108380, 0x0, 0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:160 +0x286\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*PEXReactor).Receive(0xc82000be60, 0xc820149f00, 0xc8218163f0, 0xc82184e000, 0x5b, 0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/pex_reactor.go:109 +0x457\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.newPeer.func1(0xc82011d500, 0xc82184e000, 0x5b, 0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/peer.go:58 +0x202\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).recvRoutine(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:439 +0x1177\ncreated by github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).OnStart\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:138 +0x1a1\n ```
8 years ago
prevent nil addr Error: ``` Error: runtime error: invalid memoryaddress or nil pointer dereference\nStack: goroutine 549 [running]:\nruntime/debug.Stack(0x0, 0x0, 0x0)\n\t/usr/local/go/src/runtime/debug/stack.go:24 +0x80\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection)._recover(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:173 +0x53\npanic(0xbe1500, 0xc820012080)\n\t/usr/local/go/src/runtime/panic.go:443 +0x4e9\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Valid(0x0, 0x0)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:125 +0x1c\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*NetAddress).Routable(0x0, 0xc8217bb740)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/netaddress.go:117 +0x25\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).addAddress(0xc820108380, 0x0, 0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:524 +0x45\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*AddrBook).AddAddress(0xc820108380, 0x0, 0xc821739590)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/addrbook.go:160 +0x286\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*PEXReactor).Receive(0xc82000be60, 0xc820149f00, 0xc8218163f0, 0xc82184e000, 0x5b, 0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/pex_reactor.go:109 +0x457\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.newPeer.func1(0xc82011d500, 0xc82184e000, 0x5b, 0x1000)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/peer.go:58 +0x202\ngithub.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).recvRoutine(0xc821723b00)\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:439 +0x1177\ncreated by github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p.(*MConnection).OnStart\n\t/go/src/github.com/tendermint/tendermint/vendor/github.com/tendermint/go-p2p/connection.go:138 +0x1a1\n ```
8 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
9 years ago
  1. package p2p
  2. import (
  3. "bytes"
  4. "fmt"
  5. "math/rand"
  6. "reflect"
  7. "time"
  8. . "github.com/tendermint/go-common"
  9. wire "github.com/tendermint/go-wire"
  10. )
  11. const (
  12. PexChannel = byte(0x00)
  13. ensurePeersPeriodSeconds = 30
  14. minNumOutboundPeers = 10
  15. maxPexMessageSize = 1048576 // 1MB
  16. )
  17. // PEXReactor handles PEX (peer exchange) and ensures that an
  18. // adequate number of peers are connected to the switch.
  19. type PEXReactor struct {
  20. BaseReactor
  21. sw *Switch
  22. book *AddrBook
  23. }
  24. func NewPEXReactor(b *AddrBook) *PEXReactor {
  25. r := &PEXReactor{
  26. book: b,
  27. }
  28. r.BaseReactor = *NewBaseReactor(log, "PEXReactor", r)
  29. return r
  30. }
  31. func (r *PEXReactor) OnStart() error {
  32. r.BaseReactor.OnStart()
  33. r.book.Start()
  34. go r.ensurePeersRoutine()
  35. return nil
  36. }
  37. func (r *PEXReactor) OnStop() {
  38. r.BaseReactor.OnStop()
  39. r.book.Stop()
  40. }
  41. // GetChannels implements Reactor
  42. func (r *PEXReactor) GetChannels() []*ChannelDescriptor {
  43. return []*ChannelDescriptor{
  44. &ChannelDescriptor{
  45. ID: PexChannel,
  46. Priority: 1,
  47. SendQueueCapacity: 10,
  48. },
  49. }
  50. }
  51. // AddPeer implements Reactor by adding peer to the address book (if inbound)
  52. // or by requesting more addresses (if outbound).
  53. func (r *PEXReactor) AddPeer(p *Peer) {
  54. netAddr, err := NewNetAddressString(p.ListenAddr)
  55. if err != nil {
  56. // this should never happen
  57. log.Error("Error in AddPeer: invalid peer address", "addr", p.ListenAddr, "error", err)
  58. return
  59. }
  60. if p.IsOutbound() { // For outbound peers, the address is already in the books
  61. if r.book.NeedMoreAddrs() {
  62. r.RequestPEX(p)
  63. }
  64. } else { // For inbound connections, the peer is its own source
  65. r.book.AddAddress(netAddr, netAddr)
  66. }
  67. }
  68. // RemovePeer implements Reactor
  69. func (r *PEXReactor) RemovePeer(p *Peer, reason interface{}) {
  70. // TODO
  71. }
  72. // Receive implements Reactor by handling incoming PEX messages.
  73. func (r *PEXReactor) Receive(chID byte, src *Peer, msgBytes []byte) {
  74. _, msg, err := DecodeMessage(msgBytes)
  75. if err != nil {
  76. log.Warn("Error decoding message", "error", err)
  77. return
  78. }
  79. log.Notice("Received message", "msg", msg)
  80. switch msg := msg.(type) {
  81. case *pexRequestMessage:
  82. // src requested some peers.
  83. // TODO: prevent abuse.
  84. r.SendAddrs(src, r.book.GetSelection())
  85. case *pexAddrsMessage:
  86. // We received some peer addresses from src.
  87. // TODO: prevent abuse.
  88. // (We don't want to get spammed with bad peers)
  89. srcAddr := src.Connection().RemoteAddress
  90. for _, addr := range msg.Addrs {
  91. if addr != nil {
  92. r.book.AddAddress(addr, srcAddr)
  93. }
  94. }
  95. default:
  96. log.Warn(Fmt("Unknown message type %v", reflect.TypeOf(msg)))
  97. }
  98. }
  99. // RequestPEX asks peer for more addresses.
  100. func (r *PEXReactor) RequestPEX(p *Peer) {
  101. p.Send(PexChannel, struct{ PexMessage }{&pexRequestMessage{}})
  102. }
  103. // SendAddrs sends addrs to the peer.
  104. func (r *PEXReactor) SendAddrs(p *Peer, addrs []*NetAddress) {
  105. p.Send(PexChannel, struct{ PexMessage }{&pexAddrsMessage{Addrs: addrs}})
  106. }
  107. // Ensures that sufficient peers are connected. (continuous)
  108. func (r *PEXReactor) ensurePeersRoutine() {
  109. // Randomize when routine starts
  110. time.Sleep(time.Duration(rand.Int63n(500*ensurePeersPeriodSeconds)) * time.Millisecond)
  111. // fire once immediately.
  112. r.ensurePeers()
  113. // fire periodically
  114. timer := NewRepeatTimer("pex", ensurePeersPeriodSeconds*time.Second)
  115. FOR_LOOP:
  116. for {
  117. select {
  118. case <-timer.Ch:
  119. r.ensurePeers()
  120. case <-r.Quit:
  121. break FOR_LOOP
  122. }
  123. }
  124. // Cleanup
  125. timer.Stop()
  126. }
  127. // Ensures that sufficient peers are connected. (once)
  128. func (r *PEXReactor) ensurePeers() {
  129. numOutPeers, _, numDialing := r.Switch.NumPeers()
  130. numToDial := minNumOutboundPeers - (numOutPeers + numDialing)
  131. log.Info("Ensure peers", "numOutPeers", numOutPeers, "numDialing", numDialing, "numToDial", numToDial)
  132. if numToDial <= 0 {
  133. return
  134. }
  135. toDial := NewCMap()
  136. // Try to pick numToDial addresses to dial.
  137. // TODO: improve logic.
  138. for i := 0; i < numToDial; i++ {
  139. newBias := MinInt(numOutPeers, 8)*10 + 10
  140. var picked *NetAddress
  141. // Try to fetch a new peer 3 times.
  142. // This caps the maximum number of tries to 3 * numToDial.
  143. for j := 0; j < 3; j++ {
  144. try := r.book.PickAddress(newBias)
  145. if try == nil {
  146. break
  147. }
  148. alreadySelected := toDial.Has(try.IP.String())
  149. alreadyDialing := r.Switch.IsDialing(try)
  150. alreadyConnected := r.Switch.Peers().Has(try.IP.String())
  151. if alreadySelected || alreadyDialing || alreadyConnected {
  152. /*
  153. log.Info("Cannot dial address", "addr", try,
  154. "alreadySelected", alreadySelected,
  155. "alreadyDialing", alreadyDialing,
  156. "alreadyConnected", alreadyConnected)
  157. */
  158. continue
  159. } else {
  160. log.Info("Will dial address", "addr", try)
  161. picked = try
  162. break
  163. }
  164. }
  165. if picked == nil {
  166. continue
  167. }
  168. toDial.Set(picked.IP.String(), picked)
  169. }
  170. // Dial picked addresses
  171. for _, item := range toDial.Values() {
  172. go func(picked *NetAddress) {
  173. _, err := r.Switch.DialPeerWithAddress(picked, false)
  174. if err != nil {
  175. r.book.MarkAttempt(picked)
  176. }
  177. }(item.(*NetAddress))
  178. }
  179. // If we need more addresses, pick a random peer and ask for more.
  180. if r.book.NeedMoreAddrs() {
  181. if peers := r.Switch.Peers().List(); len(peers) > 0 {
  182. i := rand.Int() % len(peers)
  183. peer := peers[i]
  184. log.Info("No addresses to dial. Sending pexRequest to random peer", "peer", peer)
  185. r.RequestPEX(peer)
  186. }
  187. }
  188. }
  189. //-----------------------------------------------------------------------------
  190. // Messages
  191. const (
  192. msgTypeRequest = byte(0x01)
  193. msgTypeAddrs = byte(0x02)
  194. )
  195. type PexMessage interface{}
  196. var _ = wire.RegisterInterface(
  197. struct{ PexMessage }{},
  198. wire.ConcreteType{&pexRequestMessage{}, msgTypeRequest},
  199. wire.ConcreteType{&pexAddrsMessage{}, msgTypeAddrs},
  200. )
  201. func DecodeMessage(bz []byte) (msgType byte, msg PexMessage, err error) {
  202. msgType = bz[0]
  203. n := new(int)
  204. r := bytes.NewReader(bz)
  205. msg = wire.ReadBinary(struct{ PexMessage }{}, r, maxPexMessageSize, n, &err).(struct{ PexMessage }).PexMessage
  206. return
  207. }
  208. /*
  209. A pexRequestMessage requests additional peer addresses.
  210. */
  211. type pexRequestMessage struct {
  212. }
  213. func (m *pexRequestMessage) String() string {
  214. return "[pexRequest]"
  215. }
  216. /*
  217. A message with announced peer addresses.
  218. */
  219. type pexAddrsMessage struct {
  220. Addrs []*NetAddress
  221. }
  222. func (m *pexAddrsMessage) String() string {
  223. return fmt.Sprintf("[pexAddrs %v]", m.Addrs)
  224. }