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.5 KiB

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