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 support for WebRTC #2579

Merged
merged 54 commits into from
Sep 20, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
54 commits
Select commit Hold shift + click to select a range
d30f3c2
wasm-node: modify index-browser to support webrtc
melekes Aug 4, 2022
81b8c4f
correct URL pattern
melekes Aug 4, 2022
4de6a30
close and send functions
melekes Aug 4, 2022
7121f25
correct fingerprint
melekes Aug 5, 2022
a5a3607
Merge branch 'main' into anton/1712-add-support-for-webrtc
melekes Aug 30, 2022
e2f3d5e
Merge branch 'main' into anton/1712-add-support-for-webrtc
melekes Sep 6, 2022
ca2ed4f
new URL format
melekes Sep 7, 2022
1668a76
noise handshake
melekes Sep 7, 2022
ed39cfd
verify peer ID
melekes Sep 8, 2022
1a18c3a
fix import bug
melekes Sep 8, 2022
6df37bf
fix remaining errors except one
melekes Sep 9, 2022
36e960a
use array to push/pull messages
melekes Sep 12, 2022
0917bf5
Various minor fixes
tomaka Sep 13, 2022
1027e25
Merge branch 'main' into anton/1712-add-support-for-webrtc
tomaka Sep 13, 2022
28e86c0
ensure client's ufrag and pwd are equal
melekes Sep 13, 2022
3985e83
Use proper ufrag/pwd in SDP
tomaka Sep 13, 2022
85d5770
Better comments
tomaka Sep 13, 2022
81aa196
Update the ufrag and pwd
tomaka Sep 14, 2022
e8f489b
Merge branch 'main' into anton/1712-add-support-for-webrtc
tomaka Sep 15, 2022
8f118c6
Fix compilation
tomaka Sep 15, 2022
a752b95
Bridge index-browser's WebRTC with smoldot
tomaka Sep 15, 2022
06bf315
Forgot a #[no_mangle]
tomaka Sep 15, 2022
7f705ee
Call reset() if the connection is closed
tomaka Sep 15, 2022
9eca8bf
Ooops, inbound <-> outbound
tomaka Sep 15, 2022
b215d6c
Restore the id: 1, negotiated: true
tomaka Sep 15, 2022
2286fbe
The data is in fact an ArrayBuffer
tomaka Sep 15, 2022
cee8d4a
Fix the definition of ready_substreams
tomaka Sep 15, 2022
71d584f
Remove callbacks before closing a substream
tomaka Sep 15, 2022
7ff2383
Make the substream IDs hack less hacky
tomaka Sep 15, 2022
29b1c4d
Fix multi-stream connections now handshaking
tomaka Sep 15, 2022
66c55b2
Print the direction
tomaka Sep 15, 2022
050a756
Fix weird unicode
tomaka Sep 15, 2022
baff21b
Fix no-std compilation
tomaka Sep 15, 2022
91d6b48
Don't send id after first substream
tomaka Sep 15, 2022
89e049d
Add a `enableExperimentalWebRTC` option flag instead of `forbidWebRTC`
tomaka Sep 16, 2022
9197982
Tweak the close() and send() functions
tomaka Sep 16, 2022
2d51af9
Extract multibaseMultihashToSha256 to separate function
tomaka Sep 16, 2022
14a7055
Move the multiaddr parsing at the right place
tomaka Sep 16, 2022
4f059f1
Minor JS tweak
tomaka Sep 16, 2022
288f14d
Don't log the candidates
tomaka Sep 16, 2022
db30446
Merge branch 'main' into anton/1712-add-support-for-webrtc
tomaka Sep 16, 2022
7f63a75
Update for the main branch
tomaka Sep 16, 2022
373865f
CHANGELOG
tomaka Sep 16, 2022
13e21cd
Improve multihashToSha256
tomaka Sep 20, 2022
ffc5f95
Fix the exception being thrown
tomaka Sep 20, 2022
17853e2
Many small improvements to JS code
tomaka Sep 20, 2022
83d8a4e
Rustfmt
tomaka Sep 20, 2022
356408e
Use a custom base64 implementation
tomaka Sep 20, 2022
daab79e
Revert moduleResolution change
tomaka Sep 20, 2022
98823ec
Tweaks
tomaka Sep 20, 2022
4365229
Ooops, wrong variant was used
tomaka Sep 20, 2022
64f82ba
Add certificate hash field
tomaka Sep 20, 2022
683a81a
Address review
tomaka Sep 20, 2022
aab2377
Merge branch 'main' into anton/1712-add-support-for-webrtc
mergify[bot] Sep 20, 2022
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
27 changes: 18 additions & 9 deletions bin/light-base/src/network_service/tasks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
use super::Shared;
use crate::platform::{Platform, PlatformConnection, PlatformSubstreamDirection};

use alloc::{string::ToString as _, sync::Arc, vec};
use alloc::{string::ToString as _, sync::Arc, vec, vec::Vec};
use core::{iter, pin::Pin};
use futures::{channel::mpsc, prelude::*};
use smoldot::{libp2p::read_write::ReadWrite, network::service};
Expand Down Expand Up @@ -372,6 +372,8 @@ async fn multi_stream_connection_task<TPlat: Platform>(
let mut pending_opening_out_substreams = 0;
// Newly-open substream that has just been yielded by the connection.
let mut newly_open_substream = None;
// `true` if the remote has force-closed our connection.
let mut has_reset = false;
// List of all currently open substreams. The index (as a `usize`) corresponds to the id
// of this substream within the `connection_task` state machine.
let mut open_substreams = slab::Slab::<TPlat::Stream>::with_capacity(16);
Expand Down Expand Up @@ -433,12 +435,12 @@ async fn multi_stream_connection_task<TPlat: Platform>(
}

// Perform a read-write on all substreams that are ready.
loop {
let substream_id = match connection_task.ready_substreams().next() {
Some(s) => *s,
None => break,
};

// TODO: what is a ready substream is a bit of a clusterfuck, figure out
for substream_id in connection_task
.ready_substreams()
.copied()
.collect::<Vec<_>>()
{
let substream = &mut open_substreams[substream_id];

let mut read_write = ReadWrite {
Expand Down Expand Up @@ -576,8 +578,15 @@ async fn multi_stream_connection_task<TPlat: Platform>(
debug_assert!(newly_open_substream.is_none());
futures::select! {
_ = message_from_coordinator => {}
substream = TPlat::next_substream(&mut connection).fuse() => {
newly_open_substream = substream;
substream = if has_reset { either::Right(future::pending()) } else { either::Left(TPlat::next_substream(&mut connection)) }.fuse() => {
match substream {
Some(s) => newly_open_substream = Some(s),
None => {
// `None` is returned if the remote has force-closed the connection.
connection_task.reset();
has_reset = true;
}
}
}
_ = poll_after => {}
_ = data_ready.fuse() => {}
Expand Down
1 change: 1 addition & 0 deletions bin/wasm-node/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@

### Added

- Add experimental support for WebRTC according to the in-progress specification for libp2p-webrtc. For now this feature must explicitly be enabled by passing `enableExperimentalWebRTC: true` as part of the ̀`ClientConfig`. The multiaddress format for WebRTC is `/ip4/.../udp/.../webrtc/certhash/...` (or `/ip6/...`), where the payload behind `/certhash` is a multibase-encoded multihash-encoded SHA256 of the DTLS certificate used by the remote. ([#2579](https://github.com/paritytech/smoldot/pull/2579))
- Add support for the `chainHead_unstable_finalizedDatabase` JSON-RPC method. This JSON-RPC method aims to be a replacement for the `databaseContent` method of the `Chain` and is expected to remain a permanently unstable smoldot-specific function. ([#2749](https://github.com/paritytech/smoldot/pull/2749))

## 0.6.33 - 2022-09-13
Expand Down
78 changes: 38 additions & 40 deletions bin/wasm-node/javascript/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

115 changes: 115 additions & 0 deletions bin/wasm-node/javascript/src/base64.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
// Smoldot
// Copyright (C) 2019-2022 Parity Technologies (UK) Ltd.
// SPDX-License-Identifier: GPL-3.0-or-later WITH Classpath-exception-2.0

// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.

// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.

// You should have received a copy of the GNU General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.

let rfc4648Alphabet: Map<string, number> = new Map();
const rfc4648AlphabetAsStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
for (let i = 0; i < rfc4648AlphabetAsStr.length; ++i) {
rfc4648Alphabet.set(rfc4648AlphabetAsStr[i]!, i)
}

let urlSafeAlphabet: Map<string, number> = new Map();
const urlSafeAlphabetAsStr = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_";
for (let i = 0; i < urlSafeAlphabetAsStr.length; ++i) {
urlSafeAlphabet.set(urlSafeAlphabetAsStr[i]!, i)
}

/**
* Decodes a multibase-encoded string.
*
* Throws an exception if the encoding isn't base64 or one of its variants.
*/
export function multibaseBase64Decode(input: string): Uint8Array {
if (input.length === 0)
throw new Error("Invalid multibase");

switch (input[0]) {
case 'm':
case 'M':
return classicDecode(input.slice(1))
case 'u':
case 'U':
return urlSafeDecode(input.slice(1))
default:
throw new Error('Unknown multibase prefix: ' + input[0]);
}
}

/**
* Decodes a base64-encoded string into bytes using the original alphabet from RFC4648.
*
* See <https://datatracker.ietf.org/doc/html/rfc4648#section-4>.
*/
export function classicDecode(input: string): Uint8Array {
return base64Decode(input, rfc4648Alphabet);
}

/**
* Decodes a base64-encoded string into bytes using the URL-safe alphabet.
*
* See <https://datatracker.ietf.org/doc/html/rfc4648#section-5>.
*/
export function urlSafeDecode(input: string): Uint8Array {
return base64Decode(input, urlSafeAlphabet);
}

/**
* Decodes a base64-encoded string into bytes using the given alphabet.
*/
export function base64Decode(input: string, alphabet: Map<string, number>): Uint8Array {
// Remove the padding bytes at the end of the string. We don't check whether the padding is
// accurate.
while (input.length !== 0 && input[input.length - 1] === '=')
input = input.slice(0, -1)

// Contains the output data.
const out = new Uint8Array(Math.floor(input.length * 6 / 8));
// Position within `out` of the next byte to write.
let outPos = 0;

// The bits decoded from the input are added to the right of this value.
let currentByte = 0;
// The left-most `validBitsInCurrentByte` bits of `currentByte` must be written out.
let validBitsInCurrentByte = 0;

for (let i = 0; i < input.length; ++i) {
const inputChr = input[i]!;

const bitsToAppend = alphabet.get(inputChr);
if (bitsToAppend === undefined)
throw new Error('Invalid base64 character: ' + inputChr);
console.assert(bitsToAppend < (1 << 6));

currentByte = (currentByte << 6) | bitsToAppend;
validBitsInCurrentByte += 6;

if (validBitsInCurrentByte >= 8) {
let outByte = currentByte >> (validBitsInCurrentByte - 8);
out[outPos] = outByte;
outPos += 1;
validBitsInCurrentByte -= 8;
}
console.assert(validBitsInCurrentByte < 8);
currentByte &= 0xff;
}

if ((currentByte & ((1 << validBitsInCurrentByte) - 1)) !== 0)
throw new Error("Unexpected EOF");
if (validBitsInCurrentByte >= 6)
throw new Error("Unexpected EOF");

return out;
}
10 changes: 10 additions & 0 deletions bin/wasm-node/javascript/src/client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,6 +253,16 @@ export interface ClientOptions {
* connections.
*/
forbidWss?: boolean;

/**
* Enable experimental support for WebRTC connections.
*
* Support for WebRTC connections is currently in progress and might have significant issues.
*
* This flag currently defaults to `false`. In a later version, it will be removed and WebRTC
* connections will be enabled by default.
*/
enableExperimentalWebRTC?: boolean;
}

/**
Expand Down
Loading