Reliability Layer

The protocol specification is only relevant as background information or if you want to make your own Nabto WebRTC Signaling protocol implementation, e.g. for a currently unsupported target platform or app framework. For most applications, the standard implementations provided by Nabto through the available SDKs are sufficient - see the Applications guide.

The Nabto WebRTC Signaling protocol is split into four layers, this document is about the Reliability layer:

  • WebRTC Signaling layer
  • Signing layer
  • Reliability layer
  • Routing layer

The message reliability layer is responsible for resending packets and removing duplicates. It uses events emitted by the Routing layer to decide when it is relevant to retransmit data.

This layer defines two JSON messages with types: DATA and ACK. These JSON documents are sent as the message field in the Routing layer as a message with the type MESSAGE.

DATA

This is used to send a signaling message to the other peer.

{
  type: "DATA",
  seq: number,
  data: json
}

The seq field is a sequence number associated with a signaling channel with a specific channel ID. The first message sent with a specific channel ID must always have sequence number 0.

The data field is the data which is transported to the reliability layer.

ACK

This message is sent to the other peer to acknowledge receiving a message with the specified sequence number.

{
  type: "ACK",
  seq: number,
}

Reliability Layer Logic

When a peer sends a message with a given sequence number, it must store a copy of the message until it receives an acknowledgement for that particular sequence number. Messages are always received eventually ordered. This means if an acknowledgement is received for a sequence number larger than the smallest unacknowledged message, the message can be discarded as it will be retransmitted in order later.

Since the Websocket connection is reliable, unacknowledged messages should only be retransmitted if either peer reconnects to the Signaling service. This means the reliability layer send logic becomes:

  • When a message is generated, it is assigned the next sequence number, stored as an unacknowledged message, and sent to the Routing layer.
  • If a PEER_OFFLINE event is received from the Routing layer, newly generated messages should only be assigned a sequence number and stored, but should not be send to the Routing layer.
  • If a PEER_ONLINE or a Websocket reconnected event is received from the Routing layer, all unacknowledged messages should be retransmitted in order.
  • If an acknowledge message is received for the smallest unacknowledged sequence number, the message is removed from the storage.
  • If an an ERROR event is received from the Routing layer, all messages should be dropped, the event should be re-emitted to the higher layer, and resources should be cleaned up.

The receive logic is significantly simpler: The next expected sequence number is stored (represented as n below). When a MESSAGE-type message is received, its sequence number (represented as seq below) is inspected:

  • If seq<n: A corresponding ACK-type message is sent. The message is discarded as a duplicate.
  • If seq==n: A corresponding ACK-type message is sent, n is updated to n=seq+1, and the message field is forwarded to the higher layer.
  • If seq>n: The message is discarded completely.