# Light-weight Data Frame Exchange Specification V1

## Overview

The LwDFX protocol describes a lightweight data frame exchange protocol used for transmitting data frames. It provides connection based duplex transmissions. The design purpose of this protocol is to allow both communicating parties to easily parse and construct the data structures to be transmitted.

## Terminology

- Message Frame

    A frame is the basic unit of a connection that carries pieces of data. Each frame includes a header and a body, where the header is a fixed-length binary chunk in all frames, and the body is a variable-length binary chunk in different frames.

    > The frame is not the same as the TCP frame. The frame is a logical unit of the connection, while the TCP frame is a physical unit of the TCP protocol.

## Frames

First of all, the frame is a binary chunk, which is composed of a header and a body payload, where the header is a fixed-length binary chunk and the body is a variable-length binary chunk. **All data fields are in the little-endian format**.

All data structure below are described in C language, but there is no memory alignment required in the LwDFX protocol. So these structure are always compacted, which means **these data structure are actually aligned to 1 byte**.

In LwDFX protocol, there are 3 types of frames:

### CLIENT_HELLO Frame

The `CLIENT_HELLO` frame is used to initiate a stream. It is a binary chunk, used to negotiate the version of the stream.

```c
typedef struct {

    /**
     * The byte-length of content.
     */
    uint8_t     cByteLength;

    /**
     * Byte string, without null-terminator.
     */
    uint8_t     content[];

} var_string_t;

struct lwdfxHelloFrame {
    uint32_t        dwByteLength;
    uint32_t        dwMagic;
    uint8_t         cVersionQty;
    uint8_t         aVersionList[];
    uint8_t         cAlpQty;
    var_string_t    aAlpList[];
};
```

Here are the explanations of the fields:

- `dwByteLength`

    The byte-length of the rest fields. It is a 32-bit unsigned integer.

- `dwMagic`

    The magic number of the `HELLO` frame. It is a 32-bit unsigned integer. It must be `0x5442774c`.

- `cVersionQty`

    The quantity of the LwDFX protocol versions that the client-side can apply to. It is a 8-bit unsigned integer.

- `aVersionList`

    The list of the LwDFX protocol versions that the client-side can apply to. It is an array of 8-bit unsigned integer.

- `cAlpQty`

    The number of application-layer protocols that the client-side preferring. It is a 8-bit unsigned integer.

- `aAlpList`

    The identities of application-layer protocols to be transported insides LwDFXv1, that the client-side preferring. It is a variable-length byte string.

    The `aAlpList` field is a variable-length byte string, which is composed of several `var_string_t` structures. Each `var_string_t` structure is a variable-length byte string, which is composed of a `cByteLength` field and a `content` field.

    Here are the explanations of the fields:

    - `cByteLength`

        The byte-length of the `content` field. It is a 8-bit unsigned integer.

    - `content`

        The content of the `var_string_t` structure. It is a variable-length byte string.

        The `content` field is not null-terminated.

### SERVER_HELLO Frame

The `SERVER_HELLO` frame is used to response the `CLIENT_HELLO` frame. It is a binary chunk.

```c
struct lwdfxHiFrame {
    uint32_t        dwByteLength;
    uint32_t        dwMagic;
    uint32_t        dwMaxFrameSize;
    uint8_t         cVersion;
    var_string_t    sAlp;
};
```

Here are the explanations of the fields:

- `dwByteLength`

    The byte-length of the rest fields. It is a 32-bit unsigned integer.

- `dwMagic`

    The magic number of the `HI` frame. It is a 32-bit unsigned integer. It must be `0x5442774d`.

- `dwMaxFrameSize`

    The maximum byte-length of each frame that the server-side would accept or send. It is a 32-bit unsigned integer.

    If the client-side sends a frame whose byte-length is greater than `dwMaxFrameSize`, the server-side should close the connection.

- `cVersion`

    The version of the LwDFX protocol that the server-side applied to. It is a 8-bit unsigned integer.

    If server accepts the client's version, it must be the a version in client-sent `aVersionList`.

    Otherwise, it must be `0xFF`. And then server must close the connection.

- `sAlp`

    The identity of application-layer protocol that the server-side selected. It is a variable-length byte string.

    The `sAlp` field is a variable-length byte string, which is composed of a `var_string_t` structure.

### Data Frame

The `DATA` frame is used to transmit data.

> It's recommended that the `DATA` frame should be sent after the `SERVER_HELLO` frame is replied. However, there is no effect even if sending `DATA` frame immediately after sending `CLIENT_HELLO` frame, because the server side will reject if protocol handshake failed, and then close the connection, so that the sent `DATA` frame will be dropped.

```c
struct lwdfxDataFrame {
    uint32_t    dwMagic;
    uint32_t    dwMessageLength;
    uint8_t     aMessageBody[];
};
```

Here are the explanations of the fields:

- `dwMagic`

    The magic of data frame, to ensure data transported correctly. The value of `dwMagic` should be always `0x86989330`.

- `dwMessageLength`

    The length of the message body, in bytes. It is a 32-bit unsigned integer.

    If a `DATA` frame whose `dwMessageLength` equal to `0` is received, it means the end of the stream, both communicating parties must close the connection.

- `aMessageBody`

    The message body of the frame. It is a variable-length binary chunk.
