Skip to content

Commit 13df7ae

Browse files
committed
Implement DTLS/SRTP/SCTP restart
Fixes #1636
1 parent 7948437 commit 13df7ae

File tree

5 files changed

+440
-8
lines changed

5 files changed

+440
-8
lines changed

datachannel.go

Lines changed: 16 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ func (api *API) NewDataChannel(transport *SCTPTransport, params *DataChannelPara
6969
return nil, err
7070
}
7171

72-
err = d.open(transport)
72+
err = d.open(transport, false)
7373
if err != nil {
7474
return nil, err
7575
}
@@ -103,14 +103,14 @@ func (api *API) newDataChannel(params *DataChannelParameters, log logging.Levele
103103
}
104104

105105
// open opens the datachannel over the sctp transport
106-
func (d *DataChannel) open(sctpTransport *SCTPTransport) error {
106+
func (d *DataChannel) open(sctpTransport *SCTPTransport, restart bool) error {
107107
association := sctpTransport.association()
108108
if association == nil {
109109
return errSCTPNotEstablished
110110
}
111111

112112
d.mu.Lock()
113-
if d.sctpTransport != nil { // already open
113+
if d.sctpTransport != nil && !restart { // already open & not restarting
114114
d.mu.Unlock()
115115
return nil
116116
}
@@ -164,6 +164,11 @@ func (d *DataChannel) open(sctpTransport *SCTPTransport) error {
164164
return err
165165
}
166166

167+
// If restarting, the `Open` event should be triggered again, once.
168+
if restart {
169+
d.openHandlerOnce = sync.Once{}
170+
}
171+
167172
// bufferedAmountLowThreshold and onBufferedAmountLow might be set earlier
168173
dc.SetBufferedAmountLowThreshold(d.bufferedAmountLowThreshold)
169174
dc.OnBufferedAmountLow(d.onBufferedAmountLow)
@@ -309,11 +314,18 @@ func (d *DataChannel) readLoop() {
309314
n, isString, err := d.dataChannel.ReadDataChannel(buffer)
310315
if err != nil {
311316
rlBufPool.Put(buffer) // nolint:staticcheck
317+
318+
previousState := d.ReadyState()
312319
d.setReadyState(DataChannelStateClosed)
320+
313321
if err != io.EOF {
314322
d.onError(err)
315323
}
316-
d.onClose()
324+
325+
// https://www.w3.org/TR/webrtc/#announcing-a-data-channel-as-closed
326+
if previousState != DataChannelStateClosed {
327+
d.onClose()
328+
}
317329
return
318330
}
319331

dtlstransport.go

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,6 +213,31 @@ func (t *DTLSTransport) startSRTP() error {
213213
return fmt.Errorf("%w: %v", errDtlsKeyExtractionFailed, err)
214214
}
215215

216+
isAlreadyRunning := func() bool {
217+
select {
218+
case <-t.srtpReady:
219+
return true
220+
default:
221+
return false
222+
}
223+
}()
224+
225+
if isAlreadyRunning {
226+
if sess, ok := t.srtpSession.Load().(*srtp.SessionSRTP); ok {
227+
if updateErr := sess.UpdateContext(srtpConfig); updateErr != nil {
228+
return updateErr
229+
}
230+
}
231+
232+
if sess, ok := t.srtcpSession.Load().(*srtp.SessionSRTCP); ok {
233+
if updateErr := sess.UpdateContext(srtpConfig); updateErr != nil {
234+
return updateErr
235+
}
236+
}
237+
238+
return nil
239+
}
240+
216241
srtpSession, err := srtp.NewSessionSRTP(t.srtpEndpoint, srtpConfig)
217242
if err != nil {
218243
return fmt.Errorf("%w: %v", errFailedToStartSRTP, err)

peerconnection.go

Lines changed: 54 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1108,7 +1108,59 @@ func (pc *PeerConnection) SetRemoteDescription(desc SessionDescription) error {
11081108
pc.ops.Enqueue(func() {
11091109
pc.startRTP(true, &desc, currentTransceivers)
11101110
})
1111+
} else if pc.dtlsTransport.State() != DTLSTransportStateNew {
1112+
fingerprint, fingerprintHash, fErr := extractFingerprint(desc.parsed)
1113+
if fErr != nil {
1114+
return fErr
1115+
}
1116+
1117+
fingerPrintDidChange := true
1118+
1119+
for _, fp := range pc.dtlsTransport.remoteParameters.Fingerprints {
1120+
if fingerprint == fp.Value && fingerprintHash == fp.Algorithm {
1121+
fingerPrintDidChange = false
1122+
break
1123+
}
1124+
}
1125+
1126+
if fingerPrintDidChange {
1127+
pc.ops.Enqueue(func() {
1128+
// SCTP uses DTLS, so prevent any use, by locking, while
1129+
// DTLS is restarting.
1130+
pc.sctpTransport.lock.Lock()
1131+
defer pc.sctpTransport.lock.Unlock()
1132+
1133+
if dErr := pc.dtlsTransport.Stop(); dErr != nil {
1134+
pc.log.Warnf("Failed to stop DTLS: %s", dErr)
1135+
}
1136+
1137+
// libwebrtc switches the connection back to `new`.
1138+
pc.dtlsTransport.lock.Lock()
1139+
pc.dtlsTransport.onStateChange(DTLSTransportStateNew)
1140+
pc.dtlsTransport.lock.Unlock()
1141+
1142+
// Restart the dtls transport with updated fingerprints
1143+
err = pc.dtlsTransport.Start(DTLSParameters{
1144+
Role: dtlsRoleFromRemoteSDP(desc.parsed),
1145+
Fingerprints: []DTLSFingerprint{{Algorithm: fingerprintHash, Value: fingerprint}},
1146+
})
1147+
pc.updateConnectionState(pc.ICEConnectionState(), pc.dtlsTransport.State())
1148+
if err != nil {
1149+
pc.log.Warnf("Failed to restart DTLS: %s", err)
1150+
return
1151+
}
1152+
1153+
// If SCTP was enabled, restart it with the new DTLS transport.
1154+
if pc.sctpTransport.isStarted {
1155+
if dErr := pc.sctpTransport.restart(pc.dtlsTransport.conn); dErr != nil {
1156+
pc.log.Warnf("Failed to restart SCTP: %s", dErr)
1157+
return
1158+
}
1159+
}
1160+
})
1161+
}
11111162
}
1163+
11121164
return nil
11131165
}
11141166

@@ -1317,7 +1369,7 @@ func (pc *PeerConnection) startSCTP() {
13171369
var openedDCCount uint32
13181370
for _, d := range dataChannels {
13191371
if d.ReadyState() == DataChannelStateConnecting {
1320-
err := d.open(pc.sctpTransport)
1372+
err := d.open(pc.sctpTransport, false)
13211373
if err != nil {
13221374
pc.log.Warnf("failed to open data channel: %s", err)
13231375
continue
@@ -1775,7 +1827,7 @@ func (pc *PeerConnection) CreateDataChannel(label string, options *DataChannelIn
17751827

17761828
// If SCTP already connected open all the channels
17771829
if pc.sctpTransport.State() == SCTPTransportStateConnected {
1778-
if err = d.open(pc.sctpTransport); err != nil {
1830+
if err = d.open(pc.sctpTransport, false); err != nil {
17791831
return nil, err
17801832
}
17811833
}

0 commit comments

Comments
 (0)