We now first exchange a very minimal header, consisting of just the
name of the protocol ("weave") and the min and max version (encoded as
a byte each) we support. This leaves all other details of the
protocol, including the contents of of the handshake, open.
Peers agree to communicate using the maximum mutually supported
version. We record this in the LocalConnection, though atm nothing is
making use of that information.
We set a shorter than normal deadline (10s instead of 60s) for the
header exchange, so we detect version mismatches, garbage, or
non-responsive remotes quickly.
We reset the protocol version to '1' since this is a fresh start; old
weaves will not be able to parse the header.
Closes #871.
77 lines
1.9 KiB
Go
77 lines
1.9 KiB
Go
package router
|
|
|
|
import (
|
|
"bytes"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
const (
|
|
Protocol = "weave"
|
|
ProtocolVersion byte = 1
|
|
ProtocolMinVersion byte = ProtocolVersion
|
|
)
|
|
|
|
var (
|
|
ProtocolBytes = []byte(Protocol)
|
|
ProtocolLen = len(ProtocolBytes)
|
|
ProtocolHeader = append(ProtocolBytes, ProtocolMinVersion, ProtocolVersion)
|
|
ProtocolHeaderLen = len(ProtocolHeader)
|
|
)
|
|
|
|
func exchangeProtocolHeader(w io.Writer, r io.Reader) (byte, error) {
|
|
if n, err := w.Write(ProtocolHeader); err != nil {
|
|
return 0, err
|
|
} else if n != ProtocolHeaderLen {
|
|
return 0, fmt.Errorf("failed to send complete protocol header")
|
|
}
|
|
header := make([]byte, ProtocolHeaderLen)
|
|
if n, err := io.ReadFull(r, header); err != nil && n == 0 {
|
|
return 0, fmt.Errorf("failed to receive remote protocol header: %s", err)
|
|
} else if err != nil {
|
|
return 0, fmt.Errorf("received incomplete remote protocol header (%d octets instead of %d): %v; error: %s",
|
|
n, ProtocolHeaderLen, header[:n], err)
|
|
}
|
|
if !bytes.Equal(ProtocolBytes, header[:ProtocolLen]) {
|
|
return 0, fmt.Errorf("remote protocol header not recognised: %v", header[:ProtocolHeaderLen])
|
|
}
|
|
var (
|
|
remoteMinVersion = header[ProtocolLen]
|
|
remoteVersion = header[ProtocolLen+1]
|
|
)
|
|
minVersion := ProtocolMinVersion
|
|
if remoteMinVersion > minVersion {
|
|
minVersion = remoteMinVersion
|
|
}
|
|
maxVersion := ProtocolVersion
|
|
if remoteVersion < maxVersion {
|
|
maxVersion = remoteVersion
|
|
}
|
|
if minVersion > maxVersion {
|
|
return 0, fmt.Errorf("remote version [%d,%d] is incompatible with our version [%d,%d]",
|
|
remoteMinVersion, remoteVersion, ProtocolMinVersion, ProtocolVersion)
|
|
}
|
|
return maxVersion, nil
|
|
}
|
|
|
|
type ProtocolTag byte
|
|
|
|
const (
|
|
ProtocolHeartbeat ProtocolTag = iota
|
|
ProtocolConnectionEstablished
|
|
ProtocolFragmentationReceived
|
|
ProtocolPMTUVerified
|
|
ProtocolGossip
|
|
ProtocolGossipUnicast
|
|
ProtocolGossipBroadcast
|
|
)
|
|
|
|
type ProtocolMsg struct {
|
|
tag ProtocolTag
|
|
msg []byte
|
|
}
|
|
|
|
type ProtocolSender interface {
|
|
SendProtocolMsg(m ProtocolMsg)
|
|
}
|