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.

131 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. return
  60. }
  61. go rs.handleConnection(conn)
  62. }
  63. }()
  64. return nil
  65. }
  66. // OnStop implements cmn.Service.
  67. func (rs *IPCRemoteSigner) OnStop() {
  68. if rs.listener != nil {
  69. if err := rs.listener.Close(); err != nil {
  70. rs.Logger.Error("OnStop", "err", cmn.ErrorWrap(err, "closing listener failed"))
  71. }
  72. }
  73. }
  74. func (rs *IPCRemoteSigner) listen() error {
  75. la, err := net.ResolveUnixAddr("unix", rs.addr)
  76. if err != nil {
  77. return err
  78. }
  79. rs.listener, err = net.ListenUnix("unix", la)
  80. return err
  81. }
  82. func (rs *IPCRemoteSigner) handleConnection(conn net.Conn) {
  83. for {
  84. if !rs.IsRunning() {
  85. return // Ignore error from listener closing.
  86. }
  87. // Reset the connection deadline
  88. conn.SetDeadline(time.Now().Add(rs.connDeadline))
  89. req, err := readMsg(conn)
  90. if err != nil {
  91. if err != io.EOF {
  92. rs.Logger.Error("handleConnection", "err", err)
  93. }
  94. return
  95. }
  96. res, err := handleRequest(req, rs.chainID, rs.privVal)
  97. if err != nil {
  98. // only log the error; we'll reply with an error in res
  99. rs.Logger.Error("handleConnection", "err", err)
  100. }
  101. err = writeMsg(conn, res)
  102. if err != nil {
  103. rs.Logger.Error("handleConnection", "err", err)
  104. return
  105. }
  106. }
  107. }