diff options
Diffstat (limited to 'vendor/github.com/pion/turn/v2/internal/proto')
14 files changed, 815 insertions, 0 deletions
diff --git a/vendor/github.com/pion/turn/v2/internal/proto/addr.go b/vendor/github.com/pion/turn/v2/internal/proto/addr.go new file mode 100644 index 0000000..b1d654d --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/addr.go @@ -0,0 +1,65 @@ +package proto + +import ( + "fmt" + "net" +) + +// Addr is ip:port. +type Addr struct { + IP net.IP + Port int +} + +// Network implements net.Addr. +func (Addr) Network() string { return "turn" } + +// FromUDPAddr sets addr to UDPAddr. +func (a *Addr) FromUDPAddr(n *net.UDPAddr) { + a.IP = n.IP + a.Port = n.Port +} + +// Equal returns true if b == a. +func (a Addr) Equal(b Addr) bool { + if a.Port != b.Port { + return false + } + return a.IP.Equal(b.IP) +} + +// EqualIP returns true if a and b have equal IP addresses. +func (a Addr) EqualIP(b Addr) bool { + return a.IP.Equal(b.IP) +} + +func (a Addr) String() string { + return fmt.Sprintf("%s:%d", a.IP, a.Port) +} + +// FiveTuple represents 5-TUPLE value. +type FiveTuple struct { + Client Addr + Server Addr + Proto Protocol +} + +func (t FiveTuple) String() string { + return fmt.Sprintf("%s->%s (%s)", + t.Client, t.Server, t.Proto, + ) +} + +// Equal returns true if b == t. +func (t FiveTuple) Equal(b FiveTuple) bool { + if t.Proto != b.Proto { + return false + } + if !t.Client.Equal(b.Client) { + return false + } + if !t.Server.Equal(b.Server) { + return false + } + return true +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/chandata.go b/vendor/github.com/pion/turn/v2/internal/proto/chandata.go new file mode 100644 index 0000000..fb1295b --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/chandata.go @@ -0,0 +1,140 @@ +package proto + +import ( + "bytes" + "encoding/binary" + "errors" + "io" +) + +// ChannelData represents The ChannelData Message. +// +// See RFC 5766 Section 11.4 +type ChannelData struct { + Data []byte // can be subslice of Raw + Length int // ignored while encoding, len(Data) is used + Number ChannelNumber + Raw []byte +} + +// Equal returns true if b == c. +func (c *ChannelData) Equal(b *ChannelData) bool { + if c == nil && b == nil { + return true + } + if c == nil || b == nil { + return false + } + if c.Number != b.Number { + return false + } + if len(c.Data) != len(b.Data) { + return false + } + return bytes.Equal(c.Data, b.Data) +} + +// grow ensures that internal buffer will fit v more bytes and +// increases it capacity if necessary. +// +// Similar to stun.Message.grow method. +func (c *ChannelData) grow(v int) { + n := len(c.Raw) + v + for cap(c.Raw) < n { + c.Raw = append(c.Raw, 0) + } + c.Raw = c.Raw[:n] +} + +// Reset resets Length, Data and Raw length. +func (c *ChannelData) Reset() { + c.Raw = c.Raw[:0] + c.Length = 0 + c.Data = c.Data[:0] +} + +// Encode encodes ChannelData Message to Raw. +func (c *ChannelData) Encode() { + c.Raw = c.Raw[:0] + c.WriteHeader() + c.Raw = append(c.Raw, c.Data...) + padded := nearestPaddedValueLength(len(c.Raw)) + if bytesToAdd := padded - len(c.Raw); bytesToAdd > 0 { + for i := 0; i < bytesToAdd; i++ { + c.Raw = append(c.Raw, 0) + } + } +} + +const padding = 4 + +func nearestPaddedValueLength(l int) int { + n := padding * (l / padding) + if n < l { + n += padding + } + return n +} + +// WriteHeader writes channel number and length. +func (c *ChannelData) WriteHeader() { + if len(c.Raw) < channelDataHeaderSize { + // Making WriteHeader call valid even when c.Raw + // is nil or len(c.Raw) is less than needed for header. + c.grow(channelDataHeaderSize) + } + // Early bounds check to guarantee safety of writes below. + _ = c.Raw[:channelDataHeaderSize] + binary.BigEndian.PutUint16(c.Raw[:channelDataNumberSize], uint16(c.Number)) + binary.BigEndian.PutUint16(c.Raw[channelDataNumberSize:channelDataHeaderSize], + uint16(len(c.Data)), + ) +} + +// ErrBadChannelDataLength means that channel data length is not equal +// to actual data length. +var ErrBadChannelDataLength = errors.New("channelData length != len(Data)") + +// Decode decodes The ChannelData Message from Raw. +func (c *ChannelData) Decode() error { + buf := c.Raw + if len(buf) < channelDataHeaderSize { + return io.ErrUnexpectedEOF + } + num := binary.BigEndian.Uint16(buf[:channelDataNumberSize]) + c.Number = ChannelNumber(num) + l := binary.BigEndian.Uint16(buf[channelDataNumberSize:channelDataHeaderSize]) + c.Data = buf[channelDataHeaderSize:] + c.Length = int(l) + if !c.Number.Valid() { + return ErrInvalidChannelNumber + } + if int(l) < len(c.Data) { + c.Data = c.Data[:int(l)] + } + if int(l) > len(buf[channelDataHeaderSize:]) { + return ErrBadChannelDataLength + } + return nil +} + +const ( + channelDataLengthSize = 2 + channelDataNumberSize = channelDataLengthSize + channelDataHeaderSize = channelDataLengthSize + channelDataNumberSize +) + +// IsChannelData returns true if buf looks like the ChannelData Message. +func IsChannelData(buf []byte) bool { + if len(buf) < channelDataHeaderSize { + return false + } + + if int(binary.BigEndian.Uint16(buf[channelDataNumberSize:channelDataHeaderSize])) > len(buf[channelDataHeaderSize:]) { + return false + } + + // Quick check for channel number. + num := binary.BigEndian.Uint16(buf[0:channelNumberSize]) + return isChannelNumberValid(num) +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/chann.go b/vendor/github.com/pion/turn/v2/internal/proto/chann.go new file mode 100644 index 0000000..d64ef73 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/chann.go @@ -0,0 +1,67 @@ +package proto + +import ( + "encoding/binary" + "errors" + "strconv" + + "github.com/pion/stun" +) + +// ChannelNumber represents CHANNEL-NUMBER attribute. +// +// The CHANNEL-NUMBER attribute contains the number of the channel. +// +// RFC 5766 Section 14.1 +type ChannelNumber uint16 // encoded as uint16 + +func (n ChannelNumber) String() string { return strconv.Itoa(int(n)) } + +// 16 bits of uint + 16 bits of RFFU = 0. +const channelNumberSize = 4 + +// AddTo adds CHANNEL-NUMBER to message. +func (n ChannelNumber) AddTo(m *stun.Message) error { + v := make([]byte, channelNumberSize) + binary.BigEndian.PutUint16(v[:2], uint16(n)) + // v[2:4] are zeroes (RFFU = 0) + m.Add(stun.AttrChannelNumber, v) + return nil +} + +// GetFrom decodes CHANNEL-NUMBER from message. +func (n *ChannelNumber) GetFrom(m *stun.Message) error { + v, err := m.Get(stun.AttrChannelNumber) + if err != nil { + return err + } + if err = stun.CheckSize(stun.AttrChannelNumber, len(v), channelNumberSize); err != nil { + return err + } + _ = v[channelNumberSize-1] // asserting length + *n = ChannelNumber(binary.BigEndian.Uint16(v[:2])) + // v[2:4] is RFFU and equals to 0. + return nil +} + +// See https://tools.ietf.org/html/rfc5766#section-11: +// +// 0x4000 through 0x7FFF: These values are the allowed channel +// numbers (16,383 possible values). +const ( + MinChannelNumber = 0x4000 + MaxChannelNumber = 0x7FFF +) + +// ErrInvalidChannelNumber means that channel number is not valid as by RFC 5766 Section 11. +var ErrInvalidChannelNumber = errors.New("channel number not in [0x4000, 0x7FFF]") + +// isChannelNumberValid returns true if c in [0x4000, 0x7FFF]. +func isChannelNumberValid(c uint16) bool { + return c >= MinChannelNumber && c <= MaxChannelNumber +} + +// Valid returns true if channel number has correct value that complies RFC 5766 Section 11 range. +func (n ChannelNumber) Valid() bool { + return isChannelNumberValid(uint16(n)) +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/data.go b/vendor/github.com/pion/turn/v2/internal/proto/data.go new file mode 100644 index 0000000..64243e0 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/data.go @@ -0,0 +1,30 @@ +package proto + +import "github.com/pion/stun" + +// Data represents DATA attribute. +// +// The DATA attribute is present in all Send and Data indications. The +// value portion of this attribute is variable length and consists of +// the application data (that is, the data that would immediately follow +// the UDP header if the data was been sent directly between the client +// and the peer). +// +// RFC 5766 Section 14.4 +type Data []byte + +// AddTo adds DATA to message. +func (d Data) AddTo(m *stun.Message) error { + m.Add(stun.AttrData, d) + return nil +} + +// GetFrom decodes DATA from message. +func (d *Data) GetFrom(m *stun.Message) error { + v, err := m.Get(stun.AttrData) + if err != nil { + return err + } + *d = v + return nil +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/dontfrag.go b/vendor/github.com/pion/turn/v2/internal/proto/dontfrag.go new file mode 100644 index 0000000..eb4d8ca --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/dontfrag.go @@ -0,0 +1,18 @@ +package proto + +import "github.com/pion/stun" + +// DontFragmentAttr represents DONT-FRAGMENT attribute. +type DontFragmentAttr struct{} + +// AddTo adds DONT-FRAGMENT attribute to message. +func (DontFragmentAttr) AddTo(m *stun.Message) error { + m.Add(stun.AttrDontFragment, nil) + return nil +} + +// IsSet returns true if DONT-FRAGMENT attribute is set. +func (DontFragmentAttr) IsSet(m *stun.Message) bool { + _, err := m.Get(stun.AttrDontFragment) + return err == nil +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/evenport.go b/vendor/github.com/pion/turn/v2/internal/proto/evenport.go new file mode 100644 index 0000000..a5a3882 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/evenport.go @@ -0,0 +1,55 @@ +package proto + +import "github.com/pion/stun" + +// EvenPort represents EVEN-PORT attribute. +// +// This attribute allows the client to request that the port in the +// relayed transport address be even, and (optionally) that the server +// reserve the next-higher port number. +// +// RFC 5766 Section 14.6 +type EvenPort struct { + // ReservePort means that the server is requested to reserve + // the next-higher port number (on the same IP address) + // for a subsequent allocation. + ReservePort bool +} + +func (p EvenPort) String() string { + if p.ReservePort { + return "reserve: true" + } + return "reserve: false" +} + +const ( + evenPortSize = 1 + firstBitSet = (1 << 8) - 1 // 0b100000000 +) + +// AddTo adds EVEN-PORT to message. +func (p EvenPort) AddTo(m *stun.Message) error { + v := make([]byte, evenPortSize) + if p.ReservePort { + // Set first bit to 1. + v[0] = firstBitSet + } + m.Add(stun.AttrEvenPort, v) + return nil +} + +// GetFrom decodes EVEN-PORT from message. +func (p *EvenPort) GetFrom(m *stun.Message) error { + v, err := m.Get(stun.AttrEvenPort) + if err != nil { + return err + } + if err = stun.CheckSize(stun.AttrEvenPort, len(v), evenPortSize); err != nil { + return err + } + if v[0]&firstBitSet > 0 { + p.ReservePort = true + } + return nil +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/fuzz.go b/vendor/github.com/pion/turn/v2/internal/proto/fuzz.go new file mode 100644 index 0000000..1a171fb --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/fuzz.go @@ -0,0 +1,111 @@ +// +build gofuzz + +package proto + +import ( + "fmt" + + "github.com/pion/stun" +) + +type attr interface { + stun.Getter + stun.Setter +} + +type attrs []struct { + g attr + t stun.AttrType +} + +func (a attrs) pick(v byte) struct { + g attr + t stun.AttrType +} { + idx := int(v) % len(a) + return a[idx] +} + +func FuzzSetters(data []byte) int { + var ( + m1 = &stun.Message{ + Raw: make([]byte, 0, 2048), + } + m2 = &stun.Message{ + Raw: make([]byte, 0, 2048), + } + m3 = &stun.Message{ + Raw: make([]byte, 0, 2048), + } + ) + attributes := attrs{ + {new(RequestedTransport), stun.AttrRequestedTransport}, + {new(RelayedAddress), stun.AttrXORRelayedAddress}, + {new(ChannelNumber), stun.AttrChannelNumber}, + {new(Data), stun.AttrData}, + {new(EvenPort), stun.AttrEvenPort}, + {new(Lifetime), stun.AttrLifetime}, + {new(ReservationToken), stun.AttrReservationToken}, + } + var firstByte = byte(0) + if len(data) > 0 { + firstByte = data[0] + } + a := attributes.pick(firstByte) + value := data + if len(data) > 1 { + value = value[1:] + } + m1.WriteHeader() + m1.Add(a.t, value) + err := a.g.GetFrom(m1) + if err == stun.ErrAttributeNotFound { + fmt.Println("unexpected 404") // nolint + panic(err) // nolint + } + if err != nil { + return 1 + } + m2.WriteHeader() + if err := a.g.AddTo(m2); err != nil { + fmt.Println("failed to add attribute to m2") // nolint + panic(err) // nolint + } + m3.WriteHeader() + v, err := m2.Get(a.t) + if err != nil { + panic(err) // nolint + } + m3.Add(a.t, v) + + if !m2.Equal(m3) { + fmt.Println(m2, "not equal", m3) // nolint + panic("not equal") // nolint + } + return 1 +} + +var d = &ChannelData{} + +func FuzzChannelData(data []byte) int { + d.Reset() + if b := bin.Uint16(data[0:4]); b > 20000 { + bin.PutUint16(data[0:4], MinChannelNumber-1) + } else if b > 40000 { + bin.PutUint16(data[0:4], MinChannelNumber+(MaxChannelNumber-MinChannelNumber)%b) + } + d.Raw = append(d.Raw, data...) + if d.Decode() != nil { + return 0 + } + d2 := &ChannelData{} + d.Encode() + if !d.Number.Valid() { + return 1 + } + d2.Raw = d.Raw + if err := d2.Decode(); err != nil { + panic(err) //nolint + } + return 1 +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/lifetime.go b/vendor/github.com/pion/turn/v2/internal/proto/lifetime.go new file mode 100644 index 0000000..b781696 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/lifetime.go @@ -0,0 +1,52 @@ +package proto + +import ( + "encoding/binary" + "time" + + "github.com/pion/stun" +) + +// DefaultLifetime in RFC 5766 is 10 minutes. +// +// RFC 5766 Section 2.2 +const DefaultLifetime = time.Minute * 10 + +// Lifetime represents LIFETIME attribute. +// +// The LIFETIME attribute represents the duration for which the server +// will maintain an allocation in the absence of a refresh. The value +// portion of this attribute is 4-bytes long and consists of a 32-bit +// unsigned integral value representing the number of seconds remaining +// until expiration. +// +// RFC 5766 Section 14.2 +type Lifetime struct { + time.Duration +} + +// uint32 seconds +const lifetimeSize = 4 // 4 bytes, 32 bits + +// AddTo adds LIFETIME to message. +func (l Lifetime) AddTo(m *stun.Message) error { + v := make([]byte, lifetimeSize) + binary.BigEndian.PutUint32(v, uint32(l.Seconds())) + m.Add(stun.AttrLifetime, v) + return nil +} + +// GetFrom decodes LIFETIME from message. +func (l *Lifetime) GetFrom(m *stun.Message) error { + v, err := m.Get(stun.AttrLifetime) + if err != nil { + return err + } + if err = stun.CheckSize(stun.AttrLifetime, len(v), lifetimeSize); err != nil { + return err + } + _ = v[lifetimeSize-1] // asserting length + seconds := binary.BigEndian.Uint32(v) + l.Duration = time.Second * time.Duration(seconds) + return nil +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/peeraddr.go b/vendor/github.com/pion/turn/v2/internal/proto/peeraddr.go new file mode 100644 index 0000000..b357b82 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/peeraddr.go @@ -0,0 +1,42 @@ +package proto + +import ( + "net" + + "github.com/pion/stun" +) + +// PeerAddress implements XOR-PEER-ADDRESS attribute. +// +// The XOR-PEER-ADDRESS specifies the address and port of the peer as +// seen from the TURN server. (For example, the peer's server-reflexive +// transport address if the peer is behind a NAT.) +// +// RFC 5766 Section 14.3 +type PeerAddress struct { + IP net.IP + Port int +} + +func (a PeerAddress) String() string { + return stun.XORMappedAddress(a).String() +} + +// AddTo adds XOR-PEER-ADDRESS to message. +func (a PeerAddress) AddTo(m *stun.Message) error { + return stun.XORMappedAddress(a).AddToAs(m, stun.AttrXORPeerAddress) +} + +// GetFrom decodes XOR-PEER-ADDRESS from message. +func (a *PeerAddress) GetFrom(m *stun.Message) error { + return (*stun.XORMappedAddress)(a).GetFromAs(m, stun.AttrXORPeerAddress) +} + +// XORPeerAddress implements XOR-PEER-ADDRESS attribute. +// +// The XOR-PEER-ADDRESS specifies the address and port of the peer as +// seen from the TURN server. (For example, the peer's server-reflexive +// transport address if the peer is behind a NAT.) +// +// RFC 5766 Section 14.3 +type XORPeerAddress = PeerAddress diff --git a/vendor/github.com/pion/turn/v2/internal/proto/proto.go b/vendor/github.com/pion/turn/v2/internal/proto/proto.go new file mode 100644 index 0000000..4b08c76 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/proto.go @@ -0,0 +1,30 @@ +// Package proto implements RFC 5766 Traversal Using Relays around NAT. +// +// Merged from gortc/turn v0.80. +package proto + +import ( + "github.com/pion/stun" +) + +// Default ports for TURN from RFC 5766 Section 4. +const ( + // DefaultPort for TURN is same as STUN. + DefaultPort = stun.DefaultPort + // DefaultTLSPort is for TURN over TLS and is same as STUN. + DefaultTLSPort = stun.DefaultTLSPort +) + +// CreatePermissionRequest is shorthand for create permission request type. +func CreatePermissionRequest() stun.MessageType { + return stun.NewType(stun.MethodCreatePermission, stun.ClassRequest) +} + +// AllocateRequest is shorthand for allocation request message type. +func AllocateRequest() stun.MessageType { return stun.NewType(stun.MethodAllocate, stun.ClassRequest) } + +// SendIndication is shorthand for send indication message type. +func SendIndication() stun.MessageType { return stun.NewType(stun.MethodSend, stun.ClassIndication) } + +// RefreshRequest is shorthand for refresh request message type. +func RefreshRequest() stun.MessageType { return stun.NewType(stun.MethodRefresh, stun.ClassRequest) } diff --git a/vendor/github.com/pion/turn/v2/internal/proto/relayedaddr.go b/vendor/github.com/pion/turn/v2/internal/proto/relayedaddr.go new file mode 100644 index 0000000..2169cb7 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/relayedaddr.go @@ -0,0 +1,40 @@ +package proto + +import ( + "net" + + "github.com/pion/stun" +) + +// RelayedAddress implements XOR-RELAYED-ADDRESS attribute. +// +// It specifies the address and port that the server allocated to the +// client. It is encoded in the same way as XOR-MAPPED-ADDRESS. +// +// RFC 5766 Section 14.5 +type RelayedAddress struct { + IP net.IP + Port int +} + +func (a RelayedAddress) String() string { + return stun.XORMappedAddress(a).String() +} + +// AddTo adds XOR-PEER-ADDRESS to message. +func (a RelayedAddress) AddTo(m *stun.Message) error { + return stun.XORMappedAddress(a).AddToAs(m, stun.AttrXORRelayedAddress) +} + +// GetFrom decodes XOR-PEER-ADDRESS from message. +func (a *RelayedAddress) GetFrom(m *stun.Message) error { + return (*stun.XORMappedAddress)(a).GetFromAs(m, stun.AttrXORRelayedAddress) +} + +// XORRelayedAddress implements XOR-RELAYED-ADDRESS attribute. +// +// It specifies the address and port that the server allocated to the +// client. It is encoded in the same way as XOR-MAPPED-ADDRESS. +// +// RFC 5766 Section 14.5 +type XORRelayedAddress = RelayedAddress diff --git a/vendor/github.com/pion/turn/v2/internal/proto/reqfamily.go b/vendor/github.com/pion/turn/v2/internal/proto/reqfamily.go new file mode 100644 index 0000000..e83d6bb --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/reqfamily.go @@ -0,0 +1,61 @@ +package proto + +import ( + "errors" + + "github.com/pion/stun" +) + +// RequestedAddressFamily represents the REQUESTED-ADDRESS-FAMILY Attribute as +// defined in RFC 6156 Section 4.1.1. +type RequestedAddressFamily byte + +const requestedFamilySize = 4 + +var errInvalidRequestedFamilyValue = errors.New("invalid value for requested family attribute") + +// GetFrom decodes REQUESTED-ADDRESS-FAMILY from message. +func (f *RequestedAddressFamily) GetFrom(m *stun.Message) error { + v, err := m.Get(stun.AttrRequestedAddressFamily) + if err != nil { + return err + } + if err = stun.CheckSize(stun.AttrRequestedAddressFamily, len(v), requestedFamilySize); err != nil { + return err + } + switch v[0] { + case byte(RequestedFamilyIPv4), byte(RequestedFamilyIPv6): + *f = RequestedAddressFamily(v[0]) + default: + return errInvalidRequestedFamilyValue + } + return nil +} + +func (f RequestedAddressFamily) String() string { + switch f { + case RequestedFamilyIPv4: + return "IPv4" + case RequestedFamilyIPv6: + return "IPv6" + default: + return "unknown" + } +} + +// AddTo adds REQUESTED-ADDRESS-FAMILY to message. +func (f RequestedAddressFamily) AddTo(m *stun.Message) error { + v := make([]byte, requestedFamilySize) + v[0] = byte(f) + // b[1:4] is RFFU = 0. + // The RFFU field MUST be set to zero on transmission and MUST be + // ignored on reception. It is reserved for future uses. + m.Add(stun.AttrRequestedAddressFamily, v) + return nil +} + +// Values for RequestedAddressFamily as defined in RFC 6156 Section 4.1.1. +const ( + RequestedFamilyIPv4 RequestedAddressFamily = 0x01 + RequestedFamilyIPv6 RequestedAddressFamily = 0x02 +) diff --git a/vendor/github.com/pion/turn/v2/internal/proto/reqtrans.go b/vendor/github.com/pion/turn/v2/internal/proto/reqtrans.go new file mode 100644 index 0000000..a4e4863 --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/reqtrans.go @@ -0,0 +1,65 @@ +package proto + +import ( + "strconv" + + "github.com/pion/stun" +) + +// Protocol is IANA assigned protocol number. +type Protocol byte + +const ( + // ProtoUDP is IANA assigned protocol number for UDP. + ProtoUDP Protocol = 17 +) + +func (p Protocol) String() string { + switch p { + case ProtoUDP: + return "UDP" + default: + return strconv.Itoa(int(p)) + } +} + +// RequestedTransport represents REQUESTED-TRANSPORT attribute. +// +// This attribute is used by the client to request a specific transport +// protocol for the allocated transport address. RFC 5766 only allows the use of +// codepoint 17 (User Datagram Protocol). +// +// RFC 5766 Section 14.7 +type RequestedTransport struct { + Protocol Protocol +} + +func (t RequestedTransport) String() string { + return "protocol: " + t.Protocol.String() +} + +const requestedTransportSize = 4 + +// AddTo adds REQUESTED-TRANSPORT to message. +func (t RequestedTransport) AddTo(m *stun.Message) error { + v := make([]byte, requestedTransportSize) + v[0] = byte(t.Protocol) + // b[1:4] is RFFU = 0. + // The RFFU field MUST be set to zero on transmission and MUST be + // ignored on reception. It is reserved for future uses. + m.Add(stun.AttrRequestedTransport, v) + return nil +} + +// GetFrom decodes REQUESTED-TRANSPORT from message. +func (t *RequestedTransport) GetFrom(m *stun.Message) error { + v, err := m.Get(stun.AttrRequestedTransport) + if err != nil { + return err + } + if err = stun.CheckSize(stun.AttrRequestedTransport, len(v), requestedTransportSize); err != nil { + return err + } + t.Protocol = Protocol(v[0]) + return nil +} diff --git a/vendor/github.com/pion/turn/v2/internal/proto/rsrvtoken.go b/vendor/github.com/pion/turn/v2/internal/proto/rsrvtoken.go new file mode 100644 index 0000000..6e2ed4d --- /dev/null +++ b/vendor/github.com/pion/turn/v2/internal/proto/rsrvtoken.go @@ -0,0 +1,39 @@ +package proto + +import "github.com/pion/stun" + +// ReservationToken represents RESERVATION-TOKEN attribute. +// +// The RESERVATION-TOKEN attribute contains a token that uniquely +// identifies a relayed transport address being held in reserve by the +// server. The server includes this attribute in a success response to +// tell the client about the token, and the client includes this +// attribute in a subsequent Allocate request to request the server use +// that relayed transport address for the allocation. +// +// RFC 5766 Section 14.9 +type ReservationToken []byte + +const reservationTokenSize = 8 // 8 bytes + +// AddTo adds RESERVATION-TOKEN to message. +func (t ReservationToken) AddTo(m *stun.Message) error { + if err := stun.CheckSize(stun.AttrReservationToken, len(t), reservationTokenSize); err != nil { + return err + } + m.Add(stun.AttrReservationToken, t) + return nil +} + +// GetFrom decodes RESERVATION-TOKEN from message. +func (t *ReservationToken) GetFrom(m *stun.Message) error { + v, err := m.Get(stun.AttrReservationToken) + if err != nil { + return err + } + if err = stun.CheckSize(stun.AttrReservationToken, len(v), reservationTokenSize); err != nil { + return err + } + *t = v + return nil +} |