github.com/franono/tendermint@v0.32.2-0.20200527150959-749313264ce9/privval/socket_listeners.go (about)

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