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.

220 lines
4.9 KiB

11 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
11 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
11 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
11 years ago
11 years ago
  1. package peer
  2. import (
  3. "bufio"
  4. "fmt"
  5. "net"
  6. "sync/atomic"
  7. "time"
  8. . "github.com/tendermint/tendermint/binary"
  9. . "github.com/tendermint/tendermint/common"
  10. )
  11. const (
  12. READ_BUFFER_MIN_SIZE = 1024
  13. WRITE_BUFFER_MIN_SIZE = 1024
  14. FLUSH_THROTTLE_MS = 50
  15. OUT_QUEUE_SIZE = 50
  16. IDLE_TIMEOUT_MINUTES = 5
  17. PING_TIMEOUT_MINUTES = 2
  18. )
  19. /* Connnection */
  20. type Connection struct {
  21. ioStats IOStats
  22. sendQueue chan Packet // never closes
  23. conn net.Conn
  24. bufReader *bufio.Reader
  25. bufWriter *bufio.Writer
  26. flushThrottler *Throttler
  27. quit chan struct{}
  28. stopped uint32
  29. pingRepeatTimer *RepeatTimer
  30. pong chan struct{}
  31. }
  32. var (
  33. PACKET_TYPE_PING = UInt8(0x00)
  34. PACKET_TYPE_PONG = UInt8(0x01)
  35. PACKET_TYPE_MSG = UInt8(0x10)
  36. )
  37. func NewConnection(conn net.Conn) *Connection {
  38. return &Connection{
  39. sendQueue: make(chan Packet, OUT_QUEUE_SIZE),
  40. conn: conn,
  41. bufReader: bufio.NewReaderSize(conn, READ_BUFFER_MIN_SIZE),
  42. bufWriter: bufio.NewWriterSize(conn, WRITE_BUFFER_MIN_SIZE),
  43. flushThrottler: NewThrottler(FLUSH_THROTTLE_MS * time.Millisecond),
  44. quit: make(chan struct{}),
  45. pingRepeatTimer: NewRepeatTimer(PING_TIMEOUT_MINUTES * time.Minute),
  46. pong: make(chan struct{}),
  47. }
  48. }
  49. // returns true if successfully queued,
  50. // returns false if connection was closed.
  51. // blocks.
  52. func (c *Connection) Send(pkt Packet) bool {
  53. select {
  54. case c.sendQueue <- pkt:
  55. return true
  56. case <-c.quit:
  57. return false
  58. }
  59. }
  60. func (c *Connection) Start(channels map[String]*Channel) {
  61. log.Debugf("Starting %v", c)
  62. go c.sendHandler()
  63. go c.recvHandler(channels)
  64. }
  65. func (c *Connection) Stop() {
  66. if atomic.CompareAndSwapUint32(&c.stopped, 0, 1) {
  67. log.Debugf("Stopping %v", c)
  68. close(c.quit)
  69. c.conn.Close()
  70. c.flushThrottler.Stop()
  71. c.pingRepeatTimer.Stop()
  72. // We can't close pong safely here because
  73. // recvHandler may write to it after we've stopped.
  74. // Though it doesn't need to get closed at all,
  75. // we close it @ recvHandler.
  76. // close(c.pong)
  77. }
  78. }
  79. func (c *Connection) LocalAddress() *NetAddress {
  80. return NewNetAddress(c.conn.LocalAddr())
  81. }
  82. func (c *Connection) RemoteAddress() *NetAddress {
  83. return NewNetAddress(c.conn.RemoteAddr())
  84. }
  85. func (c *Connection) String() string {
  86. return fmt.Sprintf("Connection{%v}", c.conn.RemoteAddr())
  87. }
  88. func (c *Connection) flush() {
  89. // TODO: this is pretty naive.
  90. // We end up flushing when we don't have to (yet).
  91. // A better solution might require us implementing our own buffered writer.
  92. err := c.bufWriter.Flush()
  93. if err != nil {
  94. if atomic.LoadUint32(&c.stopped) != 1 {
  95. log.Warnf("Connection flush failed: %v", err)
  96. }
  97. }
  98. }
  99. func (c *Connection) sendHandler() {
  100. log.Tracef("%v sendHandler", c)
  101. // TODO: catch panics & stop connection.
  102. FOR_LOOP:
  103. for {
  104. var err error
  105. select {
  106. case sendPkt := <-c.sendQueue:
  107. log.Tracef("Found pkt from sendQueue. Writing pkt to underlying connection")
  108. _, err = PACKET_TYPE_MSG.WriteTo(c.bufWriter)
  109. if err != nil {
  110. break
  111. }
  112. _, err = sendPkt.WriteTo(c.bufWriter)
  113. c.flushThrottler.Set()
  114. case <-c.flushThrottler.Ch:
  115. c.flush()
  116. case <-c.pingRepeatTimer.Ch:
  117. _, err = PACKET_TYPE_PING.WriteTo(c.bufWriter)
  118. c.flush()
  119. case <-c.pong:
  120. _, err = PACKET_TYPE_PONG.WriteTo(c.bufWriter)
  121. c.flush()
  122. case <-c.quit:
  123. break FOR_LOOP
  124. }
  125. if atomic.LoadUint32(&c.stopped) == 1 {
  126. break FOR_LOOP
  127. }
  128. if err != nil {
  129. log.Infof("%v failed @ sendHandler:\n%v", c, err)
  130. c.Stop()
  131. break FOR_LOOP
  132. }
  133. }
  134. log.Tracef("%v sendHandler done", c)
  135. // cleanup
  136. }
  137. func (c *Connection) recvHandler(channels map[String]*Channel) {
  138. log.Tracef("%v recvHandler with %v channels", c, len(channels))
  139. // TODO: catch panics & stop connection.
  140. FOR_LOOP:
  141. for {
  142. pktType, err := ReadUInt8Safe(c.bufReader)
  143. if err != nil {
  144. if atomic.LoadUint32(&c.stopped) != 1 {
  145. log.Infof("%v failed @ recvHandler", c)
  146. c.Stop()
  147. }
  148. break FOR_LOOP
  149. } else {
  150. log.Tracef("Found pktType %v", pktType)
  151. }
  152. switch pktType {
  153. case PACKET_TYPE_PING:
  154. // TODO: keep track of these, make sure it isn't abused
  155. // as they cause flush()'s in the send buffer.
  156. c.pong <- struct{}{}
  157. case PACKET_TYPE_PONG:
  158. // do nothing
  159. case PACKET_TYPE_MSG:
  160. pkt, err := ReadPacketSafe(c.bufReader)
  161. if err != nil {
  162. if atomic.LoadUint32(&c.stopped) != 1 {
  163. log.Infof("%v failed @ recvHandler", c)
  164. c.Stop()
  165. }
  166. break FOR_LOOP
  167. }
  168. channel := channels[pkt.Channel]
  169. if channel == nil {
  170. Panicf("Unknown channel %v", pkt.Channel)
  171. }
  172. channel.recvQueue <- pkt
  173. default:
  174. Panicf("Unknown message type %v", pktType)
  175. }
  176. c.pingRepeatTimer.Reset()
  177. }
  178. log.Tracef("%v recvHandler done", c)
  179. // cleanup
  180. close(c.pong)
  181. for _ = range c.pong {
  182. // drain
  183. }
  184. }
  185. /* IOStats */
  186. type IOStats struct {
  187. TimeConnected Time
  188. LastSent Time
  189. LastRecv Time
  190. BytesRecv UInt64
  191. BytesSent UInt64
  192. PktsRecv UInt64
  193. PktsSent UInt64
  194. }