Skip to content

Commit

Permalink
TURN client refactor
Browse files Browse the repository at this point in the history
Refresh and ChannelBind are not implemented yet
Resolves #74
  • Loading branch information
enobufs committed Jul 11, 2019
1 parent 3bc0fff commit c3e0edb
Show file tree
Hide file tree
Showing 15 changed files with 1,151 additions and 137 deletions.
470 changes: 432 additions & 38 deletions client.go

Large diffs are not rendered by default.

133 changes: 103 additions & 30 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,40 +3,102 @@ package turn
import (
"net"
"testing"
"time"

"github.com/pion/logging"
"github.com/pion/stun"
"github.com/stretchr/testify/assert"
)

func TestClient(t *testing.T) {
func createListeningTestClient(t *testing.T, loggerFactory logging.LoggerFactory) (*Client, bool) {
conn, err := net.ListenPacket("udp4", "0.0.0.0:0")
if !assert.NoError(t, err, "should succeed") {
return nil, false
}
c, err := NewClient(&ClientConfig{
Conn: conn,
LoggerFactory: loggerFactory,
})
if !assert.NoError(t, err, "should succeed") {
return nil, false
}
err = c.Listen()
if !assert.NoError(t, err, "should succeed") {
return nil, false
}

return c, true
}

func createListeningTestClientWithSTUNServ(t *testing.T, loggerFactory logging.LoggerFactory) (*Client, bool) {
conn, err := net.ListenPacket("udp4", "0.0.0.0:0")
if !assert.NoError(t, err, "should succeed") {
return nil, false
}
c, err := NewClient(&ClientConfig{
STUNServerAddr: "stun1.l.google.com:19302",
Conn: conn,

LoggerFactory: loggerFactory,
})
if !assert.NoError(t, err, "should succeed") {
return nil, false
}
err = c.Listen()
if !assert.NoError(t, err, "should succeed") {
return nil, false
}

return c, true
}

func TestClientWithSTUN(t *testing.T) {
loggerFactory := logging.NewDefaultLoggerFactory()
log := loggerFactory.NewLogger("test")

t.Run("SendSTUNRequest Parallel", func(t *testing.T) {
c, err := NewClient(&ClientConfig{
ListeningAddress: "0.0.0.0:0",
LoggerFactory: loggerFactory,
})
if err != nil {
t.Fatal(err)
t.Run("SendBindingRequest", func(t *testing.T) {
c, ok := createListeningTestClientWithSTUNServ(t, loggerFactory)
if !ok {
return
}
defer c.Close()

resp, err := c.SendBindingRequest()
assert.NoError(t, err, "should succeed")
log.Debugf("mapped-addr: %s", resp.String())
assert.Equal(t, 0, len(c.trMap), "should be no transaction left")
})

t.Run("SendBindingRequestTo Parallel", func(t *testing.T) {
c, ok := createListeningTestClient(t, loggerFactory)
if !ok {
return
}
defer c.Close()

// simple channel fo go routine start signaling
started := make(chan struct{})
finished := make(chan struct{})
var err1 error
var resp1 interface{}

to, err := net.ResolveUDPAddr("udp4", "stun1.l.google.com:19302")
if !assert.NoError(t, err, "should succeed") {
return
}

// stun1.l.google.com:19302, more at https://gist.github.com/zziuni/3741933#file-stuns-L5
go func() {
close(started)
resp1, err1 = c.SendSTUNRequest(net.IPv4(74, 125, 143, 127), 19302)
resp1, err1 = c.SendBindingRequestTo(to)
close(finished)
}()

// block until go routine is started to make two almost parallel requests

<-started

resp2, err2 := c.SendSTUNRequest(net.IPv4(74, 125, 143, 127), 19302)
resp2, err2 := c.SendBindingRequestTo(to)
if err2 != nil {
t.Fatal(err)
} else {
Expand All @@ -51,27 +113,38 @@ func TestClient(t *testing.T) {
}
})

t.Run("Listen error", func(t *testing.T) {
_, err := NewClient(&ClientConfig{
ListeningAddress: "255.255.255.256:65535",
LoggerFactory: loggerFactory,
t.Run("Listen error with nil conn", func(t *testing.T) {
c, err := NewClient(&ClientConfig{
LoggerFactory: loggerFactory,
})
if err == nil {
t.Fatal("listening on 255.255.255.256:65535 should fail")
}
})
assert.NoError(t, err, "should succeed")

/*
// Unable to perform this test atm because there is no timeout and the test may run infinitely
t.Run("SendSTUNRequest timeout", func(t *testing.T) {
c, err := NewClient("0.0.0.0:0")
if err != nil {
t.Fatal(err)
}
_, err = c.SendSTUNRequest(net.IPv4(255, 255, 255, 255), 65535)
if err == nil {
t.Fatal("request to 255.255.255.255:65535 should fail")
}
msg, err := stun.Build(stun.TransactionID, stun.BindingRequest)
assert.NoError(t, err, "should succeed")

ok, err := c.HandleInbound(msg.Raw, &net.UDPAddr{
IP: net.ParseIP("127.0.0.1"),
Port: 1234,
})
*/
assert.NoError(t, err, "should succeed")
assert.True(t, ok, "should return ture, but ignored")
})

t.Run("SendBindingRequestTo timeout", func(t *testing.T) {
c, ok := createListeningTestClient(t, loggerFactory)
if !ok {
return
}
defer c.Close()

to, err := net.ResolveUDPAddr("udp4", "127.0.0.1:9")
if !assert.NoError(t, err, "should succeed") {
return
}

c.rto = 10 * time.Millisecond // force short timeout

_, err = c.SendBindingRequestTo(to)
log.Debug(err.Error())
})
}
13 changes: 10 additions & 3 deletions cmd/client/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,15 +20,22 @@ func main() {
panic(errors.New("failed to parse host IP"))
}

conn, err := net.ListenPacket("udp4", "0.0.0.0:0")
if err != nil {
panic(err)
}
defer conn.Close()

c, err := turn.NewClient(&turn.ClientConfig{
ListeningAddress: "0.0.0.0:0",
LoggerFactory: logging.NewDefaultLoggerFactory(),
Conn: conn,
LoggerFactory: logging.NewDefaultLoggerFactory(),
})
if err != nil {
panic(err)
}
defer c.Close()

mappedAddr, err := c.SendSTUNRequest(ip, *port)
mappedAddr, err := c.SendBindingRequest(ip, *port)
if err != nil {
panic(err)
}
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,9 +5,9 @@ go 1.12
require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/gortc/turn v0.8.0
github.com/pion/logging v0.2.1
github.com/pion/logging v0.2.2
github.com/pion/stun v0.3.1
github.com/pion/transport v0.8.1
github.com/pion/transport v0.8.4
github.com/pkg/errors v0.8.1
github.com/stretchr/testify v1.3.0
golang.org/x/net v0.0.0-20190403144856-b630fd6fe46b
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,12 @@ github.com/gortc/turn v0.8.0 h1:WWQi1jkoPmc2E7qgUMcZleveKikT9Ksi3QGIl8ZtY3Q=
github.com/gortc/turn v0.8.0/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/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
github.com/pion/logging v0.2.2/go.mod h1:k0/tDVsRCX2Mb2ZEmTqNa7CWsQPc+YYCB7Q+5pahoms=
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.8.1 h1:FUHJFd4MaIEJmlpiGx+ZH8j9JLsERnROHQPA9zNFFAs=
github.com/pion/transport v0.8.1/go.mod h1:nAmRRnn+ArVtsoNuwktvAD+jrjSD7pA+H3iRmZwdUno=
github.com/pion/transport v0.8.4 h1:Wios3j8IFmrli4pHiXhGMVnj1DYWiukcboZGSv8kj2M=
github.com/pion/transport v0.8.4/go.mod h1:nAmRRnn+ArVtsoNuwktvAD+jrjSD7pA+H3iRmZwdUno=
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=
Expand Down
4 changes: 3 additions & 1 deletion internal/allocation/allocation.go
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,9 @@ func (a *Allocation) packetHandler(m *Manager) {
if err != nil {
a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
}
a.log.Debugf("relaying message to client at %s", a.fiveTuple.SrcAddr.String())
a.log.Debugf("relaying message from %s to client at %s",
srcAddr.String(),
a.fiveTuple.SrcAddr.String())
if _, err = a.TurnSocket.WriteTo(msg.Raw, a.fiveTuple.SrcAddr); err != nil {
a.log.Errorf("Failed to send DataIndication from allocation %v %v", srcAddr, err)
}
Expand Down
15 changes: 15 additions & 0 deletions internal/client/channel.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package client

import (
"sync"

"github.com/gortc/turn"
"github.com/pion/logging"
)

type channel struct {
log logging.LeveledLogger
mutex sync.RWMutex
number turn.ChannelNumber
peerAddr turn.PeerAddress
}
Loading

0 comments on commit c3e0edb

Please sign in to comment.