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

Add WebRTC Signaling Protocol Spec #159

Closed
wants to merge 4 commits into from
Closed
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
218 changes: 218 additions & 0 deletions webrtc-signal/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,218 @@
# WebRTC Signaling Protocol

Author: Alex Browne (@albrow)

Revision: DRAFT; 2019-04-21

This specification describes a protocol for establishing a WebRTC connection
between two peers via a common third peer, called the "signaler".

## Motivation

A standard protocol for WebRTC Signaling can be used to develop a WebRTC
transport. Such a transport can be used to faciliate connections between two
browser peers without relying on a relay or any other third-party (They only
need to rely on the signaler to establish the initial connection).

## Background

WebRTC is currently the best and most widely supported technology for
browser-based peer-to-peer communication. While often used for VoIP/video chat
applications, WebRTC also supports "data channels" for communicating arbitrary
bytes of data.

Partly due to browser security concerns, it is not possible to directly dial an
arbitrary peer (e.g. via their IP address) using WebRTC. Instead, WebRTC
utilizes the
[Interactive Connectivity Establishment (or "ICE") protocol](https://developer.mozilla.org/en-US/docs/Web/API/WebRTC_API/Connectivity)
to establish a connection between two peers. Roughly speaking, the process is
as follows:

1. One peer, called the "offerer", generates an "offer". The offer includes some
information about how this peer can be reached (IP address, port, etc.) as
well as one or more proposed configurations for the connection.
2. The offer is communicated to another peer, called the "answerer".
3. The answerer generates an "answer" corresponding to the offer. If possible,
it selects the best of the connection configurations proposed by the offerer.
4. The answer is communicated back to the original offerer. If both the offerer
and answerer have come to an agreement, a connection is established.

This process may be repeated until both the offerer and the answerer have agreed
on a configuration for their connection.

Neither WebRTC nor ICE specify _how_ answers and offers should be communicated.
That detail is left to application developers. The goal of this document is to
provide a more detailed specification about how answers and offers can be
communicated to peers using a third-party called a signaler.

## Identity and Authenticity

Each peer that communicates with the signaler is identified by a PeerID.
Messages sent to the signaler are signed with a private key
corresponding to that PeerID. This prevents tampering and impersontation. In
other words, it ensures that a peer can only be connected to the peer that they
intended to connect to.
Copy link
Member

Choose a reason for hiding this comment

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

This step is done for free when using libp2p Circuit Relay.


## Peer Discovery

This document does not specify how peers should discover one another and is
designed to be compatible with any peer discovery mechanism. Here are the
requirements for the WebRTC signaling protocol described in this document:

1. A peer knows the PeerID of the peer it wants to connect to.
2. Both peers agree to use the same signaler.

It is possible for a signaler itself to implement peer discovery (e.g.,
using the Rendezvous Protocol), but this is not a strict requirement.

## Multiaddress format

The Signaling Protocol is designed to work over existing libp2p transports. We
use the following multiaddress format for dialing and listening:

```
<signaler-multiaddr>/p2p-webrtc-signal/<signaler-peer-id>
Copy link
Member

Choose a reason for hiding this comment

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

The signaler-multiaddr can just be the relay address.

```

Where `<signaler-multiaddr>` is the multiaddress for the signaler (including
the transport to be used for signaling) and `<signaler-peer-id>` is the
base58-encoded PeerID of the signaler. `<signaler-multiaddr>` may be omitted to
use an existing connection to `<signaler-peer-id>` for signaling.

This multiaddress format allows for flexibility in the underlying transport
used. The signaler can be either centralized (all peers use the same signaler)
or decentralized (two peers use a common third peer for signaling).

### Examples

- Signaling over WebSockets using an IPv4 address:
`/ip4/192.168.1.46/tcp/9000/ws/p2p-webrtc-signal/QmWaWqTtzPCaYnpfxsAAGtrVhNumHqQ7jtdcsFsjvs3csS`
- Signaling over HTTP using a domain name:
`/dns6/signaler.myapp.com/tcp/80/http/p2p-webrtc-signal/QmZbw3TKr3dxhHXiPkbNraWaeGoqPNXAXfAcV8RP2Eqngj`
- Signaling via a common peer:
`/p2p-webrtc-signal/QmWeRHDDiwuGnS4xbjF2zXETucL7xQLjadoaTZ4yJE3hQs`
Copy link
Member

Choose a reason for hiding this comment

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

Not sure I get this one? Is it missing the ID of the common peer acting as a signaller?

Copy link
Contributor

Choose a reason for hiding this comment

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

It says above

<signaler-multiaddr> may be omitted to use an existing connection to <signaler-peer-id> for signaling.

But I'm also not entirely clear on the use case. Does this only work if I've already established a separate connection to the peer I want to reach (e.g. through a circuit relay)?

Or if we've both connected to any common peer that has the p2p-webrtc-signal capability, could I discover and use that without caring who the signaller peer is?

Copy link

Choose a reason for hiding this comment

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

Or if we've both connected to any common peer that has the p2p-webrtc-signal capability, could I discover and use that without caring who the signaller peer is?

I think that not a good idea, a better solution could be to just indicate on the DHT we are reachable with WebRTC-signal and use a circuit relay to establish the connection.
So for that we need first a ws[s] connection to establish circuit relay and discover the DHT.

Adding some special nodes is a very good way to allow anybody to get a giant control on the network.
When these kind of option are made a very few people activate them, that made people less interested in making these because we know that gonna generate a big traffic.
In fact my solution add a problem about stun server but I think thats more a client side problem (by that I mean not a DHT one) 2, because 2 totaly separated STUN server produce some compatible result (except if you are not in the same network, example: internet and hyperboria), and some STUN server are region locked (China).
We may can just allow peers to run integrated STUN server and broadcast it to the DHT (to be apocalypsical proof) since that give you way less information (a meeting server know who talk to who, can chose who talk to who but can't create fake connection like Qmxxxx... is listening for WebRTC if we require signing these kind of information to a server capable of knowing this ip (so easly matchable with a peer id via DHT), want to connect to a WebRTC node).

PS: Meeting server can maybe be used only to broadcast "Qmxxxx is listening for WebRTC, contact him via circuit relay at this node" (signed by Qmxxxx for obvious reason) but in this case why not just putting these directly in DHT listen address of Qmxxxx ?


## Message Types

### SendOffer

Used by an offerer to send an offer to a specific peer.

#### Request

```javascript
{
"peer_id": String, // The PeerID of the peer sending this request (the offerer).
"answerer_id": String, // The PeerID of the answerer.
"offer": { // An RTCSessionDescription of type "offer". See https://developer.mozilla.org/en-US/docs/Web/API/RTCSessionDescription.
"type": "offer",
"sdp:": String
}
}
```

#### Response

```javascript
{
}
```

### GetOffers

Used by an answerer to receive up to `max_count` pending offers.

#### Request

```javascript
{
"peer_id": String, // The PeerID of the peer sending this request (the answerer).
"max_count": Number, // The maximum number of offers to be returned.
}
```

#### Response

```javascript
{
"offers": [ // An array of RTCSessionDescriptions of type "offer".
{
"type": "offer",
"sdp": String
}
]
}
```

### SendAnswer

Used by an answerer to send an answer to a specific offerer.

#### Request

```javascript
{
"peer_id": String // The PeerID of the peer sending this request (the answerer).
"offerer_id": String // The PeerID of the offerer.
"answer": { // An RTCSessionDescription of type "answer". Must correspond to the offer sent by offerer.
"type": "answer",
"sdp": String
}
}
```

#### Response

```javascript
{
}
```

### GetAnswers

Used by an offerer to receive up to `max_count` pending answers.

#### Request

```javascript
{
"peer_id": String, // The PeerID of the peer sending this request (the offerer).
"max_count": Number // The maximum number of answers to be returned.
}
```

#### Response

```javascript
{
"answers": [ // An array of RTCSessionDescriptions of type "answer".
{
"type": "answer",
"sdp": String
}
]
}
```

## Statefulness and Timeouts

The API above implicitly requires the signaler to maintain some state
about pending offers and answers. When an answer or offer is sent to the
signaler, it will need to store them until the corresponding peer requests them
via `GetAnswers` or `GetOffers` requests. The timeline of an answer/offer
handshake is as follows:

1. The offerer sends a `SendOffer` request.
1. The signaler stores the offer, which is considered "pending".
1. The answerer sends a `GetOffers` request and receives the offer.
1. After the offer has been received, it is no longer pending and the signaler may safely delete it.
1. The answerer sends a `SendAnswer` request.
1. The signaler stores the answer, which is considered "pending".
1. The offerer receives a the answer via a `GetAnswers` request.
1. After the answer has been received, it is no longer pending and the signaler may safely delete it.

In order to avoid filling up storage space with pending answers and offers, the
signaler should delete any pending answers or offers that have not been
received after 60 seconds. Clients which communicate with the signaler
can also drop a peer and update their internal state if they don't receive an
answer within 60 seconds.