This is an automated email from the git hooks/post-receive script.
cohosh pushed a commit to branch main in repository pluggable-transports/snowflake-webext.
The following commit(s) were added to refs/heads/main by this push: new 874e4ac fix: send SDP answer if ICE gathering is taking long to complete 874e4ac is described below
commit 874e4acebf89d498db2de2e4dd6883625e0d51a6 Author: WofWca wofwca@protonmail.com AuthorDate: Mon Nov 7 19:49:10 2022 +0400
fix: send SDP answer if ICE gathering is taking long to complete
Fixes #68 --- config.js | 6 ++++++ proxypair.js | 42 +++++++++++++++++++++++++++++++++++------- spec/proxypair.spec.js | 4 ++++ 3 files changed, 45 insertions(+), 7 deletions(-)
diff --git a/config.js b/config.js index 8f42176..2fc8c05 100644 --- a/config.js +++ b/config.js @@ -38,6 +38,12 @@ Config.prototype.datachannelTimeout = 20 * 1000; // Timeout to close proxypair if no messages are sent Config.prototype.messageTimeout = 30 * 1000;
+// This must be smaller than the clien't timeout (`ClientTimeout`) +// (which is 10 seconds by default as of now), otherwise the client would be +// gone before we send the answer. +// And it, obviously, must be smaller than `datachannelTimeout`. +Config.prototype.answerTimeout = 6 * 1000; + Config.prototype.maxNumClients = 1;
Config.prototype.proxyType = ""; diff --git a/proxypair.js b/proxypair.js index 716aa7a..f0adba6 100644 --- a/proxypair.js +++ b/proxypair.js @@ -39,13 +39,6 @@ class ProxyPair { /** Prepare a WebRTC PeerConnection and await for an SDP offer. */ begin() { this.pc = new RTCPeerConnection(this.pcConfig); - this.pc.onicecandidate = (evt) => { - // Browser sends a null candidate once the ICE gathering completes. - if (null === evt.candidate && this.pc.connectionState !== 'closed') { - dbg('Finished gathering ICE candidates.'); - snowflake.broker.sendAnswer(this.id, this.pc.localDescription); - } - }; // OnDataChannel triggered remotely from the client when connection succeeds. this.pc.ondatachannel = (dc) => { const channel = dc.channel; @@ -71,6 +64,39 @@ class ProxyPair { return false; } dbg('SDP ' + offer.type + ' successfully received.'); + + // Send the answer when ready. + const onceSendAnswer = () => { + snowflake.broker.sendAnswer(this.id, this.pc.localDescription); + + this.pc.onicecandidate = null; + clearTimeout(this.answerTimeoutId); + }; + this.pc.onicecandidate = (evt) => { + // Browser sends a null candidate once the ICE gathering completes. + if (null === evt.candidate && this.pc.connectionState !== 'closed') { + dbg('Finished gathering ICE candidates.'); + onceSendAnswer(); + } + }; + if (this.pc.iceGatheringState === 'complete') { + // This probably never happens as we've `setRemoteDescription` just now, + // but let's play it safe. + onceSendAnswer(); + } else { + this.answerTimeoutId = setTimeout(() => { + dbg('answerTimeout'); + // ICE gathering is taking a while to complete - send what we got so far. + if (!this.pc.localDescription) { + // We don't have anything to send yet. Sigh. The client will probably timeout waiting + // for us, but let's not bail and just try to wait some more in hope that it won't. + // Worst case scenario - `datachannelTimeout` callback will run. + return; + } + onceSendAnswer(); + }, this.config.answerTimeout); + } + return true; }
@@ -196,6 +222,7 @@ class ProxyPair { close() { clearTimeout(this.connectToRelayTimeoutId); clearTimeout(this.messageTimer); + clearTimeout(this.answerTimeoutId); if (this.webrtcIsReady()) { this.client.close(); } @@ -274,6 +301,7 @@ ProxyPair.prototype.relay = null; // websocket
ProxyPair.prototype.connectToRelayTimeoutId = 0; ProxyPair.prototype.messageTimer = 0; +ProxyPair.prototype.answerTimeoutId = 0; ProxyPair.prototype.flush_timeout_id = null;
ProxyPair.prototype.onCleanup = null; diff --git a/spec/proxypair.spec.js b/spec/proxypair.spec.js index 992b4c1..8e0b330 100644 --- a/spec/proxypair.spec.js +++ b/spec/proxypair.spec.js @@ -80,6 +80,10 @@ describe('ProxyPair', function() {
it('responds with a WebRTC answer correctly', function() { spyOn(snowflake.broker, 'sendAnswer'); + pp.receiveWebRTCOffer({ + type: 'offer', + sdp: 'foo' + }); pp.pc.onicecandidate({ candidate: null });