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.

244 lines
5.1 KiB

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. "io"
  7. "sync/atomic"
  8. "time"
  9. . "github.com/tendermint/tendermint/binary"
  10. . "github.com/tendermint/tendermint/common"
  11. )
  12. var pexErrInvalidMessage = errors.New("Invalid PEX message")
  13. const (
  14. PexCh = "PEX"
  15. ensurePeersPeriodSeconds = 30
  16. minNumOutboundPeers = 10
  17. maxNumPeers = 50
  18. )
  19. /*
  20. PeerManager handles PEX (peer exchange) and ensures that an
  21. adequate number of peers are connected to the switch.
  22. */
  23. type PeerManager struct {
  24. sw *Switch
  25. book *AddrBook
  26. quit chan struct{}
  27. started uint32
  28. stopped uint32
  29. }
  30. func NewPeerManager(sw *Switch, book *AddrBook) *PeerManager {
  31. pm := &PeerManager{
  32. sw: sw,
  33. book: book,
  34. quit: make(chan struct{}),
  35. }
  36. return pm
  37. }
  38. func (pm *PeerManager) Start() {
  39. if atomic.CompareAndSwapUint32(&pm.started, 0, 1) {
  40. log.Info("Starting peerManager")
  41. go pm.ensurePeersHandler()
  42. go pm.pexHandler()
  43. }
  44. }
  45. func (pm *PeerManager) Stop() {
  46. if atomic.CompareAndSwapUint32(&pm.stopped, 0, 1) {
  47. log.Info("Stopping peerManager")
  48. close(pm.quit)
  49. }
  50. }
  51. // Ensures that sufficient peers are connected. (continuous)
  52. func (pm *PeerManager) ensurePeersHandler() {
  53. // fire once immediately.
  54. pm.ensurePeers()
  55. // fire periodically
  56. timer := NewRepeatTimer(ensurePeersPeriodSeconds * time.Second)
  57. FOR_LOOP:
  58. for {
  59. select {
  60. case <-timer.Ch:
  61. pm.ensurePeers()
  62. case <-pm.quit:
  63. break FOR_LOOP
  64. }
  65. }
  66. // Cleanup
  67. timer.Stop()
  68. }
  69. // Ensures that sufficient peers are connected. (once)
  70. func (pm *PeerManager) ensurePeers() {
  71. numOutPeers, _, numDialing := pm.sw.NumPeers()
  72. numToDial := minNumOutboundPeers - (numOutPeers + numDialing)
  73. if numToDial <= 0 {
  74. return
  75. }
  76. toDial := NewCMap()
  77. // Try to pick numToDial addresses to dial.
  78. // TODO: improve logic.
  79. for i := 0; i < numToDial; i++ {
  80. newBias := MinInt(numOutPeers, 8)*10 + 10
  81. var picked *NetAddress
  82. // Try to fetch a new peer 3 times.
  83. // This caps the maximum number of tries to 3 * numToDial.
  84. for j := 0; i < 3; j++ {
  85. picked = pm.book.PickAddress(newBias)
  86. if picked == nil {
  87. return
  88. }
  89. if toDial.Has(picked.String()) ||
  90. pm.sw.IsDialing(picked) ||
  91. pm.sw.Peers().Has(picked) {
  92. continue
  93. } else {
  94. break
  95. }
  96. }
  97. if picked == nil {
  98. continue
  99. }
  100. toDial.Set(picked.String(), picked)
  101. }
  102. // Dial picked addresses
  103. for _, item := range toDial.Values() {
  104. picked := item.(*NetAddress)
  105. go func() {
  106. _, err := pm.sw.DialPeerWithAddress(picked)
  107. if err != nil {
  108. pm.book.MarkAttempt(picked)
  109. }
  110. }()
  111. }
  112. }
  113. // Handles incoming Pex messages.
  114. func (pm *PeerManager) pexHandler() {
  115. for {
  116. inPkt := pm.sw.Receive(PexCh) // {Peer, Time, Packet}
  117. if inPkt == nil {
  118. // Client has stopped
  119. break
  120. }
  121. // decode message
  122. msg := decodeMessage(inPkt.Bytes)
  123. log.Info("pexHandler received %v", msg)
  124. switch msg.(type) {
  125. case *PexRequestMessage:
  126. // inPkt.Peer requested some peers.
  127. // TODO: prevent abuse.
  128. addrs := pm.book.GetSelection()
  129. response := &PexAddrsMessage{Addrs: addrs}
  130. pkt := NewPacket(PexCh, response)
  131. queued := inPkt.Peer.TrySend(pkt)
  132. if !queued {
  133. // ignore
  134. }
  135. case *PexAddrsMessage:
  136. // We received some peer addresses from inPkt.Peer.
  137. // TODO: prevent abuse.
  138. // (We don't want to get spammed with bad peers)
  139. srcAddr := inPkt.Peer.RemoteAddress()
  140. for _, addr := range msg.(*PexAddrsMessage).Addrs {
  141. pm.book.AddAddress(addr, srcAddr)
  142. }
  143. default:
  144. // Bad peer.
  145. pm.sw.StopPeerForError(inPkt.Peer, pexErrInvalidMessage)
  146. }
  147. }
  148. // Cleanup
  149. }
  150. //-----------------------------------------------------------------------------
  151. /* Messages */
  152. const (
  153. pexTypeUnknown = Byte(0x00)
  154. pexTypeRequest = Byte(0x01)
  155. pexTypeAddrs = Byte(0x02)
  156. )
  157. // TODO: check for unnecessary extra bytes at the end.
  158. func decodeMessage(bz ByteSlice) (msg Message) {
  159. // log.Debug("decoding msg bytes: %X", bz)
  160. switch Byte(bz[0]) {
  161. case pexTypeRequest:
  162. return &PexRequestMessage{}
  163. case pexTypeAddrs:
  164. return readPexAddrsMessage(bytes.NewReader(bz[1:]))
  165. default:
  166. return nil
  167. }
  168. }
  169. /*
  170. A PexRequestMessage requests additional peer addresses.
  171. */
  172. type PexRequestMessage struct {
  173. }
  174. // TODO: define NewPexRequestPacket instead?
  175. func NewPexRequestMessage() *PexRequestMessage {
  176. return &PexRequestMessage{}
  177. }
  178. func (m *PexRequestMessage) WriteTo(w io.Writer) (n int64, err error) {
  179. n, err = WriteOnto(pexTypeRequest, w, n, err)
  180. return
  181. }
  182. func (m *PexRequestMessage) String() string {
  183. return "[PexRequest]"
  184. }
  185. /*
  186. A message with announced peer addresses.
  187. */
  188. type PexAddrsMessage struct {
  189. Addrs []*NetAddress
  190. }
  191. func readPexAddrsMessage(r io.Reader) *PexAddrsMessage {
  192. numAddrs := int(ReadUInt32(r))
  193. addrs := []*NetAddress{}
  194. for i := 0; i < numAddrs; i++ {
  195. addr := ReadNetAddress(r)
  196. addrs = append(addrs, addr)
  197. }
  198. return &PexAddrsMessage{
  199. Addrs: addrs,
  200. }
  201. }
  202. func (m *PexAddrsMessage) WriteTo(w io.Writer) (n int64, err error) {
  203. n, err = WriteOnto(pexTypeAddrs, w, n, err)
  204. n, err = WriteOnto(UInt32(len(m.Addrs)), w, n, err)
  205. for _, addr := range m.Addrs {
  206. n, err = WriteOnto(addr, w, n, err)
  207. }
  208. return
  209. }
  210. func (m *PexAddrsMessage) String() string {
  211. return fmt.Sprintf("[PexAddrs %v]", m.Addrs)
  212. }