neoneo-go/pkg/network/server.go

308 lines
7.4 KiB
Go
Raw Normal View History

2018-01-26 18:04:13 +00:00
package network
import (
"errors"
"fmt"
"log"
"net"
"os"
2018-01-26 20:39:34 +00:00
"strconv"
2018-01-28 10:12:05 +00:00
"time"
2018-01-27 15:00:28 +00:00
"github.com/anthdm/neo-go/pkg/core"
2018-01-27 15:00:28 +00:00
"github.com/anthdm/neo-go/pkg/network/payload"
2018-01-28 07:03:18 +00:00
"github.com/anthdm/neo-go/pkg/util"
2018-01-26 18:04:13 +00:00
)
const (
2018-01-26 20:39:34 +00:00
// node version
version = "2.6.0"
// official ports according to the protocol.
2018-01-26 18:04:13 +00:00
portMainNet = 10333
portTestNet = 20333
2018-01-26 20:39:34 +00:00
)
var (
// rpcLogger used for debugging RPC messages between nodes.
2018-01-28 13:59:32 +00:00
rpcLogger = log.New(os.Stdout, "", 0)
2018-01-26 18:04:13 +00:00
)
type messageTuple struct {
peer Peer
2018-01-26 18:04:13 +00:00
msg *Message
}
// Server is the representation of a full working NEO TCP node.
type Server struct {
logger *log.Logger
2018-01-28 07:03:18 +00:00
// id of the server
id uint32
2018-01-26 20:39:34 +00:00
// the port the TCP listener is listening on.
port uint16
2018-01-26 18:04:13 +00:00
// userAgent of the server.
userAgent string
// The "magic" mode the server is currently running on.
// This can either be 0x00746e41 or 0x74746e41 for main or test net.
2018-01-26 20:39:34 +00:00
// Or 56753 to work with the docker privnet.
net NetMode
2018-01-26 18:04:13 +00:00
// map that holds all connected peers to this server.
peers map[Peer]bool
2018-01-26 18:04:13 +00:00
register chan Peer
unregister chan Peer
2018-01-26 18:04:13 +00:00
// channel for coordinating messages.
message chan messageTuple
// channel used to gracefull shutdown the server.
quit chan struct{}
// Whether this server will receive and forward messages.
relay bool
// TCP listener of the server
listener net.Listener
}
// NewServer returns a pointer to a new server.
2018-01-26 20:39:34 +00:00
func NewServer(net NetMode) *Server {
2018-01-26 18:04:13 +00:00
logger := log.New(os.Stdout, "NEO SERVER :: ", 0)
2018-01-26 20:39:34 +00:00
if net != ModeTestNet && net != ModeMainNet && net != ModeDevNet {
logger.Fatalf("invalid network mode %d", net)
2018-01-26 18:04:13 +00:00
}
s := &Server{
2018-01-28 07:03:18 +00:00
id: util.RandUint32(1111111, 9999999),
userAgent: fmt.Sprintf("/NEO:%s/", version),
2018-01-26 18:04:13 +00:00
logger: logger,
peers: make(map[Peer]bool),
register: make(chan Peer),
unregister: make(chan Peer),
2018-01-26 18:04:13 +00:00
message: make(chan messageTuple),
relay: true,
2018-01-26 20:39:34 +00:00
net: net,
2018-01-26 18:04:13 +00:00
quit: make(chan struct{}),
}
return s
}
// Start run's the server.
func (s *Server) Start(port string, seeds []string) {
2018-01-26 20:39:34 +00:00
p, err := strconv.Atoi(port[1:len(port)])
if err != nil {
s.logger.Fatalf("could not convert port to integer: %s", err)
}
s.port = uint16(p)
2018-01-26 18:04:13 +00:00
fmt.Println(logo())
2018-01-28 07:03:18 +00:00
fmt.Println(string(s.userAgent))
fmt.Println("")
s.logger.Printf("NET: %s - TCP: %d - RELAY: %v - ID: %d",
s.net, int(s.port), s.relay, s.id)
2018-01-26 18:04:13 +00:00
go listenTCP(s, port)
if len(seeds) > 0 {
connectToSeeds(s, seeds)
}
s.loop()
}
// Stop the server, attemping a gracefull shutdown.
func (s *Server) Stop() { s.quit <- struct{}{} }
// shutdown the server, disconnecting all peers.
func (s *Server) shutdown() {
s.logger.Println("attemping a quitefull shutdown.")
s.listener.Close()
// disconnect and remove all connected peers.
for peer := range s.peers {
s.unregister <- peer
}
}
func (s *Server) loop() {
for {
select {
case peer := <-s.register:
2018-01-29 07:11:08 +00:00
// When a new connection is been established, (by this server or remote node)
// its peer will be received on this channel.
// Any peer registration must happen via this channel.
s.logger.Printf("peer registered from address %s", peer.endpoint())
2018-01-27 12:39:07 +00:00
s.peers[peer] = true
2018-01-29 18:17:49 +00:00
s.handlePeerConnected(peer)
2018-01-27 12:39:07 +00:00
2018-01-26 18:04:13 +00:00
case peer := <-s.unregister:
2018-01-28 17:42:22 +00:00
// unregister should take care of all the cleanup that has to be made.
2018-01-27 07:37:07 +00:00
if _, ok := s.peers[peer]; ok {
peer.disconnect()
2018-01-27 07:37:07 +00:00
delete(s.peers, peer)
s.logger.Printf("peer %s disconnected", peer.endpoint())
2018-01-27 07:37:07 +00:00
}
2018-01-29 18:17:49 +00:00
2018-01-26 18:04:13 +00:00
case tuple := <-s.message:
2018-01-29 07:11:08 +00:00
// When a remote node sends data over its connection it will be received
// on this channel.
2018-01-29 18:17:49 +00:00
// All errors encountered should be return and handled here.
2018-01-26 18:04:13 +00:00
if err := s.processMessage(tuple.msg, tuple.peer); err != nil {
s.logger.Fatalf("failed to process message: %s", err)
2018-01-29 18:17:49 +00:00
s.unregister <- tuple.peer
2018-01-26 18:04:13 +00:00
}
2018-01-29 18:17:49 +00:00
2018-01-26 18:04:13 +00:00
case <-s.quit:
s.shutdown()
}
}
}
2018-01-29 18:17:49 +00:00
// processMessage processes the message received from the peer.
func (s *Server) processMessage(msg *Message, peer Peer) error {
2018-01-29 18:17:49 +00:00
command := msg.commandType()
rpcLogger.Printf("[NODE %d] :: IN :: %s :: %+v", peer.id(), command, msg.Payload)
2018-01-26 20:39:34 +00:00
2018-01-29 18:17:49 +00:00
// Disconnect if the remote is sending messages other then version
// if we didn't verack this peer.
if !peer.verack() && command != cmdVersion {
2018-01-29 18:17:49 +00:00
return errors.New("version noack")
}
switch command {
2018-01-26 18:04:13 +00:00
case cmdVersion:
2018-01-27 15:47:43 +00:00
return s.handleVersionCmd(msg.Payload.(*payload.Version), peer)
2018-01-26 18:04:13 +00:00
case cmdVerack:
case cmdGetAddr:
2018-01-28 15:06:41 +00:00
// return s.handleGetAddrCmd(msg, peer)
2018-01-26 18:04:13 +00:00
case cmdAddr:
2018-01-28 15:18:48 +00:00
return s.handleAddrCmd(msg.Payload.(*payload.AddressList), peer)
2018-01-26 18:04:13 +00:00
case cmdGetHeaders:
case cmdHeaders:
case cmdGetBlocks:
case cmdInv:
2018-01-30 10:56:36 +00:00
return s.handleInvCmd(msg.Payload.(*payload.Inventory), peer)
2018-01-26 18:04:13 +00:00
case cmdGetData:
case cmdBlock:
return s.handleBlockCmd(msg.Payload.(*core.Block), peer)
2018-01-26 18:04:13 +00:00
case cmdTX:
2018-01-30 10:56:36 +00:00
case cmdConsensus:
2018-01-26 18:04:13 +00:00
default:
2018-01-29 18:17:49 +00:00
return fmt.Errorf("invalid RPC command received: %s", command)
2018-01-26 18:04:13 +00:00
}
return nil
}
2018-01-29 18:17:49 +00:00
// When a new peer is connected we send our version.
// No further communication should be made before both sides has received
// the versions of eachother.
func (s *Server) handlePeerConnected(peer Peer) {
2018-01-29 18:17:49 +00:00
// TODO get heigth of block when thats implemented.
2018-01-28 07:03:18 +00:00
payload := payload.NewVersion(s.id, s.port, s.userAgent, 0, s.relay)
2018-01-27 15:00:28 +00:00
msg := newMessage(s.net, cmdVersion, payload)
2018-01-29 18:17:49 +00:00
peer.send(msg)
2018-01-26 18:04:13 +00:00
}
2018-01-27 07:37:07 +00:00
// Version declares the server's version.
func (s *Server) handleVersionCmd(v *payload.Version, peer Peer) error {
2018-01-29 18:17:49 +00:00
if s.id == v.Nonce {
return errors.New("remote nonce equal to server id")
}
if peer.endpoint().Port != v.Port {
2018-01-29 18:17:49 +00:00
return errors.New("port mismatch")
}
2018-01-27 07:37:07 +00:00
2018-01-27 12:39:07 +00:00
// we respond with a verack, we successfully received peer's version
// at this point.
peer.verify(v.Nonce)
2018-01-27 07:37:07 +00:00
verackMsg := newMessage(s.net, cmdVerack, nil)
peer.send(verackMsg)
2018-01-27 12:39:07 +00:00
2018-01-29 18:17:49 +00:00
go s.sendLoop(peer)
2018-01-28 10:12:05 +00:00
return nil
}
2018-01-28 13:59:32 +00:00
// When the remote node reveals its known peers we try to connect to all of them.
func (s *Server) handleAddrCmd(addrList *payload.AddressList, peer Peer) error {
2018-01-28 10:20:42 +00:00
for _, addr := range addrList.Addrs {
2018-01-28 17:42:22 +00:00
if !s.peerAlreadyConnected(addr.Addr) {
go connectToRemoteNode(s, addr.Addr.String())
}
2018-01-28 10:20:42 +00:00
}
2018-01-27 12:39:07 +00:00
return nil
2018-01-30 10:56:36 +00:00
}
func (s *Server) handleInvCmd(inv *payload.Inventory, peer Peer) error {
2018-01-30 10:56:36 +00:00
if !inv.Type.Valid() {
return fmt.Errorf("invalid inventory type: %s", inv.Type)
}
if len(inv.Hashes) == 0 {
return nil
}
payload := payload.NewInventory(inv.Type, inv.Hashes)
msg := newMessage(s.net, cmdGetData, payload)
peer.send(msg)
return nil
}
2018-01-30 10:56:36 +00:00
func (s *Server) handleBlockCmd(block *core.Block, peer Peer) error {
fmt.Println("Block received")
fmt.Printf("%+v\n", block)
2018-01-30 10:56:36 +00:00
return nil
2018-01-27 12:39:07 +00:00
}
2018-01-28 17:42:22 +00:00
func (s *Server) peerAlreadyConnected(addr net.Addr) bool {
2018-01-28 13:59:32 +00:00
// TODO: check for race conditions
//s.mtx.RLock()
//defer s.mtx.RUnlock()
2018-01-28 17:42:22 +00:00
// What about ourself ^^
2018-01-28 13:59:32 +00:00
for peer := range s.peers {
if peer.endpoint().String() == addr.String() {
2018-01-28 13:59:32 +00:00
return true
}
}
return false
}
2018-01-27 12:39:07 +00:00
// After receiving the "getaddr" the server needs to respond with an "addr" message.
// providing information about the other nodes in the network.
// e.g. this server's connected peers.
func (s *Server) handleGetAddrCmd(msg *Message, peer *Peer) error {
2018-01-28 17:42:22 +00:00
// TODO
2018-01-27 12:39:07 +00:00
return nil
2018-01-26 18:04:13 +00:00
}
func (s *Server) sendLoop(peer Peer) {
2018-01-28 15:18:48 +00:00
// TODO: check if this peer is still connected.
2018-01-28 10:12:05 +00:00
for {
getaddrMsg := newMessage(s.net, cmdGetAddr, nil)
peer.send(getaddrMsg)
2018-01-28 10:12:05 +00:00
time.Sleep(120 * time.Second)
2018-01-28 10:12:05 +00:00
}
}
2018-01-26 18:04:13 +00:00
func logo() string {
return `
_ ____________ __________
/ | / / ____/ __ \ / ____/ __ \
/ |/ / __/ / / / /_____/ / __/ / / /
/ /| / /___/ /_/ /_____/ /_/ / /_/ /
/_/ |_/_____/\____/ \____/\____/
`
}