Skip to content

Commit

Permalink
all: add missing STUN attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
ernado committed May 20, 2019
1 parent 8abdb7f commit 8d90138
Show file tree
Hide file tree
Showing 6 changed files with 333 additions and 0 deletions.
83 changes: 83 additions & 0 deletions icecontrol.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package ice

import "github.com/gortc/stun"

// tiebreaker is common helper for ICE-{CONTROLLED,CONTROLLING}
// and represents the so-called tiebreaker number.
type tiebreaker uint64

const tiebreakerSize = 8 // 64 bit

// AddToAs adds tiebreaker value to m as t attribute.
func (a tiebreaker) AddToAs(m *stun.Message, t stun.AttrType) error {
v := make([]byte, tiebreakerSize)
bin.PutUint64(v, uint64(a))
m.Add(t, v)
return nil
}

// GetFromAs decodes tiebreaker value in message getting it as for t type.
func (a *tiebreaker) GetFromAs(m *stun.Message, t stun.AttrType) error {
v, err := m.Get(t)
if err != nil {
return err
}
if err = stun.CheckSize(t, len(v), tiebreakerSize); err != nil {
return err
}
*a = tiebreaker(bin.Uint64(v))
return nil
}

// AttrControlled represents ICE-CONTROLLED attribute.
type AttrControlled uint64

// AddTo adds ICE-CONTROLLED to message.
func (c AttrControlled) AddTo(m *stun.Message) error {
return tiebreaker(c).AddToAs(m, stun.AttrICEControlled)
}

// GetFrom decodes ICE-CONTROLLED from message.
func (c *AttrControlled) GetFrom(m *stun.Message) error {
return (*tiebreaker)(c).GetFromAs(m, stun.AttrICEControlled)
}

// AttrControlling represents ICE-CONTROLLING attribute.
type AttrControlling uint64

// AddTo adds ICE-CONTROLLING to message.
func (c AttrControlling) AddTo(m *stun.Message) error {
return tiebreaker(c).AddToAs(m, stun.AttrICEControlling)
}

// GetFrom decodes ICE-CONTROLLING from message.
func (c *AttrControlling) GetFrom(m *stun.Message) error {
return (*tiebreaker)(c).GetFromAs(m, stun.AttrICEControlling)
}

// AttrControl is helper that wraps ICE-{CONTROLLED,CONTROLLING}.
type AttrControl struct {
Role Role
Tiebreaker uint64
}

// AddTo adds ICE-CONTROLLED or ICE-CONTROLLING attribute depending on Role.
func (c AttrControl) AddTo(m *stun.Message) error {
if c.Role == Controlling {
return tiebreaker(c.Tiebreaker).AddToAs(m, stun.AttrICEControlling)
}
return tiebreaker(c.Tiebreaker).AddToAs(m, stun.AttrICEControlled)
}

// GetFrom decodes Role and Tiebreaker value from message.
func (c *AttrControl) GetFrom(m *stun.Message) error {
if m.Contains(stun.AttrICEControlling) {
c.Role = Controlling
return (*tiebreaker)(&c.Tiebreaker).GetFromAs(m, stun.AttrICEControlling)
}
if m.Contains(stun.AttrICEControlled) {
c.Role = Controlled
return (*tiebreaker)(&c.Tiebreaker).GetFromAs(m, stun.AttrICEControlled)
}
return stun.ErrAttributeNotFound
}
139 changes: 139 additions & 0 deletions icecontrol_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
package ice

import (
"testing"

"github.com/gortc/stun"
)

func TestControlled_GetFrom(t *testing.T) {
m := new(stun.Message)
var c AttrControlled
if err := c.GetFrom(m); err != stun.ErrAttributeNotFound {
t.Error("unexpected error")
}
if err := m.Build(stun.BindingRequest, &c); err != nil {
t.Error(err)
}
m1 := new(stun.Message)
if _, err := m1.Write(m.Raw); err != nil {
t.Error(err)
}
var c1 AttrControlled
if err := c1.GetFrom(m1); err != nil {
t.Error(err)
}
if c1 != c {
t.Error("not equal")
}
t.Run("IncorrectSize", func(t *testing.T) {
m3 := new(stun.Message)
m3.Add(stun.AttrICEControlled, make([]byte, 100))
var c2 AttrControlled
if err := c2.GetFrom(m3); !stun.IsAttrSizeInvalid(err) {
t.Error("should error")
}
})
}

func TestControlling_GetFrom(t *testing.T) {
m := new(stun.Message)
var c AttrControlling
if err := c.GetFrom(m); err != stun.ErrAttributeNotFound {
t.Error("unexpected error")
}
if err := m.Build(stun.BindingRequest, &c); err != nil {
t.Error(err)
}
m1 := new(stun.Message)
if _, err := m1.Write(m.Raw); err != nil {
t.Error(err)
}
var c1 AttrControlling
if err := c1.GetFrom(m1); err != nil {
t.Error(err)
}
if c1 != c {
t.Error("not equal")
}
t.Run("IncorrectSize", func(t *testing.T) {
m3 := new(stun.Message)
m3.Add(stun.AttrICEControlling, make([]byte, 100))
var c2 AttrControlling
if err := c2.GetFrom(m3); !stun.IsAttrSizeInvalid(err) {
t.Error("should error")
}
})
}

func TestControl_GetFrom(t *testing.T) {
t.Run("Blank", func(t *testing.T) {
m := new(stun.Message)
var c AttrControl
if err := c.GetFrom(m); err != stun.ErrAttributeNotFound {
t.Error("unexpected error")
}
})
t.Run("Controlling", func(t *testing.T) {
m := new(stun.Message)
var c AttrControl
if err := c.GetFrom(m); err != stun.ErrAttributeNotFound {
t.Error("unexpected error")
}
c.Role = Controlling
c.Tiebreaker = 4321
if err := m.Build(stun.BindingRequest, &c); err != nil {
t.Error(err)
}
m1 := new(stun.Message)
if _, err := m1.Write(m.Raw); err != nil {
t.Error(err)
}
var c1 AttrControl
if err := c1.GetFrom(m1); err != nil {
t.Error(err)
}
if c1 != c {
t.Error("not equal")
}
t.Run("IncorrectSize", func(t *testing.T) {
m3 := new(stun.Message)
m3.Add(stun.AttrICEControlling, make([]byte, 100))
var c2 AttrControl
if err := c2.GetFrom(m3); !stun.IsAttrSizeInvalid(err) {
t.Error("should error")
}
})
})
t.Run("Controlled", func(t *testing.T) {
m := new(stun.Message)
var c AttrControl
if err := c.GetFrom(m); err != stun.ErrAttributeNotFound {
t.Error("unexpected error")
}
c.Role = Controlled
c.Tiebreaker = 1234
if err := m.Build(stun.BindingRequest, &c); err != nil {
t.Error(err)
}
m1 := new(stun.Message)
if _, err := m1.Write(m.Raw); err != nil {
t.Error(err)
}
var c1 AttrControl
if err := c1.GetFrom(m1); err != nil {
t.Error(err)
}
if c1 != c {
t.Error("not equal")
}
t.Run("IncorrectSize", func(t *testing.T) {
m3 := new(stun.Message)
m3.Add(stun.AttrICEControlling, make([]byte, 100))
var c2 AttrControl
if err := c2.GetFrom(m3); !stun.IsAttrSizeInvalid(err) {
t.Error("should error")
}
})
})
}
29 changes: 29 additions & 0 deletions priority.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
package ice

import "github.com/gortc/stun"

// PriorityAttr represents PRIORITY attribute.
type PriorityAttr uint32

const prioritySize = 4 // 32 bit

// AddTo adds PRIORITY attribute to message.
func (p PriorityAttr) AddTo(m *stun.Message) error {
v := make([]byte, prioritySize)
bin.PutUint32(v, uint32(p))
m.Add(stun.AttrPriority, v)
return nil
}

// GetFrom decodes PRIORITY attribute from message.
func (p *PriorityAttr) GetFrom(m *stun.Message) error {
v, err := m.Get(stun.AttrPriority)
if err != nil {
return err
}
if err = stun.CheckSize(stun.AttrPriority, len(v), prioritySize); err != nil {
return err
}
*p = PriorityAttr(bin.Uint32(v))
return nil
}
37 changes: 37 additions & 0 deletions priority_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
package ice

import (
"testing"

"github.com/gortc/stun"
)

func TestPriority_GetFrom(t *testing.T) {
m := new(stun.Message)
var p PriorityAttr
if err := p.GetFrom(m); err != stun.ErrAttributeNotFound {
t.Error("unexpected error")
}
if err := m.Build(stun.BindingRequest, &p); err != nil {
t.Error(err)
}
m1 := new(stun.Message)
if _, err := m1.Write(m.Raw); err != nil {
t.Error(err)
}
var p1 PriorityAttr
if err := p1.GetFrom(m1); err != nil {
t.Error(err)
}
if p1 != p {
t.Error("not equal")
}
t.Run("IncorrectSize", func(t *testing.T) {
m3 := new(stun.Message)
m3.Add(stun.AttrPriority, make([]byte, 100))
var p2 PriorityAttr
if err := p2.GetFrom(m3); !stun.IsAttrSizeInvalid(err) {
t.Error("should error")
}
})
}
21 changes: 21 additions & 0 deletions usecandidate.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package ice

import "github.com/gortc/stun"

// UseCandidateAttr represents USE-CANDIDATE attribute.
type UseCandidateAttr struct{}

// AddTo adds USE-CANDIDATE attribute to message.
func (UseCandidateAttr) AddTo(m *stun.Message) error {
m.Add(stun.AttrUseCandidate, nil)
return nil
}

// IsSet returns true if USE-CANDIDATE attribute is set.
func (UseCandidateAttr) IsSet(m *stun.Message) bool {
_, err := m.Get(stun.AttrUseCandidate)
return err == nil
}

// UseCandidate is shorthand for UseCandidateAttr.
var UseCandidate UseCandidateAttr
24 changes: 24 additions & 0 deletions usecandidate_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package ice

import (
"testing"

"github.com/gortc/stun"
)

func TestUseCandidateAttr_AddTo(t *testing.T) {
m := new(stun.Message)
if UseCandidate.IsSet(m) {
t.Error("should not be set")
}
if err := m.Build(stun.BindingRequest, UseCandidate); err != nil {
t.Error(err)
}
m1 := new(stun.Message)
if _, err := m1.Write(m.Raw); err != nil {
t.Error(err)
}
if !UseCandidate.IsSet(m1) {
t.Error("should be set")
}
}

0 comments on commit 8d90138

Please sign in to comment.