@@ -62,6 +62,7 @@ type Client struct {
62
62
trMap * client.TransactionMap // thread-safe
63
63
rto time.Duration // read-only
64
64
relayedConn * client.UDPConn // protected by mutex ***
65
+ tcpAllocation * client.TCPAllocation // protected by mutex ***
65
66
allocTryLock client.TryLock // thread-safe
66
67
listenTryLock client.TryLock // thread-safe
67
68
net transport.Net // read-only
@@ -238,42 +239,34 @@ func (c *Client) SendBindingRequest() (net.Addr, error) {
238
239
return c .SendBindingRequestTo (c .stunServ )
239
240
}
240
241
241
- // Allocate sends a TURN allocation request to the given transport address
242
- func (c * Client ) Allocate () (net.PacketConn , error ) {
243
- if err := c .allocTryLock .Lock (); err != nil {
244
- return nil , fmt .Errorf ("%w: %s" , errOneAllocateOnly , err .Error ())
245
- }
246
- defer c .allocTryLock .Unlock ()
247
-
248
- relayedConn := c .relayedUDPConn ()
249
- if relayedConn != nil {
250
- return nil , fmt .Errorf ("%w: %s" , errAlreadyAllocated , relayedConn .LocalAddr ().String ())
251
- }
242
+ func (c * Client ) sendAllocateRequest (protocol proto.Protocol ) (proto.RelayedAddress , proto.Lifetime , stun.Nonce , error ) {
243
+ var relayed proto.RelayedAddress
244
+ var lifetime proto.Lifetime
245
+ var nonce stun.Nonce
252
246
253
247
msg , err := stun .Build (
254
248
stun .TransactionID ,
255
249
stun .NewType (stun .MethodAllocate , stun .ClassRequest ),
256
- proto.RequestedTransport {Protocol : proto . ProtoUDP },
250
+ proto.RequestedTransport {Protocol : protocol },
257
251
stun .Fingerprint ,
258
252
)
259
253
if err != nil {
260
- return nil , err
254
+ return relayed , lifetime , nonce , err
261
255
}
262
256
263
257
trRes , err := c .PerformTransaction (msg , c .turnServ , false )
264
258
if err != nil {
265
- return nil , err
259
+ return relayed , lifetime , nonce , err
266
260
}
267
261
268
262
res := trRes .Msg
269
263
270
264
// Anonymous allocate failed, trying to authenticate.
271
- var nonce stun.Nonce
272
265
if err = nonce .GetFrom (res ); err != nil {
273
- return nil , err
266
+ return relayed , lifetime , nonce , err
274
267
}
275
268
if err = c .realm .GetFrom (res ); err != nil {
276
- return nil , err
269
+ return relayed , lifetime , nonce , err
277
270
}
278
271
c .realm = append ([]byte (nil ), c .realm ... )
279
272
c .integrity = stun .NewLongTermIntegrity (
@@ -283,48 +276,101 @@ func (c *Client) Allocate() (net.PacketConn, error) {
283
276
msg , err = stun .Build (
284
277
stun .TransactionID ,
285
278
stun .NewType (stun .MethodAllocate , stun .ClassRequest ),
286
- proto.RequestedTransport {Protocol : proto . ProtoUDP },
279
+ proto.RequestedTransport {Protocol : protocol },
287
280
& c .username ,
288
281
& c .realm ,
289
282
& nonce ,
290
283
& c .integrity ,
291
284
stun .Fingerprint ,
292
285
)
293
286
if err != nil {
294
- return nil , err
287
+ return relayed , lifetime , nonce , err
295
288
}
296
289
297
290
trRes , err = c .PerformTransaction (msg , c .turnServ , false )
298
291
if err != nil {
299
- return nil , err
292
+ return relayed , lifetime , nonce , err
300
293
}
301
294
res = trRes .Msg
302
295
303
296
if res .Type .Class == stun .ClassErrorResponse {
304
297
var code stun.ErrorCodeAttribute
305
298
if err = code .GetFrom (res ); err == nil {
306
- return nil , fmt .Errorf ("%s (error %s)" , res .Type , code ) //nolint:goerr113
299
+ return relayed , lifetime , nonce , fmt .Errorf ("%s (error %s)" , res .Type , code ) //nolint:goerr113
307
300
}
308
- return nil , fmt .Errorf ("%s" , res .Type ) //nolint:goerr113
301
+ return relayed , lifetime , nonce , fmt .Errorf ("%s" , res .Type ) //nolint:goerr113
309
302
}
310
303
311
304
// Getting relayed addresses from response.
312
- var relayed proto.RelayedAddress
313
305
if err := relayed .GetFrom (res ); err != nil {
306
+ return relayed , lifetime , nonce , err
307
+ }
308
+
309
+ // Getting lifetime from response
310
+ if err := lifetime .GetFrom (res ); err != nil {
311
+ return relayed , lifetime , nonce , err
312
+ }
313
+ return relayed , lifetime , nonce , nil
314
+ }
315
+
316
+ // Allocate sends a TURN allocation request to the given transport address
317
+ func (c * Client ) Allocate () (net.PacketConn , error ) {
318
+ if err := c .allocTryLock .Lock (); err != nil {
319
+ return nil , fmt .Errorf ("%w: %s" , errOneAllocateOnly , err .Error ())
320
+ }
321
+ defer c .allocTryLock .Unlock ()
322
+
323
+ relayedConn := c .relayedUDPConn ()
324
+ if relayedConn != nil {
325
+ return nil , fmt .Errorf ("%w: %s" , errAlreadyAllocated , relayedConn .LocalAddr ().String ())
326
+ }
327
+
328
+ relayed , lifetime , nonce , err := c .sendAllocateRequest (proto .ProtoUDP )
329
+ if err != nil {
314
330
return nil , err
315
331
}
332
+
316
333
relayedAddr := & net.UDPAddr {
317
334
IP : relayed .IP ,
318
335
Port : relayed .Port ,
319
336
}
320
337
321
- // Getting lifetime from response
322
- var lifetime proto.Lifetime
323
- if err := lifetime .GetFrom (res ); err != nil {
338
+ relayedConn = client .NewUDPConn (& client.ConnConfig {
339
+ Observer : c ,
340
+ RelayedAddr : relayedAddr ,
341
+ Integrity : c .integrity ,
342
+ Nonce : nonce ,
343
+ Lifetime : lifetime .Duration ,
344
+ Log : c .log ,
345
+ })
346
+ c .setRelayedUDPConn (relayedConn )
347
+
348
+ return relayedConn , nil
349
+ }
350
+
351
+ // Allocate TCP
352
+ func (c * Client ) AllocateTCP () (* client.TCPAllocation , error ) {
353
+ if err := c .allocTryLock .Lock (); err != nil {
354
+ return nil , fmt .Errorf ("%w: %s" , errOneAllocateOnly , err .Error ())
355
+ }
356
+ defer c .allocTryLock .Unlock ()
357
+
358
+ allocation := c .getTCPAllocation ()
359
+ if allocation != nil {
360
+ return nil , fmt .Errorf ("%w: %s" , errAlreadyAllocated , allocation .Addr ().String ())
361
+ }
362
+
363
+ relayed , lifetime , nonce , err := c .sendAllocateRequest (proto .ProtoTCP )
364
+ if err != nil {
324
365
return nil , err
325
366
}
326
367
327
- relayedConn = client .NewUDPConn (& client.UDPConnConfig {
368
+ relayedAddr := & net.TCPAddr {
369
+ IP : relayed .IP ,
370
+ Port : relayed .Port ,
371
+ }
372
+
373
+ allocation = client .NewTCPAllocation (& client.ConnConfig {
328
374
Observer : c ,
329
375
RelayedAddr : relayedAddr ,
330
376
Integrity : c .integrity ,
@@ -333,15 +379,26 @@ func (c *Client) Allocate() (net.PacketConn, error) {
333
379
Log : c .log ,
334
380
})
335
381
336
- c .setRelayedUDPConn ( relayedConn )
382
+ c .setTCPAllocation ( allocation )
337
383
338
- return relayedConn , nil
384
+ return allocation , nil
339
385
}
340
386
341
387
// CreatePermission Issues a CreatePermission request for the supplied addresses
342
388
// as described in https://datatracker.ietf.org/doc/html/rfc5766#section-9
343
389
func (c * Client ) CreatePermission (addrs ... net.Addr ) error {
344
- return c .relayedUDPConn ().CreatePermissions (addrs ... )
390
+ if conn := c .relayedUDPConn (); conn != nil {
391
+ if err := conn .CreatePermissions (addrs ... ); err != nil {
392
+ return err
393
+ }
394
+ }
395
+
396
+ if allocation := c .getTCPAllocation (); allocation != nil {
397
+ if err := allocation .CreatePermissions (addrs ... ); err != nil {
398
+ return err
399
+ }
400
+ }
401
+ return nil
345
402
}
346
403
347
404
// PerformTransaction performs STUN transaction
@@ -387,6 +444,7 @@ func (c *Client) PerformTransaction(msg *stun.Message, to net.Addr, ignoreResult
387
444
// (Called by UDPConn)
388
445
func (c * Client ) OnDeallocated (relayedAddr net.Addr ) {
389
446
c .setRelayedUDPConn (nil )
447
+ c .setTCPAllocation (nil )
390
448
}
391
449
392
450
// HandleInbound handles data received.
@@ -445,7 +503,8 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
445
503
}
446
504
447
505
if msg .Type .Class == stun .ClassIndication {
448
- if msg .Type .Method == stun .MethodData {
506
+ switch msg .Type .Method {
507
+ case stun .MethodData :
449
508
var peerAddr proto.PeerAddress
450
509
if err := peerAddr .GetFrom (msg ); err != nil {
451
510
return err
@@ -467,8 +526,32 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
467
526
c .log .Debug ("no relayed conn allocated" )
468
527
return nil // silently discard
469
528
}
470
-
471
529
relayedConn .HandleInbound (data , from )
530
+ case stun .MethodConnectionAttempt :
531
+ var peerAddr proto.PeerAddress
532
+ if err := peerAddr .GetFrom (msg ); err != nil {
533
+ return err
534
+ }
535
+
536
+ addr := & net.TCPAddr {
537
+ IP : peerAddr .IP ,
538
+ Port : peerAddr .Port ,
539
+ }
540
+
541
+ var cid proto.ConnectionID
542
+ if err := cid .GetFrom (msg ); err != nil {
543
+ return err
544
+ }
545
+
546
+ c .log .Debugf ("connection attempt from %s" , addr .String ())
547
+
548
+ allocation := c .getTCPAllocation ()
549
+ if allocation == nil {
550
+ c .log .Debug ("no TCP allocation exists" )
551
+ return nil // silently discard
552
+ }
553
+
554
+ allocation .HandleConnectionAttempt (addr , cid )
472
555
}
473
556
return nil
474
557
}
@@ -579,3 +662,17 @@ func (c *Client) relayedUDPConn() *client.UDPConn {
579
662
580
663
return c .relayedConn
581
664
}
665
+
666
+ func (c * Client ) setTCPAllocation (alloc * client.TCPAllocation ) {
667
+ c .mutex .Lock ()
668
+ defer c .mutex .Unlock ()
669
+
670
+ c .tcpAllocation = alloc
671
+ }
672
+
673
+ func (c * Client ) getTCPAllocation () * client.TCPAllocation {
674
+ c .mutex .RLock ()
675
+ defer c .mutex .RUnlock ()
676
+
677
+ return c .tcpAllocation
678
+ }
0 commit comments