package privval
|
|
|
|
import (
|
|
"net"
|
|
"time"
|
|
|
|
"github.com/tendermint/tendermint/crypto/ed25519"
|
|
p2pconn "github.com/tendermint/tendermint/p2p/conn"
|
|
)
|
|
|
|
const (
|
|
defaultAcceptDeadlineSeconds = 3
|
|
defaultConnDeadlineSeconds = 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)
|
|
|
|
// TCPListenerAcceptDeadline sets the deadline for the listener.
|
|
// A zero time value disables the deadline.
|
|
func TCPListenerAcceptDeadline(deadline time.Duration) TCPListenerOption {
|
|
return func(tl *tcpListener) { tl.acceptDeadline = deadline }
|
|
}
|
|
|
|
// TCPListenerConnDeadline sets the read and write deadline for connections
|
|
// from external signing processes.
|
|
func TCPListenerConnDeadline(deadline time.Duration) TCPListenerOption {
|
|
return func(tl *tcpListener) { tl.connDeadline = deadline }
|
|
}
|
|
|
|
// 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
|
|
|
|
acceptDeadline time.Duration
|
|
connDeadline 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,
|
|
acceptDeadline: time.Second * defaultAcceptDeadlineSeconds,
|
|
connDeadline: time.Second * defaultConnDeadlineSeconds,
|
|
}
|
|
}
|
|
|
|
// Accept implements net.Listener.
|
|
func (ln *tcpListener) Accept() (net.Conn, error) {
|
|
err := ln.SetDeadline(time.Now().Add(ln.acceptDeadline))
|
|
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.connDeadline)
|
|
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)
|
|
|
|
// UnixListenerAcceptDeadline sets the deadline for the listener.
|
|
// A zero time value disables the deadline.
|
|
func UnixListenerAcceptDeadline(deadline time.Duration) UnixListenerOption {
|
|
return func(ul *unixListener) { ul.acceptDeadline = deadline }
|
|
}
|
|
|
|
// UnixListenerConnDeadline sets the read and write deadline for connections
|
|
// from external signing processes.
|
|
func UnixListenerConnDeadline(deadline time.Duration) UnixListenerOption {
|
|
return func(ul *unixListener) { ul.connDeadline = deadline }
|
|
}
|
|
|
|
// unixListener wraps a *net.UnixListener to standardise protocol timeouts
|
|
// and potentially other tuning parameters. It returns unencrypted connections.
|
|
type unixListener struct {
|
|
*net.UnixListener
|
|
|
|
acceptDeadline time.Duration
|
|
connDeadline 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),
|
|
acceptDeadline: time.Second * defaultAcceptDeadlineSeconds,
|
|
connDeadline: time.Second * defaultConnDeadlineSeconds,
|
|
}
|
|
}
|
|
|
|
// Accept implements net.Listener.
|
|
func (ln *unixListener) Accept() (net.Conn, error) {
|
|
err := ln.SetDeadline(time.Now().Add(ln.acceptDeadline))
|
|
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.connDeadline)
|
|
|
|
// 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
|
|
|
|
connDeadline time.Duration
|
|
}
|
|
|
|
// newTimeoutConn returns an instance of timeoutConn.
|
|
func newTimeoutConn(
|
|
conn net.Conn,
|
|
connDeadline time.Duration) *timeoutConn {
|
|
return &timeoutConn{
|
|
conn,
|
|
connDeadline,
|
|
}
|
|
}
|
|
|
|
// Read implements net.Conn.
|
|
func (c timeoutConn) Read(b []byte) (n int, err error) {
|
|
// Reset deadline
|
|
c.Conn.SetReadDeadline(time.Now().Add(c.connDeadline))
|
|
|
|
return c.Conn.Read(b)
|
|
}
|
|
|
|
// Write implements net.Conn.
|
|
func (c timeoutConn) Write(b []byte) (n int, err error) {
|
|
// Reset deadline
|
|
c.Conn.SetWriteDeadline(time.Now().Add(c.connDeadline))
|
|
|
|
return c.Conn.Write(b)
|
|
}
|