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.

170 lines
3.8 KiB

10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
10 years ago
  1. package peer
  2. import (
  3. . "github.com/tendermint/tendermint/common"
  4. . "github.com/tendermint/tendermint/binary"
  5. "sync/atomic"
  6. "net"
  7. "time"
  8. )
  9. const (
  10. OUT_QUEUE_SIZE = 50
  11. IDLE_TIMEOUT_MINUTES = 5
  12. PING_TIMEOUT_MINUTES = 2
  13. )
  14. /* Connnection */
  15. type Connection struct {
  16. ioStats IOStats
  17. outQueue chan ByteSlice // never closes.
  18. conn net.Conn
  19. quit chan struct{}
  20. stopped uint32
  21. pingDebouncer *Debouncer
  22. pong chan struct{}
  23. }
  24. var (
  25. PACKET_TYPE_PING = UInt8(0x00)
  26. PACKET_TYPE_PONG = UInt8(0x01)
  27. PACKET_TYPE_MSG = UInt8(0x10)
  28. )
  29. func NewConnection(conn net.Conn) *Connection {
  30. return &Connection{
  31. outQueue: make(chan ByteSlice, OUT_QUEUE_SIZE),
  32. conn: conn,
  33. quit: make(chan struct{}),
  34. pingDebouncer: NewDebouncer(PING_TIMEOUT_MINUTES * time.Minute),
  35. pong: make(chan struct{}),
  36. }
  37. }
  38. // returns true if successfully queued,
  39. // returns false if connection was closed.
  40. // blocks.
  41. func (c *Connection) QueueOut(msg ByteSlice) bool {
  42. select {
  43. case c.outQueue <- msg:
  44. return true
  45. case <-c.quit:
  46. return false
  47. }
  48. }
  49. func (c *Connection) Start() {
  50. go c.outHandler()
  51. go c.inHandler()
  52. }
  53. func (c *Connection) Stop() {
  54. if atomic.CompareAndSwapUint32(&c.stopped, 0, 1) {
  55. close(c.quit)
  56. c.conn.Close()
  57. c.pingDebouncer.Stop()
  58. // We can't close pong safely here because
  59. // inHandler may write to it after we've stopped.
  60. // Though it doesn't need to get closed at all,
  61. // we close it @ inHandler.
  62. // close(c.pong)
  63. }
  64. }
  65. func (c *Connection) LocalAddress() *NetAddress {
  66. return NewNetAddress(c.conn.LocalAddr())
  67. }
  68. func (c *Connection) RemoteAddress() *NetAddress {
  69. return NewNetAddress(c.conn.RemoteAddr())
  70. }
  71. func (c *Connection) flush() {
  72. // TODO flush? (turn off nagel, turn back on, etc)
  73. }
  74. func (c *Connection) outHandler() {
  75. FOR_LOOP:
  76. for {
  77. var err error
  78. select {
  79. case <-c.pingDebouncer.Ch:
  80. _, err = PACKET_TYPE_PING.WriteTo(c.conn)
  81. case outMsg := <-c.outQueue:
  82. _, err = outMsg.WriteTo(c.conn)
  83. case <-c.pong:
  84. _, err = PACKET_TYPE_PONG.WriteTo(c.conn)
  85. case <-c.quit:
  86. break FOR_LOOP
  87. }
  88. if err != nil {
  89. log.Infof("Connection %v failed @ outHandler:\n%v", c, err)
  90. c.Stop()
  91. break FOR_LOOP
  92. }
  93. c.flush()
  94. }
  95. }
  96. func (c *Connection) inHandler() {
  97. FOR_LOOP:
  98. for {
  99. msgType, err := ReadUInt8Safe(c.conn)
  100. if err != nil {
  101. if atomic.LoadUint32(&c.stopped) != 1 {
  102. log.Infof("Connection %v failed @ inHandler", c)
  103. c.Stop()
  104. }
  105. break FOR_LOOP
  106. }
  107. switch msgType {
  108. case PACKET_TYPE_PING:
  109. c.pong <- struct{}{}
  110. case PACKET_TYPE_PONG:
  111. // do nothing
  112. case PACKET_TYPE_MSG:
  113. msg, err := ReadByteSliceSafe(c.conn)
  114. if err != nil {
  115. if atomic.LoadUint32(&c.stopped) != 1 {
  116. log.Infof("Connection %v failed @ inHandler", c)
  117. c.Stop()
  118. }
  119. break FOR_LOOP
  120. }
  121. // What to do?
  122. // TODO
  123. default:
  124. Panicf("Unknown message type %v", msgType)
  125. }
  126. c.pingDebouncer.Reset()
  127. }
  128. // cleanup
  129. close(c.pong)
  130. for _ = range c.pong {
  131. // drain
  132. }
  133. }
  134. /* IOStats */
  135. type IOStats struct {
  136. TimeConnected Time
  137. LastSent Time
  138. LastRecv Time
  139. BytesRecv UInt64
  140. BytesSent UInt64
  141. MsgsRecv UInt64
  142. MsgsSent UInt64
  143. }