|
|
// 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/deroproject/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 }
|