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.

239 lines
5.0 KiB

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