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

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