forked from tendermint/tendermint
-
Notifications
You must be signed in to change notification settings - Fork 0
/
signer_service_endpoint.go
139 lines (114 loc) · 3.41 KB
/
signer_service_endpoint.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
package privval
import (
"io"
"net"
"time"
cmn "github.com/tendermint/tendermint/libs/common"
"github.com/tendermint/tendermint/libs/log"
"github.com/tendermint/tendermint/types"
)
// SignerServiceEndpointOption sets an optional parameter on the SignerServiceEndpoint.
type SignerServiceEndpointOption func(*SignerServiceEndpoint)
// SignerServiceEndpointTimeoutReadWrite sets the read and write timeout for connections
// from external signing processes.
func SignerServiceEndpointTimeoutReadWrite(timeout time.Duration) SignerServiceEndpointOption {
return func(ss *SignerServiceEndpoint) { ss.timeoutReadWrite = timeout }
}
// SignerServiceEndpointConnRetries sets the amount of attempted retries to connect.
func SignerServiceEndpointConnRetries(retries int) SignerServiceEndpointOption {
return func(ss *SignerServiceEndpoint) { ss.connRetries = retries }
}
// SignerServiceEndpoint dials using its dialer and responds to any
// signature requests using its privVal.
type SignerServiceEndpoint struct {
cmn.BaseService
chainID string
timeoutReadWrite time.Duration
connRetries int
privVal types.PrivValidator
dialer SocketDialer
conn net.Conn
}
// NewSignerServiceEndpoint returns a SignerServiceEndpoint that will dial using the given
// dialer and respond to any signature requests over the connection
// using the given privVal.
func NewSignerServiceEndpoint(
logger log.Logger,
chainID string,
privVal types.PrivValidator,
dialer SocketDialer,
) *SignerServiceEndpoint {
se := &SignerServiceEndpoint{
chainID: chainID,
timeoutReadWrite: time.Second * defaultTimeoutReadWriteSeconds,
connRetries: defaultMaxDialRetries,
privVal: privVal,
dialer: dialer,
}
se.BaseService = *cmn.NewBaseService(logger, "SignerServiceEndpoint", se)
return se
}
// OnStart implements cmn.Service.
func (se *SignerServiceEndpoint) OnStart() error {
conn, err := se.connect()
if err != nil {
se.Logger.Error("OnStart", "err", err)
return err
}
se.conn = conn
go se.handleConnection(conn)
return nil
}
// OnStop implements cmn.Service.
func (se *SignerServiceEndpoint) OnStop() {
if se.conn == nil {
return
}
if err := se.conn.Close(); err != nil {
se.Logger.Error("OnStop", "err", cmn.ErrorWrap(err, "closing listener failed"))
}
}
func (se *SignerServiceEndpoint) connect() (net.Conn, error) {
for retries := 0; retries < se.connRetries; retries++ {
// Don't sleep if it is the first retry.
if retries > 0 {
time.Sleep(se.timeoutReadWrite)
}
conn, err := se.dialer()
if err == nil {
return conn, nil
}
se.Logger.Error("dialing", "err", err)
}
return nil, ErrDialRetryMax
}
func (se *SignerServiceEndpoint) handleConnection(conn net.Conn) {
for {
if !se.IsRunning() {
return // Ignore error from listener closing.
}
// Reset the connection deadline
deadline := time.Now().Add(se.timeoutReadWrite)
err := conn.SetDeadline(deadline)
if err != nil {
return
}
req, err := readMsg(conn)
if err != nil {
if err != io.EOF {
se.Logger.Error("handleConnection readMsg", "err", err)
}
return
}
res, err := handleRequest(req, se.chainID, se.privVal)
if err != nil {
// only log the error; we'll reply with an error in res
se.Logger.Error("handleConnection handleRequest", "err", err)
}
err = writeMsg(conn, res)
if err != nil {
se.Logger.Error("handleConnection writeMsg", "err", err)
return
}
}
}