123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185 |
- The CC protocol
- ===============
- We use our home-grown protocol for IPC between modules. There's a
- central daemon routing the messages.
- Addressing
- ----------
- Each connected client gets an unique address, called ``l-name''. A
- message can be sent directly to such l-name, if it is known to the
- sender.
- A client may subscribe to a group of communication. A message can be
- broadcasted to a whole group instead of a single client. There's also
- an instance parameter to addressing, but we didn't find any actual use
- for it and it is not used for anything. It is left in the default `*`
- for most of our code and should be done so in any new code. It wasn't
- priority to remove it yet.
- Wire format
- -----------
- Each message on the wire looks like this:
- <message length><header length><header><body>
- The message length is 4-byte unsigned integer in network byte order,
- specifying the number of bytes of the rest of the message (eg. header
- length, header and body put together).
- The header length is 2-byte unsigned integer in network byte order,
- specifying the length of the header.
- The header is a string representation of single JSON object. It
- specifies the type of message and routing information.
- The body is the payload of the message. It takes the whole rest of
- size of the message (so its length is message length - 2 - header
- length). The content is not examined by the routing daemon, but the
- clients expect it to be valid JSON object.
- The body may be empty in case the message is not to be routed to
- client, but it is instruction for the routing daemon. See message
- types below.
- The message is sent in this format to the routing daemon, the daemon
- optionally modifies the headers and delivers it in the same format to
- the recipient(s).
- The headers
- -----------
- The header object can contain following information:
- |====================================================================================================
- |Name |type |Description
- |====================================================================================================
- |from |string|Sender's l-name
- |type |string|Type of the message. The routed message is "send".
- |group |string|The group to deliver to.
- |instance |string|Instance in the group. Purpose lost in history. Defaults to "*".
- |to |string|Override recipient (group/instance ignored).
- |seq |int |Tracking number of the message.
- |reply |int |If present, contains a seq number of message this is a reply to.
- |want_answer|bool |If present and true, the daemon generates error if there's no matching recipient.
- |====================================================================================================
- Types of messages
- -----------------
- Get Local Name (type "getlname")
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Upon connection, this is the first message to be sent to the daemon.
- It will return the local name of this client. Each connection gets
- its own unique local name, and local names are never repeated. They
- should be considered opaque strings, in a format useful only to the
- message routing system. They are used in replies or to send to a
- specific destination.
- To request the local name, the only element included is the
- {"type": "getlname"}
- tuple. The response is also a simple, single tuple:
- {"lname" => "Opaque utf-8 string"}
- Until this message is sent, no other types of messages may be sent on
- this connection.
- Regular Group Messages (type "send")
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Message routed to other client. This one expects the body to be
- non-empty.
- Expected headers are:
- * from
- * group
- * instance (set to "*" if no specific instance desired)
- * seq (should be unique for the sender)
- * to (set to "*" if not directed to specific client)
- * reply (optional, only if it is reply)
- * want_answer (optional, only when not a reply)
- A client does not see its own transmissions.
- Group Subscriptions (type "subscribe")
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Indicates the sender wants to be included in the given group.
- Expected headers are:
- * group
- * instance (leave at "*" for default)
- There is no response to this message and the client is subscribed to
- the given group and instance.
- The group can be any utf-8 string and the group doesn't have to exist
- before (it is created when at least one client is in it). A client may
- be subscribed in multiple groups.
- Group Unsubscribe (type "unsubscribe")
- ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- The headers to be included are "group" and "instance" and have the same
- meaning as a "subscribe" message. Only, the client is removed from the
- group.
- Transmitted messages
- --------------------
- These are the messages generally transmitted in the body of the
- message.
- Command
- ~~~~~~~
- It is a command from one process to another, to do something or send
- some information. It is identified by a name and can optionally have
- parameters. It'd look like this:
- {"command": ["name", <parameters>]}
- The parameters may be omitted (then the array is 1 element long). If
- present, it may be any JSON element. However, the most usual is an
- object with named parameter values.
- It is usually transmitted with the `want_answer` header turned on to
- cope with the situation the remote end doesn't exist, and sent to a
- group (eg. `to` with value of `*`).
- Success reply
- ~~~~~~~~~~~~~
- When the command is successful, the other side answers by a reply of
- the following format:
- {"result": [0, <result>]}
- The result is the return value of the command. It may be any JSON
- element and it may be omitted (for the case of ``void'' function).
- This is transmitted with the `reply` header set to the `seq` number of
- the original command. It is sent with the `to` header set.
- Error reply
- ~~~~~~~~~~~
- In case something goes wrong, an error reply is sent. This is similar
- as throwing an exception from local function. The format is similar:
- {"result": [ecode, "Error description"]}
- The `ecode` is non-zero error code. Most of the current code uses `1`
- for all errors. The string after that is mandatory and must contain a
- human-readable description of the error.
- The negative error codes are reserved for errors from the daemon.
- Currently, only `-1` is used and it is generated when a message with
- `reply` not included is sent, it has the `want_answer` header set to
- `true` and there's no recipient to deliver the message to. This
- usually means a command was sent to a non-existent recipient.
|