Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

webrtc: add FIN_ACK to close datachannels without data loss #582

Merged
merged 7 commits into from
Oct 5, 2023
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
56 changes: 54 additions & 2 deletions webrtc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,10 @@ message Message {
// The sender abruptly terminates the sending part of the stream. The
// receiver MAY discard any data that it already received on that stream.
RESET_STREAM = 2;
// Sending the FIN_ACK flag acknowledges the previous receipt of a message
// with the FIN flag set. Receiving a FIN_ACK flag gives the recipient
// confidence that the remote has received all sent messages.
FIN_ACK = 3;
}

optional Flag flag=1;
Expand Down Expand Up @@ -132,8 +136,8 @@ real-world experiments.

`RTCDataChannel`s are negotiated in-band by the WebRTC user agent (e.g. Firefox,
Pion, ...). In other words libp2p WebRTC implementations MUST NOT change the
default value `negotiated: false` when creating a standard libp2p stream
of type `RTCDataChannel` via `RTCPeerConnection.createDataChannel`.
default value `negotiated: false` when creating a standard libp2p stream
of type `RTCDataChannel` via `RTCPeerConnection.createDataChannel`.
Setting `negotiated: true` is reserved only for creating Noise handshake channels
under certain protocol conditions.

Expand Down Expand Up @@ -161,6 +165,54 @@ MUST pass an empty string. When receiving an `RTCDataChannel` via
an empty string. This allows future versions of this specification to make use
of the `RTCDataChannel` `label` property.

## Closing an `RTCDataChannel`

Some WebRTC implementations do not guarantee that any queued messages will be
sent after a datachannel is closed. Other implementations maintain separate
outgoing message and transport queues, the status of which may not be visible
to the user. Consequently we must add an additional layer of signaling to
ensure reliable data delivery.

When a node wishes to close a stream for writing, it MUST send a message with
the `FIN` flag set.

If a `FIN` flag is received the node SHOULD respond with a `FIN_ACK`.

A node SHOULD only consider its write-half closed once it has received a
`FIN_ACK`.

When a `FIN_ACK` and a `FIN` have been received, the node may close the
datachannel.

The node MAY close the datachannel without receiving a `FIN_ACK`, for example in
the case of a timeout, but there will be no guarantee that all previously sent
messages have been received by the remote.

If a node has previously sent a `STOP_SENDING` flag to the remote node, it MUST
continue to act on any flags present in received messages in order to
successfully process an incoming `FIN_ACK`.

### Example of closing an `RTCDataChannel`

NodeA closes for writing, NodeB delays allowing the channel to close until it
also finishes writing.

```mermaid
sequenceDiagram
A->>B: DATA
A->>B: FIN
B->>A: FIN_ACK
B->>A: DATA
B->>A: FIN
A->>B: FIN_ACK
```

After _A_ has received the `FIN` it is free to close the datachannel since it
has previously received a `FIN_ACK`. If _B_ receives the `FIN_ACK` before this
it may close the channel since it previously received a `FIN`.

This way the channel can be closed from either end without data loss.

## Previous, ongoing and related work

- Completed implementations of this specification:
Expand Down