
Protocol description of libpomp.

Notations :

- All values are in decimal or in hexadecimal if prefixed with '0x'.
- Buffer descriptions have byte offsets indicated in decimal.
- First byte of buffer is at the left, last byte at the right.

Message description :

    |     MESSAGE      |
    --------------------
    | HEADER | PAYLOAD |
    --------------------
    0        12        N+12

    HEADER  : 12 bytes : message header.
    PAYLOAD : 0 or more bytes : message payload.
    N : payload size.

Header description :

    |      HEADER       |
    ---------------------
    | MAGIC | ID | SIZE |
    ---------------------
    0       4    8      12

    MAGIC : 4 bytes : 0x504D4F50. Little endian encoded.

    |           MAGIC           |
    -----------------------------
    | 0x50 | 0x4F | 0x4D | 0x50 |
    | 'P'  | 'O'  | 'M'  | 'P'  |
    -----------------------------
    0      1      2      3      4

    ID   : 4 bytes : message id.  Little endian encoded.
    SIZE : 4 bytes : size of message (header + payload).  Little endian encoded.

Payload description :

    The payload is a sequence of arguments without any alignment or padding.
    between them. If there is no arguments, there is no payload in the message.

    |     PAYLOAD     |
    -------------------
    | ARG | ... | ARG |
    -------------------
    0                 N

    ARG : 1 or more bytes : argument.
    N : payload size

Argument description :

    |     ARG     |
    ---------------
    | TYPE | DATA |
    ---------------
    0      1      N+1

    TYPE : 1 byte : type of argument.
    DATA : 0 or more bytes : data of argument.
    N : data size.

Type description :

    0x01 : I8 : 8-bit signed integer, data size is 1 byte.
    0x02 : U8 : 8-bit unsigned integer, data size is 1 byte.
    0x03 : I16 : 16-bit signed integer, little endian, data size is 2 bytes.
    0x04 : U16 : 16-bit unsigned integer, little endian, data size is 2 bytes.
    0x05 : I32 : 32-bit signed integer, zigzag varint, data size is 1-5 bytes.
    0x06 : U32 : 32-bit unsigned integer, varint, data size is 1-5 bytes.
    0x07 : I64 : 64-bit signed integer, zigzag varint, data size is 1-10 bytes.
    0x08 : U64 : 64-bit unsigned integer, varint, data size is 1-10 bytes.
    0x09 : STR : 8-bit character string with a null character at the end.
    0x0a : BUF : raw bytes.
    0x0b : F32 : 32-bit floating point, little endian, IEEE 754, data size is 4 bytes.
    0x0c : F64 : 64-bit floating point, little endian, IEEE 754, data size is 8 bytes.
    0x0d : FD  : File descriptor, little endian, data size is 4 bytes.

String description :

    |            STR            |
    -----------------------------
    | 0x09 | SIZE | DATA | 0x00 |
    -----------------------------

    0x09 : 1 byte : type.
    SIZE : 1-3 bytes : size of string. 16-bit unsigned integer, varint.
    DATA : 0 or more bytes : 8-bit character string.
    0x00 : 1 byte : final null byte.

    The size includes the final null byte and has a maximum value of 65535.

    Note : the protocol does not assume any charset encoding for the string
           and just consider it as a sequence of 8-bit characters. However,
           it is advised to used UTF8 charset when client or server needs a
           conversion.

Raw buffer description :

    |        BUF         |
    ----------------------
    | 0x0a | SIZE | DATA |
    ----------------------

    0x0a : 1 byte : type.
    SIZE : 1-5 bytes : size of data. 32-bit unsigned integer, varint.
    DATA : 0 or more bytes : raw bytes.
    N : data size.


Varint encoding :

    The varint encoding is used to minimize the number of bytes used when
    encoding numbers that are small even if the real type is 16, 32 or 64 bits

    Unsigned values are encoded as follow:
    - The value is split in groups of 7 bits, starting by low order bits.
    - Each group is emitted unless remaining groups are all 0.
    - The bit 7 of each group is 1 if another group follows, 0 for the last one.

    Signed values are zigzag encoded as follow:
    - The value is shifted left by 1.
    - If the value is negative, the resulting value is then complemented.
    - The resulting value is then encoded like an unsigned value.

    Examples :

    Encoding of 32-bit unsigned value 71000
        Original encoding :
            DEC : 71000
            HEX : 0001 1558
            BIN : 0000 0000 0000 0001 0001 0101 0101 1000

        Split in groups of 7 bits
            group0 : val[6-0]   : 101 1000
            group1 : val[13-7]  : 010 1010
            group2 : val[20-14] : 000 0100
            group3 : val[27-21] : 000 0000
            group4 : val[31-28] :     0000

        Only group[2-0] will be emitted
        group0 and group1 will have their bit 7 set to 1

            |   group0  |   group1  |   group2  |
            -------------------------------------
            | 1101 1000 | 1010 1010 | 0000 0100 |
            -------------------------------------
            |     D8    |     AA    |     04    |
            -------------------------------------

    Encoding of 32-bit signed value -71000
        Original encoding :
            DEC : -71000
            HEX : FFFE EAA8
            BIN : 1111 1111 1111 1110 1110 1010 1010 1000

        Zigzag encoding (left shift by 1 and complement):
            BIN : 0000 0000 0000 0010 0010 1010 1010 1111

        Split in groups of 7 bits
            group0 : val[6-0]   : 010 1111
            group1 : val[13-7]  : 101 0101
            group2 : val[20-14] : 000 1000
            group3 : val[27-21] : 000 0000
            group4 : val[31-28] :     0000

        Only group[2-0] will be emitted
        group0 and group1 will have their bit 7 set to 1

            |   group0  |   group1  |   group2  |
            -------------------------------------
            | 1010 1111 | 1101 0101 | 0000 1000 |
            -------------------------------------
            |     AF    |     D5    |     08    |
            -------------------------------------

IEEE 754 encoding:
    32-bit floating point:

        |   3   |   2   |   1   |   0   |
        ---------------------------------
        | S  |   E   |        M         |
        ---------------------------------
        | 31 | 30 23 | 22             0 |

        S : Sign : 1 bit.
        E : Exponent : 8 bits.
        M : Mantissa : 23 bits.

        value = ((-1) ^ S ) * 1.M * 2 ^ (E - 127)

    64-bit floating point:

        |   7   |   6   |   5   |   4   |   3   |   2   |   1   |   0   |
        -----------------------------------------------------------------
        | S  |   E   |                        M                         |
        -----------------------------------------------------------------
        | 63 | 62 52 | 51                                             0 |

        S : Sign : 1 bit.
        E : Exponent : 11 bits.
        M : Mantissa : 52 bits.

        value = ((-1) ^ S ) * 1.M * 2 ^ (E - 1023)

    Examples :
        3.1415927410125732421875
            S = 0
            E = 1000 0000
            M = 100 1001 0000 1111 1101 1011
            V = 0100 0000 0100 1001 0000 1111 1101 1011
            V = 4049 0fdb
           -> db 0f 49 40

        3.141592653589793115997963468544185161590576171875
            S = 0
            E = 100 0000 0000
            M = 1001 0010 0001 1111 1011 0101 0100 0100 0100 0010 1101 0001 1000
            V = 0100 0000 0000 1001 0010 0001 1111 1011 0101 0100 0100 0100 0010 1101 0001 1000
            V = 4009 21fb 5444 2d18
            -> 18 2d 44 54 fb 21 09 40
