Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Move URI type from pion/ice to pion/stun #134

Merged
merged 3 commits into from
May 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,14 @@ import (
)

func main() {
// Parse a STUN URI
u, err := stun.ParseURI("stun:stun.l.google.com:19302")
if err != nil {
panic(err)
}

// Creating a "connection" to STUN server.
c, err := stun.Dial("udp", "stun.l.google.com:19302")
c, err := stun.DialURI(u, &stun.DialConfig{})
if err != nil {
panic(err)
}
Expand Down Expand Up @@ -63,6 +69,7 @@ func main() {
- **RFC 5769**: [Test Vectors for Session Traversal Utilities for NAT (STUN)][rfc5769]
- **RFC 6062**: [Traversal Using Relays around NAT (TURN) Extensions for TCP Allocations][rfc6062]
- **RFC 7064**: [URI Scheme for the Session Traversal Utilities for NAT (STUN) Protocol][rfc7064]
- **RFC 7065**: [Traversal Using Relays around NAT (TURN) Uniform Resource Identifiers][rfc7065]
- **RFC 5780**: [NAT Behavior Discovery Using Session Traversal Utilities for NAT (STUN)][rfc5780] via [cmd/stun-nat-behaviour](cmd/stun-nat-behaviour)
- (TLS-over-)TCP client support

Expand All @@ -80,6 +87,7 @@ func main() {
[rfc5780]: https://tools.ietf.org/html/rfc5780
[rfc6062]: https://tools.ietf.org/html/rfc6062
[rfc7064]: https://tools.ietf.org/html/rfc7064
[rfc7065]: https://tools.ietf.org/html/rfc7065

### Stability
Package is currently stable, no backward incompatible changes are expected
Expand Down
80 changes: 80 additions & 0 deletions client.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,26 @@
package stun

import (
"crypto/tls"
"errors"
"fmt"
"io"
"log"
"net"
"runtime"
"strconv"
"sync"
"sync/atomic"
"time"

"github.com/pion/dtls/v2"
"github.com/pion/transport/v2"
"github.com/pion/transport/v2/stdnet"
)

// ErrUnsupportedURI is an error thrown if the user passes an unsupported STUN or TURN URI
stv0g marked this conversation as resolved.
Show resolved Hide resolved
var ErrUnsupportedURI = fmt.Errorf("invalid schema or transport")
stv0g marked this conversation as resolved.
Show resolved Hide resolved

// Dial connects to the address on the named network and then
// initializes Client on that connection, returning error if any.
func Dial(network, address string) (*Client, error) {
Expand All @@ -25,6 +34,77 @@ func Dial(network, address string) (*Client, error) {
return NewClient(conn)
}

// DialConfig is used to pass configuration to DialURI()
type DialConfig struct {
DTLSConfig dtls.Config
TLSConfig tls.Config

Net transport.Net
}

// DialURI connect to the STUN/TURN URI and then
// initializes Client on that connection, returning error if any.
stv0g marked this conversation as resolved.
Show resolved Hide resolved
func DialURI(uri *URI, cfg *DialConfig) (*Client, error) {
var conn Connection
var err error
stv0g marked this conversation as resolved.
Show resolved Hide resolved

nw := cfg.Net
edaniels marked this conversation as resolved.
Show resolved Hide resolved
if nw == nil {
nw, err = stdnet.NewNet()
if err != nil {
return nil, fmt.Errorf("failed to create net: %w", err)
}
}

addr := net.JoinHostPort(uri.Host, strconv.Itoa(uri.Port))

switch {
case uri.Scheme == SchemeTypeSTUN:
if conn, err = nw.Dial("udp", addr); err != nil {
return nil, fmt.Errorf("failed to listen: %w", err)
}

case uri.Scheme == SchemeTypeTURN:
network := "udp" //nolint:goconst
if uri.Proto == ProtoTypeTCP {
network = "tcp" //nolint:goconst
}

if conn, err = nw.Dial(network, addr); err != nil {
return nil, fmt.Errorf("failed to dial: %w", err)
}

case uri.Scheme == SchemeTypeTURNS && uri.Proto == ProtoTypeUDP:
dtlsCfg := cfg.DTLSConfig // Copy
dtlsCfg.ServerName = uri.Host

udpConn, err := nw.Dial("udp", addr)
if err != nil {
return nil, fmt.Errorf("failed to dial: %w", err)
}

if conn, err = dtls.Client(udpConn, &dtlsCfg); err != nil {
return nil, fmt.Errorf("failed to connect to '%s': %w", addr, err)
}

case (uri.Scheme == SchemeTypeTURNS || uri.Scheme == SchemeTypeSTUNS) && uri.Proto == ProtoTypeTCP:
tlsCfg := cfg.TLSConfig //nolint:govet
tlsCfg.ServerName = uri.Host

tcpConn, err := nw.Dial("tcp", addr)
if err != nil {
return nil, fmt.Errorf("failed to dial: %w", err)
}

conn = tls.Client(tcpConn, &tlsCfg)

default:
return nil, ErrUnsupportedURI
}

return NewClient(conn)
}

// ErrNoConnection means that ClientOptions.Connection is nil.
var ErrNoConnection = errors.New("no connection provided")

Expand Down
16 changes: 16 additions & 0 deletions client_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -471,6 +471,22 @@ func TestDial(t *testing.T) {
}()
}

func TestDialURI(t *testing.T) {
u, err := ParseURI("stun:localhost")
if err != nil {
t.Fatal(err)
}
c, err := DialURI(u, &DialConfig{})
if err != nil {
t.Fatal(err)
}
defer func() {
if err = c.Close(); err != nil {
t.Error(err)
}
}()
}

func TestDialError(t *testing.T) {
_, err := Dial("bad?network", "?????")
if err == nil {
Expand Down
15 changes: 6 additions & 9 deletions cmd/stun-bench/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ import (
"fmt"
"log"
mathRand "math/rand"
"net"
"os"
"os/signal"
"runtime"
Expand All @@ -25,17 +24,19 @@ import (

var (
workers = flag.Int("w", runtime.GOMAXPROCS(0), "concurrent workers") //nolint:gochecknoglobals
addr = flag.String("addr", "localhost", "target address") //nolint:gochecknoglobals
port = flag.Int("port", stun.DefaultPort, "target port") //nolint:gochecknoglobals
uriStr = flag.String("uri", "stun:localhost:3478", "URI of STUN server") //nolint:gochecknoglobals
duration = flag.Duration("d", time.Minute, "benchmark duration") //nolint:gochecknoglobals
network = flag.String("net", "udp", "protocol to use (udp, tcp)") //nolint:gochecknoglobals
cpuProfile = flag.String("cpuprofile", "", "file output of pprof cpu profile") //nolint:gochecknoglobals
memProfile = flag.String("memprofile", "", "file output of pprof memory profile") //nolint:gochecknoglobals
realRand = flag.Bool("crypt", false, "use crypto/rand as random source") //nolint:gochecknoglobals
)

func main() { //nolint:gocognit
flag.Parse()
uri, err := stun.ParseURI(*uriStr)
if err != nil {
log.Fatalf("failed to parse URI '%s': %s", *uriStr, err)
}
signals := make(chan os.Signal, 1)
signal.Notify(signals, os.Interrupt)
start := time.Now()
Expand Down Expand Up @@ -88,11 +89,7 @@ func main() { //nolint:gocognit
fmt.Println("using crypto/rand as random source for transaction id")
}
for i := 0; i < *workers; i++ {
wConn, connErr := net.Dial(*network, fmt.Sprintf("%s:%d", *addr, *port))
if connErr != nil {
log.Panicln("failed to dial:", wConn)
}
c, clientErr := stun.NewClient(wConn)
c, clientErr := stun.DialURI(uri, &stun.DialConfig{})
if clientErr != nil {
log.Panicln("failed to create client:", clientErr)
}
Expand Down
17 changes: 12 additions & 5 deletions cmd/stun-client/stun_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,22 @@ import (
func main() {
flag.Usage = func() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprintln(os.Stderr, os.Args[0], "stun.l.google.com:19302")
fmt.Fprintln(os.Stderr, os.Args[0], "stun:stun.l.google.com:19302")
}
flag.Parse()
addr := flag.Arg(0)
if addr == "" {
addr = "stun.l.google.com:19302"

uriStr := flag.Arg(0)
if uriStr == "" {
uriStr = "stun:stun.l.google.com:19302"
}

uri, err := stun.ParseURI(uriStr)
if err != nil {
log.Fatalf("invalid URI '%s': %s", uriStr, err)
}

// we only try the first address, so restrict ourselves to IPv4
c, err := stun.Dial("udp4", addr)
c, err := stun.DialURI(uri, &stun.DialConfig{})
if err != nil {
log.Fatal("dial:", err)
}
Expand Down
2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ module github.com/pion/stun
go 1.12

require (
github.com/pion/dtls/v2 v2.1.5
github.com/pion/logging v0.2.2
github.com/pion/transport/v2 v2.2.0
github.com/stretchr/testify v1.8.2
)
28 changes: 28 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
@@ -1,32 +1,57 @@
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/pion/dtls/v2 v2.1.5 h1:jlh2vtIyUBShchoTDqpCCqiYCyRFJ/lvf/gQ8TALs+c=
github.com/pion/dtls/v2 v2.1.5/go.mod h1:BqCE7xPZbPSubGasRoDFJeTsyJtdD1FanJYL0JGheqY=
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/transport v0.12.2/go.mod h1:N3+vZQD9HlDP5GWkZ85LohxNsDcNgofQmyL6ojX5d8Q=
github.com/pion/transport v0.13.0 h1:KWTA5ZrQogizzYwPEciGtHPLwpAjE91FgXnyu+Hv2uY=
github.com/pion/transport v0.13.0/go.mod h1:yxm9uXpK9bpBBWkITk13cLo1y5/ur5VQpG22ny6EP7g=
github.com/pion/transport/v2 v2.2.0 h1:u5lFqFHkXLMXMzai8tixZDfVjb8eOjH35yCunhPeb1c=
github.com/pion/transport/v2 v2.2.0/go.mod h1:AdSw4YBZVDkZm8fpoz+fclXyQwANWmZAlDuQdctTThQ=
github.com/pion/udp v0.1.1 h1:8UAPvyqmsxK8oOjloDk4wUt63TzFe9WEJkg5lChlj7o=
github.com/pion/udp v0.1.1/go.mod h1:6AFo+CMdKQm7UiA0eUPA8/eVCTx8jBIITLZHc9DWX5M=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.2 h1:+h33VjcLVPDHtOdpUCuF+7gSuG3yGIftsP1YvFihtJ8=
github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY=
golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
golang.org/x/crypto v0.0.0-20200622213623-75b288015ac9/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto=
golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f h1:OeJjE6G4dgCY4PIXvIRQbE8+RX+uXZyGhUy/ksMGJoc=
golang.org/x/crypto v0.0.0-20220427172511-eb4f295cb31f/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4/go.mod h1:jJ57K6gSWd91VN4djpZkiMVwK6gcyfeH4XE8wZrZaV4=
golang.org/x/mod v0.8.0/go.mod h1:iBbtSCu2XBx23ZKBPSOrRkjjQPZFPuis4dIYUhu/chs=
golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
golang.org/x/net v0.0.0-20201201195509-5d6afe98e0b7/go.mod h1:sp8m0HH+o8qH0wwXwYZr8TS3Oi6o0r6Gce1SSxlDquU=
golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20211201190559-0a0e4e1bb54c/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.0.0-20220425223048-2871e0cb64e4/go.mod h1:CfG3xpIq0wQ8r1q4Su4UZFWDARRcnwPjda9FqA0JpMk=
golang.org/x/net v0.0.0-20220722155237-a158d28d115b/go.mod h1:XRhObCWvk6IyKnWLug+ECip1KBveYUHfp+8e9klMJ9c=
golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
golang.org/x/net v0.8.0 h1:Zrh2ngAOFYneWTAIAPethzeaQLuHwhuBkuV6ZiRnUaQ=
golang.org/x/net v0.8.0/go.mod h1:QVkue5JL9kW//ek3r6jTKnTFis1tRmNAW2P1shuFdJc=
golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.0.0-20220722155255-886fb9371eb4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sync v0.1.0/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20211216021012-1d35b9e2eb4e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
Expand All @@ -39,6 +64,7 @@ golang.org/x/term v0.5.0/go.mod h1:jMB1sMXY+tzblOD4FWmEbocvup2/aLOaQEp7JmGp78k=
golang.org/x/term v0.6.0/go.mod h1:m6U89DPEgQRMq3DNkDClhWw02AUbt2daBVO4cn4Hv9U=
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
Expand All @@ -47,6 +73,8 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn
golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU=
golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
Loading