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 }