diff --git a/candidate_relay.go b/candidate_relay.go index 09b92bf..f4ed5be 100644 --- a/candidate_relay.go +++ b/candidate_relay.go @@ -47,6 +47,13 @@ func (c *CandidateRelay) start(a *Agent, conn net.PacketConn) { } func (c *CandidateRelay) close() error { + c.lock.Lock() + defer c.lock.Unlock() + for _, p := range c.permissions { + if err := p.Close(); err != nil { + return err + } + } return nil } diff --git a/candidate_relay_test.go b/candidate_relay_test.go new file mode 100644 index 0000000..ba151e7 --- /dev/null +++ b/candidate_relay_test.go @@ -0,0 +1,86 @@ +package ice + +import ( + "net" + "testing" + "time" + + "github.com/pion/transport/test" + "github.com/pion/turn" +) + +type mockTURNServer struct { +} + +func (m *mockTURNServer) AuthenticateRequest(username string, srcAddr net.Addr) (password string, ok bool) { + return "password", true +} + +func TestRelayOnlyConnection(t *testing.T) { + // Limit runtime in case of deadlocks + lim := test.TimeOut(time.Second * 30) + defer lim.Stop() + + report := test.CheckRoutines(t) + defer report() + + serverPort := randomPort(t) + server := turn.Create(turn.StartArguments{ + Server: &mockTURNServer{}, + Realm: "localhost", + }) + + serverChan := make(chan error, 1) + go func() { + serverChan <- server.Listen("0.0.0.0", serverPort) + }() + + cfg := &AgentConfig{ + NetworkTypes: supportedNetworkTypes, + Urls: []*URL{ + { + Scheme: SchemeTypeTURN, + Host: "localhost", + Username: "username", + Password: "password", + Port: serverPort, + }, + }, + CandidateTypes: []CandidateType{CandidateTypeRelay}, + } + + aAgent, err := NewAgent(cfg) + if err != nil { + t.Fatal(err) + } + + aNotifier, aConnected := onConnected() + if err = aAgent.OnConnectionStateChange(aNotifier); err != nil { + t.Fatal(err) + } + + bAgent, err := NewAgent(cfg) + if err != nil { + t.Fatal(err) + } + + bNotifier, bConnected := onConnected() + if err = bAgent.OnConnectionStateChange(bNotifier); err != nil { + t.Fatal(err) + } + + connect(aAgent, bAgent) + <-aConnected + <-bConnected + + if err = aAgent.Close(); err != nil { + t.Fatal(err) + } + if err = bAgent.Close(); err != nil { + t.Fatal(err) + } + if err = server.Close(); err != nil { + t.Fatal(err) + } + <-serverChan +} diff --git a/candidate_server_reflexive_test.go b/candidate_server_reflexive_test.go new file mode 100644 index 0000000..bcfe637 --- /dev/null +++ b/candidate_server_reflexive_test.go @@ -0,0 +1,76 @@ +package ice + +import ( + "testing" + "time" + + "github.com/pion/transport/test" + "github.com/pion/turn" +) + +func TestServerReflexiveOnlyConnection(t *testing.T) { + // Limit runtime in case of deadlocks + lim := test.TimeOut(time.Second * 30) + defer lim.Stop() + + report := test.CheckRoutines(t) + defer report() + + serverPort := randomPort(t) + server := turn.Create(turn.StartArguments{ + Server: &mockTURNServer{}, + Realm: "localhost", + }) + + serverChan := make(chan error, 1) + go func() { + serverChan <- server.Listen("0.0.0.0", serverPort) + }() + + cfg := &AgentConfig{ + NetworkTypes: []NetworkType{NetworkTypeUDP4}, + Urls: []*URL{ + { + Scheme: SchemeTypeSTUN, + Host: "localhost", + Port: serverPort, + }, + }, + CandidateTypes: []CandidateType{CandidateTypeServerReflexive}, + } + + aAgent, err := NewAgent(cfg) + if err != nil { + t.Fatal(err) + } + + aNotifier, aConnected := onConnected() + if err = aAgent.OnConnectionStateChange(aNotifier); err != nil { + t.Fatal(err) + } + + bAgent, err := NewAgent(cfg) + if err != nil { + t.Fatal(err) + } + + bNotifier, bConnected := onConnected() + if err = bAgent.OnConnectionStateChange(bNotifier); err != nil { + t.Fatal(err) + } + + connect(aAgent, bAgent) + <-aConnected + <-bConnected + + if err = aAgent.Close(); err != nil { + t.Fatal(err) + } + if err = bAgent.Close(); err != nil { + t.Fatal(err) + } + if err = server.Close(); err != nil { + t.Fatal(err) + } + <-serverChan +} diff --git a/go.mod b/go.mod index 532834e..c3b3e22 100644 --- a/go.mod +++ b/go.mod @@ -6,6 +6,7 @@ require ( github.com/pion/logging v0.2.1 github.com/pion/stun v0.3.1 github.com/pion/transport v0.7.0 - github.com/pion/turnc v0.0.4 + github.com/pion/turn v1.1.3 + github.com/pion/turnc v0.0.5 github.com/stretchr/testify v1.3.0 ) diff --git a/go.sum b/go.sum index 14d4de1..a6918f6 100644 --- a/go.sum +++ b/go.sum @@ -1,15 +1,19 @@ github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/gortc/turn v0.7.1/go.mod h1:3FZ+LvCZKCKu6YYgwuYPqEi3FqCtdjfSFnFqVQNwfjk= github.com/gortc/turn v0.7.2 h1:9h0c1CG36LTYgQD54mHxETiNBxg3dNvLOCT85uhtYj4= github.com/gortc/turn v0.7.2/go.mod h1:gvguwaGAFyv5/9KrcW9MkCgHALYD+e99mSM7pSCYYho= github.com/pion/logging v0.2.1 h1:LwASkBKZ+2ysGJ+jLv1E/9H1ge0k1nTfi1X+5zirkDk= github.com/pion/logging v0.2.1/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms= +github.com/pion/stun v0.3.0/go.mod h1:xrCld6XM+6GWDZdvjPlLMsTU21rNxnO6UO8XsAvHr/M= github.com/pion/stun v0.3.1 h1:d09JJzOmOS8ZzIp8NppCMgrxGZpJ4Ix8qirfNYyI3BA= github.com/pion/stun v0.3.1/go.mod h1:xrCld6XM+6GWDZdvjPlLMsTU21rNxnO6UO8XsAvHr/M= github.com/pion/transport v0.7.0 h1:EsXN8TglHMlKZMo4ZGqwK6QgXBu0WYg7wfGMWIXsS+w= github.com/pion/transport v0.7.0/go.mod h1:iWZ07doqOosSLMhZ+FXUTq+TamDoXSllxpbGcfkCmbE= -github.com/pion/turnc v0.0.4 h1:Ce8HSxR/ThBvLzaUqgOPOq3AyTHnPDJno4/DKwRy3Qs= -github.com/pion/turnc v0.0.4/go.mod h1:PCWBabTwSi9/z5mRFPdiYOPjMpKuSK2WjzaLr2cqNsQ= +github.com/pion/turn v1.1.3 h1:3EWUqB5knWFeGjxdzuOSg28tJ288tQS0+nQOfv0u0vQ= +github.com/pion/turn v1.1.3/go.mod h1:2O2GFDGO6+hJ5gsyExDhoNHtVcacPB1NOyc81gkq0WA= +github.com/pion/turnc v0.0.5 h1:gUQJ5u69sFsBaVkGdg/koi70OSv459UOByf0QzFV00A= +github.com/pion/turnc v0.0.5/go.mod h1:PCWBabTwSi9/z5mRFPdiYOPjMpKuSK2WjzaLr2cqNsQ= github.com/pkg/errors v0.8.1 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -17,3 +21,8 @@ github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZN github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.3.0 h1:TivCn/peBQ7UY8ooIcPgZFpTNSz0Q2U6UrFlUfqbe0Q= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/net v0.0.0-20190403144856-b630fd6fe46b h1:/zjbcJPEGAyu6Is/VBOALsgdi4z9+kz/Vtdm6S+beD0= +golang.org/x/net v0.0.0-20190403144856-b630fd6fe46b/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/transport_test.go b/transport_test.go index ca5e95f..176fd0a 100644 --- a/transport_test.go +++ b/transport_test.go @@ -2,6 +2,7 @@ package ice import ( "context" + "net" "sync" "testing" "time" @@ -341,6 +342,30 @@ func copyCandidate(o Candidate) Candidate { component: orig.component, }, } + case *CandidateServerReflexive: + return &CandidateServerReflexive{ + candidateBase{ + candidateType: orig.candidateType, + networkType: orig.networkType, + ip: orig.ip, + port: orig.port, + component: orig.component, + relatedAddress: orig.relatedAddress, + }, + } + + case *CandidateRelay: + return &CandidateRelay{ + candidateBase{ + candidateType: orig.candidateType, + networkType: orig.networkType, + ip: orig.ip, + port: orig.port, + component: orig.component, + relatedAddress: orig.relatedAddress, + }, + nil, nil, + } default: return nil } @@ -354,3 +379,21 @@ func onConnected() (func(ConnectionState), chan struct{}) { } }, done } + +func randomPort(t testing.TB) int { + t.Helper() + conn, err := net.ListenPacket("udp4", "127.0.0.1:0") + if err != nil { + t.Fatalf("failed to pickPort: %v", err) + } + defer func() { + _ = conn.Close() + }() + switch addr := conn.LocalAddr().(type) { + case *net.UDPAddr: + return addr.Port + default: + t.Fatalf("unknown addr type %T", addr) + return 0 + } +}