Next Previous Contents

## 7. Protocol reference

Under some circumstances, it may be preferable to communicate directly with BrlAPI's server rather than using BrlAPI's library. Here are the needed details to be able to do this. This chapter is also of interest if a precise understanding of how the communication stuff works is desired, to be sure to understand how to write multithreaded clients, for instance.

In all the following, integer will mean an unsigned 32 bits integer in network byte order (ie most significant bytes first).

## 7.1 Reliable packet transmission channel

The protocol between BrlAPI's server and clients is based on exchanges of packets. So as to avoid locks due to packet loss, these exchanges are supposed reliable, and ordering must be preserved, thus BrlAPI needs a reliable packet transmission channel.

To achieve this, BrlAPI uses a TCP-based connection, on which packets are transmitted this way:

- the size in bytes of the packet is transmitted first as an integer,
- then the type of the packet, as an integer,
- and finally the packet data.

The size does not include the { size, type } header, so that packets which don't need any data have a size of 0 byte. The type of the packet can be either of `BRLAPI_PACKET_*` constants defined in `api_protocol.h`. Each type of packet will be further discussed below.

BrlAPI's library ships two functions to achieve packets sending and receiving using this protocol: `brlapi_writePacket` and `brlapi_readPacket`. It is a good idea to use these functions rather than rewriting them, since this protocol might change one day in favor of a real reliable packet transmission protocol such as the experimental RDP.

## 7.2 Responses from the server

As described below, many packets are `acknowledged'. It means that upon reception, the server sends either:

- a `BRLAPI_PACKET_ACK` packet, with no data, which means the operation corresponding to the received packet was successful,
- or a `BRLAPI_PACKET_ERROR` packet, the data being an integer which should be one of `BRLAPI_ERROR_*` constants. This means the operation corresponding to the received packet failed.

Some other packets need some information as a response. Upon reception, the server will send either:

- a packet of the same type, its data being the response,
- or a `BRLAPI_PACKET_ERROR` packet.

If at some point an ill-formed or non-sense packet is received by the server, and `BRLAPI_PACKET_EXCEPTION` is returned, holding the guilty packet for further analysis.

## 7.3 Operating modes

The connection between the client and the server can be in either of the four following modes:

- authorization mode: this is the initial mode, when the client hasn't got the authorization to use the server yet. The server first sends a `BRLAPI_PACKET_VERSION` packet that announces the server version. The client must send back a `BRLAPI_PACKET_VERSION` for announcing its own version too. The server then sends a `BRLAPI_PACKET_AUTH` packet that announces which authorization methods are allowed. The client can then send `BRLAPI_PACKET_AUTH` packets, which makes the connection enter normal mode. If no authorization is needed, the server can announce the `NONE` method, the client then doesn't need to send a `BRLAPI_PACKET_AUTH` packet.
- normal mode: the client is authorized to use the server, but didn't ask for a tty or raw mode. The client can send either of these types of packet:
  - `BRLAPI_PACKET_GETDRIVERNAME` or `BRLAPI_PACKET_GETDISPLAYSIZE` to get pieces of information from the server,
  - `BRLAPI_PACKET_ENTERTTYMODE` to enter tty handling mode,
  - `BRLAPI_PACKET_ENTERRAWMODE` to enter raw mode,
- tty handling mode: the client holds the control of a tty: brltty has no power on it any more, masked keys excepted. It's up to the client to manage display and keypresses. For this, it can send either of these types of packet:
  - `BRLAPI_PACKET_LEAVETTYMODE` to leave tty handling mode and go back to normal mode,
  - `BRLAPI_PACKET_IGNOREKEYRANGE` and `BRLAPI_PACKET_ACCEPTKEYRANGE` to mask and unmask keys,
  - `BRLAPI_PACKET_WRITE` to display text on this tty,
  - `BRLAPI_PACKET_ENTERRAWMODE` to enter raw mode,
  - `BRLAPI_PACKET_GETDRIVERNAME` or `BRLAPI_PACKET_GETDISPLAYSIZE` to get pieces of information from the server,
  And the server might send `BRLAPI_PACKET_KEY` packets to signal key presses.
- raw mode: the client wants to exchange packets directly with the braille terminal. Only these types of packet will be accepted.
  - `BRLAPI_PACKET_LEAVERAWMODE` to get back to previous mode, either normal or tty handling mode.
  - `BRLAPI_PACKET_PACKET` to send a packet to the braille terminal.
  And the server might send `BRLAPI_PACKET_PACKET` packets to give received packets from the terminal to the client.
- suspend mode: the client wants to completely drive the braille terminal. The device driver is hence kept closed. No type of packet is allowed except `BRLAPI_PACKET_RESUME`

Termination of the connection is initiated by the client in normal mode by simply closing its side of the socket. The server will then close the connection.

## 7.4 Details for each type of packet

Here is described the semantics of each type of packet. Most of them are directly linked to some of BrlAPI's library's functions. Reading their online manual page as well will hence be of good help for understanding.

### `BRLAPI_PACKET_VERSION`This must be the first packet ever transmitted from the server to the client and from the client to the server. The server sends one first for letting the client know its protocol version. Data is an integer indicating the protocol version. Then client must then respond the same way for giving its version. If the protocol version can't be handled by the server, a `BRLAPI_ERROR_PROTOCOL_VERSION` error packet is returned and the connection is closed.

### `BRLAPI_PACKET_AUTH`

This must be the second packet ever transmitted from the server to the client and from the client to the server. The server sends one first for letting the client know which authorization methods are available. Data is the allowed authorization types, as integers.

If the `NONE` method is not announced by the server, the client can then try to get authorized by sending packets whose data is the type of authorization that is tried (as an integer), and eventually some data (if the authorization type needs it).

If the authorization is successful, the server acknowledges the packet, and other types of packets might be used, other `BRLAPI_PACKET_AUTH` shouldn't be sent by the client.

If the authorization is not successful, the server sends a `BRLAPI_ERROR_AUTHENTICATION` error, and the client can try another authorization method.

Authorization methods are as follow:

- `NONE`: the client doesn't need to send an authorization packet.
- `KEY`: data holds a secret key, the authorization is successful only if the key matches the server secret key.
- `CREDENTIALS`: Operating-System-specific credentials are explicitly sent over the socket, the authorization is successful if the server considers the credentials sufficient.

Note: when the Operating system permits it, the server may use implicit credential check, and then advertise the `none` method.

### `BRLAPI_PACKET_GETDRIVERNAME` (see brlapi_getDriverName())

This should be sent by the client when it needs the full name of the current `brltty` driver. The returned string is \0 terminated.

### `BRLAPI_PACKET_GETMODELID` (see brlapi_getModelIdentifier())

This should be sent by the client when it needs to identify which model of braille display is currently used by `brltty`. The returned string is \0 terminated.

### `BRLAPI_PACKET_GETDISPLAYSIZE` (see brlapi_getDisplaySize())

This should be sent by the client when it needs to know the braille display size. The returned data are two integers: width and then height.

### `BRLAPI_PACKET_ENTERTTYMODE` (see brlapi_enterTtyMode() and brlapi_enterTtyModeWithPath())

This should be sent by the client to get control of a tty. Sent data are first a series of integers: the first one gives the number of following integers, which are the numbers of ttys that leads to the tty that the application wants to take control of (it can be empty if the tty is one of the machine's VT). The last integer of this series tells the number of the tty to get control of. Finally, how key presses should be reported is sent: either a driver name or "", preceded by the number of characters in the driver name (0 in the case of ""), as an unsigned byte. This packet is then acknowledged by the server.

### `BRLAPI_PACKET_KEY` (see brlapi_readKey())

As soon as the client gets a tty, it must be prepared to handle `BRLAPI_PACKET_KEY` incoming packets at any time (as soon as the key was pressed on the braille terminal, hopefully). The data holds a key code as 2 integers, or the key flags then the command code as 2 integers, depending on what has been request in the `BRLAPI_PACKET_ENTERTTYMODE` packet.

### `BRLAPI_PACKET_SETFOCUS` (see brlapi_setFocus())

For the server to know which tty is active, one particular client is responsible for sending `BRLAPI_PACKET_SETFOCUS` packets. They hold a single integer telling the new current tty. For instance, when running an X server on VT 7, the `xbrlapi` client would have sent a `BRLAPI_PACKET_ENTERTTYMODE(7)` and will send window IDs whenever X focus changes, allowing display and keypresses switching between xterms.

### `BRLAPI_PACKET_LEAVETTYMODE` (see brlapi_leaveTtyMode())

This should be sent to free the tty and masked keys lists. This is acknowledged by the server.

### `BRLAPI_PACKET_IGNOREKEYRANGE` and `BRLAPI_PACKET_ACCEPTKEYRANGE`(see brlapi_ignoreKeyRange() and brlapi_acceptKeyRange())

If the client doesn't want every key press to be signaled to it, but some of them to be given to `brltty` for normal processing, it can send `BRLAPI_PACKET_IGNOREKEYRANGE` packets to tell ranges of key codes which shouldn't be sent to it, but given to `brltty`, and `BRLAPI_PACKET_ACCEPTKEYRANGE` packets to tell ranges of key codes which should be sent to it, and not given to `brltty`. The server keeps a dynamic list of ranges, so that arbitrary sequences of such packets can be sent. A range is composed of 2 keycodes: the "first" and the "last" boundaries. Each keycode is composed of 2 integers: the key flags then the command code. The range expressed by these two keycodes is the set of keycodes whose command codes are between the command code of the "first" keycode and the "last" keycode (inclusive), and whose flags contain at least the flags of the "first" keycode and at most the flags of the "last" keycode. Setting the "first" and "last" keycode to the same value express only one keycode, for instance. Setting the first and last keycode to the same command code but setting no flags in the "first" keycode and setting one flag in the "last" keycode expresses only two keycode, with the same command code and no flags set except possibly the flag that is set in the "last" keycode. Setting one flag i in the "first" keycode and setting the same flag plus another flag j in the "last" keycode expresses that the keycodes in the range have flag i set and possibly flag j set, but no other flag. Several such ranges can be provided one after the other.

### `BRLAPI_PACKET_WRITE` (see brlapi_write())

To display text on the braille terminal and set the position of the cursor, the client can send a `BRLAPI_PACKET_WRITE` packet. The packet begins with an integer holding flags (see `BRLAPI_WF_*`). These flags indicate which data will then be available, in the following order (corresponding to flag weight):

- A display number can be given as a integer, in case the braille display has several. If not given, usual display is used.
- A region must be given as two integers indicating the beginning and the number of characters of the part of the braille display which is to be updated, the first cell of the display being numbered 1. For braille displays that have several lines, the first cell of the second line of the display is numbered the length of lines plus one, etc., in other words the display is handled as the concatenation of the lines of the display. If the number is negative, its absolute value is taken into account, and the update is padded or truncated to fill the rest of the display.
- The text to display can then be given, preceded by its size in bytes expressed as an integer. It will erase the corresponding region in the AND and OR fields. If the region size is positive, the text's length in characters must exactly match the region size. For multibyte text, this is the number of wide characters. Notably, combining and double-width characters count for 1.
- Then an AND field can be given, one byte per character: the 8-dot representation of the above text will be AND-ed with this field, hence allowing to erase some unwanted parts of characters. Dots are coded as described in ISO/TR 11548-1: dot 1 is set iff bit 0 is set, dot 2 is set iff bit 1 is set, ... dot i+1 is set if bit i is set. This also corresponds to the low-order byte of the coding of unicode's braille row `U+2800`.
- As well, an OR field may be given, one byte per character: the 8-dot result of the AND operation above (or the 8-dot representation of the text if no AND operation was performed) is OR-ed with this field, hence allowing to set some dots, to underline characters for instance.
- A cursor position can be specified. 1 representing the first character of the display, 0 turning the cursor off. If not given, the cursor (if any) is left unmodified.
- Last but not least, the charset of the text can be specified: the length of the name first in one byte, then the name itself in ASCII characters. If the charset is not specified, an 8-bit charset is assumed, and it is assumed to be the same as the server's. Multibyte charsets may be used, AND and OR fields' bytes will correspond to each text's wide character, be it a combining or a double-width character.

A `BRLAPI_PACKET_WRITE` packet without any flag (and hence no data) means a "void" WRITE: the server clears the output buffer for this connection.

### `BRLAPI_PACKET_ENTERRAWMODE` (see brlapi_enterRawMode())

To enter raw mode, the client must send a `BRLAPI_PACKET_ENTERRAWMODE` packet, which is acknowledged. Once in raw mode, no other packet than `BRLAPI_PACKET_LEAVERAWMODE` or `BRLAPI_PACKET_PACKET` will be accepted. The data must hold the special value `BRLAPI_DEVICE_MAGIC`: `0xdeadbeef`, then the name of the driver (one byte for the length, then the name) to avoid erroneous raw mode activating.

### `BRLAPI_PACKET_LEAVERAWMODE` (see brlapi_leaveRawMode())

To leave raw mode, the client must send a `BRLAPI_PACKET_LEAVERAWMODE` packet, which is acknowledged.

### `BRLAPI_PACKET_PACKET` (see brlapi_sendRaw() and brlapi_recvRaw())

While in raw mode, only `BRLAPI_PACKET_PACKET` packets can be exchanged between the client and the server: to send a packet to the braille terminal, the client merely sends a `BRLAPI_PACKET_PACKET` packet, its data being the packet to send to the terminal. Whenever its receives a packet from the terminal, the server does exactly the same, so that packet exchanges between the terminal and the server are exactly reproduced between the server and the client.

### `BRLAPI_PACKET_SUSPENDDRIVER` (see brlapi_suspendDriver())

To enter suspend mode, the client must send a `BRLAPI_PACKET_SUSPEND` packet, which is acknowledge. Once in suspend mode, no other packet than `BRLAPI_PACKET_RESUME` will be accepted. The data must hold the special value `BRLAPI_DEVICE_MAGIC`: `0xdeadbeef`, then the name of the driver (one byte for the length, then the name) to avoid erroneous raw mode activating.

### `BRLAPI_PACKET_PARAM_REQUEST`

This packet is sent by the client to request values of parameters. The packet begins with an integer which holds flags (see `BRLAPI_PARAMF_*`) which describe which, how, and when the value should be returned by the server:

- When the `BRLAPI_PARAMF_GLOBAL` flag is set, the server will return/subscribe the global value instead of the local value.
- When the `BRLAPI_PARAMF_GET` flag is set, the server acknowledges the request by returning the latest value with a `BRLAPI_PACKET_PARAM_VALUE` packet. Otherwise the server acknowledges the request with a `BRLAPI_PACKET_ACK` packet, without providing the value.
- When the `BRLAPI_PARAMF_SUBSCRIBE` flag is set, the server will keep sending asynchronously the value of the parameter whenever it changes, with `BRLAPI_PACKET_PARAM_UPDATE` packets, until another request packet has the `BRLAPI_PARAMF_UNSUBSCRIBE` flag set for this parameter.
- When the `BRLAPI_PARAMF_SELF` flag is set along `BRLAPI_PARAMF_SUBSCRIBE`, the server will send the value of the parameter when it is changed even by the client itself.
- When the `BRLAPI_PARAMF_UNSUBSCRIBE` flag is set, the server will stop sending asynchronously the value of the parameter with `BRLAPI_PACKET_PARAM_UPDATE` packets.

It does not make sense to set both the `BRLAPI_PARAMF_SUBSCRIBE` and `BRLAPI_PARAMF_UNSUBSCRIBE` flags.

Then an integer representing the parameter to be requested. Then two integers that form (in big-endian order) a 64bit value used to subspecify the precise parameter to be requested (e.g. a keycode number).

If several `BRLAPI_PARAMF_SUBSCRIBE` packets are sent by the client, as many `BRLAPI_PARAMF_UNSUBSCRIBE` packets have to be sent by the client before the server stops sending `BRLAPI_PACKET_PARAM_UPDATE` packets.

### `BRLAPI_PACKET_PARAM_VALUE`

This packet is sent by the client or the server to provide the value of a parameter. The packet begins with an integer which holds flags (see `BRLAPI_PVF_*`) which describe which value is being transmitted:

- When the `BRLAPI_PVF_GLOBAL` flag is set, the value is the global value instead of the local value.

Then an integer representing the parameter being transmitted. Then two integers that form (in big-endian order) a 64bit value used to subspecify the precise parameter being transmitted (e.g. a keycode number). Eventually, the packet contains the value.

When the packet is sent by the client, it defines the new value of the parameter, and if it is a global value, the server broadcasts the new value to all clients which have subscribed to updates. The packet is then acknowledged by the server on success. If the value can not be changed, the server returns an error (e.g. `BRLAPI_ERROR_READONLY_PARAMETER`).

### `BRLAPI_PACKET_PARAM_VALUE`This packet is sent asynchronously by the server to provide an update of a value of a parameter. This is sent only if the client has previously sent a `BRLAPI_PACKET_PARAM_REQUEST` packet with the `BRLAPI_PARAMF_SUBSCRIBE`for the corresponding parameter. It is structured exactly like a `BRLAPI_PACKET_PARAM_VALUE` packet.

### `BRLAPI_PACKET_SYNCHRONIZE`This packet is sent by the client and just acknowledged by the server. This allows the client to perform a round-try with the server, thus collecting any pending exception notification.

Next Previous Contents