github.com/mendersoftware/go-lib-micro@v0.0.0-20240304135804-e8e39c59b148/ws/protomsg.go (about)

     1  // Copyright 2023 Northern.tech AS
     2  //
     3  //    Licensed under the Apache License, Version 2.0 (the "License");
     4  //    you may not use this file except in compliance with the License.
     5  //    You may obtain a copy of the License at
     6  //
     7  //        http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  //    Unless required by applicable law or agreed to in writing, software
    10  //    distributed under the License is distributed on an "AS IS" BASIS,
    11  //    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  //    See the License for the specific language governing permissions and
    13  //    limitations under the License.
    14  
    15  package ws
    16  
    17  import "encoding"
    18  
    19  const ProtocolVersion = 1
    20  
    21  // ProtoType defines how the ProtoMsg should be interpreted.
    22  type ProtoType uint16
    23  
    24  const (
    25  	// ProtoInvalid signifies an invalid (uninitialized) ProtoMsg.
    26  	ProtoInvalid ProtoType = iota
    27  	// ProtoTypeShell is used for communicating remote terminal session data.
    28  	ProtoTypeShell
    29  	// ProtoTypeFileTransfer is used for file transfer from/to the device.
    30  	ProtoTypeFileTransfer
    31  	// ProtoTypePortForward is used for port-forwarding connections to the device.
    32  	ProtoTypePortForward
    33  	// ProtoTypeMenderClient is used for communication with the Mender client.
    34  	ProtoTypeMenderClient
    35  
    36  	// ProtoTypeControl is a reserved proto type for session control messages.
    37  	ProtoTypeControl ProtoType = 0xFFFF
    38  )
    39  
    40  const (
    41  	// MessageTypes for session control messages (ProtoTypeControl).
    42  
    43  	// MessageTypePing sends a ping. After receiving a ping, the receiver
    44  	// MUST respond with a pong message or the session will time out.
    45  	MessageTypePing = "ping"
    46  	// MessageTypePong is sent in response to a MessageTypePing.
    47  	MessageTypePong = "pong"
    48  	// MessageTypeOpen allocates a new peer-to-peer deviceconnect session.
    49  	// The other peer can either respond with MessageTypeAccept or
    50  	// MessageTypeError
    51  	MessageTypeOpen = "open"
    52  	// MessageTypeAccept is a successful response to an open request.
    53  	MessageTypeAccept = "accept"
    54  	// MessageTypeClose is sent when the session MUST close. All
    55  	// communication on the session stop after receiving this message.
    56  	MessageTypeClose = "close"
    57  	// MessageTypeError is sent on a general protocol violation/error.
    58  	// An error message MUST contain an Error object. If the object's
    59  	// "close" field is set this message also closes the session.
    60  	MessageTypeError = "error"
    61  )
    62  
    63  // ProtoHdr provides the info about what the ProtoMsg contains and
    64  // to which protocol the message should be routed.
    65  type ProtoHdr struct {
    66  	// Proto defines which protocol this message belongs
    67  	// to (required).
    68  	Proto ProtoType `msgpack:"proto"`
    69  	// MsgType is an optional content type header describing
    70  	// the protocol specific content type of the message.
    71  	MsgType string `msgpack:"typ,omitempty"`
    72  	// SessionID is used to identify one ProtoMsg stream for
    73  	// multiplexing multiple ProtoMsg sessions over the same connection.
    74  	SessionID string `msgpack:"sid,omitempty"`
    75  	// Properties provide a map of optional prototype specific
    76  	// properties (such as http headers or other meta-data).
    77  	Properties map[string]interface{} `msgpack:"props,omitempty"`
    78  }
    79  
    80  // ProtoMsg is a wrapper to messages communicated on bidirectional interfaces
    81  // such as websockets to wrap data from other application protocols.
    82  type ProtoMsg struct {
    83  	// Header contains a protocol specific header with a single
    84  	// fixed ProtoType ("typ") field and optional hints for decoding
    85  	// the payload.
    86  	Header ProtoHdr `msgpack:"hdr"`
    87  	// Body contains the raw protocol data. The data contained in Body
    88  	// can be arbitrary and must be decoded according to the protocol
    89  	// defined in the header.
    90  	Body []byte `msgpack:"body,omitempty"`
    91  }
    92  
    93  func (m *ProtoMsg) Bind(b encoding.BinaryMarshaler) error {
    94  	data, err := b.MarshalBinary()
    95  	m.Body = data
    96  	return err
    97  }
    98  
    99  // The Error struct is passed in the Body of MessageTypeError.
   100  type Error struct {
   101  	// The error description, as in "Permission denied while opening a file"
   102  	Error string `msgpack:"err" json:"error"`
   103  	// Close determines whether the session closed as a result of this error.
   104  	Close bool `msgpack:"close" json:"close"`
   105  	// Code is the error code associated with the error. Values in the
   106  	// range 400-599 carry the same semantic meaning as the HTTP equivalent.
   107  	// Please allocate new error codes starting from 1000 for custom error codes.
   108  	Code int `msgpack:"code,omitempty" json:"code,omitempty"`
   109  	// MessageProto is the protocol of the message that caused the error.
   110  	MessageProto ProtoType `msgpack:"msgproto,omitempty" json:"message_protocol,omitempty"`
   111  	// Type of message that raised the error
   112  	MessageType string `msgpack:"msgtype,omitempty" json:"message_type,omitempty"`
   113  	// Message id is passed in the MsgProto Properties, and in case it is available and
   114  	// error occurs it is passed for reference in the Body of the error message
   115  	MessageID string `msgpack:"msgid,omitempty" json:"message_id,omitempty"`
   116  }
   117  
   118  // ProtoMsg handshake semantics:
   119  // 1)  The requester sends an "open" control message with all the protocol
   120  //     versions it supports to the peer.
   121  // 2a) On success, the peer will respond with a message of type Accept with an
   122  //     agreed upon version together with all the ProtoTypes the peer is willing
   123  //     to accept.
   124  // 2b) On failure, the peer will respond with an Error message with a reasoning.*
   125  //
   126  //     *The client can also expect to get an Open message type in return. In
   127  //     this case it MUST check the header's "status" property, if the property
   128  //     exists and equal to 1 the client is version 0, and does not support
   129  //     features added after Mender 2.6.
   130  
   131  // Open is the schema used for initiating a ProtoMsg handshake.
   132  type Open struct {
   133  	// Versions is a list of versions the client is able to interpret.
   134  	Versions []int `msgpack:"versions"`
   135  }
   136  
   137  // Accept is the schema for the message type "accept" for a successful response to
   138  // a ProtoMsg handshake.
   139  type Accept struct {
   140  	// Version is the accepted version used for this session.
   141  	Version int `msgpack:"version"`
   142  	// Protocols is a list of protocols the peer is willing to accept.
   143  	Protocols []ProtoType `msgpack:"protocols"`
   144  }