Skip to content

Commit

Permalink
fix: WebRTC uncaught promise rejection on incoming connection (#2302)
Browse files Browse the repository at this point in the history
We catch WebRTC errors, log them and throw normalised errors to ensure they are the same across WebRTC stacks (FF, Chrome, node).

#2299 made one of these operations async which would cause an UHPR if thrown.
  • Loading branch information
achingbrain authored Dec 6, 2023
1 parent 64a915a commit d105061
Show file tree
Hide file tree
Showing 3 changed files with 7 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,10 @@ export async function initiateConnection ({ peerConnection, signal, metrics, mul
}

// create an offer
const offerSdp = await peerConnection.createOffer()
const offerSdp = await peerConnection.createOffer().catch(err => {
log.error('could not execute createOffer', err)
throw new CodeError('Failed to set createOffer', 'ERR_SDP_HANDSHAKE_FAILED')
})

log.trace('initiator send SDP offer %s', offerSdp.sdp)

Expand All @@ -117,7 +120,7 @@ export async function initiateConnection ({ peerConnection, signal, metrics, mul
})

if (answerMessage.type !== Message.Type.SDP_ANSWER) {
throw new CodeError('remote should send an SDP answer', 'ERR_SDP_HANDSHAKE_FAILED')
throw new CodeError('Remote should send an SDP answer', 'ERR_SDP_HANDSHAKE_FAILED')
}

log.trace('initiator receive SDP answer %s', answerMessage.data)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import { CodeError } from '@libp2p/interface'
import { multiaddr, type Multiaddr } from '@multiformats/multiaddr'
import { pbStream } from 'it-protobuf-stream'
import pDefer, { type DeferredPromise } from 'p-defer'
import { type RTCPeerConnection, RTCSessionDescription } from '../webrtc/index.js'
import { Message } from './pb/message.js'
import { readCandidatesUntilConnected } from './util.js'
Expand All @@ -20,8 +19,6 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
const messageStream = pbStream(stream).pb(Message)

try {
const answerSentPromise: DeferredPromise<void> = pDefer()

// candidate callbacks
peerConnection.onicecandidate = ({ candidate }) => {
// a null candidate means end-of-candidates, an empty string candidate
Expand Down Expand Up @@ -67,7 +64,6 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
// create and write an SDP answer
const answer = await peerConnection.createAnswer().catch(err => {
log.error('could not execute createAnswer', err)
answerSentPromise.reject(err)
throw new CodeError('Failed to create answer', 'ERR_SDP_HANDSHAKE_FAILED')
})

Expand All @@ -78,16 +74,11 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
signal
})

peerConnection.setLocalDescription(answer).then(() => {
answerSentPromise.resolve()
}, err => {
await peerConnection.setLocalDescription(answer).catch(err => {
log.error('could not execute setLocalDescription', err)
answerSentPromise.reject(err)
throw new CodeError('Failed to set localDescription', 'ERR_SDP_HANDSHAKE_FAILED')
})

await answerSentPromise.promise

log.trace('recipient read candidates until connected')

// wait until candidates are connected
Expand All @@ -96,11 +87,6 @@ export async function handleIncomingStream ({ peerConnection, stream, signal, co
signal,
log
})

log.trace('recipient connected, closing signaling stream')
await messageStream.unwrap().unwrap().close({
signal
})
} catch (err: any) {
if (peerConnection.connectionState !== 'connected') {
log.error('error while handling signaling stream from peer %a', connection.remoteAddr, err)
Expand Down
2 changes: 1 addition & 1 deletion packages/transport-webrtc/test/peer.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -214,7 +214,7 @@ describe('webrtc dialer', () => {
const answer = await pc.createAnswer()
await pc.setLocalDescription(answer)

await expect(initiatorPeerConnectionPromise).to.be.rejectedWith(/remote should send an SDP answer/)
await expect(initiatorPeerConnectionPromise).to.be.rejectedWith(/Remote should send an SDP answer/)

pc.close()
})
Expand Down

0 comments on commit d105061

Please sign in to comment.