github.com/DFWallet/tendermint-cosmos@v0.0.2/privval/socket_listeners.go (about) 1 package privval 2 3 import ( 4 "net" 5 "time" 6 7 "github.com/DFWallet/tendermint-cosmos/crypto/ed25519" 8 p2pconn "github.com/DFWallet/tendermint-cosmos/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 standardise 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 standardise 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/DFWallet/tendermint-cosmos/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 standardise 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 }