package privval import ( "net" "time" cmn "github.com/tendermint/tendermint/libs/common" "github.com/tendermint/tendermint/libs/log" "github.com/tendermint/tendermint/types" ) // IPCValOption sets an optional parameter on the SocketPV. type IPCValOption func(*IPCVal) // IPCValConnTimeout sets the read and write timeout for connections // from external signing processes. func IPCValConnTimeout(timeout time.Duration) IPCValOption { return func(sc *IPCVal) { sc.connTimeout = timeout } } // IPCValHeartbeat sets the period on which to check the liveness of the // connected Signer connections. func IPCValHeartbeat(period time.Duration) IPCValOption { return func(sc *IPCVal) { sc.connHeartbeat = period } } // IPCVal implements PrivValidator, it uses a unix socket to request signatures // from an external process. type IPCVal struct { cmn.BaseService *RemoteSignerClient addr string connTimeout time.Duration connHeartbeat time.Duration conn net.Conn cancelPing chan struct{} pingTicker *time.Ticker } // Check that IPCVal implements PrivValidator. var _ types.PrivValidator = (*IPCVal)(nil) // NewIPCVal returns an instance of IPCVal. func NewIPCVal( logger log.Logger, socketAddr string, ) *IPCVal { sc := &IPCVal{ addr: socketAddr, connTimeout: connTimeout, connHeartbeat: connHeartbeat, } sc.BaseService = *cmn.NewBaseService(logger, "IPCVal", sc) return sc } // OnStart implements cmn.Service. func (sc *IPCVal) OnStart() error { err := sc.connect() if err != nil { sc.Logger.Error("OnStart", "err", err) return err } sc.RemoteSignerClient = NewRemoteSignerClient(sc.conn) // Start a routine to keep the connection alive sc.cancelPing = make(chan struct{}, 1) sc.pingTicker = time.NewTicker(sc.connHeartbeat) go func() { for { select { case <-sc.pingTicker.C: err := sc.Ping() if err != nil { sc.Logger.Error("Ping", "err", err) } case <-sc.cancelPing: sc.pingTicker.Stop() return } } }() return nil } // OnStop implements cmn.Service. func (sc *IPCVal) OnStop() { if sc.cancelPing != nil { close(sc.cancelPing) } if sc.conn != nil { if err := sc.conn.Close(); err != nil { sc.Logger.Error("OnStop", "err", err) } } } func (sc *IPCVal) connect() error { la, err := net.ResolveUnixAddr("unix", sc.addr) if err != nil { return err } conn, err := net.DialUnix("unix", nil, la) if err != nil { return err } sc.conn = newTimeoutConn(conn, sc.connTimeout) return nil }