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

webtransport: add message framing to allow graceful stream closing #606

Draft
wants to merge 1 commit into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
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
10 changes: 9 additions & 1 deletion noise/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,6 @@ and spec status.
<!-- START doctoc generated TOC please keep comment here to allow auto update -->
<!-- DON'T EDIT THIS SECTION, INSTEAD RE-RUN doctoc TO UPDATE -->


- [Overview](#overview)
- [Negotiation](#negotiation)
- [The Noise Handshake](#the-noise-handshake)
Expand All @@ -48,6 +47,7 @@ and spec status.
- [The libp2p Handshake Payload](#the-libp2p-handshake-payload)
- [Handshake Pattern](#handshake-pattern)
- [XX](#xx)
- [Noise Extensions](#noise-extensions)
- [Cryptographic Primitives](#cryptographic-primitives)
- [Noise Protocol Name](#noise-protocol-name)
- [Wire Format](#wire-format)
Expand All @@ -61,6 +61,9 @@ and spec status.
- [Changelog](#changelog)
- [r1 - 2020-01-20](#r1---2020-01-20)
- [r2 - 2020-03-30](#r2---2020-03-30)
- [r3 - 2022-09-20](#r3---2022-09-20)
- [r4 - 2022-09-22](#r4---2022-09-22)
- [r5 - 2024-03-05](#r5---2024-03-05)

<!-- END doctoc generated TOC please keep comment here to allow auto update -->

Expand Down Expand Up @@ -221,6 +224,7 @@ syntax = "proto2";
message NoiseExtensions {
repeated bytes webtransport_certhashes = 1;
repeated string stream_muxers = 2;
boolean webtransport_message_framing = 3;
}

message NoiseHandshakePayload {
Expand Down Expand Up @@ -461,6 +465,10 @@ unsupported types like RSA.

- Add Noise extension registry

### r5 - 2024-03-05

- Add WebTransport message framing to extension registry


[peer-id-spec]: ../peer-ids/peer-ids.md
[peer-id-spec-signing-rules]: ../peer-ids/peer-ids.md#how-keys-are-encoded-and-messages-signed
Expand Down
36 changes: 36 additions & 0 deletions webtransport/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,3 +69,39 @@ In order to verify end-to-end encryption of the connection, the peers need to es
On receipt of the `webtransport_certhashes` extension, the client MUST verify that the certificate hash of the certificate that was used on the connection is contained in the server's list. If the client was willing to accept multiple certificate hashes, but cannot determine which certificate was actually used to establish the connection (this will commonly be the case for browser clients), it MUST verify that all certificate hashes are contained in the server's list. If verification fails, it MUST abort the handshake.

For the client, the libp2p connection is fully established once it has sent the last Noise handshake message. For the server, processing of that message completes the handshake.

## Message framing

Upon closing a WebTransport stream, some implementations do not wait for all outstanding stream data to be sent over the wire before freeing up stream resources and making queue memory available for other uses.

To allow cleanly closing streams without the loss of data using these implementations it's necessary to adopt similar semantics to the WebRTC transport when [closing datachannels](../webrtc/README.md#closing-an-rtcdatachannel).

During the [security handshake](#security-handshake), a `webtransport_message_framing` boolean value may be supplied as part of the Noise extension block.

If present, all messages sent over this connection will framed within a protobuf wrapper with the following structure:

```proto
syntax = "proto3";

message Message {
enum Flag {
// The sender will no longer send messages on the stream.
FIN = 0;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not sure if this is an issue, but the flag field is optional and the 0 value starts closing the stream.

If you were to write a data message following proto3 semantics which let you omit the flag field, then read the message using proto2 semantics, the flag field would get initialised to it's default value of 0 and the receiver would think the sender wanted to close the stream.

We can work around this by having a NIL flag as the 0 value, which would be ignored by any receiver when read by a proto2 or proto3 decoder.

Or we expect implementations to apply proto3 semantics because that's what the definition here says.

// The sender acknowledges receipt of a FIN
FIN_ACK = 1;
}

optional Flag flag = 1;
optional bytes message = 2;
}
```

If a node sends the `webtransport_message_framing` flag but does not receive one from the remote, it MUST fall back to sending unframed messages.

If both nodes send the `webtransport_message_framing` flag, when either 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 close it's writable end of the stream once it has received a `FIN_ACK`.

The node MAY close the writable end of the stream 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.