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.

156 lines
5.0 KiB

  1. // Copyright 2017-2018 DERO Project. All rights reserved.
  2. // Use of this source code in any form is governed by RESEARCH license.
  3. // license can be found in the LICENSE file.
  4. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8
  5. //
  6. //
  7. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
  8. // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  9. // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
  10. // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  11. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  12. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
  13. // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
  14. // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
  15. // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  16. package p2pv2
  17. /* this file implements the connection pool manager, keeping a list of active connections etc
  18. * this will also ensure that a single IP is connected only once
  19. *
  20. */
  21. import "fmt"
  22. import "net"
  23. import "sync"
  24. import "container/list"
  25. import log "github.com/sirupsen/logrus"
  26. import "github.com/arnaucode/derosuite/crypto"
  27. // any connection incoming/outgoing can only be in this state
  28. type Conn_State string
  29. const (
  30. HANDSHAKE_PENDING Conn_State = "Pending"
  31. IDLE = "Idle"
  32. ACTIVE = "Active"
  33. )
  34. // This structure is used to do book keeping for the connection and keeps other DATA related to peer
  35. type Connection struct {
  36. Incoming bool // is connection incoming or outgoing
  37. Addr *net.TCPAddr // endpoint on the other end
  38. Port uint32 // port advertised by other end as its server,if it's 0 server cannot accept connections
  39. Peer_Info // all peer info parameters are present here
  40. Peer_ID uint64 // Remote peer id
  41. Last_Height uint64 // last height sent by peer
  42. Top_Version uint64 // current hard fork version supported by peer
  43. Exit bool // Exit marker that connection needs to be killed
  44. State Conn_State // state of the connection
  45. Top_ID crypto.Hash // top block id of the connection
  46. Cumulative_Difficulty uint64 // cumulative difficulty of top block of peer
  47. logger *log.Entry // connection specific logger
  48. Requested_Objects [][32]byte // currently unused as we sync up with a single peer at a time
  49. Conn net.Conn // actual object to talk
  50. Command_queue *list.List // New protocol is partly syncronous/partly asyncronous
  51. sync.Mutex
  52. HandShakeCompleted bool // whether handshake is completed
  53. Bytes_Sent uint64 // total bytes sent
  54. Bytes_Received uint64 // total bytes received
  55. // TODO a bloom filter that an object has been relayed
  56. }
  57. var connection_map = map[string]*Connection{}
  58. var connection_mutex sync.Mutex
  59. func Key(ip net.IP) string {
  60. return string(ip.To16()) // Simple []byte => string conversion
  61. }
  62. // check whether an IP is in the map already
  63. func IsConnected(ip net.IP) bool {
  64. connection_mutex.Lock()
  65. defer connection_mutex.Unlock()
  66. if _, ok := connection_map[Key(ip)]; ok {
  67. return true
  68. }
  69. return false
  70. }
  71. // add connection to map
  72. func Connection_Add(c *Connection) {
  73. connection_mutex.Lock()
  74. defer connection_mutex.Unlock()
  75. connection_map[Key(c.Addr.IP)] = c
  76. }
  77. // add connection to map
  78. func Connection_Delete(c *Connection) {
  79. connection_mutex.Lock()
  80. defer connection_mutex.Unlock()
  81. delete(connection_map, Key(c.Addr.IP))
  82. }
  83. // prints all the connection info to screen
  84. func Connection_Print() {
  85. connection_mutex.Lock()
  86. defer connection_mutex.Unlock()
  87. fmt.Printf("Connection info for peers\n")
  88. fmt.Printf("%-20s %-16s %-5s %-7s %9s %3s\n", "Remote Addr", "PEER ID", "PORT", " State", "Height", "DIR")
  89. for _, v := range connection_map {
  90. dir := "OUT"
  91. if v.Incoming {
  92. dir = "INC"
  93. }
  94. fmt.Printf("%-20s %16x %5d %7s %9d %s\n", v.Addr.IP, v.Peer_ID, v.Port, v.State, v.Last_Height, dir)
  95. }
  96. }
  97. // for continuos update on command line, get the maximum height of all peers
  98. func Best_Peer_Height() (best_height uint64) {
  99. connection_mutex.Lock()
  100. for _, v := range connection_map {
  101. if v.Last_Height > best_height {
  102. best_height = v.Last_Height
  103. }
  104. }
  105. connection_mutex.Unlock()
  106. return
  107. }
  108. // this function return peer count which have successful handshake
  109. func Peer_Count() (Count uint64) {
  110. connection_mutex.Lock()
  111. for _, v := range connection_map {
  112. if v.State != HANDSHAKE_PENDING {
  113. Count++
  114. }
  115. }
  116. connection_mutex.Unlock()
  117. return
  118. }
  119. // this returns count of peers in both directions
  120. func Peer_Direction_Count() (Incoming uint64, Outgoing uint64) {
  121. connection_mutex.Lock()
  122. for _, v := range connection_map {
  123. if v.State != HANDSHAKE_PENDING {
  124. if v.Incoming {
  125. Incoming++
  126. } else {
  127. Outgoing++
  128. }
  129. }
  130. }
  131. connection_mutex.Unlock()
  132. return
  133. }