From 9c3794144e01014c64cab7ef356fa9d9f13d7922 Mon Sep 17 00:00:00 2001 From: Raja Subramanian Date: Fri, 4 Feb 2022 23:11:27 +0530 Subject: [PATCH] Force DTLS role client for the simulated client side peer connection (#403) * Force DTLE role client for the simulated client side peer connection during migration. Without that, with remote side being ice-lite (i. e. server offer is subscriber peer connection), pion chooses the server DTLS role and both side end up being servers. * pion/webrtc -> 3.1.21 * remove local reference * Use setup from previous answer * more comments --- go.mod | 6 ++--- go.sum | 10 +++++--- pkg/rtc/transport.go | 59 +++++++++++++++++++++++++++++++++++++++----- 3 files changed, 62 insertions(+), 13 deletions(-) diff --git a/go.mod b/go.mod index 524e8a0f8..6979b17d0 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/pion/stun v0.3.5 github.com/pion/transport v0.13.0 github.com/pion/turn/v2 v2.0.6 - github.com/pion/webrtc/v3 v3.1.20 + github.com/pion/webrtc/v3 v3.1.21 github.com/pkg/errors v0.9.1 github.com/prometheus/client_golang v1.11.0 github.com/rs/cors v1.8.2 @@ -73,10 +73,10 @@ require ( github.com/prometheus/procfs v0.6.0 // indirect github.com/russross/blackfriday/v2 v2.1.0 // indirect go.uber.org/multierr v1.6.0 // indirect - golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect + golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 // indirect golang.org/x/mod v0.5.1 // indirect golang.org/x/net v0.0.0-20220127200216-cd36cc0744dd // indirect - golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e // indirect + golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 // indirect golang.org/x/text v0.3.7 // indirect golang.org/x/tools v0.1.7 // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect diff --git a/go.sum b/go.sum index 6ea9a1ed1..7025e97dd 100644 --- a/go.sum +++ b/go.sum @@ -205,8 +205,8 @@ github.com/pion/turn/v2 v2.0.6 h1:AsXjSPR6Im15DMTB39NlfdTY9BQfieANPBjdg/aVNwY= github.com/pion/turn/v2 v2.0.6/go.mod h1:+y7xl719J8bAEVpSXBXvTxStjJv3hbz9YFflvkpcGPw= github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o= github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M= -github.com/pion/webrtc/v3 v3.1.20 h1:rOTH68dp/K4MXh4d+9NQFzzKJXAoMy874zFglSUwB+8= -github.com/pion/webrtc/v3 v3.1.20/go.mod h1:dIT2ETlP5dnlkgp46fAH56UizvOKuXJ9ySgFkhtmBbw= +github.com/pion/webrtc/v3 v3.1.21 h1:6b/65m5hSw2mF+sssHBx7Q2WPccklA0U0veEYtqZSuM= +github.com/pion/webrtc/v3 v3.1.21/go.mod h1:dIT2ETlP5dnlkgp46fAH56UizvOKuXJ9ySgFkhtmBbw= github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= @@ -286,8 +286,9 @@ golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACk golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20210314154223-e6e6c4f2bb5b/go.mod h1:T9bdIzuCu7OtxOm1hfPfRQxPLYneinmdGuTeoZ9dtd4= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838 h1:71vQrMauZZhcTVK6KdYM+rklehEEwb3E+ZhaE5jrPrE= +golang.org/x/crypto v0.0.0-20220131195533-30dcbda58838/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= @@ -359,8 +360,9 @@ golang.org/x/sys v0.0.0-20210510120138-977fb7262007/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210603081109-ebe580a85c40/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e h1:fLOSk5Q00efkSvAm+4xcoXD+RRmLmmulPn5I3Y9F2EM= golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27 h1:XDXtA5hveEEV8JB2l7nhMTp3t3cHp9ZpwcdjqyEWLlo= +golang.org/x/sys v0.0.0-20220128215802-99c3d69c2c27/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/pkg/rtc/transport.go b/pkg/rtc/transport.go index a2db9675d..4ed4eb4ea 100644 --- a/pkg/rtc/transport.go +++ b/pkg/rtc/transport.go @@ -392,7 +392,20 @@ func (t *PCTransport) preparePC(previousAnswer webrtc.SessionDescription) error } t.pc.SetLocalDescription(offer) - pc2, err := webrtc.NewPeerConnection(webrtc.Configuration{}) + // + // Simulcate client side peer connection and set DTLS role from previous answer. + // Role needs to be set properly (one side needs to be server and the other side + // eeds to be the client) for DTLS connection to form properly. As this is + // trying to replicate previous setup, read from previous answer and use that role. + // + se := webrtc.SettingEngine{} + se.SetAnsweringDTLSRole(extractDTLSRole(parsed)) + api := webrtc.NewAPI( + webrtc.WithSettingEngine(se), + ) + pc2, err := api.NewPeerConnection(webrtc.Configuration{ + SDPSemantics: webrtc.SDPSemanticsUnifiedPlan, + }) if err != nil { return err } @@ -432,12 +445,12 @@ func (t *PCTransport) preparePC(previousAnswer webrtc.SessionDescription) error return t.pc.SetRemoteDescription(ans) } -func (t *PCTransport) initPCWithPreviousAnswer(previousOffer webrtc.SessionDescription) error { - if err := t.preparePC(previousOffer); err != nil { +func (t *PCTransport) initPCWithPreviousAnswer(previousAnswer webrtc.SessionDescription) error { + if err := t.preparePC(previousAnswer); err != nil { return err } - parsed, err := previousOffer.Unmarshal() + parsed, err := previousAnswer.Unmarshal() if err != nil { return err } @@ -492,11 +505,11 @@ func (t *PCTransport) RemoveTrack(subTrack types.SubscribedTrack) { t.streamAllocator.RemoveTrack(subTrack.DownTrack()) } -func (t *PCTransport) SetPreviousAnswer(offer *webrtc.SessionDescription) { +func (t *PCTransport) SetPreviousAnswer(answer *webrtc.SessionDescription) { t.lock.Lock() defer t.lock.Unlock() if t.pc.RemoteDescription() == nil && t.previousAnswer == nil { - t.previousAnswer = offer + t.previousAnswer = answer t.initPCWithPreviousAnswer(*t.previousAnswer) } } @@ -539,3 +552,37 @@ func extractFingerprint(desc *sdp.SessionDescription) (string, string, error) { } return parts[1], parts[0], nil } + +func extractDTLSRole(desc *sdp.SessionDescription) webrtc.DTLSRole { + for _, md := range desc.MediaDescriptions { + setup, ok := md.Attribute(sdp.AttrKeyConnectionSetup) + if !ok { + continue + } + + if setup == sdp.ConnectionRoleActive.String() { + return webrtc.DTLSRoleClient + } + + if setup == sdp.ConnectionRolePassive.String() { + return webrtc.DTLSRoleServer + } + } + + // + // If 'setup' attribute is not available, use client role + // as that is the default behaviour of answerers + // + // There seems to be some differences in how role is decided. + // libwebrtc (Chrome) code - (https://source.chromium.org/chromium/chromium/src/+/main:third_party/webrtc/pc/jsep_transport.cc;l=592;drc=369fb686729e7eb20d2bd09717cec14269a399d7) + // does not mention anything about ICE role when determining + // DTLS Role. + // + // But, ORTC has this - https://github.com/w3c/ortc/issues/167#issuecomment-69409953 + // and pion/webrtc follows that (https://github.com/pion/webrtc/blob/e071a4eded1efd5d9b401bcfc4efacb3a2a5a53c/dtlstransport.go#L269) + // + // So if remote is ice-lite, pion will use DTLSRoleServer when answering + // while browsers pick DTLSRoleClient. + // + return webrtc.DTLSRoleClient +}