1package stun
2
3import "errors"
4
5// UnknownAttributes represents UNKNOWN-ATTRIBUTES attribute.
6//
7// RFC 5389 Section 15.9
8type UnknownAttributes []AttrType
9
10func (a UnknownAttributes) String() string {
11	s := ""
12	if len(a) == 0 {
13		return "<nil>"
14	}
15	last := len(a) - 1
16	for i, t := range a {
17		s += t.String()
18		if i != last {
19			s += ", "
20		}
21	}
22	return s
23}
24
25// type size is 16 bit.
26const attrTypeSize = 4
27
28// AddTo adds UNKNOWN-ATTRIBUTES attribute to message.
29func (a UnknownAttributes) AddTo(m *Message) error {
30	v := make([]byte, 0, attrTypeSize*20) // 20 should be enough
31	// If len(a.Types) > 20, there will be allocations.
32	for i, t := range a {
33		v = append(v, 0, 0, 0, 0) // 4 times by 0 (16 bits)
34		first := attrTypeSize * i
35		last := first + attrTypeSize
36		bin.PutUint16(v[first:last], t.Value())
37	}
38	m.Add(AttrUnknownAttributes, v)
39	return nil
40}
41
42// ErrBadUnknownAttrsSize means that UNKNOWN-ATTRIBUTES attribute value
43// has invalid length.
44var ErrBadUnknownAttrsSize = errors.New("bad UNKNOWN-ATTRIBUTES size")
45
46// GetFrom parses UNKNOWN-ATTRIBUTES from message.
47func (a *UnknownAttributes) GetFrom(m *Message) error {
48	v, err := m.Get(AttrUnknownAttributes)
49	if err != nil {
50		return err
51	}
52	if len(v)%attrTypeSize != 0 {
53		return ErrBadUnknownAttrsSize
54	}
55	*a = (*a)[:0]
56	first := 0
57	for first < len(v) {
58		last := first + attrTypeSize
59		*a = append(*a, AttrType(bin.Uint16(v[first:last])))
60		first = last
61	}
62	return nil
63}
64