// Copyright 2017-2018 DERO Project. All rights reserved. // Use of this source code in any form is governed by RESEARCH license. // license can be found in the LICENSE file. // GPG: 0F39 E425 8C65 3947 702A 8234 08B2 0360 A03A 9DE8 // // // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY // EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF // MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL // THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, // STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF // THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. package p2p /* this file implements the connection pool manager, keeping a list of active connections etc * this will also ensure that a single IP is connected only once * */ import "fmt" import "net" import "sync" import "container/list" import log "github.com/sirupsen/logrus" import "github.com/arnaucode/derosuite/crypto" // any connection incoming/outgoing can only be in this state type Conn_State string const ( HANDSHAKE_PENDING Conn_State = "Pending" IDLE = "Idle" ACTIVE = "Active" ) // This structure is used to do book keeping for the connection and keeps other DATA related to peer type Connection struct { Incoming bool // is connection incoming or outgoing Addr *net.TCPAddr // endpoint on the other end Port uint32 // port advertised by other end as its server,if it's 0 server cannot accept connections Peer_ID uint64 // Remote peer id Last_Height uint64 // last height sent by peer Top_Version uint64 // current hard fork version supported by peer Exit bool // Exit marker that connection needs to be killed State Conn_State // state of the connection Top_ID crypto.Hash // top block id of the connection Cumulative_Difficulty uint64 // cumulative difficulty of top block of peer logger *log.Entry // connection specific logger Requested_Objects [][32]byte // currently unused as we sync up with a single peer at a time Conn net.Conn // actual object to talk Command_queue *list.List // LEVIN protocol is syncronous sync.Mutex } var connection_map = map[string]*Connection{} var connection_mutex sync.Mutex func Key(ip net.IP) string { return string(ip.To16()) // Simple []byte => string conversion } // check whether an IP is in the map already func IsConnected(ip net.IP) bool { connection_mutex.Lock() defer connection_mutex.Unlock() if _, ok := connection_map[Key(ip)]; ok { return true } return false } // add connection to map func Connection_Add(c *Connection) { connection_mutex.Lock() defer connection_mutex.Unlock() connection_map[Key(c.Addr.IP)] = c } // add connection to map func Connection_Delete(c *Connection) { connection_mutex.Lock() defer connection_mutex.Unlock() delete(connection_map, Key(c.Addr.IP)) } // prints all the connection info to screen func Connection_Print() { connection_mutex.Lock() defer connection_mutex.Unlock() fmt.Printf("Connection info for peers\n") fmt.Printf("%-20s %-16s %-5s %-7s %9s %3s\n", "Remote Addr", "PEER ID", "PORT", " State", "Height", "DIR") for _, v := range connection_map { dir := "OUT" if v.Incoming { dir = "INC" } fmt.Printf("%-20s %16x %5d %7s %9d %s\n", v.Addr.IP, v.Peer_ID, v.Port, v.State, v.Last_Height, dir) } } // for continuos update on command line, get the maximum height of all peers func Best_Peer_Height() (best_height uint64) { connection_mutex.Lock() for _, v := range connection_map { if v.Last_Height > best_height { best_height = v.Last_Height } } connection_mutex.Unlock() return } // this function return peer count which have successful handshake func Peer_Count() (Count uint64) { connection_mutex.Lock() for _, v := range connection_map { if v.State != HANDSHAKE_PENDING { Count++ } } connection_mutex.Unlock() return } // this returns count of peers in both directions func Peer_Direction_Count() (Incoming uint64, Outgoing uint64) { connection_mutex.Lock() for _, v := range connection_map { if v.State != HANDSHAKE_PENDING { if v.Incoming { Incoming++ } else { Outgoing++ } } } connection_mutex.Unlock() return }