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.

171 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
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. "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. log.Tracef("%v", msg)
  124. default:
  125. Panicf("Unknown message type %v", msgType)
  126. }
  127. c.pingDebouncer.Reset()
  128. }
  129. // cleanup
  130. close(c.pong)
  131. for _ = range c.pong {
  132. // drain
  133. }
  134. }
  135. /* IOStats */
  136. type IOStats struct {
  137. TimeConnected Time
  138. LastSent Time
  139. LastRecv Time
  140. BytesRecv UInt64
  141. BytesSent UInt64
  142. MsgsRecv UInt64
  143. MsgsSent UInt64
  144. }