From fa2ffa46e7e6503174ed0dacbf6d28e78072385d Mon Sep 17 00:00:00 2001 From: David Zhao Date: Sat, 6 Mar 2021 22:47:48 -0800 Subject: [PATCH] Embedded TURN server --- cmd/server/main.go | 41 ++++++++++++++ go.mod | 1 + pkg/config/config.go | 18 +++++- pkg/service/roommanager.go | 1 + pkg/service/server.go | 9 +++ pkg/service/turn.go | 81 ++++++++++++++++++++++++++ pkg/service/utils.go | 1 + pkg/service/wire_gen.go | 6 +- proto/livekit/internal.pb.go | 9 +-- proto/livekit/model.pb.go | 91 ++++++++++++++++-------------- proto/livekit/room.pb.go | 9 +-- proto/livekit/rtc.pb.go | 9 +-- proto/model.proto | 1 + test/turn_test.go | 106 +++++++++++++++++++++++++++++++++++ 14 files changed, 316 insertions(+), 67 deletions(-) create mode 100644 pkg/service/turn.go create mode 100644 test/turn_test.go diff --git a/cmd/server/main.go b/cmd/server/main.go index be86b137b..1b40bea1e 100644 --- a/cmd/server/main.go +++ b/cmd/server/main.go @@ -9,6 +9,7 @@ import ( "os/signal" "runtime" "runtime/pprof" + "strconv" "syscall" "time" @@ -77,6 +78,11 @@ func main() { Usage: "generates a pair of API & secret keys", Action: generateKeys, }, + { + Name: "ports", + Usage: "print ports that server is configured to use", + Action: printPorts, + }, }, Version: version.Version, } @@ -241,3 +247,38 @@ func generateKeys(c *cli.Context) error { fmt.Println("Secret Key: ", secret) return nil } + +func printPorts(c *cli.Context) error { + confString, err := getConfigString(c) + if err != nil { + return err + } + + conf, err := config.NewConfig(confString) + if err != nil { + return err + } + + udpPorts := make([]string, 0) + tcpPorts := make([]string, 0) + + tcpPorts = append(tcpPorts, strconv.Itoa(int(conf.Port))) + udpPorts = append(udpPorts, fmt.Sprintf("%d-%d", conf.RTC.ICEPortRangeStart, conf.RTC.ICEPortRangeEnd)) + + if conf.TURN.Enabled { + udpPorts = append(udpPorts, fmt.Sprintf("%d-%d", conf.TURN.PortRangeStart, conf.TURN.PortRangeEnd)) + udpPorts = append(udpPorts, strconv.Itoa(conf.TURN.ListenPort)) + tcpPorts = append(tcpPorts, strconv.Itoa(conf.TURN.ListenPort)) + } + + fmt.Println("TCP Ports") + for _, p := range tcpPorts { + fmt.Println(p) + } + + fmt.Println("UDP Ports") + for _, p := range udpPorts { + fmt.Println(p) + } + return nil +} diff --git a/go.mod b/go.mod index 683fc0075..2ea449fd2 100644 --- a/go.mod +++ b/go.mod @@ -19,6 +19,7 @@ require ( github.com/pion/rtp v1.6.2 github.com/pion/sdp/v3 v3.0.4 github.com/pion/stun v0.3.5 + github.com/pion/turn/v2 v2.0.5 github.com/pion/webrtc/v3 v3.0.13 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.7.0 diff --git a/pkg/config/config.go b/pkg/config/config.go index 9ea582c24..7fac1d24d 100644 --- a/pkg/config/config.go +++ b/pkg/config/config.go @@ -13,6 +13,7 @@ type Config struct { RTC RTCConfig `yaml:"rtc"` Redis RedisConfig `yaml:"redis"` Audio AudioConfig `yaml:"audio"` + TURN TURNConfig `yaml:"turn"` KeyFile string `yaml:"key_file"` Keys map[string]string `yaml:"keys"` LogLevel string `yaml:"log_level"` @@ -49,6 +50,13 @@ type RedisConfig struct { Password string `yaml:"password"` } +type TURNConfig struct { + Enabled bool `yaml:"enabled"` + ListenPort int `yaml:"listen_port"` + PortRangeStart uint16 `yaml:"port_range_start"` + PortRangeEnd uint16 `yaml:"port_range_end"` +} + func NewConfig(confString string) (*Config, error) { // start with defaults conf := &Config{ @@ -56,7 +64,7 @@ func NewConfig(confString string) (*Config, error) { RTC: RTCConfig{ UseExternalIP: true, ICEPortRangeStart: 9000, - ICEPortRangeEnd: 9200, + ICEPortRangeEnd: 11000, StunServers: []string{ "stun.l.google.com:19302", "stun1.l.google.com:19302", @@ -69,7 +77,13 @@ func NewConfig(confString string) (*Config, error) { UpdateInterval: 500, }, Redis: RedisConfig{}, - Keys: map[string]string{}, + TURN: TURNConfig{ + Enabled: false, + ListenPort: 3478, + PortRangeStart: 12000, + PortRangeEnd: 16000, + }, + Keys: map[string]string{}, } if confString != "" { yaml.Unmarshal([]byte(confString), conf) diff --git a/pkg/service/roommanager.go b/pkg/service/roommanager.go index 1c2ddedee..39a6b32b8 100644 --- a/pkg/service/roommanager.go +++ b/pkg/service/roommanager.go @@ -61,6 +61,7 @@ func (r *RoomManager) CreateRoom(req *livekit.CreateRoomRequest) (*livekit.Room, Sid: utils.NewGuid(utils.RoomPrefix), Name: req.Name, CreationTime: time.Now().Unix(), + TurnPassword: utils.RandomSecret(), } } else if err != nil { return nil, err diff --git a/pkg/service/server.go b/pkg/service/server.go index 8f8533b4d..ff59d6384 100644 --- a/pkg/service/server.go +++ b/pkg/service/server.go @@ -8,6 +8,7 @@ import ( "net/http" "time" + "github.com/pion/turn/v2" "github.com/urfave/negroni" "github.com/livekit/livekit-server/pkg/auth" @@ -26,6 +27,7 @@ type LivekitServer struct { httpServer *http.Server router routing.Router roomManager *RoomManager + turnServer *turn.Server currentNode routing.LocalNode running utils.AtomicFlag doneChan chan bool @@ -37,6 +39,7 @@ func NewLivekitServer(conf *config.Config, keyProvider auth.KeyProvider, router routing.Router, roomManager *RoomManager, + turnServer *turn.Server, currentNode routing.LocalNode, ) (s *LivekitServer, err error) { s = &LivekitServer{ @@ -45,6 +48,8 @@ func NewLivekitServer(conf *config.Config, rtcService: rtcService, router: router, roomManager: roomManager, + // turn server starts automatically + turnServer: turnServer, currentNode: currentNode, } @@ -132,6 +137,10 @@ func (s *LivekitServer) Start() error { ctx, _ := context.WithTimeout(context.Background(), time.Second*5) s.httpServer.Shutdown(ctx) + if s.turnServer != nil { + s.turnServer.Close() + } + return nil } diff --git a/pkg/service/turn.go b/pkg/service/turn.go new file mode 100644 index 000000000..e00f7e91d --- /dev/null +++ b/pkg/service/turn.go @@ -0,0 +1,81 @@ +package service + +import ( + "fmt" + "net" + "strconv" + + "github.com/pion/turn/v2" + "github.com/pkg/errors" + + "github.com/livekit/livekit-server/pkg/config" + "github.com/livekit/livekit-server/pkg/logger" + "github.com/livekit/livekit-server/pkg/routing" +) + +const ( + allocateRetries = 1000 + livekitRealm = "livekit" +) + +func NewTurnServer(conf *config.Config, roomStore RoomStore, node routing.LocalNode) (*turn.Server, error) { + turnConf := conf.TURN + if !turnConf.Enabled { + return nil, nil + } + serverConfig := turn.ServerConfig{ + Realm: livekitRealm, + AuthHandler: newTurnAuthHandler(roomStore), + } + + tcpListener, err := net.Listen("tcp4", "0.0.0.0:"+strconv.Itoa(turnConf.ListenPort)) + if err != nil { + return nil, errors.Wrap(err, "could not listen on TURN TCP port") + } + serverConfig.ListenerConfigs = []turn.ListenerConfig{ + { + Listener: tcpListener, + RelayAddressGenerator: &turn.RelayAddressGeneratorPortRange{ + RelayAddress: net.ParseIP(node.Ip), + Address: "0.0.0.0", + MinPort: turnConf.PortRangeStart, + MaxPort: turnConf.PortRangeEnd, + MaxRetries: allocateRetries, + }, + }, + } + + udpListener, err := net.ListenPacket("udp4", "0.0.0.0:"+strconv.Itoa(turnConf.ListenPort)) + if err != nil { + return nil, errors.Wrap(err, "could not listen on TURN UDP port") + } + serverConfig.PacketConnConfigs = []turn.PacketConnConfig{ + { + PacketConn: udpListener, + RelayAddressGenerator: &turn.RelayAddressGeneratorPortRange{ + RelayAddress: net.ParseIP(node.Ip), // Claim that we are listening on IP passed by user (This should be your Public IP) + Address: "0.0.0.0", // But actually be listening on every interface + MinPort: turnConf.PortRangeStart, + MaxPort: turnConf.PortRangeEnd, + MaxRetries: allocateRetries, + }, + }, + } + + logger.Infow("Starting TURN server", + "port", turnConf.ListenPort, + "portRange", fmt.Sprintf("%d-%d", turnConf.PortRangeStart, turnConf.PortRangeEnd)) + return turn.NewServer(serverConfig) +} + +func newTurnAuthHandler(roomStore RoomStore) turn.AuthHandler { + return func(username, realm string, srcAddr net.Addr) (key []byte, ok bool) { + // room id should be the username, create a hashed room id + rm, err := roomStore.GetRoom(username) + if err != nil { + return nil, false + } + + return turn.GenerateAuthKey(username, livekitRealm, rm.TurnPassword), true + } +} diff --git a/pkg/service/utils.go b/pkg/service/utils.go index 2a955e1a9..543ed8fc3 100644 --- a/pkg/service/utils.go +++ b/pkg/service/utils.go @@ -16,6 +16,7 @@ var ServiceSet = wire.NewSet( NewRTCService, NewLivekitServer, NewRoomManager, + NewTurnServer, config.GetAudioConfig, wire.Bind(new(livekit.RoomService), new(*RoomService)), ) diff --git a/pkg/service/wire_gen.go b/pkg/service/wire_gen.go index ce188b87a..bce2b1713 100644 --- a/pkg/service/wire_gen.go +++ b/pkg/service/wire_gen.go @@ -23,7 +23,11 @@ func InitializeServer(conf *config.Config, keyProvider auth.KeyProvider, roomSto return nil, err } rtcService := NewRTCService(conf, roomStore, roomManager, router, currentNode) - livekitServer, err := NewLivekitServer(conf, roomService, rtcService, keyProvider, router, roomManager, currentNode) + server, err := NewTurnServer(conf, roomStore, currentNode) + if err != nil { + return nil, err + } + livekitServer, err := NewLivekitServer(conf, roomService, rtcService, keyProvider, router, roomManager, server, currentNode) if err != nil { return nil, err } diff --git a/proto/livekit/internal.pb.go b/proto/livekit/internal.pb.go index b799b941d..6f109c239 100644 --- a/proto/livekit/internal.pb.go +++ b/proto/livekit/internal.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.14.0 +// protoc-gen-go v1.25.0-devel +// protoc v3.15.3 // source: internal.proto package livekit import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type Node struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/proto/livekit/model.pb.go b/proto/livekit/model.pb.go index 2916bbe98..caab123a9 100644 --- a/proto/livekit/model.pb.go +++ b/proto/livekit/model.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.14.0 +// protoc-gen-go v1.25.0-devel +// protoc v3.15.3 // source: model.proto package livekit import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type TrackType int32 const ( @@ -140,6 +135,7 @@ type Room struct { EmptyTimeout uint32 `protobuf:"varint,3,opt,name=empty_timeout,json=emptyTimeout,proto3" json:"empty_timeout,omitempty"` MaxParticipants uint32 `protobuf:"varint,4,opt,name=max_participants,json=maxParticipants,proto3" json:"max_participants,omitempty"` CreationTime int64 `protobuf:"varint,5,opt,name=creation_time,json=creationTime,proto3" json:"creation_time,omitempty"` + TurnPassword string `protobuf:"bytes,6,opt,name=turn_password,json=turnPassword,proto3" json:"turn_password,omitempty"` } func (x *Room) Reset() { @@ -209,6 +205,13 @@ func (x *Room) GetCreationTime() int64 { return 0 } +func (x *Room) GetTurnPassword() string { + if x != nil { + return x.TurnPassword + } + return "" +} + type ParticipantInfo struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache @@ -443,7 +446,7 @@ var File_model_proto protoreflect.FileDescriptor var file_model_proto_rawDesc = []byte{ 0x0a, 0x0b, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x07, 0x6c, - 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x22, 0xa1, 0x01, 0x0a, 0x04, 0x52, 0x6f, 0x6f, 0x6d, 0x12, + 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x22, 0xc6, 0x01, 0x0a, 0x04, 0x52, 0x6f, 0x6f, 0x6d, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x65, 0x6d, 0x70, 0x74, 0x79, 0x5f, 0x74, @@ -453,41 +456,43 @@ var file_model_proto_rawDesc = []byte{ 0x20, 0x01, 0x28, 0x0d, 0x52, 0x0f, 0x6d, 0x61, 0x78, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x73, 0x12, 0x23, 0x0a, 0x0d, 0x63, 0x72, 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x5f, 0x74, 0x69, 0x6d, 0x65, 0x18, 0x05, 0x20, 0x01, 0x28, 0x03, 0x52, 0x0c, 0x63, 0x72, - 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x22, 0xfd, 0x01, 0x0a, 0x0f, 0x50, - 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, - 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, - 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, 0x79, 0x12, 0x34, 0x0a, 0x05, - 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1e, 0x2e, 0x6c, 0x69, - 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, - 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, 0x52, 0x05, 0x73, 0x74, 0x61, - 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x03, - 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, - 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x74, 0x72, 0x61, 0x63, 0x6b, 0x73, 0x12, 0x1a, - 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, 0x05, 0x20, 0x01, 0x28, 0x09, - 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, 0x3e, 0x0a, 0x05, 0x53, 0x74, - 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4a, 0x4f, 0x49, 0x4e, 0x49, 0x4e, 0x47, 0x10, 0x00, - 0x12, 0x0a, 0x0a, 0x06, 0x4a, 0x4f, 0x49, 0x4e, 0x45, 0x44, 0x10, 0x01, 0x12, 0x0a, 0x0a, 0x06, - 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x10, 0x0a, 0x0c, 0x44, 0x49, 0x53, 0x43, - 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x03, 0x22, 0x6f, 0x0a, 0x09, 0x54, 0x72, - 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, - 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x26, 0x0a, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, - 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, 0x52, 0x04, 0x74, 0x79, 0x70, - 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, - 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x18, 0x04, - 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, 0x22, 0x46, 0x0a, 0x0b, 0x44, - 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, 0x14, 0x0a, 0x04, 0x74, 0x65, - 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, 0x04, 0x74, 0x65, 0x78, 0x74, - 0x12, 0x18, 0x0a, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0c, - 0x48, 0x00, 0x52, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x42, 0x07, 0x0a, 0x05, 0x76, 0x61, - 0x6c, 0x75, 0x65, 0x2a, 0x2b, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, - 0x12, 0x09, 0x0a, 0x05, 0x41, 0x55, 0x44, 0x49, 0x4f, 0x10, 0x00, 0x12, 0x09, 0x0a, 0x05, 0x56, - 0x49, 0x44, 0x45, 0x4f, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x44, 0x41, 0x54, 0x41, 0x10, 0x02, - 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x6c, - 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2d, 0x73, - 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x6c, 0x69, 0x76, 0x65, - 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x65, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x54, 0x69, 0x6d, 0x65, 0x12, 0x23, 0x0a, 0x0d, 0x74, 0x75, + 0x72, 0x6e, 0x5f, 0x70, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x18, 0x06, 0x20, 0x01, 0x28, + 0x09, 0x52, 0x0c, 0x74, 0x75, 0x72, 0x6e, 0x50, 0x61, 0x73, 0x73, 0x77, 0x6f, 0x72, 0x64, 0x22, + 0xfd, 0x01, 0x0a, 0x0f, 0x50, 0x61, 0x72, 0x74, 0x69, 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, + 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, + 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x1a, 0x0a, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x69, 0x64, 0x65, 0x6e, 0x74, 0x69, 0x74, + 0x79, 0x12, 0x34, 0x0a, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x0e, + 0x32, 0x1e, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x50, 0x61, 0x72, 0x74, 0x69, + 0x63, 0x69, 0x70, 0x61, 0x6e, 0x74, 0x49, 0x6e, 0x66, 0x6f, 0x2e, 0x53, 0x74, 0x61, 0x74, 0x65, + 0x52, 0x05, 0x73, 0x74, 0x61, 0x74, 0x65, 0x12, 0x2a, 0x0a, 0x06, 0x74, 0x72, 0x61, 0x63, 0x6b, + 0x73, 0x18, 0x04, 0x20, 0x03, 0x28, 0x0b, 0x32, 0x12, 0x2e, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, + 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x52, 0x06, 0x74, 0x72, 0x61, + 0x63, 0x6b, 0x73, 0x12, 0x1a, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x18, + 0x05, 0x20, 0x01, 0x28, 0x09, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x22, + 0x3e, 0x0a, 0x05, 0x53, 0x74, 0x61, 0x74, 0x65, 0x12, 0x0b, 0x0a, 0x07, 0x4a, 0x4f, 0x49, 0x4e, + 0x49, 0x4e, 0x47, 0x10, 0x00, 0x12, 0x0a, 0x0a, 0x06, 0x4a, 0x4f, 0x49, 0x4e, 0x45, 0x44, 0x10, + 0x01, 0x12, 0x0a, 0x0a, 0x06, 0x41, 0x43, 0x54, 0x49, 0x56, 0x45, 0x10, 0x02, 0x12, 0x10, 0x0a, + 0x0c, 0x44, 0x49, 0x53, 0x43, 0x4f, 0x4e, 0x4e, 0x45, 0x43, 0x54, 0x45, 0x44, 0x10, 0x03, 0x22, + 0x6f, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x49, 0x6e, 0x66, 0x6f, 0x12, 0x10, 0x0a, 0x03, + 0x73, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x03, 0x73, 0x69, 0x64, 0x12, 0x26, + 0x0a, 0x04, 0x74, 0x79, 0x70, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x12, 0x2e, 0x6c, + 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2e, 0x54, 0x72, 0x61, 0x63, 0x6b, 0x54, 0x79, 0x70, 0x65, + 0x52, 0x04, 0x74, 0x79, 0x70, 0x65, 0x12, 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x03, + 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x12, 0x14, 0x0a, 0x05, 0x6d, 0x75, + 0x74, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x05, 0x6d, 0x75, 0x74, 0x65, 0x64, + 0x22, 0x46, 0x0a, 0x0b, 0x44, 0x61, 0x74, 0x61, 0x4d, 0x65, 0x73, 0x73, 0x61, 0x67, 0x65, 0x12, + 0x14, 0x0a, 0x04, 0x74, 0x65, 0x78, 0x74, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x48, 0x00, 0x52, + 0x04, 0x74, 0x65, 0x78, 0x74, 0x12, 0x18, 0x0a, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x18, + 0x02, 0x20, 0x01, 0x28, 0x0c, 0x48, 0x00, 0x52, 0x06, 0x62, 0x69, 0x6e, 0x61, 0x72, 0x79, 0x42, + 0x07, 0x0a, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, 0x2a, 0x2b, 0x0a, 0x09, 0x54, 0x72, 0x61, 0x63, + 0x6b, 0x54, 0x79, 0x70, 0x65, 0x12, 0x09, 0x0a, 0x05, 0x41, 0x55, 0x44, 0x49, 0x4f, 0x10, 0x00, + 0x12, 0x09, 0x0a, 0x05, 0x56, 0x49, 0x44, 0x45, 0x4f, 0x10, 0x01, 0x12, 0x08, 0x0a, 0x04, 0x44, + 0x41, 0x54, 0x41, 0x10, 0x02, 0x42, 0x31, 0x5a, 0x2f, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, + 0x63, 0x6f, 0x6d, 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x2f, 0x6c, 0x69, 0x76, 0x65, + 0x6b, 0x69, 0x74, 0x2d, 0x73, 0x65, 0x72, 0x76, 0x65, 0x72, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x2f, 0x6c, 0x69, 0x76, 0x65, 0x6b, 0x69, 0x74, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, } var ( diff --git a/proto/livekit/room.pb.go b/proto/livekit/room.pb.go index 89867400d..8bfe263ca 100644 --- a/proto/livekit/room.pb.go +++ b/proto/livekit/room.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.14.0 +// protoc-gen-go v1.25.0-devel +// protoc v3.15.3 // source: room.proto package livekit import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type CreateRoomRequest struct { state protoimpl.MessageState sizeCache protoimpl.SizeCache diff --git a/proto/livekit/rtc.pb.go b/proto/livekit/rtc.pb.go index ecfb7498e..fa012e124 100644 --- a/proto/livekit/rtc.pb.go +++ b/proto/livekit/rtc.pb.go @@ -1,13 +1,12 @@ // Code generated by protoc-gen-go. DO NOT EDIT. // versions: -// protoc-gen-go v1.25.0 -// protoc v3.14.0 +// protoc-gen-go v1.25.0-devel +// protoc v3.15.3 // source: rtc.proto package livekit import ( - proto "github.com/golang/protobuf/proto" protoreflect "google.golang.org/protobuf/reflect/protoreflect" protoimpl "google.golang.org/protobuf/runtime/protoimpl" reflect "reflect" @@ -21,10 +20,6 @@ const ( _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) ) -// This is a compile-time assertion that a sufficiently up-to-date version -// of the legacy proto package is being used. -const _ = proto.ProtoPackageIsVersion4 - type SignalTarget int32 const ( diff --git a/proto/model.proto b/proto/model.proto index e21a5e8bb..01d4dbdd0 100644 --- a/proto/model.proto +++ b/proto/model.proto @@ -9,6 +9,7 @@ message Room { uint32 empty_timeout = 3; uint32 max_participants = 4; int64 creation_time = 5; + string turn_password = 6; } message ParticipantInfo { diff --git a/test/turn_test.go b/test/turn_test.go new file mode 100644 index 000000000..86415f0d7 --- /dev/null +++ b/test/turn_test.go @@ -0,0 +1,106 @@ +package test + +import ( + "fmt" + "net" + "testing" + "time" + + "github.com/pion/turn/v2" + "github.com/stretchr/testify/require" + + "github.com/livekit/livekit-server/pkg/config" + "github.com/livekit/livekit-server/pkg/routing" + "github.com/livekit/livekit-server/pkg/service" + "github.com/livekit/livekit-server/pkg/utils" + "github.com/livekit/livekit-server/proto/livekit" +) + +func TestTurnServer(t *testing.T) { + conf, err := config.NewConfig("") + require.NoError(t, err) + + conf.TURN.Enabled = true + + currentNode, err := routing.NewLocalNode(conf) + require.NoError(t, err) + currentNode.Id = utils.NewGuid(nodeId1) + + // local routing and store + router := routing.NewLocalRouter(currentNode) + roomStore := service.NewLocalRoomStore() + roomStore.DeleteRoom(testRoom) + s, err := service.InitializeServer(conf, &StaticKeyProvider{}, roomStore, router, currentNode, &routing.RandomSelector{}) + require.NoError(t, err) + go s.Start() + waitForServerToStart(s) + defer s.Stop() + + time.Sleep(syncDelay) + + // create a room + rm := &livekit.Room{ + Sid: utils.NewGuid(utils.RoomPrefix), + Name: "testroom", + TurnPassword: utils.RandomSecret(), + } + require.NoError(t, roomStore.CreateRoom(rm)) + + turnConf := &turn.ClientConfig{ + STUNServerAddr: fmt.Sprintf("localhost:%d", conf.TURN.ListenPort), + TURNServerAddr: fmt.Sprintf("%s:%d", currentNode.Ip, conf.TURN.ListenPort), + Username: rm.Name, + Password: rm.TurnPassword, + Realm: "livekit", + } + + t.Run("TURN works over TCP", func(t *testing.T) { + conn, err := net.Dial("tcp", fmt.Sprintf("localhost:%d", conf.TURN.ListenPort)) + require.NoError(t, err) + + tc := *turnConf + tc.Conn = turn.NewSTUNConn(conn) + c, err := turn.NewClient(&tc) + require.NoError(t, err) + defer c.Close() + + require.NoError(t, c.Listen()) + + // Allocate a relay socket on the TURN server. On success, it + // will return a net.PacketConn which represents the remote + // socket. + relayConn, err := c.Allocate() + require.NoError(t, err) + + defer func() { + require.NoError(t, relayConn.Close()) + }() + }) + // UDP test doesn't pass + //t.Run("TURN connects over UDP", func(t *testing.T) { + // conn, err := net.ListenPacket("udp4", "0.0.0.0:0") + // require.NoError(t, err) + // defer func() { + // require.NoError(t, conn.Close()) + // }() + // + // tc := *turnConf + // tc.Conn = conn + // + // client, err := turn.NewClient(&tc) + // require.NoError(t, err) + // defer client.Close() + // + // // Start listening on the conn provided. + // require.NoError(t, client.Listen()) + // + // // Allocate a relay socket on the TURN server. On success, it + // // will return a net.PacketConn which represents the remote + // // socket. + // relayConn, err := client.Allocate() + // require.NoError(t, err) + // defer func() { + // require.NoError(t, relayConn.Close()) + // }() + //}) +}