github.com/pokt-network/tendermint@v0.32.11-0.20230426215212-59310158d3e9/privval/signer_listener_endpoint.go (about) 1 package privval 2 3 import ( 4 "fmt" 5 "net" 6 "sync" 7 "time" 8 9 "github.com/tendermint/tendermint/libs/log" 10 "github.com/tendermint/tendermint/libs/service" 11 ) 12 13 // SignerValidatorEndpointOption sets an optional parameter on the SocketVal. 14 type SignerValidatorEndpointOption func(*SignerListenerEndpoint) 15 16 // SignerListenerEndpoint listens for an external process to dial in 17 // and keeps the connection alive by dropping and reconnecting 18 type SignerListenerEndpoint struct { 19 signerEndpoint 20 21 listener net.Listener 22 connectRequestCh chan struct{} 23 connectionAvailableCh chan net.Conn 24 25 timeoutAccept time.Duration 26 pingTimer *time.Ticker 27 28 instanceMtx sync.Mutex // Ensures instance public methods access, i.e. SendRequest 29 } 30 31 // NewSignerListenerEndpoint returns an instance of SignerListenerEndpoint. 32 func NewSignerListenerEndpoint( 33 logger log.Logger, 34 listener net.Listener, 35 ) *SignerListenerEndpoint { 36 sc := &SignerListenerEndpoint{ 37 listener: listener, 38 timeoutAccept: defaultTimeoutAcceptSeconds * time.Second, 39 } 40 41 sc.BaseService = *service.NewBaseService(logger, "SignerListenerEndpoint", sc) 42 sc.signerEndpoint.timeoutReadWrite = defaultTimeoutReadWriteSeconds * time.Second 43 return sc 44 } 45 46 // OnStart implements service.Service. 47 func (sl *SignerListenerEndpoint) OnStart() error { 48 sl.connectRequestCh = make(chan struct{}) 49 sl.connectionAvailableCh = make(chan net.Conn) 50 51 sl.pingTimer = time.NewTicker(defaultPingPeriodMilliseconds * time.Millisecond) 52 53 go sl.serviceLoop() 54 go sl.pingLoop() 55 56 sl.connectRequestCh <- struct{}{} 57 58 return nil 59 } 60 61 // OnStop implements service.Service 62 func (sl *SignerListenerEndpoint) OnStop() { 63 sl.instanceMtx.Lock() 64 defer sl.instanceMtx.Unlock() 65 _ = sl.Close() 66 67 // Stop listening 68 if sl.listener != nil { 69 if err := sl.listener.Close(); err != nil { 70 sl.Logger.Error("Closing Listener", "err", err) 71 sl.listener = nil 72 } 73 } 74 75 sl.pingTimer.Stop() 76 } 77 78 // WaitForConnection waits maxWait for a connection or returns a timeout error 79 func (sl *SignerListenerEndpoint) WaitForConnection(maxWait time.Duration) error { 80 sl.instanceMtx.Lock() 81 defer sl.instanceMtx.Unlock() 82 return sl.ensureConnection(maxWait) 83 } 84 85 // SendRequest ensures there is a connection, sends a request and waits for a response 86 func (sl *SignerListenerEndpoint) SendRequest(request SignerMessage) (SignerMessage, error) { 87 sl.instanceMtx.Lock() 88 defer sl.instanceMtx.Unlock() 89 90 err := sl.ensureConnection(sl.timeoutAccept) 91 if err != nil { 92 return nil, err 93 } 94 95 err = sl.WriteMessage(request) 96 if err != nil { 97 return nil, err 98 } 99 100 res, err := sl.ReadMessage() 101 if err != nil { 102 return nil, err 103 } 104 105 return res, nil 106 } 107 108 func (sl *SignerListenerEndpoint) ensureConnection(maxWait time.Duration) error { 109 if sl.IsConnected() { 110 return nil 111 } 112 113 // Is there a connection ready? then use it 114 if sl.GetAvailableConnection(sl.connectionAvailableCh) { 115 return nil 116 } 117 118 // block until connected or timeout 119 sl.triggerConnect() 120 err := sl.WaitConnection(sl.connectionAvailableCh, maxWait) 121 if err != nil { 122 return err 123 } 124 125 return nil 126 } 127 128 func (sl *SignerListenerEndpoint) acceptNewConnection() (net.Conn, error) { 129 if !sl.IsRunning() || sl.listener == nil { 130 return nil, fmt.Errorf("endpoint is closing") 131 } 132 133 // wait for a new conn 134 sl.Logger.Info("SignerListener: Listening for new connection") 135 conn, err := sl.listener.Accept() 136 if err != nil { 137 return nil, err 138 } 139 140 return conn, nil 141 } 142 143 func (sl *SignerListenerEndpoint) triggerConnect() { 144 select { 145 case sl.connectRequestCh <- struct{}{}: 146 default: 147 } 148 } 149 150 func (sl *SignerListenerEndpoint) triggerReconnect() { 151 sl.DropConnection() 152 sl.triggerConnect() 153 } 154 155 func (sl *SignerListenerEndpoint) serviceLoop() { 156 for { 157 select { 158 case <-sl.connectRequestCh: 159 { 160 conn, err := sl.acceptNewConnection() 161 if err == nil { 162 sl.Logger.Info("SignerListener: Connected") 163 164 // We have a good connection, wait for someone that needs one otherwise cancellation 165 select { 166 case sl.connectionAvailableCh <- conn: 167 case <-sl.Quit(): 168 return 169 } 170 } 171 172 select { 173 case sl.connectRequestCh <- struct{}{}: 174 default: 175 } 176 } 177 case <-sl.Quit(): 178 return 179 } 180 } 181 } 182 183 func (sl *SignerListenerEndpoint) pingLoop() { 184 for { 185 select { 186 case <-sl.pingTimer.C: 187 { 188 _, err := sl.SendRequest(&PingRequest{}) 189 if err != nil { 190 sl.Logger.Error("SignerListener: Ping timeout") 191 sl.triggerReconnect() 192 } 193 } 194 case <-sl.Quit(): 195 return 196 } 197 } 198 }