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.

235 lines
5.4 KiB

10 years ago
11 years ago
10 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
11 years ago
10 years ago
10 years ago
10 years ago
  1. package p2p
  2. import (
  3. "errors"
  4. "net"
  5. "sync/atomic"
  6. "time"
  7. . "github.com/tendermint/tendermint/binary"
  8. . "github.com/tendermint/tendermint/common"
  9. )
  10. type Reactor interface {
  11. GetChannels() []*ChannelDescriptor
  12. AddPeer(peer *Peer)
  13. RemovePeer(peer *Peer, reason interface{})
  14. Receive(chId byte, peer *Peer, msgBytes []byte)
  15. }
  16. //-----------------------------------------------------------------------------
  17. /*
  18. All communication amongst peers are multiplexed by "channels".
  19. (Not the same as Go "channels")
  20. To send a message, serialize it into a ByteSlice and send it to each peer.
  21. For best performance, re-use the same immutable ByteSlice to each peer.
  22. You can also use a TypedBytes{} struct for convenience.
  23. You can find all connected and active peers by iterating over ".Peers().List()".
  24. ".Broadcast()" is provided for convenience, but by iterating over
  25. the peers manually the caller can decide which subset receives a message.
  26. Inbound messages are received by calling ".Receive()".
  27. The receiver is responsible for decoding the message bytes, which may be preceded
  28. by a single type byte if a TypedBytes{} was used.
  29. */
  30. type Switch struct {
  31. reactors []Reactor
  32. chDescs []*ChannelDescriptor
  33. reactorsByCh map[byte]Reactor
  34. peers *PeerSet
  35. dialing *CMap
  36. listeners *CMap // listenerName -> chan interface{}
  37. quit chan struct{}
  38. started uint32
  39. stopped uint32
  40. }
  41. var (
  42. ErrSwitchStopped = errors.New("Switch already stopped")
  43. ErrSwitchDuplicatePeer = errors.New("Duplicate peer")
  44. )
  45. const (
  46. peerDialTimeoutSeconds = 30
  47. )
  48. func NewSwitch(reactors []Reactor) *Switch {
  49. // Validate the reactors. no two reactors can share the same channel.
  50. chDescs := []*ChannelDescriptor{}
  51. reactorsByCh := make(map[byte]Reactor)
  52. for _, reactor := range reactors {
  53. reactorChannels := reactor.GetChannels()
  54. for _, chDesc := range reactorChannels {
  55. chId := chDesc.Id
  56. if reactorsByCh[chId] != nil {
  57. Panicf("Channel %X has multiple reactors %v & %v", chId, reactorsByCh[chId], reactor)
  58. }
  59. chDescs = append(chDescs, chDesc)
  60. reactorsByCh[chId] = reactor
  61. }
  62. }
  63. s := &Switch{
  64. reactors: reactors,
  65. chDescs: chDescs,
  66. reactorsByCh: reactorsByCh,
  67. peers: NewPeerSet(),
  68. dialing: NewCMap(),
  69. listeners: NewCMap(),
  70. quit: make(chan struct{}),
  71. stopped: 0,
  72. }
  73. return s
  74. }
  75. func (s *Switch) Start() {
  76. if atomic.CompareAndSwapUint32(&s.started, 0, 1) {
  77. log.Info("Starting switch")
  78. }
  79. }
  80. func (s *Switch) Stop() {
  81. if atomic.CompareAndSwapUint32(&s.stopped, 0, 1) {
  82. log.Info("Stopping switch")
  83. close(s.quit)
  84. // stop each peer.
  85. for _, peer := range s.peers.List() {
  86. peer.stop()
  87. }
  88. // empty tree.
  89. s.peers = NewPeerSet()
  90. }
  91. }
  92. func (s *Switch) AddPeerWithConnection(conn net.Conn, outbound bool) (*Peer, error) {
  93. if atomic.LoadUint32(&s.stopped) == 1 {
  94. return nil, ErrSwitchStopped
  95. }
  96. peer := newPeer(conn, outbound, s.reactorsByCh, s.chDescs, s.StopPeerForError)
  97. // Add the peer to .peers
  98. if s.peers.Add(peer) {
  99. log.Info("+ %v", peer)
  100. } else {
  101. log.Info("Ignoring duplicate: %v", peer)
  102. return nil, ErrSwitchDuplicatePeer
  103. }
  104. // Start the peer
  105. go peer.start()
  106. // Notify listeners.
  107. s.doAddPeer(peer)
  108. return peer, nil
  109. }
  110. func (s *Switch) DialPeerWithAddress(addr *NetAddress) (*Peer, error) {
  111. if atomic.LoadUint32(&s.stopped) == 1 {
  112. return nil, ErrSwitchStopped
  113. }
  114. log.Info("Dialing peer @ %v", addr)
  115. s.dialing.Set(addr.String(), addr)
  116. conn, err := addr.DialTimeout(peerDialTimeoutSeconds * time.Second)
  117. s.dialing.Delete(addr.String())
  118. if err != nil {
  119. return nil, err
  120. }
  121. peer, err := s.AddPeerWithConnection(conn, true)
  122. if err != nil {
  123. return nil, err
  124. }
  125. return peer, nil
  126. }
  127. func (s *Switch) IsDialing(addr *NetAddress) bool {
  128. return s.dialing.Has(addr.String())
  129. }
  130. func (s *Switch) Broadcast(chId byte, msg Binary) (numSuccess, numFailure int) {
  131. if atomic.LoadUint32(&s.stopped) == 1 {
  132. return
  133. }
  134. log.Debug("Broadcast on [%X]", chId, msg)
  135. for _, peer := range s.peers.List() {
  136. success := peer.TrySend(chId, msg)
  137. log.Debug("Broadcast for peer %v success: %v", peer, success)
  138. if success {
  139. numSuccess += 1
  140. } else {
  141. numFailure += 1
  142. }
  143. }
  144. return
  145. }
  146. // Returns the count of outbound/inbound and outbound-dialing peers.
  147. func (s *Switch) NumPeers() (outbound, inbound, dialing int) {
  148. peers := s.peers.List()
  149. for _, peer := range peers {
  150. if peer.outbound {
  151. outbound++
  152. } else {
  153. inbound++
  154. }
  155. }
  156. dialing = s.dialing.Size()
  157. return
  158. }
  159. func (s *Switch) Peers() IPeerSet {
  160. return s.peers
  161. }
  162. // Disconnect from a peer due to external error.
  163. // TODO: make record depending on reason.
  164. func (s *Switch) StopPeerForError(peer *Peer, reason interface{}) {
  165. log.Info("- %v !! reason: %v", peer, reason)
  166. s.peers.Remove(peer)
  167. peer.stop()
  168. // Notify listeners
  169. s.doRemovePeer(peer, reason)
  170. }
  171. // Disconnect from a peer gracefully.
  172. // TODO: handle graceful disconnects.
  173. func (s *Switch) StopPeerGracefully(peer *Peer) {
  174. log.Info("- %v", peer)
  175. s.peers.Remove(peer)
  176. peer.stop()
  177. // Notify listeners
  178. s.doRemovePeer(peer, nil)
  179. }
  180. func (s *Switch) doAddPeer(peer *Peer) {
  181. for _, reactor := range s.reactors {
  182. reactor.AddPeer(peer)
  183. }
  184. }
  185. func (s *Switch) doRemovePeer(peer *Peer, reason interface{}) {
  186. for _, reactor := range s.reactors {
  187. reactor.RemovePeer(peer, reason)
  188. }
  189. }
  190. //-----------------------------------------------------------------------------
  191. type SwitchEventNewPeer struct {
  192. Peer *Peer
  193. }
  194. type SwitchEventDonePeer struct {
  195. Peer *Peer
  196. Error interface{}
  197. }