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.

262 lines
6.2 KiB

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