[Circle-dev] An overview of Tangence - Wire Protocol

Paul LeoNerd Evans leonerd at leonerd.org.uk
Sun Feb 15 23:49:39 GMT 2009


4. Wire Protocol
----------------

The wire protocol used by Tangence operates over a reliable stream. This
stream may be provided by a TCP socket, UNIX local socket, or even the
STDIN/STDOUT pipe pair of an SSH connection.

The following message descriptions all use the symbolic constant names
from the Tangence::Constants perl module, to be more readable.

4.1. Messages

At its lowest level, the wire protocol consists of a pair of endpoints to
the stream, each sending and receiving messages to its peer. The protocol
at this level is symmetric between the client and the server. It consists
of messages that are either reqests or responses. 

An endpoint sends a request, which the peer must then respond to. Each
request has exactly one response. The requests and responses are paired
sequentially in a pipeline fashion.

The two endpoints are distinct from each other, in that there is no
requirement for a peer to respond to an outstanding request it has
received before sending a new request of its own. There is also no
requirement to wait on the response to a request it has sent, before
sending another.

The basic message format is a binary exchange of messages in the following
format:

 Type:    1 byte  integer
 Length:  4 bytes integer, big-endian
 Payload: (n-5) bytes

The type is a single byte which defines the message type. The collection 
of message types is given below. The length is a big-endian 4 byte integer
which gives the total size of the message, including this header. Thus,
the length will always be at least 5. The data payload of the message is
encoded in the data serialisation scheme given below. Each argument to the
message is encoded as a single serialisation item. For message types with
a variable number of arguments, the length of the message itself defines
the number of arguments given.

4.2. Data Serialisation

The data serialisation format applies recursively down a data structure
tree. Each node in structure is either a string, an object reference, or
a list or dictionary of other values. The serialised bytes encode the tree
structure recursively. Other types of entry also exist in the serialised
stream, which carry metadata about the types, such as object classes and
instances.

The encoding of each node in the data structure consists of a type, a
size, and the actual data payload. The first byte of a node encodes both
its type and size. The top three bits in the byte encode the type:

 Type           Bits                    Description

 DATA_STRING    0 0 1 s s s s s         string
 DATA_LIST      0 1 0 s s s s s         list of values
 DATA_DICT      0 1 1 s s s s s         dictionary of string->value
 DATA_OBJECT    1 0 0 s s s s s         Tangence object reference
        where 'sssss' gives the size

 DATA_META      1 1 1 n n n n n
        where 'nnnnn' gives the metadata type

For non-metadata items, the lower five bits give a number, 0 to 31, which
helps encode the size. For items of size 30 or below, this size is encoded
directly. Where the size is 31 or more, the number 31 is encoded, and the
actual size follows this leading byte. For sizes 31 to 127, the next byte
encodes it. For sizes 128 or above, the next 4 bytes encode it in
big-endian format, with the top bit set. Sizes above 2^31 cannot be
encoded.

Following the size, are bytes encoding the data. The exact meaning of the
size depends on the type of the node.

For strings, the size gives the number of bytes in the string. These
bytes then follow the type/size area.

For lists, the size gives the number of elements in the list. Following
the type/size area will be this number of data serialisations, one per
list element.

For dictionaries, this size gives the number of key/value pairs. Following
the type/size area will be this number of key/value pairs. Each pair
consists of a null-terminated string for the key name, then a data
serialisation for the value.

For objects, the size gives the number of bytes in the object's ID number,
followed by a big-endian encoding of the object's ID number. Currently,
this will always be a 4 byte number.

Meta-data items may be embedded within a data stream in order to create
the object classes and instances which it contains. These metadata items
do not count towards the overall size of a collection value.

Meta-data operations encode a subtype number, rather than a size, in the
bottom five bits.

 Metadata type          Bits                    Description

 DATAMETA_CONSTRUCT     1 1 1 0 0 0 0 1         Construct an object
 DATAMETA_CLASS         1 1 1 0 0 0 1 0         Create a new object class

Following each metadata item is an encoding of its arguments.

DATAMETA_CONSTRUCT:
  Object ID:    4 byte big-endian
  Object class: null-terminated string
  Smash values: 0 or more bytes, data encoded (list)

  If the object class defines smash properties, the construct message will
  also contain the values for the smash properties. These will be sent in
  a list, one value per property, in the same order as the object class's
  schema defines the smash keys.

DATAMETA_CLASS:
  Class name:   null-terminated string
  Schema:       data encoded (dict)
  Smash keys:   data encoded (list)

  The schema will be encoded as a dictionary, in the following layout.

  DATA_DICT:
    'methods' = DATA_DICT:
      one key per method, values are DATA_DICT:
        'args' = string description of argument types
        'ret'  = string description of return type

    'events' = DATA_DICT:
      one key per event, values are DATA_DICT:
        'args' = string description of argument types

    'properties' = DATA_DICT:
      one key per property, values are DATA_DICT:
        'dim' = dimension, one of:
          DIM_SCALAR, DIM_HASH, DIM_ARRAY, DIM_OBJSET
        'type' = string description of the type
        'auto' = true if this is an autoprop

    'isa' = DATA_LIST:
      class names

  The smash keys will be encoded as a possibly-empty list of strings.

4.3. Message Types

Each of the messages defines the layout of its data payload. Some messages
pass a fixed number of items, some have a variable number of items in the
last position. For these messages, no explicit encoding of the size is
given. Instead, the data payload area is packed with as many data
encodings as are required. The receiver should use the size of the
containing message to know when all the items have been unpacked.

The following request types are defined. Any message may be responded to
by MSG_ERROR in case of an error, so this response type is not listed.
Some of these messages are sent from the client to the server (C->S),
others are sent from the server to client (S->C)

MSG_CALL (C->S)
  STRING        object ID
  STRING        method name
  data...       arguments

  Responses: MSG_RESULT

  Calls the named method on the given object.

MSG_SUBSCRIBE (C->S)
  STRING        object ID
  STRING        event name

  Responses: MSG_SUBSCRIBED

  Subscribes the client to be informed of the event on given object.

MSG_UNSUBSCRIBE (C->S)
  STRING        object ID
  STRING        event name
  STRING        subscription ID

  Responses: MSG_OK

  Cancels an event subscription.

MSG_EVENT (S->C)
  STRING        object ID
  STRING        event name
  data...       arguments

  Responses: MSG_OK

  Informs the client that the event has occured.

MSG_GETPROP (C->S)
  STRING        object ID
  STRING        property name

  Responses: MSG_RESULT

  Requests the current value of the property

MSG_SETPROP (C->S)
  STRING        object ID
  STRING        property name
  data          new value

  Responses: MSG_OK

  Sets the new value of the property

MSG_WATCH (C->S)
  STRING        object ID
  STRING        property name
  STRING        want initial?

  Responses: MSG_WATCHING

  Requests to be informed of changes to the property value. If the
  boolean 'want initial' value is true, the client will be sent an
  initial MSG_CHANGE message for the current value of the property.

MSG_UNWATCH (C->S)
  STRING        object ID
  STRING        property name
  STRING        watch ID

  Responses: MSG_OK

  Cancels a request to watch a property

MSG_UPDATE (S->C)
  STRING        object ID
  STRING        property name
  STRING        change type
  data...       change value

  Responses: MSG_OK

  Informs the client that the property value has now changed. The
  type of change is given by the change type argument, and defines the
  data layout in the value arguments. The exact meaning of the operation
  depends on the dimension of the property it acts on.

  For DIM_SCALAR:

    CHANGE_SET:
      data      new value

      Sets the new value of the property.

  For DIM_HASH:
    CHANGE_SET:
      DICT      new value

      Sets the new value of the property.

    CHANGE_ADD:
      STRING    key
      data      value

      Adds a new element to the hash.

    CHANGE_DEL:
      STRING    key

      Deletes an element from the hash.

  For DIM_ARRAY:
    CHANGE_SET:
      LIST      new value

      Sets the new value of the property.

    CHANGE_PUSH:
      data...   additional values

      Appends the additional values to the end of the array.

    CHANGE_SHIFT:
      STRING    number of elements

      Removes a number of leading elements from the beginning of the
      array.

    CHANGE_SPLICE:
      STRING    start
      STRING    count
      data...   new elements

      Replaces the given range of the array with the new elements given.
      The new list of values may be a different length to the replaced
      section - in this case, subsequent elements will be shifted up or
      down accordingly.

  For DIM_OBJSET:
    CHANGE_SET:
      LIST      objects

      Sets the new value for the property. Will be given a list of
      Tangence object references.

    CHANGE_ADD:
      OBJECT    new object

      Adds the given object to the set

    CHANGE_DEL:
      STRING    object ID

      Removes the object of the given ID from the set.

MSG_DESTROY (S->C)
  STRING        object ID

  Responses: MSG_OK

  Informs the client that the object is due for destruction in
  the server. Upon receipt of this message the client should destroy
  any remaining references it has to the object. After it has sent the
  MSG_OK response, it will not be allowed to invoke any methods,
  subscribe to any events, nor interact with any properties on
  the object. Any existing event subscriptions or property
  watches will have been removed by the server before this message is
  sent.

MSG_GETROOT (C->S)
  STRING        identity

  Responses: MSG_RESULT

  Initial message to be sent by the client to obtain the root object. The
  identity may be used to identify this particular client, as part of its
  login procedure. The result will contain a single object reference,
  being the root object.

MSG_GETREGISTRY (C->S)
  [no arguments]

  Responses: MSG_RESULT

  Requests the registry object from the server. The result will contain a
  single object reference, being the registry object.


The following responses may be sent to a request:

MSG_OK
  [no arguments]

  A simple OK message, informing the requester that the operation was
  successful, an no error occured.

MSG_ERROR
  STRING        error message

  An error occured; the text of the message is included.

MSG_RESULT
  data...       values

  Contains the return value from a method call, a property value, or the
  initial root or registry object.

MSG_SUBSCRIBED
  [no arguments]

  Informs the client that a MSG_SUBSCRIBE was successful.

MSG_WATCHING
  [no arguments]

  Informs the client that a MSG_WATCH was successful.



-- 
Paul "LeoNerd" Evans

leonerd at leonerd.org.uk
ICQ# 4135350       |  Registered Linux# 179460
http://www.leonerd.org.uk/
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 189 bytes
Desc: Digital signature
URL: <http://mail.leonerd.org.uk/pipermail/circle-dev/attachments/20090215/b01e8c29/attachment.pgp>


More information about the Circle-dev mailing list