Browse Source

Implement reception of Close message

Jakob Borg 11 years ago
parent
commit
b7176d2204
4 changed files with 107 additions and 0 deletions
  1. 27 0
      protocol/PROTOCOL.md
  2. 4 0
      protocol/message.go
  3. 61 0
      protocol/message_xdr.go
  4. 15 0
      protocol/protocol.go

+ 27 - 0
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
 -------------
 

+ 4 - 0
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
+}

+ 61 - 0
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()
+}

+ 15 - 0
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)
 }