github.com/ari-anchor/sei-tendermint@v0.0.0-20230519144642-dc826b7b56bb/privval/socket_listeners.go (about)

     1  package privval
     2  
     3  import (
     4  	"net"
     5  	"time"
     6  
     7  	"github.com/ari-anchor/sei-tendermint/crypto/ed25519"
     8  )
     9  
    10  const (
    11  	defaultTimeoutAcceptSeconds = 3
    12  )
    13  
    14  // timeoutError can be used to check if an error returned from the netp package
    15  // was due to a timeout.
    16  type timeoutError interface {
    17  	Timeout() bool
    18  }
    19  
    20  //------------------------------------------------------------------
    21  // TCP Listener
    22  
    23  // TCPListenerOption sets an optional parameter on the tcpListener.
    24  type TCPListenerOption func(*TCPListener)
    25  
    26  // TCPListenerTimeoutAccept sets the timeout for the listener.
    27  // A zero time value disables the timeout.
    28  func TCPListenerTimeoutAccept(timeout time.Duration) TCPListenerOption {
    29  	return func(tl *TCPListener) { tl.timeoutAccept = timeout }
    30  }
    31  
    32  // TCPListenerTimeoutReadWrite sets the read and write timeout for connections
    33  // from external signing processes.
    34  func TCPListenerTimeoutReadWrite(timeout time.Duration) TCPListenerOption {
    35  	return func(tl *TCPListener) { tl.timeoutReadWrite = timeout }
    36  }
    37  
    38  // tcpListener implements net.Listener.
    39  var _ net.Listener = (*TCPListener)(nil)
    40  
    41  // TCPListener wraps a *net.TCPListener to standardize protocol timeouts
    42  // and potentially other tuning parameters. It also returns encrypted connections.
    43  type TCPListener struct {
    44  	*net.TCPListener
    45  
    46  	secretConnKey ed25519.PrivKey
    47  
    48  	timeoutAccept    time.Duration
    49  	timeoutReadWrite time.Duration
    50  }
    51  
    52  // NewTCPListener returns a listener that accepts authenticated encrypted connections
    53  // using the given secretConnKey and the default timeout values.
    54  func NewTCPListener(ln net.Listener, secretConnKey ed25519.PrivKey) *TCPListener {
    55  	return &TCPListener{
    56  		TCPListener:      ln.(*net.TCPListener),
    57  		secretConnKey:    secretConnKey,
    58  		timeoutAccept:    time.Second * defaultTimeoutAcceptSeconds,
    59  		timeoutReadWrite: time.Second * defaultTimeoutReadWriteSeconds,
    60  	}
    61  }
    62  
    63  // Accept implements net.Listener.
    64  func (ln *TCPListener) Accept() (net.Conn, error) {
    65  	deadline := time.Now().Add(ln.timeoutAccept)
    66  	err := ln.SetDeadline(deadline)
    67  	if err != nil {
    68  		return nil, err
    69  	}
    70  
    71  	tc, err := ln.AcceptTCP()
    72  	if err != nil {
    73  		return nil, err
    74  	}
    75  
    76  	// Wrap the conn in our timeout and encryption wrappers
    77  	timeoutConn := newTimeoutConn(tc, ln.timeoutReadWrite)
    78  	secretConn, err := MakeSecretConnection(timeoutConn, ln.secretConnKey)
    79  	if err != nil {
    80  		return nil, err
    81  	}
    82  
    83  	return secretConn, nil
    84  }
    85  
    86  //------------------------------------------------------------------
    87  // Unix Listener
    88  
    89  // unixListener implements net.Listener.
    90  var _ net.Listener = (*UnixListener)(nil)
    91  
    92  type UnixListenerOption func(*UnixListener)
    93  
    94  // UnixListenerTimeoutAccept sets the timeout for the listener.
    95  // A zero time value disables the timeout.
    96  func UnixListenerTimeoutAccept(timeout time.Duration) UnixListenerOption {
    97  	return func(ul *UnixListener) { ul.timeoutAccept = timeout }
    98  }
    99  
   100  // UnixListenerTimeoutReadWrite sets the read and write timeout for connections
   101  // from external signing processes.
   102  func UnixListenerTimeoutReadWrite(timeout time.Duration) UnixListenerOption {
   103  	return func(ul *UnixListener) { ul.timeoutReadWrite = timeout }
   104  }
   105  
   106  // UnixListener wraps a *net.UnixListener to standardize protocol timeouts
   107  // and potentially other tuning parameters. It returns unencrypted connections.
   108  type UnixListener struct {
   109  	*net.UnixListener
   110  
   111  	timeoutAccept    time.Duration
   112  	timeoutReadWrite time.Duration
   113  }
   114  
   115  // NewUnixListener returns a listener that accepts unencrypted connections
   116  // using the default timeout values.
   117  func NewUnixListener(ln net.Listener) *UnixListener {
   118  	return &UnixListener{
   119  		UnixListener:     ln.(*net.UnixListener),
   120  		timeoutAccept:    time.Second * defaultTimeoutAcceptSeconds,
   121  		timeoutReadWrite: time.Second * defaultTimeoutReadWriteSeconds,
   122  	}
   123  }
   124  
   125  // Accept implements net.Listener.
   126  func (ln *UnixListener) Accept() (net.Conn, error) {
   127  	deadline := time.Now().Add(ln.timeoutAccept)
   128  	err := ln.SetDeadline(deadline)
   129  	if err != nil {
   130  		return nil, err
   131  	}
   132  
   133  	tc, err := ln.AcceptUnix()
   134  	if err != nil {
   135  		return nil, err
   136  	}
   137  
   138  	// Wrap the conn in our timeout wrapper
   139  	conn := newTimeoutConn(tc, ln.timeoutReadWrite)
   140  
   141  	// TODO: wrap in something that authenticates
   142  	// with a MAC - https://github.com/ari-anchor/sei-tendermint/issues/3099
   143  
   144  	return conn, nil
   145  }
   146  
   147  //------------------------------------------------------------------
   148  // Connection
   149  
   150  // timeoutConn implements net.Conn.
   151  var _ net.Conn = (*timeoutConn)(nil)
   152  
   153  // timeoutConn wraps a net.Conn to standardize protocol timeouts / deadline resets.
   154  type timeoutConn struct {
   155  	net.Conn
   156  	timeout time.Duration
   157  }
   158  
   159  // newTimeoutConn returns an instance of timeoutConn.
   160  func newTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn {
   161  	return &timeoutConn{
   162  		conn,
   163  		timeout,
   164  	}
   165  }
   166  
   167  // Read implements net.Conn.
   168  func (c timeoutConn) Read(b []byte) (n int, err error) {
   169  	// Reset deadline
   170  	deadline := time.Now().Add(c.timeout)
   171  	err = c.Conn.SetReadDeadline(deadline)
   172  	if err != nil {
   173  		return
   174  	}
   175  
   176  	return c.Conn.Read(b)
   177  }
   178  
   179  // Write implements net.Conn.
   180  func (c timeoutConn) Write(b []byte) (n int, err error) {
   181  	// Reset deadline
   182  	deadline := time.Now().Add(c.timeout)
   183  	err = c.Conn.SetWriteDeadline(deadline)
   184  	if err != nil {
   185  		return
   186  	}
   187  
   188  	return c.Conn.Write(b)
   189  }