- package privval
-
- import (
- "net"
- "time"
-
- "github.com/tendermint/tendermint/crypto/ed25519"
- p2pconn "github.com/tendermint/tendermint/p2p/conn"
- )
-
- const (
- defaultTimeoutAcceptSeconds = 3
- defaultTimeoutReadWriteSeconds = 3
- )
-
- // timeoutError can be used to check if an error returned from the netp package
- // was due to a timeout.
- type timeoutError interface {
- Timeout() bool
- }
-
- //------------------------------------------------------------------
- // TCP Listener
-
- // TCPListenerOption sets an optional parameter on the tcpListener.
- type TCPListenerOption func(*tcpListener)
-
- // TCPListenerTimeoutAccept sets the timeout for the listener.
- // A zero time value disables the timeout.
- func TCPListenerTimeoutAccept(timeout time.Duration) TCPListenerOption {
- return func(tl *tcpListener) { tl.timeoutAccept = timeout }
- }
-
- // TCPListenerTimeoutReadWrite sets the read and write timeout for connections
- // from external signing processes.
- func TCPListenerTimeoutReadWrite(timeout time.Duration) TCPListenerOption {
- return func(tl *tcpListener) { tl.timeoutReadWrite = timeout }
- }
-
- // tcpListener implements net.Listener.
- var _ net.Listener = (*tcpListener)(nil)
-
- // tcpListener wraps a *net.TCPListener to standardise protocol timeouts
- // and potentially other tuning parameters. It also returns encrypted connections.
- type tcpListener struct {
- *net.TCPListener
-
- secretConnKey ed25519.PrivKeyEd25519
-
- timeoutAccept time.Duration
- timeoutReadWrite time.Duration
- }
-
- // NewTCPListener returns a listener that accepts authenticated encrypted connections
- // using the given secretConnKey and the default timeout values.
- func NewTCPListener(ln net.Listener, secretConnKey ed25519.PrivKeyEd25519) *tcpListener {
- return &tcpListener{
- TCPListener: ln.(*net.TCPListener),
- secretConnKey: secretConnKey,
- timeoutAccept: time.Second * defaultTimeoutAcceptSeconds,
- timeoutReadWrite: time.Second * defaultTimeoutReadWriteSeconds,
- }
- }
-
- // Accept implements net.Listener.
- func (ln *tcpListener) Accept() (net.Conn, error) {
- deadline := time.Now().Add(ln.timeoutAccept)
- err := ln.SetDeadline(deadline)
- if err != nil {
- return nil, err
- }
-
- tc, err := ln.AcceptTCP()
- if err != nil {
- return nil, err
- }
-
- // Wrap the conn in our timeout and encryption wrappers
- timeoutConn := newTimeoutConn(tc, ln.timeoutReadWrite)
- secretConn, err := p2pconn.MakeSecretConnection(timeoutConn, ln.secretConnKey)
- if err != nil {
- return nil, err
- }
-
- return secretConn, nil
- }
-
- //------------------------------------------------------------------
- // Unix Listener
-
- // unixListener implements net.Listener.
- var _ net.Listener = (*unixListener)(nil)
-
- type UnixListenerOption func(*unixListener)
-
- // UnixListenerTimeoutAccept sets the timeout for the listener.
- // A zero time value disables the timeout.
- func UnixListenerTimeoutAccept(timeout time.Duration) UnixListenerOption {
- return func(ul *unixListener) { ul.timeoutAccept = timeout }
- }
-
- // UnixListenerTimeoutReadWrite sets the read and write timeout for connections
- // from external signing processes.
- func UnixListenerTimeoutReadWrite(timeout time.Duration) UnixListenerOption {
- return func(ul *unixListener) { ul.timeoutReadWrite = timeout }
- }
-
- // unixListener wraps a *net.UnixListener to standardise protocol timeouts
- // and potentially other tuning parameters. It returns unencrypted connections.
- type unixListener struct {
- *net.UnixListener
-
- timeoutAccept time.Duration
- timeoutReadWrite time.Duration
- }
-
- // NewUnixListener returns a listener that accepts unencrypted connections
- // using the default timeout values.
- func NewUnixListener(ln net.Listener) *unixListener {
- return &unixListener{
- UnixListener: ln.(*net.UnixListener),
- timeoutAccept: time.Second * defaultTimeoutAcceptSeconds,
- timeoutReadWrite: time.Second * defaultTimeoutReadWriteSeconds,
- }
- }
-
- // Accept implements net.Listener.
- func (ln *unixListener) Accept() (net.Conn, error) {
- deadline := time.Now().Add(ln.timeoutAccept)
- err := ln.SetDeadline(deadline)
- if err != nil {
- return nil, err
- }
-
- tc, err := ln.AcceptUnix()
- if err != nil {
- return nil, err
- }
-
- // Wrap the conn in our timeout wrapper
- conn := newTimeoutConn(tc, ln.timeoutReadWrite)
-
- // TODO: wrap in something that authenticates
- // with a MAC - https://github.com/tendermint/tendermint/issues/3099
-
- return conn, nil
- }
-
- //------------------------------------------------------------------
- // Connection
-
- // timeoutConn implements net.Conn.
- var _ net.Conn = (*timeoutConn)(nil)
-
- // timeoutConn wraps a net.Conn to standardise protocol timeouts / deadline resets.
- type timeoutConn struct {
- net.Conn
- timeout time.Duration
- }
-
- // newTimeoutConn returns an instance of timeoutConn.
- func newTimeoutConn(conn net.Conn, timeout time.Duration) *timeoutConn {
- return &timeoutConn{
- conn,
- timeout,
- }
- }
-
- // Read implements net.Conn.
- func (c timeoutConn) Read(b []byte) (n int, err error) {
- // Reset deadline
- deadline := time.Now().Add(c.timeout)
- err = c.Conn.SetReadDeadline(deadline)
- if err != nil {
- return
- }
-
- return c.Conn.Read(b)
- }
-
- // Write implements net.Conn.
- func (c timeoutConn) Write(b []byte) (n int, err error) {
- // Reset deadline
- deadline := time.Now().Add(c.timeout)
- err = c.Conn.SetWriteDeadline(deadline)
- if err != nil {
- return
- }
-
- return c.Conn.Write(b)
- }
|