From ffa929ea11acf60560922a17c8ed8dddccbf774d Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Tue, 19 Mar 2019 15:14:13 -0700 Subject: [PATCH 1/4] Add spec for WebRTC Signal Protocol --- signal/README.md | 205 +++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 205 insertions(+) create mode 100644 signal/README.md diff --git a/signal/README.md b/signal/README.md new file mode 100644 index 000000000..124e0b0c1 --- /dev/null +++ b/signal/README.md @@ -0,0 +1,205 @@ +# WebRTC Signal Protocol + +Author: Alex Browne (@albrow) + +Revision: DRAFT; 2019-03-18 + +This specification describes a protocol for establishing a WebRTC connection +between two peers via a "Signaling Server". + +## 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 Signaling Server 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 Signaling Server. + +## Identity and Authenticity + +Each peer that communicates with the Signaling Server is identified by a PeerID. +Messages sent to the Signaling Server 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. + +## 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 Signaling Server. + +It is possible for a Signaling Server itself to implement peer discovery (e.g., +using the Rendezvous Protocol), but this is not a strict requirement. + +## Signaling Server API + +The Signaling Server uses a simple HTTP API with support for long-polling. The +HTTP endpoints for the server are as follows: + +### POST /send_offer + +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 +{ +} +``` + +### POST /get_offers + +Used by an answerer to receive up to `max_count` pending offers. + +This endpoint supports long-polling and the request may be kept alive until at +least one answer is available. The server may, at its discretion, decide to +close the request by returning an empty array of answers if no answers are +available after a certain amount of time has passed. + +#### 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 + } + ] +} +``` + +### POST /send_answer + +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 +{ +} +``` + +### POST /get_answers + +Used by an offerer to receive up to `max_count` pending answers. + +This endpoint supports long-polling and the request may be kept alive until at +least one answer is available. The server may, at its discretion, decide to +close the request by returning an empty array of answers if no answers are +available after a certain amount of time has passed. + +#### 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 HTTP API above implicitly requires the Signaling Server to maintain some +state about pending offers and answers. When an answer or offer is sent to the +server, it will need to store them (typically in a database) until the +corresponding peer requests them via the `/get_answers` or `/get_offers` +endpoint. The timeline of an answer/offer handshake is as follows: + +1. The offerer sends a `/create_offer` request. +1. The Signaling Server stores the offer, which is considered "pending". +1. The answerer polls the `/get_offers` endpoint and receives the offer. +1. After the offer has been received, it is no longer pending and the Signaling Server may safely delete it. +1. The answerer sends a `/create_answer` request. +1. The Signaling Server stores the answer, which is considered "pending". +1. The offerer receives a the answer via the `/get_answers` endpoint. +1. After the answer has been received, it is no longer pending and the Signaling Server may safely delete it. + +In order to avoid filling up storage space with pending answers and offers, the +Signaling Server should delete any pending answers or offers that have not been +received after 60 seconds. Clients which communicate with the Signaling Server +will also understand that if they don't see a response from a specific peer (via +the `/get_offers` or `/get_answers` endpoint) within 60 seconds, the +answer/offer has timed out. From 415d1065cc137bd5289cec1499a442ea74f8bb0e Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Wed, 20 Mar 2019 14:53:13 -0700 Subject: [PATCH 2/4] Modify spec to be transport-agnostic --- signal/README.md | 50 +++++++++++++++++++++--------------------------- 1 file changed, 22 insertions(+), 28 deletions(-) diff --git a/signal/README.md b/signal/README.md index 124e0b0c1..d540a3b19 100644 --- a/signal/README.md +++ b/signal/README.md @@ -67,10 +67,15 @@ using the Rendezvous Protocol), but this is not a strict requirement. ## Signaling Server API -The Signaling Server uses a simple HTTP API with support for long-polling. The -HTTP endpoints for the server are as follows: +The Signaling Server uses a transport-agnostic request/response API. It is +possible to implement a Signaling Server using HTTP or any other transport +that can support request/response semantics. -### POST /send_offer +In practice, not all peers and not all Signaling Servers will support all +possible transports. There is an implicit requirement for transport negotiation +which is not covered in this spec. + +### SendOffer Used by an offerer to send an offer to a specific peer. @@ -94,15 +99,10 @@ Used by an offerer to send an offer to a specific peer. } ``` -### POST /get_offers +### GetOffers Used by an answerer to receive up to `max_count` pending offers. -This endpoint supports long-polling and the request may be kept alive until at -least one answer is available. The server may, at its discretion, decide to -close the request by returning an empty array of answers if no answers are -available after a certain amount of time has passed. - #### Request ```javascript @@ -125,7 +125,7 @@ available after a certain amount of time has passed. } ``` -### POST /send_answer +### SendAnswer Used by an answerer to send an answer to a specific offerer. @@ -149,15 +149,10 @@ Used by an answerer to send an answer to a specific offerer. } ``` -### POST /get_answers +### GetAnswers Used by an offerer to receive up to `max_count` pending answers. -This endpoint supports long-polling and the request may be kept alive until at -least one answer is available. The server may, at its discretion, decide to -close the request by returning an empty array of answers if no answers are -available after a certain amount of time has passed. - #### Request ```javascript @@ -182,24 +177,23 @@ available after a certain amount of time has passed. ## Statefulness and Timeouts -The HTTP API above implicitly requires the Signaling Server to maintain some -state about pending offers and answers. When an answer or offer is sent to the -server, it will need to store them (typically in a database) until the -corresponding peer requests them via the `/get_answers` or `/get_offers` -endpoint. The timeline of an answer/offer handshake is as follows: +The API above implicitly requires the Signaling Server to maintain some state +about pending offers and answers. When an answer or offer is sent to the server, +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 `/create_offer` request. +1. The offerer sends a `CreateOffer` request. 1. The Signaling Server stores the offer, which is considered "pending". -1. The answerer polls the `/get_offers` endpoint and receives the offer. +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 Signaling Server may safely delete it. -1. The answerer sends a `/create_answer` request. +1. The answerer sends a `CreateAnswer` request. 1. The Signaling Server stores the answer, which is considered "pending". -1. The offerer receives a the answer via the `/get_answers` endpoint. +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 Signaling Server may safely delete it. In order to avoid filling up storage space with pending answers and offers, the Signaling Server should delete any pending answers or offers that have not been received after 60 seconds. Clients which communicate with the Signaling Server -will also understand that if they don't see a response from a specific peer (via -the `/get_offers` or `/get_answers` endpoint) within 60 seconds, the -answer/offer has timed out. +can also drop a peer and update their internal state if they don't receive an +answer within 60 seconds. From fc4ad657db6df83739d70b6f4113d1d5c19a418f Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Wed, 20 Mar 2019 16:50:42 -0700 Subject: [PATCH 3/4] Rename Signaling Server -> Signaler --- signal/README.md | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/signal/README.md b/signal/README.md index d540a3b19..d2c0d4e6b 100644 --- a/signal/README.md +++ b/signal/README.md @@ -5,14 +5,14 @@ Author: Alex Browne (@albrow) Revision: DRAFT; 2019-03-18 This specification describes a protocol for establishing a WebRTC connection -between two peers via a "Signaling Server". +between two peers via a third-party, 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 Signaling Server to establish the initial connection). +need to rely on the signaler to establish the initial connection). ## Background @@ -43,12 +43,12 @@ 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 Signaling Server. +communicated to peers using a third-party called a signaler. ## Identity and Authenticity -Each peer that communicates with the Signaling Server is identified by a PeerID. -Messages sent to the Signaling Server are signed with a private key +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. @@ -60,18 +60,18 @@ 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 Signaling Server. +2. Both peers agree to use the same signaler. -It is possible for a Signaling Server itself to implement peer discovery (e.g., +It is possible for a signaler itself to implement peer discovery (e.g., using the Rendezvous Protocol), but this is not a strict requirement. -## Signaling Server API +## Signaler API -The Signaling Server uses a transport-agnostic request/response API. It is -possible to implement a Signaling Server using HTTP or any other transport +The signaler uses a transport-agnostic request/response API. It is +possible to implement a signaler using HTTP or any other transport that can support request/response semantics. -In practice, not all peers and not all Signaling Servers will support all +In practice, not all peers and not all signalers will support all possible transports. There is an implicit requirement for transport negotiation which is not covered in this spec. @@ -177,23 +177,23 @@ Used by an offerer to receive up to `max_count` pending answers. ## Statefulness and Timeouts -The API above implicitly requires the Signaling Server to maintain some state -about pending offers and answers. When an answer or offer is sent to the server, -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: +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 `CreateOffer` request. -1. The Signaling Server stores the offer, which is considered "pending". +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 Signaling Server may safely delete it. +1. After the offer has been received, it is no longer pending and the signaler may safely delete it. 1. The answerer sends a `CreateAnswer` request. -1. The Signaling Server stores the answer, which is considered "pending". +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 Signaling Server may safely delete it. +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 -Signaling Server should delete any pending answers or offers that have not been -received after 60 seconds. Clients which communicate with the Signaling Server +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. From 84cc297b1a6aafc7fc9b403ead7cd3e831d9df7c Mon Sep 17 00:00:00 2001 From: Alex Browne Date: Tue, 21 May 2019 13:58:41 -0700 Subject: [PATCH 4/4] Include multiaddress format as part of the protocol --- {signal => webrtc-signal}/README.md | 43 +++++++++++++++++++++-------- 1 file changed, 31 insertions(+), 12 deletions(-) rename {signal => webrtc-signal}/README.md (80%) diff --git a/signal/README.md b/webrtc-signal/README.md similarity index 80% rename from signal/README.md rename to webrtc-signal/README.md index d2c0d4e6b..039b634fe 100644 --- a/signal/README.md +++ b/webrtc-signal/README.md @@ -1,11 +1,11 @@ -# WebRTC Signal Protocol +# WebRTC Signaling Protocol Author: Alex Browne (@albrow) -Revision: DRAFT; 2019-03-18 +Revision: DRAFT; 2019-04-21 This specification describes a protocol for establishing a WebRTC connection -between two peers via a third-party, called the "signaler". +between two peers via a common third peer, called the "signaler". ## Motivation @@ -65,15 +65,34 @@ requirements for the WebRTC signaling protocol described in this document: It is possible for a signaler itself to implement peer discovery (e.g., using the Rendezvous Protocol), but this is not a strict requirement. -## Signaler API +## Multiaddress format -The signaler uses a transport-agnostic request/response API. It is -possible to implement a signaler using HTTP or any other transport -that can support request/response semantics. +The Signaling Protocol is designed to work over existing libp2p transports. We +use the following multiaddress format for dialing and listening: -In practice, not all peers and not all signalers will support all -possible transports. There is an implicit requirement for transport negotiation -which is not covered in this spec. +``` +/p2p-webrtc-signal/ +``` + +Where `` is the multiaddress for the signaler (including +the transport to be used for signaling) and `` is the +base58-encoded PeerID of the signaler. `` may be omitted to +use an existing connection to `` 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` + +## Message Types ### SendOffer @@ -183,11 +202,11 @@ 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 `CreateOffer` request. +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 `CreateAnswer` request. +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.