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

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