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.

132 lines
3.0 KiB

  1. package privval
  2. import (
  3. "io"
  4. "net"
  5. "time"
  6. cmn "github.com/tendermint/tendermint/libs/common"
  7. "github.com/tendermint/tendermint/libs/log"
  8. "github.com/tendermint/tendermint/types"
  9. )
  10. // IPCRemoteSignerOption sets an optional parameter on the IPCRemoteSigner.
  11. type IPCRemoteSignerOption func(*IPCRemoteSigner)
  12. // IPCRemoteSignerConnDeadline sets the read and write deadline for connections
  13. // from external signing processes.
  14. func IPCRemoteSignerConnDeadline(deadline time.Duration) IPCRemoteSignerOption {
  15. return func(ss *IPCRemoteSigner) { ss.connDeadline = deadline }
  16. }
  17. // IPCRemoteSignerConnRetries sets the amount of attempted retries to connect.
  18. func IPCRemoteSignerConnRetries(retries int) IPCRemoteSignerOption {
  19. return func(ss *IPCRemoteSigner) { ss.connRetries = retries }
  20. }
  21. // IPCRemoteSigner is a RPC implementation of PrivValidator that listens on a unix socket.
  22. type IPCRemoteSigner struct {
  23. cmn.BaseService
  24. addr string
  25. chainID string
  26. connDeadline time.Duration
  27. connRetries int
  28. privVal types.PrivValidator
  29. listener *net.UnixListener
  30. }
  31. // NewIPCRemoteSigner returns an instance of IPCRemoteSigner.
  32. func NewIPCRemoteSigner(
  33. logger log.Logger,
  34. chainID, socketAddr string,
  35. privVal types.PrivValidator,
  36. ) *IPCRemoteSigner {
  37. rs := &IPCRemoteSigner{
  38. addr: socketAddr,
  39. chainID: chainID,
  40. connDeadline: time.Second * defaultConnDeadlineSeconds,
  41. connRetries: defaultDialRetries,
  42. privVal: privVal,
  43. }
  44. rs.BaseService = *cmn.NewBaseService(logger, "IPCRemoteSigner", rs)
  45. return rs
  46. }
  47. // OnStart implements cmn.Service.
  48. func (rs *IPCRemoteSigner) OnStart() error {
  49. err := rs.listen()
  50. if err != nil {
  51. err = cmn.ErrorWrap(err, "listen")
  52. rs.Logger.Error("OnStart", "err", err)
  53. return err
  54. }
  55. go func() {
  56. for {
  57. conn, err := rs.listener.AcceptUnix()
  58. if err != nil {
  59. rs.Logger.Error("AcceptUnix", "err", err)
  60. return
  61. }
  62. go rs.handleConnection(conn)
  63. }
  64. }()
  65. return nil
  66. }
  67. // OnStop implements cmn.Service.
  68. func (rs *IPCRemoteSigner) OnStop() {
  69. if rs.listener != nil {
  70. if err := rs.listener.Close(); err != nil {
  71. rs.Logger.Error("OnStop", "err", cmn.ErrorWrap(err, "closing listener failed"))
  72. }
  73. }
  74. }
  75. func (rs *IPCRemoteSigner) listen() error {
  76. la, err := net.ResolveUnixAddr("unix", rs.addr)
  77. if err != nil {
  78. return err
  79. }
  80. rs.listener, err = net.ListenUnix("unix", la)
  81. return err
  82. }
  83. func (rs *IPCRemoteSigner) handleConnection(conn net.Conn) {
  84. for {
  85. if !rs.IsRunning() {
  86. return // Ignore error from listener closing.
  87. }
  88. // Reset the connection deadline
  89. conn.SetDeadline(time.Now().Add(rs.connDeadline))
  90. req, err := readMsg(conn)
  91. if err != nil {
  92. if err != io.EOF {
  93. rs.Logger.Error("handleConnection", "err", err)
  94. }
  95. return
  96. }
  97. res, err := handleRequest(req, rs.chainID, rs.privVal)
  98. if err != nil {
  99. // only log the error; we'll reply with an error in res
  100. rs.Logger.Error("handleConnection", "err", err)
  101. }
  102. err = writeMsg(conn, res)
  103. if err != nil {
  104. rs.Logger.Error("handleConnection", "err", err)
  105. return
  106. }
  107. }
  108. }