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.

146 lines
4.7 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 p2p
  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_ID uint64 // Remote peer id
  40. Last_Height uint64 // last height sent by peer
  41. Top_Version uint64 // current hard fork version supported by peer
  42. Exit bool // Exit marker that connection needs to be killed
  43. State Conn_State // state of the connection
  44. Top_ID crypto.Hash // top block id of the connection
  45. Cumulative_Difficulty uint64 // cumulative difficulty of top block of peer
  46. logger *log.Entry // connection specific logger
  47. Requested_Objects [][32]byte // currently unused as we sync up with a single peer at a time
  48. Conn net.Conn // actual object to talk
  49. Command_queue *list.List // LEVIN protocol is syncronous
  50. sync.Mutex
  51. }
  52. var connection_map = map[string]*Connection{}
  53. var connection_mutex sync.Mutex
  54. func Key(ip net.IP) string {
  55. return string(ip.To16()) // Simple []byte => string conversion
  56. }
  57. // check whether an IP is in the map already
  58. func IsConnected(ip net.IP) bool {
  59. connection_mutex.Lock()
  60. defer connection_mutex.Unlock()
  61. if _, ok := connection_map[Key(ip)]; ok {
  62. return true
  63. }
  64. return false
  65. }
  66. // add connection to map
  67. func Connection_Add(c *Connection) {
  68. connection_mutex.Lock()
  69. defer connection_mutex.Unlock()
  70. connection_map[Key(c.Addr.IP)] = c
  71. }
  72. // add connection to map
  73. func Connection_Delete(c *Connection) {
  74. connection_mutex.Lock()
  75. defer connection_mutex.Unlock()
  76. delete(connection_map, Key(c.Addr.IP))
  77. }
  78. // prints all the connection info to screen
  79. func Connection_Print() {
  80. connection_mutex.Lock()
  81. defer connection_mutex.Unlock()
  82. fmt.Printf("Connection info for peers\n")
  83. fmt.Printf("%-20s %-16s %-5s %-7s %9s %3s\n", "Remote Addr", "PEER ID", "PORT", " State", "Height", "DIR")
  84. for _, v := range connection_map {
  85. dir := "OUT"
  86. if v.Incoming {
  87. dir = "INC"
  88. }
  89. fmt.Printf("%-20s %16x %5d %7s %9d %s\n", v.Addr.IP, v.Peer_ID, v.Port, v.State, v.Last_Height, dir)
  90. }
  91. }
  92. // for continuos update on command line, get the maximum height of all peers
  93. func Best_Peer_Height() (best_height uint64) {
  94. connection_mutex.Lock()
  95. for _, v := range connection_map {
  96. if v.Last_Height > best_height {
  97. best_height = v.Last_Height
  98. }
  99. }
  100. connection_mutex.Unlock()
  101. return
  102. }
  103. // this function return peer count which have successful handshake
  104. func Peer_Count() (Count uint64) {
  105. connection_mutex.Lock()
  106. for _, v := range connection_map {
  107. if v.State != HANDSHAKE_PENDING {
  108. Count++
  109. }
  110. }
  111. connection_mutex.Unlock()
  112. return
  113. }
  114. // this returns count of peers in both directions
  115. func Peer_Direction_Count() (Incoming uint64, Outgoing uint64) {
  116. connection_mutex.Lock()
  117. for _, v := range connection_map {
  118. if v.State != HANDSHAKE_PENDING {
  119. if v.Incoming {
  120. Incoming++
  121. } else {
  122. Outgoing++
  123. }
  124. }
  125. }
  126. connection_mutex.Unlock()
  127. return
  128. }