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