ForceTCP only for supported clients (#997)

* ForceTCP only for supported clients

Revert back to standard if forceRelay with TLS fails
Don't force TLS unless it's configured

* fix lint
This commit is contained in:
David Zhao
2022-09-09 18:14:36 -07:00
committed by GitHub
parent 47faedc27a
commit 7e3155dcd6
7 changed files with 150 additions and 21 deletions

2
go.mod
View File

@@ -45,6 +45,7 @@ require (
github.com/urfave/negroni v1.0.0
go.uber.org/atomic v1.10.0
go.uber.org/zap v1.23.0
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3
golang.org/x/sync v0.0.0-20220819030929-7fc1605a5dde
google.golang.org/protobuf v1.28.1
gopkg.in/yaml.v3 v3.0.1
@@ -85,7 +86,6 @@ require (
github.com/xrash/smetrics v0.0.0-20201216005158-039620a65673 // indirect
go.uber.org/multierr v1.6.0 // indirect
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d // indirect
golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 // indirect
golang.org/x/net v0.0.0-20220728211354-c7608f3a8462 // indirect
golang.org/x/sys v0.0.0-20220728004956-3c1f35247d10 // indirect
golang.org/x/text v0.3.7 // indirect

View File

@@ -324,6 +324,18 @@ func (conf *Config) UseSentinel() bool {
return conf.Redis.SentinelAddresses != nil
}
func (conf *Config) IsTURNSEnabled() bool {
if conf.TURN.Enabled && conf.TURN.TLSPort != 0 {
return true
}
for _, s := range conf.RTC.TURNServers {
if s.Protocol == "tls" {
return true
}
}
return false
}
func (conf *Config) updateFromCLI(c *cli.Context) error {
if c.IsSet("dev") {
conf.Development = c.Bool("dev")

View File

@@ -1,6 +1,11 @@
package rtc
import "github.com/livekit/protocol/livekit"
import (
"strconv"
"strings"
"github.com/livekit/protocol/livekit"
)
type ClientInfo struct {
*livekit.ClientInfo
@@ -9,3 +14,45 @@ type ClientInfo struct {
func (c ClientInfo) SupportsAudioRED() bool {
return c.ClientInfo != nil && c.ClientInfo.Browser != "firefox" && c.ClientInfo.Browser != "safari"
}
// CompareVersion compares two semver versions
// returning 1 if current version is greater than version
// 0 if they are the same, and -1 if it's an earlier version
func (c ClientInfo) CompareVersion(version string) int {
if c.ClientInfo == nil {
return -1
}
parts0 := strings.Split(c.ClientInfo.Version, ".")
parts1 := strings.Split(version, ".")
ints0 := make([]int, 3)
ints1 := make([]int, 3)
for i := 0; i < 3; i++ {
if len(parts0) > i {
ints0[i], _ = strconv.Atoi(parts0[i])
}
if len(parts1) > i {
ints1[i], _ = strconv.Atoi(parts1[i])
}
if ints0[i] > ints1[i] {
return 1
} else if ints0[i] < ints1[i] {
return -1
}
}
return 0
}
func (c ClientInfo) SupportsICETCP() bool {
if c.ClientInfo == nil {
return false
}
if c.ClientInfo.Sdk == livekit.ClientInfo_GO {
return false
}
if c.ClientInfo.Sdk == livekit.ClientInfo_SWIFT {
// ICE/TCP added in 1.0.5
return c.CompareVersion("1.0.5") >= 0
}
// most SDKs support ICE/TCP
return true
}

View File

@@ -0,0 +1,59 @@
/*
* Copyright 2022 LiveKit, Inc
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package rtc
import (
"testing"
"github.com/stretchr/testify/require"
"github.com/livekit/protocol/livekit"
)
func TestClientInfo_CompareVersion(t *testing.T) {
c := ClientInfo{
ClientInfo: &livekit.ClientInfo{
Version: "1",
},
}
require.Equal(t, 1, c.CompareVersion("0.1.0"))
require.Equal(t, 0, c.CompareVersion("1.0.0"))
require.Equal(t, -1, c.CompareVersion("1.0.5"))
}
func TestClientInfo_SupportsICETCP(t *testing.T) {
t.Run("GO SDK cannot support TCP", func(t *testing.T) {
c := ClientInfo{
ClientInfo: &livekit.ClientInfo{
Sdk: livekit.ClientInfo_GO,
},
}
require.False(t, c.SupportsICETCP())
})
t.Run("Swift SDK cannot support TCP before 1.0.5", func(t *testing.T) {
c := ClientInfo{
ClientInfo: &livekit.ClientInfo{
Sdk: livekit.ClientInfo_SWIFT,
Version: "1.0.4",
},
}
require.False(t, c.SupportsICETCP())
c.Version = "1.0.5"
require.True(t, c.SupportsICETCP())
})
}

View File

@@ -84,6 +84,7 @@ type ParticipantParams struct {
Migration bool
AdaptiveStream bool
AllowTCPFallback bool
TURNSEnabled bool
}
type ParticipantImpl struct {
@@ -1107,6 +1108,7 @@ func (p *ParticipantImpl) setupTransportManager() error {
ClientInfo: p.params.ClientInfo,
Migration: p.params.Migration,
AllowTCPFallback: p.params.AllowTCPFallback,
TURNSEnabled: p.params.TURNSEnabled,
Logger: p.params.Logger,
})
if err != nil {

View File

@@ -32,6 +32,7 @@ type TransportManagerParams struct {
ClientInfo ClientInfo
Migration bool
AllowTCPFallback bool
TURNSEnabled bool
Logger logger.Logger
}
@@ -463,29 +464,36 @@ func (t *TransportManager) handleConnectionFailed(isShortLived bool) {
iceConfig := t.iceConfig
t.lock.RUnlock()
var nextConfig types.IceConfig
// irrespective of which one fails, force prefer candidate on both as the other one might
// fail at a different time and cause another disruption
switch iceConfig.PreferSub {
case types.PreferNone:
t.params.Logger.Infow("restricting transport to TCP on both peer connections")
nextConfig = types.IceConfig{
PreferPub: types.PreferTcp,
PreferSub: types.PreferTcp,
}
var preferNext types.PreferCandidateType
if iceConfig.PreferSub == types.PreferNone && t.params.ClientInfo.SupportsICETCP() {
preferNext = types.PreferTcp
} else if iceConfig.PreferSub != types.PreferTls && t.params.TURNSEnabled {
preferNext = types.PreferTls
} else {
preferNext = types.PreferNone
}
case types.PreferTcp:
t.params.Logger.Infow("prefer transport to TLS on both peer connections")
nextConfig = types.IceConfig{
PreferPub: types.PreferTls,
PreferSub: types.PreferTls,
}
default:
if preferNext == iceConfig.PreferSub {
return
}
t.SetICEConfig(nextConfig)
switch preferNext {
case types.PreferTcp:
t.params.Logger.Infow("restricting transport to TCP on both peer connections")
case types.PreferTls:
t.params.Logger.Infow("prefer transport to TLS on both peer connections")
case types.PreferNone:
t.params.Logger.Infow("allowing all transports on both peer connections")
}
// irrespective of which one fails, force prefer candidate on both as the other one might
// fail at a different time and cause another disruption
t.SetICEConfig(types.IceConfig{
PreferPub: preferNext,
PreferSub: preferNext,
})
}
func (t *TransportManager) SetMigrateInfo(previousOffer, previousAnswer *webrtc.SessionDescription, dataChannels []*livekit.DataChannelInfo) {

View File

@@ -292,6 +292,7 @@ func (r *RoomManager) StartSession(
Region: pi.Region,
AdaptiveStream: pi.AdaptiveStream,
AllowTCPFallback: allowFallback,
TURNSEnabled: r.config.IsTURNSEnabled(),
})
if err != nil {
return err