@@ -31,6 +31,20 @@ export var filterCandidatesFromSdp = (sdp:string) : string => {
3131 } ) . join ( '\n' ) ;
3232}
3333
34+ export var getMidFromSdp = ( sdp :string ) : string => {
35+ var mids :string [ ] = [ ] ;
36+ sdp . split ( '\n' ) . forEach ( ( s ) => {
37+ var match = s . match ( / ^ a = m i d : ( \S + ) \s * $ / ) ;
38+ if ( match ) {
39+ mids . push ( match [ 1 ] ) ;
40+ }
41+ } ) ;
42+ if ( mids . length !== 1 ) {
43+ throw new Error ( 'Expected 1 mid, but there are actually ' + mids . length ) ;
44+ }
45+ return mids [ 0 ] ;
46+ }
47+
3448export interface NatPair {
3549 internal : net . Endpoint ;
3650 external : net . Endpoint ;
@@ -137,13 +151,17 @@ export class Connection implements peerconnection.PeerConnection<ChurnSignalling
137151 // Number of instances created, for logging purposes.
138152 private static id_ = 0 ;
139153
154+ // The "mid"
155+ private mid_ :string ;
156+
140157 // Maximum time to spend gathering ICE candidates.
141158 // We cap this so that slow STUN servers, in the absence
142159 // of trickle ICE, don't make the user wait unnecessarily.
143160 private static PROBE_TIMEOUT_MS_ = 3000 ;
144161
145162 public peerOpenedChannelQueue :handler . QueueHandler < peerconnection . DataChannel , void > ;
146163 public signalForPeerQueue :handler . Queue < ChurnSignallingMessage , void > ;
164+ private candidateQueue_ :handler . Queue < Candidate , void > ;
147165
148166 public onceConnected :Promise < void > ;
149167 public onceClosed :Promise < void > ;
@@ -196,6 +214,7 @@ export class Connection implements peerconnection.PeerConnection<ChurnSignalling
196214 Connection . id_ ++ ;
197215
198216 this . signalForPeerQueue = new handler . Queue < ChurnSignallingMessage , void > ( ) ;
217+ this . candidateQueue_ = new handler . Queue < Candidate , void > ( ) ;
199218
200219 this . configureObfuscatedConnection_ ( ) ;
201220 // When the probe connection is complete, it will trigger the
@@ -246,13 +265,10 @@ export class Connection implements peerconnection.PeerConnection<ChurnSignalling
246265 }
247266 }
248267
249- // It's immediately safe to send each candidate to the remote peer,
250- // because the remote peer will retry for several seconds, and the
251- // probe connection will not respond to any pings because it doesn't
252- // have a remote description.
253- this . signalForPeerQueue . handle ( {
254- webrtcMessage : message
255- } ) ;
268+ // We enqueue this candidate for transmission to the remote peer.
269+ // This queue will start draining once an Offer is available, so
270+ // that we can make sure that the mid matches.
271+ this . candidateQueue_ . handle ( c ) ;
256272
257273 // We cannot rebind any local ports until the probe connection has
258274 // released them, so we have to store them and wait until probing is
@@ -281,6 +297,20 @@ export class Connection implements peerconnection.PeerConnection<ChurnSignalling
281297 this . probeConnection_ . negotiateConnection ( ) ;
282298 }
283299
300+ private candidateQueueHandler_ = ( candidate :Candidate ) : Promise < void > => {
301+ // The candidate was generated by the probe connection, which might have a
302+ // different mid from the obfuscated connection. Make sure that the mid
303+ // matches before we transmit the candidate.
304+ candidate . sdpMid = this . mid_ ;
305+
306+ return this . signalForPeerQueue . handle ( {
307+ webrtcMessage : {
308+ type : signals . Type . CANDIDATE ,
309+ candidate : candidate . toRTCIceCandidate ( )
310+ }
311+ } ) ;
312+ }
313+
284314 private processProbeCandidates_ = ( candidates :Candidate [ ] ) => {
285315 candidates . forEach ( ( c ) => {
286316 this . pipe_ . bindLocal ( c . getLocalEndpoint ( ) ) ;
@@ -367,6 +397,11 @@ export class Connection implements peerconnection.PeerConnection<ChurnSignalling
367397 webrtcMessage : message
368398 } ;
369399 this . signalForPeerQueue . handle ( churnSignal ) ;
400+
401+ // We need to know the MID so that we can rewrite candidates to
402+ // have the correct MID before transmitting them.
403+ this . mid_ = getMidFromSdp ( message . description . sdp ) ;
404+ this . candidateQueue_ . setHandler ( this . candidateQueueHandler_ ) ;
370405 } else if ( message . type === signals . Type . CANDIDATE ) {
371406 // This will tell us on which port webrtc is operating.
372407 // There's no need to send this to the peer because it can
0 commit comments