github.com/okex/exchain@v1.8.0/libs/tendermint/privval/signer_endpoint.go (about) 1 package privval 2 3 import ( 4 "fmt" 5 "net" 6 "sync" 7 "time" 8 9 "github.com/pkg/errors" 10 11 "github.com/okex/exchain/libs/tendermint/libs/service" 12 ) 13 14 const ( 15 defaultTimeoutReadWriteSeconds = 5 16 ) 17 18 type signerEndpoint struct { 19 service.BaseService 20 21 connMtx sync.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 SignerMessage, err error) { 84 se.connMtx.Lock() 85 defer se.connMtx.Unlock() 86 87 if !se.isConnected() { 88 return nil, fmt.Errorf("endpoint is not connected") 89 } 90 91 // Reset read deadline 92 deadline := time.Now().Add(se.timeoutReadWrite) 93 94 err = se.conn.SetReadDeadline(deadline) 95 if err != nil { 96 return 97 } 98 99 const maxRemoteSignerMsgSize = 1024 * 10 100 _, err = cdc.UnmarshalBinaryLengthPrefixedReader(se.conn, &msg, maxRemoteSignerMsgSize) 101 if _, ok := err.(timeoutError); ok { 102 if err != nil { 103 err = errors.Wrap(ErrReadTimeout, err.Error()) 104 } else { 105 err = errors.Wrap(ErrReadTimeout, "Empty error") 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 SignerMessage) (err error) { 116 se.connMtx.Lock() 117 defer se.connMtx.Unlock() 118 119 if !se.isConnected() { 120 return errors.Wrap(ErrNoConnection, "endpoint is not connected") 121 } 122 123 // Reset read deadline 124 deadline := time.Now().Add(se.timeoutReadWrite) 125 err = se.conn.SetWriteDeadline(deadline) 126 if err != nil { 127 return 128 } 129 130 _, err = cdc.MarshalBinaryLengthPrefixedWriter(se.conn, msg) 131 if _, ok := err.(timeoutError); ok { 132 if err != nil { 133 err = errors.Wrap(ErrWriteTimeout, err.Error()) 134 } else { 135 err = errors.Wrap(ErrWriteTimeout, "Empty error") 136 } 137 se.dropConnection() 138 } 139 140 return 141 } 142 143 func (se *signerEndpoint) isConnected() bool { 144 return se.conn != nil 145 } 146 147 func (se *signerEndpoint) dropConnection() { 148 if se.conn != nil { 149 if err := se.conn.Close(); err != nil { 150 se.Logger.Error("signerEndpoint::dropConnection", "err", err) 151 } 152 se.conn = nil 153 } 154 }