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.

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