tendermint/privval/tcp_server.go
Ismail Khoffi 1ee32d3089 playing with show validator cmd and experimenting with spawning new
sessions / connections if the connection is lost
2018-12-13 12:26:11 +01:00

167 lines
3.7 KiB
Go

package privval
import (
"fmt"
"io"
"net"
"time"
"github.com/tendermint/tendermint/crypto/ed25519"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log"
p2pconn "github.com/tendermint/tendermint/p2p/conn"
"github.com/tendermint/tendermint/types"
)
// RemoteSignerOption sets an optional parameter on the RemoteSigner.
type RemoteSignerOption func(*RemoteSigner)
// RemoteSignerConnDeadline sets the read and write deadline for connections
// from external signing processes.
func RemoteSignerConnDeadline(deadline time.Duration) RemoteSignerOption {
return func(ss *RemoteSigner) { ss.connDeadline = deadline }
}
// RemoteSignerConnRetries sets the amount of attempted retries to connect.
func RemoteSignerConnRetries(retries int) RemoteSignerOption {
return func(ss *RemoteSigner) { ss.connRetries = retries }
}
// RemoteSigner implements PrivValidator by dialing to a socket.
type RemoteSigner struct {
cmn.BaseService
addr string
chainID string
connDeadline time.Duration
connRetries int
privKey ed25519.PrivKeyEd25519
privVal types.PrivValidator
conn net.Conn
}
// NewRemoteSigner returns an instance of RemoteSigner.
func NewRemoteSigner(
logger log.Logger,
chainID, socketAddr string,
privVal types.PrivValidator,
privKey ed25519.PrivKeyEd25519,
) *RemoteSigner {
rs := &RemoteSigner{
addr: socketAddr,
chainID: chainID,
connDeadline: time.Second * defaultConnDeadlineSeconds,
connRetries: defaultDialRetries,
privKey: privKey,
privVal: privVal,
}
rs.BaseService = *cmn.NewBaseService(logger, "RemoteSigner", rs)
return rs
}
// OnStart implements cmn.Service.
func (rs *RemoteSigner) OnStart() error {
go rs.handleConnection()
return nil
}
// OnStop implements cmn.Service.
func (rs *RemoteSigner) OnStop() {
if rs.conn == nil {
return
}
if err := rs.conn.Close(); err != nil {
rs.Logger.Error("OnStop", "err", cmn.ErrorWrap(err, "closing listener failed"))
}
}
func (rs *RemoteSigner) connect() (net.Conn, error) {
//for retries := rs.connRetries; retries > 0; retries-- {
// Don't sleep if it is the first retry.
//if retries != rs.connRetries {
// time.Sleep(rs.connDeadline)
//}
conn, err := cmn.Connect(rs.addr)
if err != nil {
rs.Logger.Error(
"connect",
"addr", rs.addr,
"err", err,
)
return nil, err
}
//if err := conn.SetDeadline(time.Now().Add(connTimeout)); err != nil {
// rs.Logger.Error(
// "connect",
// "err", err,
// )
// //continue
// return nil, err
//}
conn, err = p2pconn.MakeSecretConnection(conn, rs.privKey)
if err != nil {
rs.Logger.Error(
"connect",
"err", err,
)
return nil, err
}
fmt.Println("connected", conn.RemoteAddr())
return conn, nil
//}
return nil, ErrDialRetryMax
}
func (rs *RemoteSigner) handleConnection() {
for { // establish connection loop:
if !rs.IsRunning() {
return // Ignore error from listener closing.
}
fmt.Println("Connecting again ...")
conn, err := rs.connect()
if err != nil {
rs.Logger.Error("OnStart", "err", err)
fmt.Println("failed to connect", err)
time.Sleep(rs.connDeadline)
continue
}
// Reset the connection deadline
//conn.SetDeadline(time.Now().Add(rs.connDeadline*10))
for { // handle request loop
req, err := readMsg(conn)
if err != nil {
if err != io.EOF {
rs.Logger.Error("handleConnection readMsg", "err", err)
}
conn.Close()
break
}
res, err := handleRequest(req, rs.chainID, rs.privVal)
if err != nil {
// only log the error; we'll reply with an error in res
rs.Logger.Error("handleConnection handleRequest", "err", err)
}
err = writeMsg(conn, res)
if err != nil {
rs.Logger.Error("handleConnection writeMsg", "err", err)
break
}
}
}
}