stasatdaglabs d14809694f
[NOD-1223] Reorganize directory structure (#874)
* [NOD-1223] Delete unused files/packages.

* [NOD-1223] Move signal and limits to the os package.

* [NOD-1223] Put database and dbaccess into the db package.

* [NOD-1223] Fold the logs package into the logger package.

* [NOD-1223] Rename domainmessage to appmessage.

* [NOD-1223] Rename to/from DomainMessage to AppMessage.

* [NOD-1223] Move appmessage to the app packge.

* [NOD-1223] Move protocol to the app packge.

* [NOD-1223] Move the network package to the infrastructure packge.

* [NOD-1223] Rename cmd to executables.

* [NOD-1223] Fix go.doc in the logger package.
2020-08-18 10:26:39 +03:00

216 lines
5.6 KiB
Go

package netadapter
import (
"net"
"strconv"
"sync"
"sync/atomic"
"github.com/kaspanet/kaspad/app/appmessage"
"github.com/kaspanet/kaspad/infrastructure/config"
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/id"
routerpkg "github.com/kaspanet/kaspad/infrastructure/network/netadapter/router"
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/server"
"github.com/kaspanet/kaspad/infrastructure/network/netadapter/server/grpcserver"
"github.com/pkg/errors"
)
// RouterInitializer is a function that initializes a new
// router to be used with a new connection
type RouterInitializer func(*routerpkg.Router, *NetConnection)
// NetAdapter is an abstraction layer over networking.
// This type expects a RouteInitializer function. This
// function weaves together the various "routes" (messages
// and message handlers) without exposing anything related
// to networking internals.
type NetAdapter struct {
cfg *config.Config
id *id.ID
server server.Server
routerInitializer RouterInitializer
stop uint32
connections map[*NetConnection]struct{}
connectionsLock sync.RWMutex
}
// NewNetAdapter creates and starts a new NetAdapter on the
// given listeningPort
func NewNetAdapter(cfg *config.Config) (*NetAdapter, error) {
netAdapterID, err := id.GenerateID()
if err != nil {
return nil, err
}
s, err := grpcserver.NewGRPCServer(cfg.Listeners)
if err != nil {
return nil, err
}
adapter := NetAdapter{
cfg: cfg,
id: netAdapterID,
server: s,
connections: make(map[*NetConnection]struct{}),
}
adapter.server.SetOnConnectedHandler(adapter.onConnectedHandler)
return &adapter, nil
}
// Start begins the operation of the NetAdapter
func (na *NetAdapter) Start() error {
if na.routerInitializer == nil {
return errors.New("routerInitializer was not set")
}
err := na.server.Start()
if err != nil {
return err
}
return nil
}
// Stop safely closes the NetAdapter
func (na *NetAdapter) Stop() error {
if atomic.AddUint32(&na.stop, 1) != 1 {
return errors.New("net adapter stopped more than once")
}
return na.server.Stop()
}
// Connect tells the NetAdapter's underlying server to initiate a connection
// to the given address
func (na *NetAdapter) Connect(address string) error {
_, err := na.server.Connect(address)
return err
}
// Connections returns a list of connections currently connected and active
func (na *NetAdapter) Connections() []*NetConnection {
na.connectionsLock.RLock()
defer na.connectionsLock.RUnlock()
netConnections := make([]*NetConnection, 0, len(na.connections))
for netConnection := range na.connections {
netConnections = append(netConnections, netConnection)
}
return netConnections
}
// ConnectionCount returns the count of the connected connections
func (na *NetAdapter) ConnectionCount() int {
na.connectionsLock.RLock()
defer na.connectionsLock.RUnlock()
return len(na.connections)
}
func (na *NetAdapter) onConnectedHandler(connection server.Connection) error {
netConnection := newNetConnection(connection, na.routerInitializer)
na.connectionsLock.Lock()
defer na.connectionsLock.Unlock()
netConnection.setOnDisconnectedHandler(func() {
na.connectionsLock.Lock()
defer na.connectionsLock.Unlock()
delete(na.connections, netConnection)
})
na.connections[netConnection] = struct{}{}
netConnection.start()
return nil
}
// SetRouterInitializer sets the routerInitializer function
// for the net adapter
func (na *NetAdapter) SetRouterInitializer(routerInitializer RouterInitializer) {
na.routerInitializer = routerInitializer
}
// ID returns this netAdapter's ID in the network
func (na *NetAdapter) ID() *id.ID {
return na.id
}
// Broadcast sends the given `message` to every peer corresponding
// to each NetConnection in the given netConnections
func (na *NetAdapter) Broadcast(netConnections []*NetConnection, message appmessage.Message) error {
na.connectionsLock.RLock()
defer na.connectionsLock.RUnlock()
for _, netConnection := range netConnections {
err := netConnection.router.OutgoingRoute().Enqueue(message)
if err != nil {
if errors.Is(err, routerpkg.ErrRouteClosed) {
log.Debugf("Cannot enqueue message to %s: router is closed", netConnection)
continue
}
return err
}
}
return nil
}
// GetBestLocalAddress returns the most appropriate local address to use
// for the given remote address.
func (na *NetAdapter) GetBestLocalAddress() (*appmessage.NetAddress, error) {
if len(na.cfg.ExternalIPs) > 0 {
host, portString, err := net.SplitHostPort(na.cfg.ExternalIPs[0])
if err != nil {
portString = na.cfg.NetParams().DefaultPort
}
portInt, err := strconv.Atoi(portString)
if err != nil {
return nil, err
}
ip := net.ParseIP(host)
if ip == nil {
hostAddrs, err := net.LookupHost(host)
if err != nil {
return nil, err
}
ip = net.ParseIP(hostAddrs[0])
if ip == nil {
return nil, errors.Errorf("Cannot resolve IP address for host '%s'", host)
}
}
return appmessage.NewNetAddressIPPort(ip, uint16(portInt), appmessage.SFNodeNetwork), nil
}
listenAddress := na.cfg.Listeners[0]
_, portString, err := net.SplitHostPort(listenAddress)
if err != nil {
portString = na.cfg.NetParams().DefaultPort
}
portInt, err := strconv.Atoi(portString)
if err != nil {
return nil, err
}
addresses, err := net.InterfaceAddrs()
if err != nil {
return nil, err
}
for _, address := range addresses {
ip, _, err := net.ParseCIDR(address.String())
if err != nil {
continue
}
return appmessage.NewNetAddressIPPort(ip, uint16(portInt), appmessage.SFNodeNetwork), nil
}
return nil, errors.New("no address was found")
}