github.com/Team-Kujira/tendermint@v0.34.24-indexer/privval/signer_endpoint.go (about) 1 package privval 2 3 import ( 4 "fmt" 5 "net" 6 "time" 7 8 "github.com/tendermint/tendermint/libs/protoio" 9 "github.com/tendermint/tendermint/libs/service" 10 tmsync "github.com/tendermint/tendermint/libs/sync" 11 privvalproto "github.com/tendermint/tendermint/proto/tendermint/privval" 12 ) 13 14 const ( 15 defaultTimeoutReadWriteSeconds = 5 16 ) 17 18 type signerEndpoint struct { 19 service.BaseService 20 21 connMtx tmsync.Mutex 22 conn net.Conn 23 24 timeoutReadWrite time.Duration 25 } 26 27 // Close closes the underlying net.Conn. 28 func (se *signerEndpoint) Close() error { 29 se.DropConnection() 30 return nil 31 } 32 33 // IsConnected indicates if there is an active connection 34 func (se *signerEndpoint) IsConnected() bool { 35 se.connMtx.Lock() 36 defer se.connMtx.Unlock() 37 return se.isConnected() 38 } 39 40 // TryGetConnection retrieves a connection if it is already available 41 func (se *signerEndpoint) GetAvailableConnection(connectionAvailableCh chan net.Conn) bool { 42 se.connMtx.Lock() 43 defer se.connMtx.Unlock() 44 45 // Is there a connection ready? 46 select { 47 case se.conn = <-connectionAvailableCh: 48 return true 49 default: 50 } 51 return false 52 } 53 54 // TryGetConnection retrieves a connection if it is already available 55 func (se *signerEndpoint) WaitConnection(connectionAvailableCh chan net.Conn, maxWait time.Duration) error { 56 se.connMtx.Lock() 57 defer se.connMtx.Unlock() 58 59 select { 60 case se.conn = <-connectionAvailableCh: 61 case <-time.After(maxWait): 62 return ErrConnectionTimeout 63 } 64 65 return nil 66 } 67 68 // SetConnection replaces the current connection object 69 func (se *signerEndpoint) SetConnection(newConnection net.Conn) { 70 se.connMtx.Lock() 71 defer se.connMtx.Unlock() 72 se.conn = newConnection 73 } 74 75 // IsConnected indicates if there is an active connection 76 func (se *signerEndpoint) DropConnection() { 77 se.connMtx.Lock() 78 defer se.connMtx.Unlock() 79 se.dropConnection() 80 } 81 82 // ReadMessage reads a message from the endpoint 83 func (se *signerEndpoint) ReadMessage() (msg privvalproto.Message, err error) { 84 se.connMtx.Lock() 85 defer se.connMtx.Unlock() 86 87 if !se.isConnected() { 88 return msg, fmt.Errorf("endpoint is not connected: %w", ErrNoConnection) 89 } 90 // Reset read deadline 91 deadline := time.Now().Add(se.timeoutReadWrite) 92 93 err = se.conn.SetReadDeadline(deadline) 94 if err != nil { 95 return 96 } 97 const maxRemoteSignerMsgSize = 1024 * 10 98 protoReader := protoio.NewDelimitedReader(se.conn, maxRemoteSignerMsgSize) 99 _, err = protoReader.ReadMsg(&msg) 100 if _, ok := err.(timeoutError); ok { 101 if err != nil { 102 err = fmt.Errorf("%v: %w", err, ErrReadTimeout) 103 } else { 104 err = fmt.Errorf("empty error: %w", ErrReadTimeout) 105 } 106 107 se.Logger.Debug("Dropping [read]", "obj", se) 108 se.dropConnection() 109 } 110 111 return 112 } 113 114 // WriteMessage writes a message from the endpoint 115 func (se *signerEndpoint) WriteMessage(msg privvalproto.Message) (err error) { 116 se.connMtx.Lock() 117 defer se.connMtx.Unlock() 118 119 if !se.isConnected() { 120 return fmt.Errorf("endpoint is not connected: %w", ErrNoConnection) 121 } 122 123 protoWriter := protoio.NewDelimitedWriter(se.conn) 124 125 // Reset read deadline 126 deadline := time.Now().Add(se.timeoutReadWrite) 127 err = se.conn.SetWriteDeadline(deadline) 128 if err != nil { 129 return 130 } 131 132 _, err = protoWriter.WriteMsg(&msg) 133 if _, ok := err.(timeoutError); ok { 134 if err != nil { 135 err = fmt.Errorf("%v: %w", err, ErrWriteTimeout) 136 } else { 137 err = fmt.Errorf("empty error: %w", ErrWriteTimeout) 138 } 139 se.dropConnection() 140 } 141 142 return 143 } 144 145 func (se *signerEndpoint) isConnected() bool { 146 return se.conn != nil 147 } 148 149 func (se *signerEndpoint) dropConnection() { 150 if se.conn != nil { 151 if err := se.conn.Close(); err != nil { 152 se.Logger.Error("signerEndpoint::dropConnection", "err", err) 153 } 154 se.conn = nil 155 } 156 }