7
7
"fmt"
8
8
"io"
9
9
"net"
10
- "strings"
11
10
"sync"
12
11
"time"
13
12
@@ -18,8 +17,26 @@ import (
18
17
"cdr.dev/coder-cli/coder-sdk"
19
18
)
20
19
20
+ // Codes for DialChannelResponse.
21
+ const (
22
+ CodeDialErr = "dial_error"
23
+ CodePermissionErr = "permission_error"
24
+ CodeBadAddressErr = "bad_address_error"
25
+ )
26
+
21
27
var connectionRetryInterval = time .Second
22
28
29
+ // DialChannelResponse is used to notify a dial channel of a
30
+ // listening state. Modeled after net.OpError, and marshalled
31
+ // to that if Net is not "".
32
+ type DialChannelResponse struct {
33
+ Code string
34
+ Err string
35
+ // Fields are set if the code is CodeDialErr.
36
+ Net string
37
+ Op string
38
+ }
39
+
23
40
// Listen connects to the broker proxies connections to the local net.
24
41
// Close will end all RTC connections.
25
42
func Listen (ctx context.Context , broker string ) (io.Closer , error ) {
@@ -124,7 +141,7 @@ func (l *listener) negotiate(conn net.Conn) {
124
141
// Sends the error provided then closes the connection.
125
142
// If RTC isn't connected, we'll close it.
126
143
closeError = func (err error ) {
127
- d , _ := json .Marshal (& protoMessage {
144
+ d , _ := json .Marshal (& BrokerMessage {
128
145
Error : err .Error (),
129
146
})
130
147
_ , _ = conn .Write (d )
@@ -139,7 +156,7 @@ func (l *listener) negotiate(conn net.Conn) {
139
156
)
140
157
141
158
for {
142
- var msg protoMessage
159
+ var msg BrokerMessage
143
160
err = decoder .Decode (& msg )
144
161
if err != nil {
145
162
closeError (err )
@@ -190,7 +207,7 @@ func (l *listener) negotiate(conn net.Conn) {
190
207
l .connClosersMut .Lock ()
191
208
l .connClosers = append (l .connClosers , rtc )
192
209
l .connClosersMut .Unlock ()
193
- rtc .OnDataChannel (l .handle )
210
+ rtc .OnDataChannel (l .handle ( msg ) )
194
211
err = rtc .SetRemoteDescription (* msg .Offer )
195
212
if err != nil {
196
213
closeError (fmt .Errorf ("apply offer: %w" , err ))
@@ -208,7 +225,7 @@ func (l *listener) negotiate(conn net.Conn) {
208
225
}
209
226
flushCandidates ()
210
227
211
- data , err := json .Marshal (& protoMessage {
228
+ data , err := json .Marshal (& BrokerMessage {
212
229
Answer : rtc .LocalDescription (),
213
230
})
214
231
if err != nil {
@@ -233,70 +250,89 @@ func (l *listener) negotiate(conn net.Conn) {
233
250
}
234
251
}
235
252
236
- func (l * listener ) handle (dc * webrtc.DataChannel ) {
237
- if dc .Protocol () == controlChannel {
238
- // The control channel handles pings.
253
+ func (l * listener ) handle (msg BrokerMessage ) func (dc * webrtc.DataChannel ) {
254
+ return func (dc * webrtc.DataChannel ) {
255
+ if dc .Protocol () == controlChannel {
256
+ // The control channel handles pings.
257
+ dc .OnOpen (func () {
258
+ rw , err := dc .Detach ()
259
+ if err != nil {
260
+ return
261
+ }
262
+ // We'll read and write back a single byte for ping/pongin'.
263
+ d := make ([]byte , 1 )
264
+ for {
265
+ _ , err = rw .Read (d )
266
+ if errors .Is (err , io .EOF ) {
267
+ return
268
+ }
269
+ if err != nil {
270
+ continue
271
+ }
272
+ _ , _ = rw .Write (d )
273
+ }
274
+ })
275
+ return
276
+ }
277
+
239
278
dc .OnOpen (func () {
240
279
rw , err := dc .Detach ()
241
280
if err != nil {
242
281
return
243
282
}
244
- // We'll read and write back a single byte for ping/pongin'.
245
- d := make ([]byte , 1 )
246
- for {
247
- _ , err = rw .Read (d )
248
- if errors .Is (err , io .EOF ) {
283
+
284
+ var init DialChannelResponse
285
+ sendInitMessage := func () {
286
+ initData , err := json .Marshal (& init )
287
+ if err != nil {
288
+ rw .Close ()
249
289
return
250
290
}
291
+ _ , err = rw .Write (initData )
251
292
if err != nil {
252
- continue
293
+ return
294
+ }
295
+ if init .Err != "" {
296
+ // If an error occurred, we're safe to close the connection.
297
+ dc .Close ()
298
+ return
253
299
}
254
- _ , _ = rw .Write (d )
255
300
}
256
- })
257
- return
258
- }
259
301
260
- dc .OnOpen (func () {
261
- rw , err := dc .Detach ()
262
- if err != nil {
263
- return
264
- }
265
- parts := strings .SplitN (dc .Protocol (), ":" , 2 )
266
- network := parts [0 ]
267
- addr := parts [1 ]
302
+ network , addr , err := msg .getAddress (dc .Protocol ())
303
+ if err != nil {
304
+ init .Code = CodeBadAddressErr
305
+ init .Err = err .Error ()
306
+ var policyErr notPermittedByPolicyErr
307
+ if errors .As (err , & policyErr ) {
308
+ init .Code = CodePermissionErr
309
+ }
310
+ sendInitMessage ()
311
+ return
312
+ }
268
313
269
- var init dialChannelMessage
270
- conn , err := net .Dial (network , addr )
271
- if err != nil {
272
- init .Err = err .Error ()
273
- if op , ok := err .(* net.OpError ); ok {
274
- init .Net = op .Net
275
- init .Op = op .Op
314
+ conn , err := net .Dial (network , addr )
315
+ if err != nil {
316
+ init .Code = CodeDialErr
317
+ init .Err = err .Error ()
318
+ if op , ok := err .(* net.OpError ); ok {
319
+ init .Net = op .Net
320
+ init .Op = op .Op
321
+ }
276
322
}
277
- }
278
- initData , err := json .Marshal (& init )
279
- if err != nil {
280
- rw .Close ()
281
- return
282
- }
283
- _ , err = rw .Write (initData )
284
- if err != nil {
285
- return
286
- }
287
- if init .Err != "" {
288
- // If an error occurred, we're safe to close the connection.
289
- dc .Close ()
290
- return
291
- }
292
- defer conn .Close ()
293
- defer dc .Close ()
323
+ sendInitMessage ()
324
+ if init .Err != "" {
325
+ return
326
+ }
327
+ defer conn .Close ()
328
+ defer dc .Close ()
294
329
295
- go func () {
296
- _ , _ = io .Copy (rw , conn )
297
- }()
298
- _ , _ = io .Copy (conn , rw )
299
- })
330
+ go func () {
331
+ _ , _ = io .Copy (rw , conn )
332
+ }()
333
+ _ , _ = io .Copy (conn , rw )
334
+ })
335
+ }
300
336
}
301
337
302
338
// Close closes the broker socket and all created RTC connections.
0 commit comments