-
Notifications
You must be signed in to change notification settings - Fork 10
/
config.go
294 lines (242 loc) · 6.91 KB
/
config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
// Copyright (c) 2022-present Mattermost, Inc. All Rights Reserved.
// See LICENSE.txt for license information.
package rtc
import (
"encoding/json"
"fmt"
"net"
"strconv"
"strings"
)
type ServerConfig struct {
// ICEAddressUDP specifies the UDP address the RTC service should listen on.
ICEAddressUDP string `toml:"ice_address_udp"`
// ICEPortUDP specifies the UDP port the RTC service should listen to.
ICEPortUDP int `toml:"ice_port_udp"`
// ICEAddressTCP specifies the TCP address the RTC service should listen on.
ICEAddressTCP string `toml:"ice_address_tcp"`
// ICEPortTCP specifies the TCP port the RTC service should listen to.
ICEPortTCP int `toml:"ice_port_tcp"`
// ICEHostOverride optionally specifies an IP address (or hostname)
// to be used as the main host ICE candidate.
ICEHostOverride string `toml:"ice_host_override"`
// ICEHostPortOverride optionally specifies a port number to override the one
// used to listen on when sharing host candidates.
ICEHostPortOverride ICEHostPortOverride `toml:"ice_host_port_override"`
// A list of ICE server (STUN/TURN) configurations to use.
ICEServers ICEServers `toml:"ice_servers"`
TURNConfig TURNConfig `toml:"turn"`
// EnableIPv6 specifies whether or not IPv6 should be used.
EnableIPv6 bool `toml:"enable_ipv6"`
}
func (c ServerConfig) IsValid() error {
if c.ICEAddressUDP != "" && net.ParseIP(c.ICEAddressUDP) == nil {
return fmt.Errorf("invalid ICEAddressUDP value: not a valid address")
}
if c.ICEAddressTCP != "" && net.ParseIP(c.ICEAddressTCP) == nil {
return fmt.Errorf("invalid ICEAddressTCP value: not a valid address")
}
if c.ICEPortUDP < 80 || c.ICEPortUDP > 49151 {
return fmt.Errorf("invalid ICEPortUDP value: %d is not in allowed range [80, 49151]", c.ICEPortUDP)
}
if c.ICEPortTCP < 80 || c.ICEPortTCP > 49151 {
return fmt.Errorf("invalid ICEPortTCP value: %d is not in allowed range [80, 49151]", c.ICEPortTCP)
}
if err := c.ICEServers.IsValid(); err != nil {
return fmt.Errorf("invalid ICEServers value: %w", err)
}
if err := c.TURNConfig.IsValid(); err != nil {
return fmt.Errorf("invalid TURNConfig: %w", err)
}
if err := c.ICEHostPortOverride.IsValid(); err != nil {
return fmt.Errorf("invalid ICEHostPortOverride value: %w", err)
}
return nil
}
type SessionConfig struct {
// GroupID specifies the id of the group the session should belong to.
GroupID string
// CallID specifies the id of the call the session should belong to.
CallID string
// UserID specifies the id of the user the session belongs to.
UserID string
// SessionID specifies the unique identifier for the session.
SessionID string
}
func (c SessionConfig) IsValid() error {
if c.GroupID == "" {
return fmt.Errorf("invalid GroupID value: should not be empty")
}
if c.CallID == "" {
return fmt.Errorf("invalid CallID value: should not be empty")
}
if c.UserID == "" {
return fmt.Errorf("invalid UserID value: should not be empty")
}
if c.SessionID == "" {
return fmt.Errorf("invalid SessionID value: should not be empty")
}
return nil
}
type ICEServerConfig struct {
URLs []string `toml:"urls" json:"urls"`
Username string `toml:"username,omitempty" json:"username,omitempty"`
Credential string `toml:"credential,omitempty" json:"credential,omitempty"`
}
type ICEServers []ICEServerConfig
func (c ICEServerConfig) IsValid() error {
if len(c.URLs) == 0 {
return fmt.Errorf("invalid empty URLs")
}
for _, u := range c.URLs {
if u == "" {
return fmt.Errorf("invalid empty URL")
}
if !c.IsSTUN() && !c.IsTURN() {
return fmt.Errorf("URL is not a valid STUN/TURN server")
}
}
return nil
}
func (c ICEServerConfig) IsTURN() bool {
for _, u := range c.URLs {
if !strings.HasPrefix(u, "turn:") && !strings.HasPrefix(u, "turns:") {
return false
}
}
return len(c.URLs) > 0
}
func (c ICEServerConfig) IsSTUN() bool {
for _, u := range c.URLs {
if !strings.HasPrefix(u, "stun:") && !strings.HasPrefix(u, "stuns:") {
return false
}
}
return len(c.URLs) > 0
}
func (s ICEServers) IsValid() error {
for _, cfg := range s {
if err := cfg.IsValid(); err != nil {
return err
}
}
return nil
}
func (s ICEServers) getSTUN() string {
for _, cfg := range s {
if cfg.IsSTUN() {
return cfg.URLs[0]
}
}
return ""
}
func (s *ICEServers) Decode(value string) error {
var urls []string
err := json.Unmarshal([]byte(value), &urls)
if err == nil {
iceServers := []ICEServerConfig{
{
URLs: urls,
},
}
*s = iceServers
return nil
}
return json.Unmarshal([]byte(value), s)
}
func (s *ICEServers) UnmarshalTOML(data interface{}) error {
d, ok := data.([]interface{})
if !ok {
return fmt.Errorf("invalid type %T", data)
}
var iceServers []ICEServerConfig
for _, obj := range d {
var server ICEServerConfig
switch t := obj.(type) {
case string:
server.URLs = append(server.URLs, obj.(string))
case map[string]interface{}:
m := obj.(map[string]interface{})
urls, _ := m["urls"].([]interface{})
for _, u := range urls {
uVal, _ := u.(string)
server.URLs = append(server.URLs, uVal)
}
server.Username, _ = m["username"].(string)
server.Credential, _ = m["credential"].(string)
default:
return fmt.Errorf("unknown type %T", t)
}
iceServers = append(iceServers, server)
}
*s = iceServers
return nil
}
type ICEHostPortOverride string
func (s *ICEHostPortOverride) SinglePort() int {
if s == nil {
return 0
}
p, _ := strconv.Atoi(string(*s))
return p
}
func (s *ICEHostPortOverride) ParseMap() (map[string]int, error) {
if s == nil {
return nil, fmt.Errorf("should not be nil")
}
if *s == "" {
return nil, nil
}
pairs := strings.Split(string(*s), ",")
m := make(map[string]int, len(pairs))
ports := make(map[int]bool, len(pairs))
for _, p := range pairs {
pair := strings.Split(p, "/")
if len(pair) != 2 {
return nil, fmt.Errorf("invalid map pairing syntax")
}
port, err := strconv.Atoi(pair[1])
if err != nil {
return nil, fmt.Errorf("failed to parse port number: %w", err)
}
if _, ok := m[pair[0]]; ok {
return nil, fmt.Errorf("duplicate mapping found for %s", pair[0])
}
if ports[port] {
return nil, fmt.Errorf("duplicate port found for %d", port)
}
m[pair[0]] = port
ports[port] = true
}
return m, nil
}
func (s *ICEHostPortOverride) IsValid() error {
if s == nil {
return fmt.Errorf("should not be nil")
}
if *s == "" {
return nil
}
if port := s.SinglePort(); port != 0 {
if port < 80 || port > 49151 {
return fmt.Errorf("%d is not in allowed range [80, 49151]", port)
}
return nil
}
if _, err := s.ParseMap(); err != nil {
return fmt.Errorf("failed to parse mapping: %w", err)
}
return nil
}
func (s *ICEHostPortOverride) UnmarshalTOML(data interface{}) error {
switch t := data.(type) {
case string:
*s = ICEHostPortOverride(data.(string))
return nil
case int, int32, int64:
*s = ICEHostPortOverride(fmt.Sprintf("%v", data))
default:
return fmt.Errorf("unknown type %T", t)
}
return nil
}