github.com/vipernet-xyz/tm@v0.34.24/privval/signer_endpoint.go (about)

     1  package privval
     2  
     3  import (
     4  	"fmt"
     5  	"net"
     6  	"time"
     7  
     8  	"github.com/vipernet-xyz/tm/libs/protoio"
     9  	"github.com/vipernet-xyz/tm/libs/service"
    10  	tmsync "github.com/vipernet-xyz/tm/libs/sync"
    11  	privvalproto "github.com/vipernet-xyz/tm/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  }