Documentation ¶
Overview ¶
Package versionhandshake wraps a transport.{Connecter,AuthenticatedListener} to add an exchange of protocol version information on connection establishment.
The protocol version information (banner) is plain text, thus making it easy to diagnose issues with standard tools.
Index ¶
Constants ¶
const HandshakeMessageMaxLen = 16 * 4096
const MaxProtocolVersion = 9999
MaxProtocolVersion is the maximum allowed protocol version. This is a protocol constant, changing it may break the wire format.
Variables ¶
This section is empty.
Functions ¶
func Listener ¶
func Listener(l transport.AuthenticatedListener, timeout time.Duration) transport.AuthenticatedListener
Types ¶
type HandshakeConnecter ¶
type HandshakeConnecter struct {
// contains filtered or unexported fields
}
type HandshakeError ¶
type HandshakeError struct { // If not nil, the underlying IO error that caused the handshake to fail. IOError error // contains filtered or unexported fields }
A HandshakeError describes what went wrong during the handshake. It implements net.Error and is always temporary.
func DoHandshakeCurrentVersion ¶
func DoHandshakeCurrentVersion(conn net.Conn, deadline time.Time) *HandshakeError
func DoHandshakeVersion ¶
func (HandshakeError) Error ¶
func (e HandshakeError) Error() string
func (HandshakeError) Temporary ¶
func (e HandshakeError) Temporary() bool
When a net.Listener.Accept() returns an error, the server must decide whether to retry calling Accept() or not. On some platforms (e.g., Linux), Accept() can return errors related to the specific protocol connection that was supposed to be returned as asocket FD. Obviously, we want to ignore, maybe log, those errors and retry Accept() immediately to serve other connections. But there are also conditions where we get Accept() errors because the process has run out of file descriptors. In that case, retrying won't help. We need to close some file descriptor to make progress. Note that there could be lots of open file descriptors because we have accepted, and not yet closed, lots of connections in the past. And then, of course there can be errors where we just want to return, e.g., if there's a programming error and we're getting an EBADFD or whatever.
So, the serve loops in net/http.Server.Serve() or gRPC's server.Serve() must inspect the error and decide what to do. The vehicle for this is the
interface { Temporary() bool }
Behavior in both of the aforementioned Serve() loops:
- if the error doesn't implement the interface, stop serving and return
- `Temporary() == true`: retry with back-off
- `Temporary() == false`: stop serving and return
So, to make this package's HandshakeListener work with these Serve() loops, we return Temporary() == true if the handshake fails. In the aforementioned categories, that's the case of a per-connection protocol error.
Note: the net.Error interface has deprecated the Temporary() method in go.dev/issue/45729, but there is no replacement for users of .Accept(). Existing users of .Accept() continue to check for the interface. So, we need to continue supporting Temporary() until there's a different mechanism for serve loops to decide whether to retry or not. The following mailing list post proposes to eliminate the retries completely, but it seems like the effort has stalled. https://groups.google.com/g/golang-nuts/c/-JcZzOkyqYI/m/xwaZzjCgAwAJ
func (HandshakeError) Timeout ¶
func (e HandshakeError) Timeout() bool
If the underlying IOError was net.Error.Timeout(), Timeout() returns that value. Otherwise false.
type HandshakeListener ¶
type HandshakeListener struct {
// contains filtered or unexported fields
}
wrapper type that performs a a protocol version handshake before returning the connection
func (HandshakeListener) Addr ¶
func (l HandshakeListener) Addr() net.Addr
func (HandshakeListener) Close ¶
func (l HandshakeListener) Close() error
type HandshakeMessage ¶
func (*HandshakeMessage) DecodeReader ¶
func (m *HandshakeMessage) DecodeReader(r io.Reader, maxLen int) error
func (*HandshakeMessage) Encode ¶
func (m *HandshakeMessage) Encode() ([]byte, error)
Only returns *HandshakeError as error.