1package stun
2
3import (
4	"errors"
5	"fmt"
6	"io"
7)
8
9// ErrorCodeAttribute represents ERROR-CODE attribute.
10//
11// RFC 5389 Section 15.6
12type ErrorCodeAttribute struct {
13	Code   ErrorCode
14	Reason []byte
15}
16
17func (c ErrorCodeAttribute) String() string {
18	return fmt.Sprintf("%d: %s", c.Code, c.Reason)
19}
20
21// constants for ERROR-CODE encoding.
22const (
23	errorCodeReasonStart = 4
24	errorCodeClassByte   = 2
25	errorCodeNumberByte  = 3
26	errorCodeReasonMaxB  = 763
27	errorCodeModulo      = 100
28)
29
30// AddTo adds ERROR-CODE to m.
31func (c ErrorCodeAttribute) AddTo(m *Message) error {
32	value := make([]byte, 0, errorCodeReasonMaxB)
33	if err := CheckOverflow(AttrErrorCode,
34		len(c.Reason)+errorCodeReasonStart,
35		errorCodeReasonMaxB+errorCodeReasonStart,
36	); err != nil {
37		return err
38	}
39	value = value[:errorCodeReasonStart+len(c.Reason)]
40	number := byte(c.Code % errorCodeModulo) // error code modulo 100
41	class := byte(c.Code / errorCodeModulo)  // hundred digit
42	value[errorCodeClassByte] = class
43	value[errorCodeNumberByte] = number
44	copy(value[errorCodeReasonStart:], c.Reason)
45	m.Add(AttrErrorCode, value)
46	return nil
47}
48
49// GetFrom decodes ERROR-CODE from m. Reason is valid until m.Raw is valid.
50func (c *ErrorCodeAttribute) GetFrom(m *Message) error {
51	v, err := m.Get(AttrErrorCode)
52	if err != nil {
53		return err
54	}
55	if len(v) < errorCodeReasonStart {
56		return io.ErrUnexpectedEOF
57	}
58	var (
59		class  = uint16(v[errorCodeClassByte])
60		number = uint16(v[errorCodeNumberByte])
61		code   = int(class*errorCodeModulo + number)
62	)
63	c.Code = ErrorCode(code)
64	c.Reason = v[errorCodeReasonStart:]
65	return nil
66}
67
68// ErrorCode is code for ERROR-CODE attribute.
69type ErrorCode int
70
71// ErrNoDefaultReason means that default reason for provided error code
72// is not defined in RFC.
73var ErrNoDefaultReason = errors.New("no default reason for ErrorCode")
74
75// AddTo adds ERROR-CODE with default reason to m. If there
76// is no default reason, returns ErrNoDefaultReason.
77func (c ErrorCode) AddTo(m *Message) error {
78	reason := errorReasons[c]
79	if reason == nil {
80		return ErrNoDefaultReason
81	}
82	a := &ErrorCodeAttribute{
83		Code:   c,
84		Reason: reason,
85	}
86	return a.AddTo(m)
87}
88
89// Possible error codes.
90const (
91	CodeTryAlternate     ErrorCode = 300
92	CodeBadRequest       ErrorCode = 400
93	CodeUnauthorized     ErrorCode = 401
94	CodeUnknownAttribute ErrorCode = 420
95	CodeStaleNonce       ErrorCode = 438
96	CodeRoleConflict     ErrorCode = 487
97	CodeServerError      ErrorCode = 500
98)
99
100// DEPRECATED constants.
101const (
102	// DEPRECATED, use CodeUnauthorized.
103	CodeUnauthorised = CodeUnauthorized
104)
105
106// Error codes from RFC 5766.
107//
108// RFC 5766 Section 15
109const (
110	CodeForbidden             ErrorCode = 403 // Forbidden
111	CodeAllocMismatch         ErrorCode = 437 // Allocation Mismatch
112	CodeWrongCredentials      ErrorCode = 441 // Wrong Credentials
113	CodeUnsupportedTransProto ErrorCode = 442 // Unsupported Transport Protocol
114	CodeAllocQuotaReached     ErrorCode = 486 // Allocation Quota Reached
115	CodeInsufficientCapacity  ErrorCode = 508 // Insufficient Capacity
116)
117
118// Error codes from RFC 6062.
119//
120// RFC 6062 Section 6.3
121const (
122	CodeConnAlreadyExists    ErrorCode = 446
123	CodeConnTimeoutOrFailure ErrorCode = 447
124)
125
126// Error codes from RFC 6156.
127//
128// RFC 6156 Section 10.2
129const (
130	CodeAddrFamilyNotSupported ErrorCode = 440 // Address Family not Supported
131	CodePeerAddrFamilyMismatch ErrorCode = 443 // Peer Address Family Mismatch
132)
133
134var errorReasons = map[ErrorCode][]byte{
135	CodeTryAlternate:     []byte("Try Alternate"),
136	CodeBadRequest:       []byte("Bad Request"),
137	CodeUnauthorized:     []byte("Unauthorized"),
138	CodeUnknownAttribute: []byte("Unknown Attribute"),
139	CodeStaleNonce:       []byte("Stale Nonce"),
140	CodeServerError:      []byte("Server Error"),
141	CodeRoleConflict:     []byte("Role Conflict"),
142
143	// RFC 5766.
144	CodeForbidden:             []byte("Forbidden"),
145	CodeAllocMismatch:         []byte("Allocation Mismatch"),
146	CodeWrongCredentials:      []byte("Wrong Credentials"),
147	CodeUnsupportedTransProto: []byte("Unsupported Transport Protocol"),
148	CodeAllocQuotaReached:     []byte("Allocation Quota Reached"),
149	CodeInsufficientCapacity:  []byte("Insufficient Capacity"),
150
151	// RFC 6062.
152	CodeConnAlreadyExists:    []byte("Connection Already Exists"),
153	CodeConnTimeoutOrFailure: []byte("Connection Timeout or Failure"),
154
155	// RFC 6156.
156	CodeAddrFamilyNotSupported: []byte("Address Family not Supported"),
157	CodePeerAddrFamilyMismatch: []byte("Peer Address Family Mismatch"),
158}
159