From b7176d22049502f108c0c520292696f4c2e0738e Mon Sep 17 00:00:00 2001 From: Jakob Borg Date: Sat, 26 Jul 2014 21:27:55 +0200 Subject: [PATCH] Implement reception of Close message --- protocol/PROTOCOL.md | 27 ++++++++++++++++++ protocol/message.go | 4 +++ protocol/message_xdr.go | 61 +++++++++++++++++++++++++++++++++++++++++ protocol/protocol.go | 15 ++++++++++ 4 files changed, 107 insertions(+) diff --git a/protocol/PROTOCOL.md b/protocol/PROTOCOL.md index 761ea78f8..b541b2a16 100644 --- a/protocol/PROTOCOL.md +++ b/protocol/PROTOCOL.md @@ -594,6 +594,33 @@ firewalls and NAT gateways. The Ping message has no contents. The Pong message is sent in response to a Ping. The Pong message has no contents, but copies the Message ID from the Ping. +### Close (Type = 7) + +The Close message MAY be sent to indicate that the connection will be +torn down due to an error condition. A Close message MUST NOT be +followed by further messages. + +#### Graphical Representation + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + | Length of Reason | + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + / / + \ Reason (variable length) \ + / / + +-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + +#### Fields + +The Reason field contains a human description of the error condition, +suitable for consumption by a human. + + struct CloseMessage { + string Reason<1024>; + } + Sharing Modes ------------- diff --git a/protocol/message.go b/protocol/message.go index 3d6370a4f..e3b54d236 100644 --- a/protocol/message.go +++ b/protocol/message.go @@ -71,3 +71,7 @@ type Option struct { Key string // max:64 Value string // max:1024 } + +type CloseMessage struct { + Reason string // max:1024 +} diff --git a/protocol/message_xdr.go b/protocol/message_xdr.go index 32f64b51d..899a8b426 100644 --- a/protocol/message_xdr.go +++ b/protocol/message_xdr.go @@ -691,3 +691,64 @@ func (o *Option) decodeXDR(xr *xdr.Reader) error { o.Value = xr.ReadStringMax(1024) return xr.Error() } + +/* + +CloseMessage Structure: + + 0 1 2 3 + 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 2 3 4 5 6 7 8 9 0 1 ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +| Length of Reason | ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ +/ / +\ Reason (variable length) \ +/ / ++-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+-+ + + +struct CloseMessage { + string Reason<1024>; +} + +*/ + +func (o CloseMessage) EncodeXDR(w io.Writer) (int, error) { + var xw = xdr.NewWriter(w) + return o.encodeXDR(xw) +} + +func (o CloseMessage) MarshalXDR() []byte { + return o.AppendXDR(make([]byte, 0, 128)) +} + +func (o CloseMessage) AppendXDR(bs []byte) []byte { + var aw = xdr.AppendWriter(bs) + var xw = xdr.NewWriter(&aw) + o.encodeXDR(xw) + return []byte(aw) +} + +func (o CloseMessage) encodeXDR(xw *xdr.Writer) (int, error) { + if len(o.Reason) > 1024 { + return xw.Tot(), xdr.ErrElementSizeExceeded + } + xw.WriteString(o.Reason) + return xw.Tot(), xw.Error() +} + +func (o *CloseMessage) DecodeXDR(r io.Reader) error { + xr := xdr.NewReader(r) + return o.decodeXDR(xr) +} + +func (o *CloseMessage) UnmarshalXDR(bs []byte) error { + var br = bytes.NewReader(bs) + var xr = xdr.NewReader(br) + return o.decodeXDR(xr) +} + +func (o *CloseMessage) decodeXDR(xr *xdr.Reader) error { + o.Reason = xr.ReadStringMax(1024) + return xr.Error() +} diff --git a/protocol/protocol.go b/protocol/protocol.go index 887315220..195ba9e08 100644 --- a/protocol/protocol.go +++ b/protocol/protocol.go @@ -25,6 +25,7 @@ const ( messageTypePing = 4 messageTypePong = 5 messageTypeIndexUpdate = 6 + messageTypeClose = 7 ) const ( @@ -306,6 +307,11 @@ func (c *rawConnection) readerLoop() (err error) { } c.state = stateCCRcvd + case messageTypeClose: + if err := c.handleClose(); err != nil { + return err + } + default: return fmt.Errorf("protocol error: %s: unknown message type %#x", c.id, hdr.msgType) } @@ -389,6 +395,15 @@ func (c *rawConnection) handleClusterConfig() error { return nil } +func (c *rawConnection) handleClose() error { + var cm CloseMessage + cm.decodeXDR(c.xr) + if err := c.xr.Error(); err != nil { + return err + } + return errors.New(cm.Reason) +} + type encodable interface { encodeXDR(*xdr.Writer) (int, error) }