Repository: pion/ice
Pull request #566 (2023-05-10 11:05:06)

Move pion/ice.URL to pion/stun.URI
This PR completes the migration of STUN/TURN URL parsing types & functions to the pion/stun module.

I've kept compatibility wrappers around the old functions, types and constants which simply point to the types in pion/stun.
However, those are now marked as deprecated and downstream projects should get linter warnings.

We can remove the compatability wrappers with a v3 release of pion/ice.

codecov[bot]: ## [Codecov](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=h1&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) Report
Patch coverage has no change and project coverage change: **`-55.66`** :warning:
> Comparison is base [(`3172e05`)](https://app.codecov.io/gh/pion/ice/commit/3172e05931860535f86112c3a36309537561bcc9?el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) 78.36% compared to head [(`fb8ec60`)](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=desc&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) 22.70%.

<details><summary>Additional details and impacted files</summary>


```diff
@@             Coverage Diff             @@
##           master     #566       +/-   ##
===========================================
- Coverage   78.36%   22.70%   -55.66%     
===========================================
  Files          42       36        -6     
  Lines        4354     4113      -241     
===========================================
- Hits         3412      934     -2478     
- Misses        732     3139     +2407     
+ Partials      210       40      -170     
```

| Flag | Coverage Δ | |
|---|---|---|
| go | `?` | |
| wasm | `22.70% <0.00%> (-2.30%)` | :arrow_down: |

Flags with carried forward coverage won't be shown. [Click here](https://docs.codecov.io/docs/carryforward-flags?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#carryforward-flags-in-the-pull-request-comment) to find out more.

| [Impacted Files](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion) | Coverage Δ | |
|---|---|---|
| [agent.go](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-YWdlbnQuZ28=) | `0.00% <ø> (-81.88%)` | :arrow_down: |
| [agent\_config.go](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-YWdlbnRfY29uZmlnLmdv) | `0.00% <ø> (-82.15%)` | :arrow_down: |
| [gather.go](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-Z2F0aGVyLmdv) | `0.00% <0.00%> (-67.15%)` | :arrow_down: |
| [ice.go](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=tree&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion#diff-aWNlLmdv) | `100.00% <ø> (ø)` | |

... and [27 files with indirect coverage changes](https://app.codecov.io/gh/pion/ice/pull/566/indirect-changes?src=pr&el=tree-more&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion)


</details>

[:umbrella: View full report in Codecov by Sentry](https://app.codecov.io/gh/pion/ice/pull/566?src=pr&el=continue&utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion).   
:loudspeaker: Do you have feedback about the report comment? [Let us know in this issue](https://about.codecov.io/codecov-pr-comment-feedback/?utm_medium=referral&utm_source=github&utm_content=comment&utm_campaign=pr+comments&utm_term=pion).


Patch:
diff --git a/agent.go b/agent.go
index e896756..0ad6ff2 100644
--- a/agent.go
+++ b/agent.go
@@ -105,7 +105,7 @@ type Agent struct {
 
 	selectedPair atomic.Value // *CandidatePair
 
-	urls         []*URL
+	urls         []*stun.URI
 	networkTypes []NetworkType
 
 	buf *packetio.Buffer
@@ -435,6 +435,7 @@ func (a *Agent) connectivityChecks() {
 					a.updateConnectionState(ConnectionStateFailed)
 					return
 				}
+			default:
 			}
 
 			a.selector.ContactCandidates()
diff --git a/agent_config.go b/agent_config.go
index 04d74b1..f5897cd 100644
--- a/agent_config.go
+++ b/agent_config.go
@@ -8,6 +8,7 @@ import (
 	"time"
 
 	"github.com/pion/logging"
+	"github.com/pion/stun"
 	"github.com/pion/transport/v2"
 	"golang.org/x/net/proxy"
 )
@@ -54,7 +55,7 @@ func defaultCandidateTypes() []CandidateType {
 // AgentConfig collects the arguments to ice.Agent construction into
 // a single structure, for future-proofness of the interface
 type AgentConfig struct {
-	Urls []*URL
+	Urls []*stun.URI
 
 	// PortMin and PortMax are optional. Leave them 0 for the default UDP port allocation strategy.
 	PortMin uint16
diff --git a/errors.go b/errors.go
index eaae591..e05cce8 100644
--- a/errors.go
+++ b/errors.go
@@ -124,8 +124,6 @@ var (
 	errReadingStreamingPacket        = errors.New("error reading streaming packet")
 	errWriting                       = errors.New("error writing to")
 	errClosingConnection             = errors.New("error closing connection")
-	errMissingProtocolScheme         = errors.New("missing protocol scheme")
-	errTooManyColonsAddr             = errors.New("too many colons in address")
 	errRead                          = errors.New("unexpected error trying to read")
 	errUnknownRole                   = errors.New("unknown role")
 	errICEWriteSTUNMessage           = errors.New("the ICE conn can't write STUN messages")
diff --git a/gather.go b/gather.go
index eab5ca7..15e2da1 100644
--- a/gather.go
+++ b/gather.go
@@ -17,6 +17,7 @@ import (
 	"github.com/pion/ice/v2/internal/fakenet"
 	stunx "github.com/pion/ice/v2/internal/stun"
 	"github.com/pion/logging"
+	"github.com/pion/stun"
 	"github.com/pion/turn/v2"
 )
 
@@ -376,7 +377,7 @@ func (a *Agent) gatherCandidatesSrflxMapped(ctx context.Context, networkTypes []
 	}
 }
 
-func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*URL, networkTypes []NetworkType) { //nolint:gocognit
+func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*stun.URI, networkTypes []NetworkType) { //nolint:gocognit
 	var wg sync.WaitGroup
 	defer wg.Wait()
 
@@ -393,7 +394,7 @@ func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*URL, ne
 					continue
 				}
 				wg.Add(1)
-				go func(url URL, network string, localAddr *net.UDPAddr) {
+				go func(url stun.URI, network string, localAddr *net.UDPAddr) {
 					defer wg.Done()
 
 					hostPort := fmt.Sprintf("%s:%d", url.Host, url.Port)
@@ -444,7 +445,7 @@ func (a *Agent) gatherCandidatesSrflxUDPMux(ctx context.Context, urls []*URL, ne
 	}
 }
 
-func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*URL, networkTypes []NetworkType) { //nolint:gocognit
+func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*stun.URI, networkTypes []NetworkType) { //nolint:gocognit
 	var wg sync.WaitGroup
 	defer wg.Wait()
 
@@ -455,7 +456,7 @@ func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*URL, networkT
 
 		for i := range urls {
 			wg.Add(1)
-			go func(url URL, network string) {
+			go func(url stun.URI, network string) {
 				defer wg.Done()
 
 				hostPort := fmt.Sprintf("%s:%d", url.Host, url.Port)
@@ -518,14 +519,14 @@ func (a *Agent) gatherCandidatesSrflx(ctx context.Context, urls []*URL, networkT
 	}
 }
 
-func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //nolint:gocognit
+func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*stun.URI) { //nolint:gocognit
 	var wg sync.WaitGroup
 	defer wg.Wait()
 
 	network := NetworkTypeUDP4.String()
 	for i := range urls {
 		switch {
-		case urls[i].Scheme != SchemeTypeTURN && urls[i].Scheme != SchemeTypeTURNS:
+		case urls[i].Scheme != stun.SchemeTypeTURN && urls[i].Scheme != stun.SchemeTypeTURNS:
 			continue
 		case urls[i].Username == "":
 			a.log.Errorf("Failed to gather relay candidates: %v", ErrUsernameEmpty)
@@ -536,7 +537,7 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
 		}
 
 		wg.Add(1)
-		go func(url URL) {
+		go func(url stun.URI) {
 			defer wg.Done()
 			turnServerAddr := fmt.Sprintf("%s:%d", url.Host, url.Port)
 			var (
@@ -548,7 +549,7 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
 			)
 
 			switch {
-			case url.Proto == ProtoTypeUDP && url.Scheme == SchemeTypeTURN:
+			case url.Proto == stun.ProtoTypeUDP && url.Scheme == stun.SchemeTypeTURN:
 				if locConn, err = a.net.ListenPacket(network, "0.0.0.0:0"); err != nil {
 					a.log.Warnf("Failed to listen %s: %v", network, err)
 					return
@@ -557,8 +558,8 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
 				relAddr = locConn.LocalAddr().(*net.UDPAddr).IP.String() //nolint:forcetypeassert
 				relPort = locConn.LocalAddr().(*net.UDPAddr).Port        //nolint:forcetypeassert
 				relayProtocol = udp
-			case a.proxyDialer != nil && url.Proto == ProtoTypeTCP &&
-				(url.Scheme == SchemeTypeTURN || url.Scheme == SchemeTypeTURNS):
+			case a.proxyDialer != nil && url.Proto == stun.ProtoTypeTCP &&
+				(url.Scheme == stun.SchemeTypeTURN || url.Scheme == stun.SchemeTypeTURNS):
 				conn, connectErr := a.proxyDialer.Dial(NetworkTypeTCP4.String(), turnServerAddr)
 				if connectErr != nil {
 					a.log.Warnf("Failed to dial TCP address %s via proxy dialer: %v", turnServerAddr, connectErr)
@@ -567,14 +568,14 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
 
 				relAddr = conn.LocalAddr().(*net.TCPAddr).IP.String() //nolint:forcetypeassert
 				relPort = conn.LocalAddr().(*net.TCPAddr).Port        //nolint:forcetypeassert
-				if url.Scheme == SchemeTypeTURN {
+				if url.Scheme == stun.SchemeTypeTURN {
 					relayProtocol = tcp
-				} else if url.Scheme == SchemeTypeTURNS {
+				} else if url.Scheme == stun.SchemeTypeTURNS {
 					relayProtocol = "tls"
 				}
 				locConn = turn.NewSTUNConn(conn)
 
-			case url.Proto == ProtoTypeTCP && url.Scheme == SchemeTypeTURN:
+			case url.Proto == stun.ProtoTypeTCP && url.Scheme == stun.SchemeTypeTURN:
 				tcpAddr, connectErr := a.net.ResolveTCPAddr(NetworkTypeTCP4.String(), turnServerAddr)
 				if connectErr != nil {
 					a.log.Warnf("Failed to resolve TCP address %s: %v", turnServerAddr, connectErr)
@@ -591,7 +592,7 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
 				relPort = conn.LocalAddr().(*net.TCPAddr).Port        //nolint:forcetypeassert
 				relayProtocol = tcp
 				locConn = turn.NewSTUNConn(conn)
-			case url.Proto == ProtoTypeUDP && url.Scheme == SchemeTypeTURNS:
+			case url.Proto == stun.ProtoTypeUDP && url.Scheme == stun.SchemeTypeTURNS:
 				udpAddr, connectErr := a.net.ResolveUDPAddr(network, turnServerAddr)
 				if connectErr != nil {
 					a.log.Warnf("Failed to resolve UDP address %s: %v", turnServerAddr, connectErr)
@@ -617,7 +618,7 @@ func (a *Agent) gatherCandidatesRelay(ctx context.Context, urls []*URL) { //noli
 				relPort = conn.LocalAddr().(*net.UDPAddr).Port        //nolint:forcetypeassert
 				relayProtocol = "dtls"
 				locConn = &fakenet.PacketConn{Conn: conn}
-			case url.Proto == ProtoTypeTCP && url.Scheme == SchemeTypeTURNS:
+			case url.Proto == stun.ProtoTypeTCP && url.Scheme == stun.SchemeTypeTURNS:
 				tcpAddr, resolvErr := a.net.ResolveTCPAddr(NetworkTypeTCP4.String(), turnServerAddr)
 				if resolvErr != nil {
 					a.log.Warnf("Failed to resolve relay address %s: %v", turnServerAddr, resolvErr)
diff --git a/go.mod b/go.mod
index 3736bd1..f0d6ffd 100644
--- a/go.mod
+++ b/go.mod
@@ -9,10 +9,11 @@ require (
 	github.com/pion/logging v0.2.2
 	github.com/pion/mdns v0.0.7
 	github.com/pion/randutil v0.1.0
-	github.com/pion/stun v0.4.0
+	github.com/pion/stun v0.5.1
 	github.com/pion/transport/v2 v2.2.0
 	github.com/pion/turn/v2 v2.1.0
 	github.com/stretchr/testify v1.8.2
-	golang.org/x/net v0.8.0
+	golang.org/x/crypto v0.9.0 // indirect
+	golang.org/x/net v0.10.0
 	gopkg.in/check.v1 v1.0.0-20190902080502-41f04d3bba15 // indirect
 )
diff --git a/go.sum b/go.sum
index 5df740d..58b495e 100644
--- a/go.sum
+++ b/go.sum
@@ -8,6 +8,7 @@ github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORN
 github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
 github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE=
 github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
+github.com/pion/dtls/v2 v2.2.4/go.mod h1:WGKfxqhrddne4Kg3p11FUMJrynkOY4lb25zHNO49wuw=
 github.com/pion/dtls/v2 v2.2.6 h1:yXMxKr0Skd+Ub6A8UqXTRLSywskx93ooMRHsQUtd+Z4=
 github.com/pion/dtls/v2 v2.2.6/go.mod h1:t8fWJCIquY5rlQZwA2yWxUS1+OCrAdXrhVKXB5oD/wY=
 github.com/pion/logging v0.2.2 h1:M9+AIj/+pxNsDfAT64+MAVgJO0rsyLnoJKCqf//DoeY=
@@ -16,14 +17,17 @@ github.com/pion/mdns v0.0.7 h1:P0UB4Sr6xDWEox0kTVxF0LmQihtCbSAdW0H2nEgkA3U=
 github.com/pion/mdns v0.0.7/go.mod h1:4iP2UbeFhLI/vWju/bw6ZfwjJzk0z8DNValjGxR/dD8=
 github.com/pion/randutil v0.1.0 h1:CFG1UdESneORglEsnimhUjf33Rwjubwj6xfiOXBa3mA=
 github.com/pion/randutil v0.1.0/go.mod h1:XcJrSMMbbMRhASFVOlj/5hQial/Y8oH/HVo7TBZq+j8=
-github.com/pion/stun v0.4.0 h1:vgRrbBE2htWHy7l3Zsxckk7rkjnjOsSM7PHZnBwo8rk=
 github.com/pion/stun v0.4.0/go.mod h1:QPsh1/SbXASntw3zkkrIk3ZJVKz4saBY2G7S10P3wCw=
+github.com/pion/stun v0.5.1 h1:EaiOQMDJU4ngyKJv9P+kKLJ02v3OU6PtCvqJi+ZOTDs=
+github.com/pion/stun v0.5.1/go.mod h1:wrVR5q7ACNsmm65J9ZgrDzMiT4sguceUjxS0CLUA4Ik=
 github.com/pion/transport/v2 v2.0.0/go.mod h1:HS2MEBJTwD+1ZI2eSXSvHJx/HnzQqRy2/LXxt6eVMHc=
 github.com/pion/transport/v2 v2.0.2/go.mod h1:vrz6bUbFr/cjdwbnxq8OdDDzHf7JJfGsIRkxfpZoTA0=
 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/turn/v2 v2.1.0 h1:5wGHSgGhJhP/RpabkUb/T9PdsAjkGLS6toYz5HNzoSI=
 github.com/pion/turn/v2 v2.1.0/go.mod h1:yrT5XbXSGX1VFSF31A3c1kCNB5bBZgk/uu5LET162qs=
+github.com/pion/udp v0.1.4 h1:OowsTmu1Od3sD6i3fQUJxJn2fEvJO6L1TidgadtbTI8=
+github.com/pion/udp v0.1.4/go.mod h1:G8LDo56HsFwC24LIcnT4YIDU5qcB6NepqqjP0keL2us=
 github.com/pion/udp/v2 v2.0.1 h1:xP0z6WNux1zWEjhC7onRA3EwwSliXqu1ElUZAQhUP54=
 github.com/pion/udp/v2 v2.0.1/go.mod h1:B7uvTMP00lzWdyMr/1PVZXtV3wpPIxBRd4Wl6AksXn8=
 github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
@@ -39,8 +43,9 @@ github.com/stretchr/testify v1.8.2/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o
 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-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
-golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
 golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
+golang.org/x/crypto v0.9.0 h1:LF6fAI+IutBocDJ2OT0Q1g8plpYljMZ4+lty+dsqw3g=
+golang.org/x/crypto v0.9.0/go.mod h1:yrmDGqONDYtNj3tH8X9dzUun2m2lzPa9ngI6/RUPGR0=
 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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
@@ -50,8 +55,9 @@ golang.org/x/net v0.1.0/go.mod h1:Cx3nUiGt4eDBEyega/BKRp+/AlGL8hYe7U9odMt2Cco=
 golang.org/x/net v0.5.0/go.mod h1:DivGGAXEgPSlEBzxGzZI+ZLohi+xUj054jfeKui00ws=
 golang.org/x/net v0.6.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs=
 golang.org/x/net v0.7.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/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
+golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
 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=
@@ -65,14 +71,16 @@ golang.org/x/sys v0.2.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.4.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
-golang.org/x/sys v0.7.0 h1:3jlCCIQZPdOYu1h8BkNvLz8Kgwtae2cagcG/VamtZRU=
 golang.org/x/sys v0.7.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
+golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
 golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
 golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.1.0/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8=
 golang.org/x/term v0.4.0/go.mod h1:9P2UbLfCdcvo3p/nzKvsmas4TnlujnuoV9hGgYzW1lQ=
 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/term v0.8.0/go.mod h1:xPskH00ivmX89bAKVGSKKtLOWNx2+17Eiy94tnKShWo=
 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.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
@@ -80,6 +88,7 @@ golang.org/x/text v0.4.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 golang.org/x/text v0.6.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8=
 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=
+golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
 golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
 golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
 golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc=
diff --git a/ice.go b/ice.go
index 9769ae1..bd55120 100644
--- a/ice.go
+++ b/ice.go
@@ -8,8 +8,11 @@ type ConnectionState int
 
 // List of supported States
 const (
+	// ConnectionStateUnknown represents an unknown state
+	ConnectionStateUnknown ConnectionState = iota
+
 	// ConnectionStateNew ICE agent is gathering addresses
-	ConnectionStateNew = iota + 1
+	ConnectionStateNew
 
 	// ConnectionStateChecking ICE agent has been given local and remote candidates, and is attempting to find a match
 	ConnectionStateChecking
@@ -55,8 +58,11 @@ func (c ConnectionState) String() string {
 type GatheringState int
 
 const (
+	// GatheringStateUnknown represents an unknown state
+	GatheringStateUnknown GatheringState = iota
+
 	// GatheringStateNew indicates candidate gathering is not yet started
-	GatheringStateNew GatheringState = iota + 1
+	GatheringStateNew
 
 	// GatheringStateGathering indicates candidate gathering is ongoing
 	GatheringStateGathering
diff --git a/url.go b/url.go
index 747379e..b2b9f8b 100644
--- a/url.go
+++ b/url.go
@@ -3,228 +3,80 @@
 
 package ice
 
-import (
-	"errors"
-	"net"
-	"net/url"
-	"strconv"
+import "github.com/pion/stun"
+
+type (
+	// URL represents a STUN (rfc7064) or TURN (rfc7065) URI
+	//
+	// Deprecated: Please use pion/stun.URI
+	URL = stun.URI
+
+	// ProtoType indicates the transport protocol type that is used in the ice.URL
+	// structure.
+	//
+	// Deprecated: TPlease use pion/stun.ProtoType
+	ProtoType = stun.ProtoType
+
+	// SchemeType indicates the type of server used in the ice.URL structure.
+	//
+	// Deprecated: Please use pion/stun.SchemeType
+	SchemeType = stun.SchemeType
 )
 
-// SchemeType indicates the type of server used in the ice.URL structure.
-type SchemeType int
-
-// Unknown defines default public constant to use for "enum" like struct
-// comparisons when no value was defined.
-const Unknown = iota
-
 const (
 	// SchemeTypeSTUN indicates the URL represents a STUN server.
-	SchemeTypeSTUN SchemeType = iota + 1
+	//
+	// Deprecated: Please use pion/stun.SchemeTypeSTUN
+	SchemeTypeSTUN = stun.SchemeTypeSTUN
 
 	// SchemeTypeSTUNS indicates the URL represents a STUNS (secure) server.
-	SchemeTypeSTUNS
+	//
+	// Deprecated: Please use pion/stun.SchemeTypeSTUNS
+	SchemeTypeSTUNS = stun.SchemeTypeSTUNS
 
 	// SchemeTypeTURN indicates the URL represents a TURN server.
-	SchemeTypeTURN
+	//
+	// Deprecated: Please use pion/stun.SchemeTypeTURN
+	SchemeTypeTURN = stun.SchemeTypeTURN
 
 	// SchemeTypeTURNS indicates the URL represents a TURNS (secure) server.
-	SchemeTypeTURNS
+	//
+	// Deprecated: Please use pion/stun.SchemeTypeTURNS
+	SchemeTypeTURNS = stun.SchemeTypeTURNS
 )
 
-// NewSchemeType defines a procedure for creating a new SchemeType from a raw
-// string naming the scheme type.
-func NewSchemeType(raw string) SchemeType {
-	switch raw {
-	case "stun":
-		return SchemeTypeSTUN
-	case "stuns":
-		return SchemeTypeSTUNS
-	case "turn":
-		return SchemeTypeTURN
-	case "turns":
-		return SchemeTypeTURNS
-	default:
-		return SchemeType(Unknown)
-	}
-}
-
-func (t SchemeType) String() string {
-	switch t {
-	case SchemeTypeSTUN:
-		return "stun"
-	case SchemeTypeSTUNS:
-		return "stuns"
-	case SchemeTypeTURN:
-		return "turn"
-	case SchemeTypeTURNS:
-		return "turns"
-	default:
-		return ErrUnknownType.Error()
-	}
-}
-
-// ProtoType indicates the transport protocol type that is used in the ice.URL
-// structure.
-type ProtoType int
-
 const (
 	// ProtoTypeUDP indicates the URL uses a UDP transport.
-	ProtoTypeUDP ProtoType = iota + 1
+	//
+	// Deprecated: Please use pion/stun.ProtoTypeUDP
+	ProtoTypeUDP = stun.ProtoTypeUDP
 
 	// ProtoTypeTCP indicates the URL uses a TCP transport.
-	ProtoTypeTCP
+	//
+	// Deprecated: Please use pion/stun.ProtoTypeTCP
+	ProtoTypeTCP = stun.ProtoTypeTCP
 )
 
-// NewProtoType defines a procedure for creating a new ProtoType from a raw
-// string naming the transport protocol type.
-func NewProtoType(raw string) ProtoType {
-	switch raw {
-	case "udp":
-		return ProtoTypeUDP
-	case "tcp":
-		return ProtoTypeTCP
-	default:
-		return ProtoType(Unknown)
-	}
-}
-
-func (t ProtoType) String() string {
-	switch t {
-	case ProtoTypeUDP:
-		return "udp"
-	case ProtoTypeTCP:
-		return "tcp"
-	default:
-		return ErrUnknownType.Error()
-	}
-}
-
-// URL represents a STUN (rfc7064) or TURN (rfc7065) URL
-type URL struct {
-	Scheme   SchemeType
-	Host     string
-	Port     int
-	Username string
-	Password string
-	Proto    ProtoType
-}
+// Unknown represents and unknown ProtoType or SchemeType
+//
+// Deprecated: Please use pion/stun.SchemeTypeUnknown or pion/stun.ProtoTypeUnknown
+const Unknown = 0
 
 // ParseURL parses a STUN or TURN urls following the ABNF syntax described in
 // https://tools.ietf.org/html/rfc7064 and https://tools.ietf.org/html/rfc7065
 // respectively.
-func ParseURL(raw string) (*URL, error) { //nolint:gocognit
-	rawParts, err := url.Parse(raw)
-	if err != nil {
-		return nil, err
-	}
-
-	var u URL
-	u.Scheme = NewSchemeType(rawParts.Scheme)
-	if u.Scheme == SchemeType(Unknown) {
-		return nil, ErrSchemeType
-	}
-
-	var rawPort string
-	if u.Host, rawPort, err = net.SplitHostPort(rawParts.Opaque); err != nil {
-		var e *net.AddrError
-		if errors.As(err, &e) {
-			if e.Err == "missing port in address" {
-				nextRawURL := u.Scheme.String() + ":" + rawParts.Opaque
-				switch {
-				case u.Scheme == SchemeTypeSTUN || u.Scheme == SchemeTypeTURN:
-					nextRawURL += ":3478"
-					if rawParts.RawQuery != "" {
-						nextRawURL += "?" + rawParts.RawQuery
-					}
-					return ParseURL(nextRawURL)
-				case u.Scheme == SchemeTypeSTUNS || u.Scheme == SchemeTypeTURNS:
-					nextRawURL += ":5349"
-					if rawParts.RawQuery != "" {
-						nextRawURL += "?" + rawParts.RawQuery
-					}
-					return ParseURL(nextRawURL)
-				}
-			}
-		}
-		return nil, err
-	}
-
-	if u.Host == "" {
-		return nil, ErrHost
-	}
+//
+// Deprecated: Please use pion/stun.ParseURI
+var ParseURL = stun.ParseURI //nolint:gochecknoglobals
 
-	if u.Port, err = strconv.Atoi(rawPort); err != nil {
-		return nil, ErrPort
-	}
-
-	switch u.Scheme {
-	case SchemeTypeSTUN:
-		qArgs, err := url.ParseQuery(rawParts.RawQuery)
-		if err != nil || len(qArgs) > 0 {
-			return nil, ErrSTUNQuery
-		}
-		u.Proto = ProtoTypeUDP
-	case SchemeTypeSTUNS:
-		qArgs, err := url.ParseQuery(rawParts.RawQuery)
-		if err != nil || len(qArgs) > 0 {
-			return nil, ErrSTUNQuery
-		}
-		u.Proto = ProtoTypeTCP
-	case SchemeTypeTURN:
-		proto, err := parseProto(rawParts.RawQuery)
-		if err != nil {
-			return nil, err
-		}
-
-		u.Proto = proto
-		if u.Proto == ProtoType(Unknown) {
-			u.Proto = ProtoTypeUDP
-		}
-	case SchemeTypeTURNS:
-		proto, err := parseProto(rawParts.RawQuery)
-		if err != nil {
-			return nil, err
-		}
-
-		u.Proto = proto
-		if u.Proto == ProtoType(Unknown) {
-			u.Proto = ProtoTypeTCP
-		}
-	}
-
-	return &u, nil
-}
-
-func parseProto(raw string) (ProtoType, error) {
-	qArgs, err := url.ParseQuery(raw)
-	if err != nil || len(qArgs) > 1 {
-		return ProtoType(Unknown), ErrInvalidQuery
-	}
-
-	var proto ProtoType
-	if rawProto := qArgs.Get("transport"); rawProto != "" {
-		if proto = NewProtoType(rawProto); proto == ProtoType(0) {
-			return ProtoType(Unknown), ErrProtoType
-		}
-		return proto, nil
-	}
-
-	if len(qArgs) > 0 {
-		return ProtoType(Unknown), ErrInvalidQuery
-	}
-
-	return proto, nil
-}
-
-func (u URL) String() string {
-	rawURL := u.Scheme.String() + ":" + net.JoinHostPort(u.Host, strconv.Itoa(u.Port))
-	if u.Scheme == SchemeTypeTURN || u.Scheme == SchemeTypeTURNS {
-		rawURL += "?transport=" + u.Proto.String()
-	}
-	return rawURL
-}
+// NewSchemeType defines a procedure for creating a new SchemeType from a raw
+// string naming the scheme type.
+//
+// Deprecated: Please use pion/stun.NewSchemeType
+var NewSchemeType = stun.NewSchemeType //nolint:gochecknoglobals
 
-// IsSecure returns whether the this URL's scheme describes secure scheme or not.
-func (u URL) IsSecure() bool {
-	return u.Scheme == SchemeTypeSTUNS || u.Scheme == SchemeTypeTURNS
-}
+// NewProtoType defines a procedure for creating a new ProtoType from a raw
+// string naming the transport protocol type.
+//
+// Deprecated: Please use pion/stun.NewProtoType
+var NewProtoType = stun.NewProtoType //nolint:gochecknoglobals


Test patch:
diff --git a/agent_test.go b/agent_test.go
index b7d6dea..ba24f53 100644
--- a/agent_test.go
+++ b/agent_test.go
@@ -301,11 +301,11 @@ func TestConnectivityLite(t *testing.T) {
 	lim := test.TimeOut(time.Second * 30)
 	defer lim.Stop()
 
-	stunServerURL := &URL{
+	stunServerURL := &stun.URI{
 		Scheme: SchemeTypeSTUN,
 		Host:   "1.2.3.4",
 		Port:   3478,
-		Proto:  ProtoTypeUDP,
+		Proto:  stun.ProtoTypeUDP,
 	}
 
 	natType := &vnet.NATType{
@@ -320,7 +320,7 @@ func TestConnectivityLite(t *testing.T) {
 	bNotifier, bConnected := onConnected()
 
 	cfg0 := &AgentConfig{
-		Urls:             []*URL{stunServerURL},
+		Urls:             []*stun.URI{stunServerURL},
 		NetworkTypes:     supportedNetworkTypes(),
 		MulticastDNSMode: MulticastDNSModeDisabled,
 		Net:              v.net0,
@@ -331,7 +331,7 @@ func TestConnectivityLite(t *testing.T) {
 	require.NoError(t, aAgent.OnConnectionStateChange(aNotifier))
 
 	cfg1 := &AgentConfig{
-		Urls:             []*URL{},
+		Urls:             []*stun.URI{},
 		Lite:             true,
 		CandidateTypes:   []CandidateType{CandidateTypeHost},
 		NetworkTypes:     supportedNetworkTypes(),
@@ -548,7 +548,7 @@ func TestConnectionStateCallback(t *testing.T) {
 	KeepaliveInterval := time.Duration(0)
 
 	cfg := &AgentConfig{
-		Urls:                []*URL{},
+		Urls:                []*stun.URI{},
 		NetworkTypes:        supportedNetworkTypes(),
 		DisconnectedTimeout: &disconnectedDuration,
 		FailedTimeout:       &failedDuration,
@@ -582,6 +582,7 @@ func TestConnectionStateCallback(t *testing.T) {
 			close(isFailed)
 		case ConnectionStateClosed:
 			close(isClosed)
+		default:
 		}
 	})
 	if err != nil {
@@ -1161,9 +1162,9 @@ func TestConnectionStateConnectingToFailed(t *testing.T) {
 			isFailed.Done()
 		case ConnectionStateChecking:
 			isChecking.Done()
-		case ConnectionStateConnected:
 		case ConnectionStateCompleted:
 			t.Errorf("Unexpected ConnectionState: %v", c)
+		default:
 		}
 	}
 
@@ -1330,7 +1331,7 @@ func TestCloseInConnectionStateCallback(t *testing.T) {
 	CheckInterval := 500 * time.Millisecond
 
 	cfg := &AgentConfig{
-		Urls:                []*URL{},
+		Urls:                []*stun.URI{},
 		NetworkTypes:        supportedNetworkTypes(),
 		DisconnectedTimeout: &disconnectedDuration,
 		FailedTimeout:       &failedDuration,
@@ -1357,6 +1358,7 @@ func TestCloseInConnectionStateCallback(t *testing.T) {
 			assert.NoError(t, aAgent.Close())
 		case ConnectionStateClosed:
 			close(isClosed)
+		default:
 		}
 	})
 	if err != nil {
@@ -1382,7 +1384,7 @@ func TestRunTaskInConnectionStateCallback(t *testing.T) {
 	CheckInterval := 50 * time.Millisecond
 
 	cfg := &AgentConfig{
-		Urls:                []*URL{},
+		Urls:                []*stun.URI{},
 		NetworkTypes:        supportedNetworkTypes(),
 		DisconnectedTimeout: &oneSecond,
 		FailedTimeout:       &oneSecond,
@@ -1427,7 +1429,7 @@ func TestRunTaskInSelectedCandidatePairChangeCallback(t *testing.T) {
 	CheckInterval := 50 * time.Millisecond
 
 	cfg := &AgentConfig{
-		Urls:                []*URL{},
+		Urls:                []*stun.URI{},
 		NetworkTypes:        supportedNetworkTypes(),
 		DisconnectedTimeout: &oneSecond,
 		FailedTimeout:       &oneSecond,
@@ -1513,6 +1515,7 @@ func TestLiteLifecycle(t *testing.T) {
 			close(bDisconnected)
 		case ConnectionStateFailed:
 			close(bFailed)
+		default:
 		}
 	}))
 
diff --git a/candidate_relay_test.go b/candidate_relay_test.go
index 76054a1..870f76a 100644
--- a/candidate_relay_test.go
+++ b/candidate_relay_test.go
@@ -12,6 +12,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/pion/stun"
 	"github.com/pion/transport/v2/test"
 	"github.com/pion/turn/v2"
 	"github.com/stretchr/testify/assert"
@@ -47,14 +48,14 @@ func TestRelayOnlyConnection(t *testing.T) {
 
 	cfg := &AgentConfig{
 		NetworkTypes: supportedNetworkTypes(),
-		Urls: []*URL{
+		Urls: []*stun.URI{
 			{
-				Scheme:   SchemeTypeTURN,
+				Scheme:   stun.SchemeTypeTURN,
 				Host:     "127.0.0.1",
 				Username: "username",
 				Password: "password",
 				Port:     serverPort,
-				Proto:    ProtoTypeUDP,
+				Proto:    stun.ProtoTypeUDP,
 			},
 		},
 		CandidateTypes: []CandidateType{CandidateTypeRelay},
diff --git a/candidate_server_reflexive_test.go b/candidate_server_reflexive_test.go
index c226f93..953d84a 100644
--- a/candidate_server_reflexive_test.go
+++ b/candidate_server_reflexive_test.go
@@ -12,6 +12,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/pion/stun"
 	"github.com/pion/transport/v2/test"
 	"github.com/pion/turn/v2"
 	"github.com/stretchr/testify/assert"
@@ -43,7 +44,7 @@ func TestServerReflexiveOnlyConnection(t *testing.T) {
 
 	cfg := &AgentConfig{
 		NetworkTypes: []NetworkType{NetworkTypeUDP4},
-		Urls: []*URL{
+		Urls: []*stun.URI{
 			{
 				Scheme: SchemeTypeSTUN,
 				Host:   "127.0.0.1",
diff --git a/connectivity_vnet_test.go b/connectivity_vnet_test.go
index a9e993f..b8f8dd3 100644
--- a/connectivity_vnet_test.go
+++ b/connectivity_vnet_test.go
@@ -226,7 +226,7 @@ func connectWithVNet(aAgent, bAgent *Agent) (*Conn, *Conn) {
 }
 
 type agentTestConfig struct {
-	urls                   []*URL
+	urls                   []*stun.URI
 	nat1To1IPCandidateType CandidateType
 }
 
@@ -305,20 +305,20 @@ func TestConnectivityVNet(t *testing.T) {
 	report := test.CheckRoutines(t)
 	defer report()
 
-	stunServerURL := &URL{
-		Scheme: SchemeTypeSTUN,
+	stunServerURL := &stun.URI{
+		Scheme: stun.SchemeTypeSTUN,
 		Host:   vnetSTUNServerIP,
 		Port:   vnetSTUNServerPort,
-		Proto:  ProtoTypeUDP,
+		Proto:  stun.ProtoTypeUDP,
 	}
 
-	turnServerURL := &URL{
-		Scheme:   SchemeTypeTURN,
+	turnServerURL := &stun.URI{
+		Scheme:   stun.SchemeTypeTURN,
 		Host:     vnetSTUNServerIP,
 		Port:     vnetSTUNServerPort,
 		Username: "user",
 		Password: "pass",
-		Proto:    ProtoTypeUDP,
+		Proto:    stun.ProtoTypeUDP,
 	}
 
 	t.Run("Full-cone NATs on both ends", func(t *testing.T) {
@@ -339,12 +339,12 @@ func TestConnectivityVNet(t *testing.T) {
 
 		log.Debug("Connecting...")
 		a0TestConfig := &agentTestConfig{
-			urls: []*URL{
+			urls: []*stun.URI{
 				stunServerURL,
 			},
 		}
 		a1TestConfig := &agentTestConfig{
-			urls: []*URL{
+			urls: []*stun.URI{
 				stunServerURL,
 			},
 		}
@@ -376,13 +376,13 @@ func TestConnectivityVNet(t *testing.T) {
 
 		log.Debug("Connecting...")
 		a0TestConfig := &agentTestConfig{
-			urls: []*URL{
+			urls: []*stun.URI{
 				stunServerURL,
 				turnServerURL,
 			},
 		}
 		a1TestConfig := &agentTestConfig{
-			urls: []*URL{
+			urls: []*stun.URI{
 				stunServerURL,
 			},
 		}
@@ -416,11 +416,11 @@ func TestConnectivityVNet(t *testing.T) {
 
 		log.Debug("Connecting...")
 		a0TestConfig := &agentTestConfig{
-			urls:                   []*URL{},
+			urls:                   []*stun.URI{},
 			nat1To1IPCandidateType: CandidateTypeHost, // Use 1:1 NAT IP as a host candidate
 		}
 		a1TestConfig := &agentTestConfig{
-			urls: []*URL{},
+			urls: []*stun.URI{},
 		}
 		ca, cb := pipeWithVNet(v, a0TestConfig, a1TestConfig)
 
@@ -452,11 +452,11 @@ func TestConnectivityVNet(t *testing.T) {
 
 		log.Debug("Connecting...")
 		a0TestConfig := &agentTestConfig{
-			urls:                   []*URL{},
+			urls:                   []*stun.URI{},
 			nat1To1IPCandidateType: CandidateTypeServerReflexive, // Use 1:1 NAT IP as a srflx candidate
 		}
 		a1TestConfig := &agentTestConfig{
-			urls: []*URL{},
+			urls: []*stun.URI{},
 		}
 		ca, cb := pipeWithVNet(v, a0TestConfig, a1TestConfig)
 
diff --git a/gather_test.go b/gather_test.go
index 14583c2..9baf11b 100644
--- a/gather_test.go
+++ b/gather_test.go
@@ -224,16 +224,16 @@ func TestSTUNConcurrency(t *testing.T) {
 	})
 	assert.NoError(t, err)
 
-	urls := []*URL{}
+	urls := []*stun.URI{}
 	for i := 0; i <= 10; i++ {
-		urls = append(urls, &URL{
-			Scheme: SchemeTypeSTUN,
+		urls = append(urls, &stun.URI{
+			Scheme: stun.SchemeTypeSTUN,
 			Host:   "127.0.0.1",
 			Port:   serverPort + 1,
 		})
 	}
-	urls = append(urls, &URL{
-		Scheme: SchemeTypeSTUN,
+	urls = append(urls, &stun.URI{
+		Scheme: stun.SchemeTypeSTUN,
 		Host:   "127.0.0.1",
 		Port:   serverPort,
 	})
@@ -284,7 +284,7 @@ func TestTURNConcurrency(t *testing.T) {
 	lim := test.TimeOut(time.Second * 30)
 	defer lim.Stop()
 
-	runTest := func(protocol ProtoType, scheme SchemeType, packetConn net.PacketConn, listener net.Listener, serverPort int) {
+	runTest := func(protocol stun.ProtoType, scheme stun.SchemeType, packetConn net.PacketConn, listener net.Listener, serverPort int) {
 		packetConnConfigs := []turn.PacketConnConfig{}
 		if packetConn != nil {
 			packetConnConfigs = append(packetConnConfigs, turn.PacketConnConfig{
@@ -309,9 +309,9 @@ func TestTURNConcurrency(t *testing.T) {
 		})
 		assert.NoError(t, err)
 
-		urls := []*URL{}
+		urls := []*stun.URI{}
 		for i := 0; i <= 10; i++ {
-			urls = append(urls, &URL{
+			urls = append(urls, &stun.URI{
 				Scheme:   scheme,
 				Host:     "127.0.0.1",
 				Username: "username",
@@ -320,7 +320,7 @@ func TestTURNConcurrency(t *testing.T) {
 				Port:     serverPort + 1 + i,
 			})
 		}
-		urls = append(urls, &URL{
+		urls = append(urls, &stun.URI{
 			Scheme:   scheme,
 			Host:     "127.0.0.1",
 			Username: "username",
@@ -356,7 +356,7 @@ func TestTURNConcurrency(t *testing.T) {
 		serverListener, err := net.ListenPacket("udp", "127.0.0.1:"+strconv.Itoa(serverPort))
 		assert.NoError(t, err)
 
-		runTest(ProtoTypeUDP, SchemeTypeTURN, serverListener, nil, serverPort)
+		runTest(stun.ProtoTypeUDP, stun.SchemeTypeTURN, serverListener, nil, serverPort)
 	})
 
 	t.Run("TCP Relay", func(t *testing.T) {
@@ -364,7 +364,7 @@ func TestTURNConcurrency(t *testing.T) {
 		serverListener, err := net.Listen("tcp", "127.0.0.1:"+strconv.Itoa(serverPort))
 		assert.NoError(t, err)
 
-		runTest(ProtoTypeTCP, SchemeTypeTURN, nil, serverListener, serverPort)
+		runTest(stun.ProtoTypeTCP, stun.SchemeTypeTURN, nil, serverListener, serverPort)
 	})
 
 	t.Run("TLS Relay", func(t *testing.T) {
@@ -377,7 +377,7 @@ func TestTURNConcurrency(t *testing.T) {
 		})
 		assert.NoError(t, err)
 
-		runTest(ProtoTypeTCP, SchemeTypeTURNS, nil, serverListener, serverPort)
+		runTest(stun.ProtoTypeTCP, stun.SchemeTypeTURNS, nil, serverListener, serverPort)
 	})
 
 	t.Run("DTLS Relay", func(t *testing.T) {
@@ -390,7 +390,7 @@ func TestTURNConcurrency(t *testing.T) {
 		})
 		assert.NoError(t, err)
 
-		runTest(ProtoTypeUDP, SchemeTypeTURNS, nil, serverListener, serverPort)
+		runTest(stun.ProtoTypeUDP, stun.SchemeTypeTURNS, nil, serverListener, serverPort)
 	})
 }
 
@@ -418,17 +418,17 @@ func TestSTUNTURNConcurrency(t *testing.T) {
 	})
 	assert.NoError(t, err)
 
-	urls := []*URL{}
+	urls := []*stun.URI{}
 	for i := 0; i <= 10; i++ {
-		urls = append(urls, &URL{
-			Scheme: SchemeTypeSTUN,
+		urls = append(urls, &stun.URI{
+			Scheme: stun.SchemeTypeSTUN,
 			Host:   "127.0.0.1",
 			Port:   serverPort + 1,
 		})
 	}
-	urls = append(urls, &URL{
-		Scheme:   SchemeTypeTURN,
-		Proto:    ProtoTypeUDP,
+	urls = append(urls, &stun.URI{
+		Scheme:   stun.SchemeTypeTURN,
+		Proto:    stun.ProtoTypeUDP,
 		Host:     "127.0.0.1",
 		Port:     serverPort,
 		Username: "username",
@@ -490,9 +490,9 @@ func TestTURNSrflx(t *testing.T) {
 	})
 	assert.NoError(t, err)
 
-	urls := []*URL{{
-		Scheme:   SchemeTypeTURN,
-		Proto:    ProtoTypeUDP,
+	urls := []*stun.URI{{
+		Scheme:   stun.SchemeTypeTURN,
+		Proto:    stun.ProtoTypeUDP,
 		Host:     "127.0.0.1",
 		Port:     serverPort,
 		Username: "username",
@@ -574,13 +574,13 @@ func TestTURNProxyDialer(t *testing.T) {
 	a, err := NewAgent(&AgentConfig{
 		CandidateTypes: []CandidateType{CandidateTypeRelay},
 		NetworkTypes:   supportedNetworkTypes(),
-		Urls: []*URL{
+		Urls: []*stun.URI{
 			{
-				Scheme:   SchemeTypeTURN,
+				Scheme:   stun.SchemeTypeTURN,
 				Host:     "127.0.0.1",
 				Username: "username",
 				Password: "password",
-				Proto:    ProtoTypeTCP,
+				Proto:    stun.ProtoTypeTCP,
 				Port:     5000,
 			},
 		},
@@ -782,9 +782,9 @@ func TestUniversalUDPMuxUsage(t *testing.T) {
 	}
 
 	numSTUNS := 3
-	urls := []*URL{}
+	urls := []*stun.URI{}
 	for i := 0; i < numSTUNS; i++ {
-		urls = append(urls, &URL{
+		urls = append(urls, &stun.URI{
 			Scheme: SchemeTypeSTUN,
 			Host:   "127.0.0.1",
 			Port:   3478 + i,
diff --git a/gather_vnet_test.go b/gather_vnet_test.go
index 084d279..3f344bd 100644
--- a/gather_vnet_test.go
+++ b/gather_vnet_test.go
@@ -14,6 +14,7 @@ import (
 	"testing"
 
 	"github.com/pion/logging"
+	"github.com/pion/stun"
 	"github.com/pion/transport/v2/test"
 	"github.com/pion/transport/v2/vnet"
 	"github.com/stretchr/testify/assert"
@@ -445,13 +446,13 @@ func TestVNetGather_TURNConnectionLeak(t *testing.T) {
 	report := test.CheckRoutines(t)
 	defer report()
 
-	turnServerURL := &URL{
-		Scheme:   SchemeTypeTURN,
+	turnServerURL := &stun.URI{
+		Scheme:   stun.SchemeTypeTURN,
 		Host:     vnetSTUNServerIP,
 		Port:     vnetSTUNServerPort,
 		Username: "user",
 		Password: "pass",
-		Proto:    ProtoTypeUDP,
+		Proto:    stun.ProtoTypeUDP,
 	}
 
 	// buildVNet with a Symmetric NATs for both LANs
@@ -467,7 +468,7 @@ func TestVNetGather_TURNConnectionLeak(t *testing.T) {
 	defer v.close()
 
 	cfg0 := &AgentConfig{
-		Urls: []*URL{
+		Urls: []*stun.URI{
 			turnServerURL,
 		},
 		NetworkTypes:     supportedNetworkTypes(),
@@ -480,7 +481,7 @@ func TestVNetGather_TURNConnectionLeak(t *testing.T) {
 		return
 	}
 
-	aAgent.gatherCandidatesRelay(context.Background(), []*URL{turnServerURL})
+	aAgent.gatherCandidatesRelay(context.Background(), []*stun.URI{turnServerURL})
 	// Assert relay conn leak on close.
 	assert.NoError(t, aAgent.Close())
 }
diff --git a/ice_test.go b/ice_test.go
index d203d09..5740cd1 100644
--- a/ice_test.go
+++ b/ice_test.go
@@ -14,7 +14,7 @@ func TestConnectedState_String(t *testing.T) {
 		connectionState ConnectionState
 		expectedString  string
 	}{
-		{ConnectionState(Unknown), "Invalid"},
+		{ConnectionStateUnknown, "Invalid"},
 		{ConnectionStateNew, "New"},
 		{ConnectionStateChecking, "Checking"},
 		{ConnectionStateConnected, "Connected"},
@@ -38,7 +38,7 @@ func TestGatheringState_String(t *testing.T) {
 		gatheringState GatheringState
 		expectedString string
 	}{
-		{GatheringState(Unknown), ErrUnknownType.Error()},
+		{GatheringStateUnknown, ErrUnknownType.Error()},
 		{GatheringStateNew, "new"},
 		{GatheringStateGathering, "gathering"},
 		{GatheringStateComplete, "complete"},
diff --git a/transport_test.go b/transport_test.go
index b47287d..c9861a7 100644
--- a/transport_test.go
+++ b/transport_test.go
@@ -13,6 +13,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/pion/stun"
 	"github.com/pion/transport/v2/test"
 )
 
@@ -228,7 +229,7 @@ func connect(aAgent, bAgent *Agent) (*Conn, *Conn) {
 }
 
 func pipe(defaultConfig *AgentConfig) (*Conn, *Conn) {
-	var urls []*URL
+	var urls []*stun.URI
 
 	aNotifier, aConnected := onConnected()
 	bNotifier, bConnected := onConnected()
@@ -261,7 +262,7 @@ func pipe(defaultConfig *AgentConfig) (*Conn, *Conn) {
 }
 
 func pipeWithTimeout(disconnectTimeout time.Duration, iceKeepalive time.Duration) (*Conn, *Conn) {
-	var urls []*URL
+	var urls []*stun.URI
 
 	aNotifier, aConnected := onConnected()
 	bNotifier, bConnected := onConnected()
diff --git a/transport_vnet_test.go b/transport_vnet_test.go
index ffdfd38..976cf73 100644
--- a/transport_vnet_test.go
+++ b/transport_vnet_test.go
@@ -12,6 +12,7 @@ import (
 	"testing"
 	"time"
 
+	"github.com/pion/stun"
 	"github.com/pion/transport/v2/test"
 	"github.com/pion/transport/v2/vnet"
 	"github.com/stretchr/testify/assert"
@@ -37,11 +38,11 @@ func TestRemoteLocalAddr(t *testing.T) {
 	}
 	defer v.close()
 
-	stunServerURL := &URL{
-		Scheme: SchemeTypeSTUN,
+	stunServerURL := &stun.URI{
+		Scheme: stun.SchemeTypeSTUN,
 		Host:   vnetSTUNServerIP,
 		Port:   vnetSTUNServerPort,
-		Proto:  ProtoTypeUDP,
+		Proto:  stun.ProtoTypeUDP,
 	}
 
 	t.Run("Disconnected Returns nil", func(t *testing.T) {
@@ -58,10 +59,10 @@ func TestRemoteLocalAddr(t *testing.T) {
 	t.Run("Remote/Local Pair Match between Agents", func(t *testing.T) {
 		ca, cb := pipeWithVNet(v,
 			&agentTestConfig{
-				urls: []*URL{stunServerURL},
+				urls: []*stun.URI{stunServerURL},
 			},
 			&agentTestConfig{
-				urls: []*URL{stunServerURL},
+				urls: []*stun.URI{stunServerURL},
 			},
 		)
 
diff --git a/url_test.go b/url_test.go
deleted file mode 100644
index 9c010c5..0000000
--- a/url_test.go
+++ /dev/null
@@ -1,87 +0,0 @@
-// SPDX-FileCopyrightText: 2023 The Pion community <https://pion.ly>
-// SPDX-License-Identifier: MIT
-
-package ice
-
-import (
-	"errors"
-	"fmt"
-	"net"
-	"net/url"
-	"testing"
-
-	"github.com/stretchr/testify/assert"
-)
-
-func TestParseURL(t *testing.T) {
-	t.Run("Success", func(t *testing.T) {
-		testCases := []struct {
-			rawURL            string
-			expectedURLString string
-			expectedScheme    SchemeType
-			expectedSecure    bool
-			expectedHost      string
-			expectedPort      int
-			expectedProto     ProtoType
-		}{
-			{"stun:google.de", "stun:google.de:3478", SchemeTypeSTUN, false, "google.de", 3478, ProtoTypeUDP},
-			{"stun:google.de:1234", "stun:google.de:1234", SchemeTypeSTUN, false, "google.de", 1234, ProtoTypeUDP},
-			{"stuns:google.de", "stuns:google.de:5349", SchemeTypeSTUNS, true, "google.de", 5349, ProtoTypeTCP},
-			{"stun:[::1]:123", "stun:[::1]:123", SchemeTypeSTUN, false, "::1", 123, ProtoTypeUDP},
-			{"turn:google.de", "turn:google.de:3478?transport=udp", SchemeTypeTURN, false, "google.de", 3478, ProtoTypeUDP},
-			{"turns:google.de", "turns:google.de:5349?transport=tcp", SchemeTypeTURNS, true, "google.de", 5349, ProtoTypeTCP},
-			{"turn:google.de?transport=udp", "turn:google.de:3478?transport=udp", SchemeTypeTURN, false, "google.de", 3478, ProtoTypeUDP},
-			{"turns:google.de?transport=tcp", "turns:google.de:5349?transport=tcp", SchemeTypeTURNS, true, "google.de", 5349, ProtoTypeTCP},
-		}
-
-		for i, testCase := range testCases {
-			url, err := ParseURL(testCase.rawURL)
-			assert.Nil(t, err, "testCase: %d %v", i, testCase)
-			if err != nil {
-				return
-			}
-
-			assert.Equal(t, testCase.expectedScheme, url.Scheme, "testCase: %d %v", i, testCase)
-			assert.Equal(t, testCase.expectedURLString, url.String(), "testCase: %d %v", i, testCase)
-			assert.Equal(t, testCase.expectedSecure, url.IsSecure(), "testCase: %d %v", i, testCase)
-			assert.Equal(t, testCase.expectedHost, url.Host, "testCase: %d %v", i, testCase)
-			assert.Equal(t, testCase.expectedPort, url.Port, "testCase: %d %v", i, testCase)
-			assert.Equal(t, testCase.expectedProto, url.Proto, "testCase: %d %v", i, testCase)
-		}
-	})
-	t.Run("Failure", func(t *testing.T) {
-		testCases := []struct {
-			rawURL      string
-			expectedErr error
-		}{
-			{"", ErrSchemeType},
-			{":::", errMissingProtocolScheme},
-			{"stun:[::1]:123:", errTooManyColonsAddr},
-			{"stun:[::1]:123a", ErrPort},
-			{"google.de", ErrSchemeType},
-			{"stun:", ErrHost},
-			{"stun:google.de:abc", ErrPort},
-			{"stun:google.de?transport=udp", ErrSTUNQuery},
-			{"stuns:google.de?transport=udp", ErrSTUNQuery},
-			{"turn:google.de?trans=udp", ErrInvalidQuery},
-			{"turns:google.de?trans=udp", ErrInvalidQuery},
-			{"turns:google.de?transport=udp&another=1", ErrInvalidQuery},
-			{"turn:google.de?transport=ip", ErrProtoType},
-		}
-
-		for i, testCase := range testCases {
-			_, err := ParseURL(testCase.rawURL)
-			var (
-				urlError  *url.Error
-				addrError *net.AddrError
-			)
-			switch {
-			case errors.As(err, &urlError):
-				err = urlError.Err
-			case errors.As(err, &addrError):
-				err = fmt.Errorf(addrError.Err) //nolint:goerr113
-			}
-			assert.EqualError(t, err, testCase.expectedErr.Error(), "testCase: %d %v", i, testCase)
-		}
-	})
-}