1
Fork 0
mirror of https://github.com/jech/galene.git synced 2024-11-22 16:45:58 +01:00

Move ICE code into own module, add tests.

This commit is contained in:
Juliusz Chroboczek 2021-01-02 00:20:47 +01:00
parent 845dccc2bb
commit 450601f0e8
5 changed files with 89 additions and 21 deletions

View file

@ -13,6 +13,7 @@ import (
"github.com/jech/galene/diskwriter" "github.com/jech/galene/diskwriter"
"github.com/jech/galene/group" "github.com/jech/galene/group"
"github.com/jech/galene/ice"
"github.com/jech/galene/webserver" "github.com/jech/galene/webserver"
) )
@ -39,7 +40,7 @@ func main() {
flag.StringVar(&mutexprofile, "mutexprofile", "", flag.StringVar(&mutexprofile, "mutexprofile", "",
"store mutex profile in `file`") "store mutex profile in `file`")
flag.BoolVar(&group.UseMDNS, "mdns", false, "gather mDNS addresses") flag.BoolVar(&group.UseMDNS, "mdns", false, "gather mDNS addresses")
flag.BoolVar(&group.ICERelayOnly, "relay-only", false, flag.BoolVar(&ice.ICERelayOnly, "relay-only", false,
"require use of TURN relays for all media traffic") "require use of TURN relays for all media traffic")
flag.Parse() flag.Parse()
@ -81,7 +82,7 @@ func main() {
}() }()
} }
group.ICEFilename = filepath.Join(dataDir, "ice-servers.json") ice.ICEFilename = filepath.Join(dataDir, "ice-servers.json")
go group.ReadPublicGroups() go group.ReadPublicGroups()

View file

@ -1,4 +1,4 @@
package group package ice
import ( import (
"bytes" "bytes"
@ -16,14 +16,14 @@ import (
"github.com/pion/webrtc/v3" "github.com/pion/webrtc/v3"
) )
type ICEServer struct { type Server struct {
URLs []string `json:"urls"` URLs []string `json:"urls"`
Username string `json:"username,omitempty"` Username string `json:"username,omitempty"`
Credential interface{} `json:"credential,omitempty"` Credential interface{} `json:"credential,omitempty"`
CredentialType string `json:"credentialType,omitempty"` CredentialType string `json:"credentialType,omitempty"`
} }
func getICEServer(server ICEServer) (webrtc.ICEServer, error) { func getServer(server Server) (webrtc.ICEServer, error) {
s := webrtc.ICEServer{ s := webrtc.ICEServer{
URLs: server.URLs, URLs: server.URLs,
Username: server.Username, Username: server.Username,
@ -65,16 +65,16 @@ func getICEServer(server ICEServer) (webrtc.ICEServer, error) {
var ICEFilename string var ICEFilename string
var ICERelayOnly bool var ICERelayOnly bool
type iceConf struct { type configuration struct {
conf webrtc.Configuration conf webrtc.Configuration
timestamp time.Time timestamp time.Time
} }
var iceConfiguration atomic.Value var conf atomic.Value
func updateICEConfiguration() *iceConf { func updateICEConfiguration() *configuration {
now := time.Now() now := time.Now()
var conf webrtc.Configuration var cf webrtc.Configuration
if ICEFilename != "" { if ICEFilename != "" {
file, err := os.Open(ICEFilename) file, err := os.Open(ICEFilename)
@ -83,36 +83,36 @@ func updateICEConfiguration() *iceConf {
} else { } else {
defer file.Close() defer file.Close()
d := json.NewDecoder(file) d := json.NewDecoder(file)
var servers []ICEServer var servers []Server
err = d.Decode(&servers) err = d.Decode(&servers)
if err != nil { if err != nil {
log.Printf("Get ICE configuration: %v", err) log.Printf("Get ICE configuration: %v", err)
} }
for _, s := range servers { for _, s := range servers {
ss, err := getICEServer(s) ss, err := getServer(s)
if err != nil { if err != nil {
log.Printf("parse ICE server: %v", err) log.Printf("parse ICE server: %v", err)
continue continue
} }
conf.ICEServers = append(conf.ICEServers, ss) cf.ICEServers = append(cf.ICEServers, ss)
} }
} }
} }
if ICERelayOnly { if ICERelayOnly {
conf.ICETransportPolicy = webrtc.ICETransportPolicyRelay cf.ICETransportPolicy = webrtc.ICETransportPolicyRelay
} }
iceConf := iceConf{ iceConf := configuration{
conf: conf, conf: cf,
timestamp: now, timestamp: now,
} }
iceConfiguration.Store(&iceConf) conf.Store(&iceConf)
return &iceConf return &iceConf
} }
func ICEConfiguration() *webrtc.Configuration { func ICEConfiguration() *webrtc.Configuration {
conf, ok := iceConfiguration.Load().(*iceConf) conf, ok := conf.Load().(*configuration)
if !ok || time.Since(conf.timestamp) > 5*time.Minute { if !ok || time.Since(conf.timestamp) > 5*time.Minute {
conf = updateICEConfiguration() conf = updateICEConfiguration()
} else if time.Since(conf.timestamp) > 2*time.Minute { } else if time.Since(conf.timestamp) > 2*time.Minute {

65
ice/ice_test.go Normal file
View file

@ -0,0 +1,65 @@
package ice
import (
"bytes"
"crypto/hmac"
"crypto/sha1"
"encoding/base64"
"reflect"
"strings"
"testing"
"github.com/pion/webrtc/v3"
)
func TestPassword(t *testing.T) {
s := Server{
URLs: []string{"turn:turn.example.org"},
Username: "jch",
Credential: "secret",
}
ss := webrtc.ICEServer{
URLs: []string{"turn:turn.example.org"},
Username: "jch",
Credential: "secret",
}
sss, err := getServer(s)
if err != nil || !reflect.DeepEqual(sss, ss) {
t.Errorf("Got %v, expected %v", sss, ss)
}
}
func TestHMAC(t *testing.T) {
s := Server{
URLs: []string{"turn:turn.example.org"},
Username: "jch",
Credential: "secret",
CredentialType: "hmac-sha1",
}
ss := webrtc.ICEServer{
URLs: []string{"turn:turn.example.org"},
}
sss, err := getServer(s)
if !strings.HasSuffix(sss.Username, ":"+s.Username) {
t.Errorf("username is %v", ss.Username)
}
ss.Username = sss.Username
mac := hmac.New(sha1.New, []byte(s.Credential.(string)))
mac.Write([]byte(sss.Username))
buf := bytes.Buffer{}
e := base64.NewEncoder(base64.StdEncoding, &buf)
e.Write(mac.Sum(nil))
e.Close()
ss.Credential = string(buf.Bytes())
if err != nil || !reflect.DeepEqual(sss, ss) {
t.Errorf("Got %v, expected %v", sss, ss)
}
}

View file

@ -16,6 +16,7 @@ import (
"github.com/jech/galene/conn" "github.com/jech/galene/conn"
"github.com/jech/galene/estimator" "github.com/jech/galene/estimator"
"github.com/jech/galene/group" "github.com/jech/galene/group"
"github.com/jech/galene/ice"
"github.com/jech/galene/jitter" "github.com/jech/galene/jitter"
"github.com/jech/galene/packetcache" "github.com/jech/galene/packetcache"
"github.com/jech/galene/rtptime" "github.com/jech/galene/rtptime"
@ -138,7 +139,7 @@ type rtpDownConnection struct {
func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) { func newDownConn(c group.Client, id string, remote conn.Up) (*rtpDownConnection, error) {
api := group.APIFromCodecs(remote.Codecs()) api := group.APIFromCodecs(remote.Codecs())
pc, err := api.NewPeerConnection(*group.ICEConfiguration()) pc, err := api.NewPeerConnection(*ice.ICEConfiguration())
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -457,7 +458,7 @@ func pushConn(up *rtpUpConnection, g *group.Group, cs []group.Client) {
} }
func newUpConn(c group.Client, id string, labels map[string]string) (*rtpUpConnection, error) { func newUpConn(c group.Client, id string, labels map[string]string) (*rtpUpConnection, error) {
pc, err := c.Group().API().NewPeerConnection(*group.ICEConfiguration()) pc, err := c.Group().API().NewPeerConnection(*ice.ICEConfiguration())
if err != nil { if err != nil {
return nil, err return nil, err
} }

View file

@ -16,6 +16,7 @@ import (
"github.com/jech/galene/diskwriter" "github.com/jech/galene/diskwriter"
"github.com/jech/galene/estimator" "github.com/jech/galene/estimator"
"github.com/jech/galene/group" "github.com/jech/galene/group"
"github.com/jech/galene/ice"
) )
func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) { func errorToWSCloseMessage(id string, err error) (*clientMessage, []byte) {
@ -877,7 +878,7 @@ func clientLoop(c *webClient, ws *websocket.Conn) error {
Kind: "change", Kind: "change",
Group: g.Name(), Group: g.Name(),
Permissions: &perms, Permissions: &perms,
RTCConfiguration: group.ICEConfiguration(), RTCConfiguration: ice.ICEConfiguration(),
}) })
if !c.permissions.Present { if !c.permissions.Present {
up := getUpConns(c) up := getUpConns(c)
@ -1084,7 +1085,7 @@ func handleClientMessage(c *webClient, m clientMessage) error {
Kind: "join", Kind: "join",
Group: m.Group, Group: m.Group,
Permissions: &perms, Permissions: &perms,
RTCConfiguration: group.ICEConfiguration(), RTCConfiguration: ice.ICEConfiguration(),
}) })
if err != nil { if err != nil {
return err return err