Ensure backwards compatibility before modifying protocol

This change makes sure that things work smoothly when "we" are a newer
version than our peer and have more fields in our messages than they do.
Missing fields will be left at zero/nil.

(The other side will ignore our extra fields, for the same effect.)
This commit is contained in:
Jakob Borg 2015-01-08 14:21:58 +01:00
parent 09b534b8a3
commit a3ea9427d1

View File

@ -133,6 +133,10 @@ type encodable interface {
AppendXDR([]byte) ([]byte, error) AppendXDR([]byte) ([]byte, error)
} }
type isEofer interface {
IsEOF() bool
}
const ( const (
pingTimeout = 30 * time.Second pingTimeout = 30 * time.Second
pingIdleTime = 60 * time.Second pingIdleTime = 60 * time.Second
@ -376,20 +380,36 @@ func (c *rawConnection) readMessage() (hdr header, msg encodable, err error) {
} }
} }
// We check each returned error for the XDRError.IsEOF() method.
// IsEOF()==true here means that the message contained fewer fields than
// expected. It does not signify an EOF on the socket, because we've
// successfully read a size value and that many bytes already. New fields
// we expected but the other peer didn't send should be interpreted as
// zero/nil, and if that's not valid we'll verify it somewhere else.
switch hdr.msgType { switch hdr.msgType {
case messageTypeIndex, messageTypeIndexUpdate: case messageTypeIndex, messageTypeIndexUpdate:
var idx IndexMessage var idx IndexMessage
err = idx.UnmarshalXDR(msgBuf) err = idx.UnmarshalXDR(msgBuf)
if xdrErr, ok := err.(isEofer); ok && xdrErr.IsEOF() {
err = nil
}
msg = idx msg = idx
case messageTypeRequest: case messageTypeRequest:
var req RequestMessage var req RequestMessage
err = req.UnmarshalXDR(msgBuf) err = req.UnmarshalXDR(msgBuf)
if xdrErr, ok := err.(isEofer); ok && xdrErr.IsEOF() {
err = nil
}
msg = req msg = req
case messageTypeResponse: case messageTypeResponse:
var resp ResponseMessage var resp ResponseMessage
err = resp.UnmarshalXDR(msgBuf) err = resp.UnmarshalXDR(msgBuf)
if xdrErr, ok := err.(isEofer); ok && xdrErr.IsEOF() {
err = nil
}
msg = resp msg = resp
case messageTypePing, messageTypePong: case messageTypePing, messageTypePong:
@ -398,11 +418,17 @@ func (c *rawConnection) readMessage() (hdr header, msg encodable, err error) {
case messageTypeClusterConfig: case messageTypeClusterConfig:
var cc ClusterConfigMessage var cc ClusterConfigMessage
err = cc.UnmarshalXDR(msgBuf) err = cc.UnmarshalXDR(msgBuf)
if xdrErr, ok := err.(isEofer); ok && xdrErr.IsEOF() {
err = nil
}
msg = cc msg = cc
case messageTypeClose: case messageTypeClose:
var cm CloseMessage var cm CloseMessage
err = cm.UnmarshalXDR(msgBuf) err = cm.UnmarshalXDR(msgBuf)
if xdrErr, ok := err.(isEofer); ok && xdrErr.IsEOF() {
err = nil
}
msg = cm msg = cm
default: default: