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.

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