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.

130 lines
3.8 KiB

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
}