@@ -41,6 +41,7 @@ type ClientConfig struct {
41
41
Password string
42
42
Realm string
43
43
Software string
44
+ Protocol string
44
45
RTO time.Duration
45
46
Conn net.PacketConn // Listening socket (net.PacketConn)
46
47
LoggerFactory logging.LoggerFactory
@@ -49,25 +50,27 @@ type ClientConfig struct {
49
50
50
51
// Client is a STUN server client
51
52
type Client struct {
52
- conn net.PacketConn // read-only
53
- stunServ net.Addr // read-only
54
- turnServ net.Addr // read-only
55
- stunServStr string // read-only, used for de-multiplexing
56
- turnServStr string // read-only, used for de-multiplexing
57
- username stun.Username // read-only
58
- password string // read-only
59
- realm stun.Realm // read-only
60
- integrity stun.MessageIntegrity // read-only
61
- software stun.Software // read-only
62
- trMap * client.TransactionMap // thread-safe
63
- rto time.Duration // read-only
64
- relayedConn * client.UDPConn // protected by mutex ***
65
- allocTryLock client.TryLock // thread-safe
66
- listenTryLock client.TryLock // thread-safe
67
- net transport.Net // read-only
68
- mutex sync.RWMutex // thread-safe
69
- mutexTrMap sync.Mutex // thread-safe
70
- log logging.LeveledLogger // read-only
53
+ conn net.PacketConn // read-only // connection to the regular turn server.
54
+ stunServ net.Addr // read-only
55
+ turnServ net.Addr // read-only
56
+ stunServStr string // read-only, used for de-multiplexing
57
+ turnServStr string // read-only, used for de-multiplexing
58
+ username stun.Username // read-only
59
+ password string // read-only
60
+ realm stun.Realm // read-only
61
+ integrity stun.MessageIntegrity // read-only
62
+ software stun.Software // read-only
63
+ trMap * client.TransactionMap // thread-safe
64
+ rto time.Duration // read-only
65
+ relayedConn * client.UDPConn // protected by mutex ***
66
+ relayedTCPConn * client.TCPConn // protected by mutex ***
67
+ allocTryLock client.TryLock // thread-safe
68
+ listenTryLock client.TryLock // thread-safe
69
+ net transport.Net // read-only
70
+ mutex sync.RWMutex // thread-safe
71
+ mutexTrMap sync.Mutex // thread-safe
72
+ log logging.LeveledLogger // read-only
73
+ protocol proto.Protocol // read-only
71
74
}
72
75
73
76
// NewClient returns a new Client instance. listeningAddress is the address and port to listen on, default "0.0.0.0:0"
@@ -93,24 +96,47 @@ func NewClient(config *ClientConfig) (*Client, error) {
93
96
log .Warn ("Virtual network is enabled" )
94
97
}
95
98
99
+ protocol := proto .ProtoUDP
100
+ if config .Protocol == "tcp" {
101
+ protocol = proto .ProtoTCP
102
+ }
103
+
96
104
var stunServ , turnServ net.Addr
97
105
var stunServStr , turnServStr string
98
106
if len (config .STUNServerAddr ) > 0 {
99
107
log .Debugf ("resolving %s" , config .STUNServerAddr )
100
- stunServ , err = config .Net .ResolveUDPAddr ("udp4" , config .STUNServerAddr )
101
- if err != nil {
102
- return nil , err
108
+ switch protocol {
109
+ case proto .ProtoUDP :
110
+ stunServ , err = config .Net .ResolveUDPAddr ("udp4" , config .STUNServerAddr )
111
+ if err != nil {
112
+ return nil , err
113
+ }
114
+ stunServStr = stunServ .String ()
115
+ case proto .ProtoTCP :
116
+ stunServ , err = config .Net .ResolveTCPAddr ("tcp4" , config .STUNServerAddr )
117
+ if err != nil {
118
+ return nil , err
119
+ }
120
+ stunServStr = stunServ .String ()
103
121
}
104
- stunServStr = stunServ .String ()
105
122
log .Debugf ("stunServ: %s" , stunServStr )
106
123
}
107
124
if len (config .TURNServerAddr ) > 0 {
108
125
log .Debugf ("resolving %s" , config .TURNServerAddr )
109
- turnServ , err = config .Net .ResolveUDPAddr ("udp4" , config .TURNServerAddr )
110
- if err != nil {
111
- return nil , err
126
+ switch protocol {
127
+ case proto .ProtoUDP :
128
+ turnServ , err = config .Net .ResolveUDPAddr ("udp4" , config .TURNServerAddr )
129
+ if err != nil {
130
+ return nil , err
131
+ }
132
+ turnServStr = turnServ .String ()
133
+ case proto .ProtoTCP :
134
+ turnServ , err = config .Net .ResolveTCPAddr ("tcp4" , config .TURNServerAddr )
135
+ if err != nil {
136
+ return nil , err
137
+ }
138
+ turnServStr = turnServ .String ()
112
139
}
113
- turnServStr = turnServ .String ()
114
140
log .Debugf ("turnServ: %s" , turnServStr )
115
141
}
116
142
@@ -133,6 +159,7 @@ func NewClient(config *ClientConfig) (*Client, error) {
133
159
trMap : client .NewTransactionMap (),
134
160
rto : rto ,
135
161
log : log ,
162
+ protocol : protocol ,
136
163
}
137
164
138
165
return c , nil
@@ -238,42 +265,34 @@ func (c *Client) SendBindingRequest() (net.Addr, error) {
238
265
return c .SendBindingRequestTo (c .stunServ )
239
266
}
240
267
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
- }
268
+ func (c * Client ) sendAllocateRequest () (proto.RelayedAddress , proto.Lifetime , stun.Nonce , error ) {
269
+ var relayed proto.RelayedAddress
270
+ var lifetime proto.Lifetime
271
+ var nonce stun.Nonce
252
272
253
273
msg , err := stun .Build (
254
274
stun .TransactionID ,
255
275
stun .NewType (stun .MethodAllocate , stun .ClassRequest ),
256
- proto.RequestedTransport {Protocol : proto . ProtoUDP },
276
+ proto.RequestedTransport {Protocol : c . protocol },
257
277
stun .Fingerprint ,
258
278
)
259
279
if err != nil {
260
- return nil , err
280
+ return relayed , lifetime , nonce , err
261
281
}
262
282
263
283
trRes , err := c .PerformTransaction (msg , c .turnServ , false )
264
284
if err != nil {
265
- return nil , err
285
+ return relayed , lifetime , nonce , err
266
286
}
267
287
268
288
res := trRes .Msg
269
289
270
290
// Anonymous allocate failed, trying to authenticate.
271
- var nonce stun.Nonce
272
291
if err = nonce .GetFrom (res ); err != nil {
273
- return nil , err
292
+ return relayed , lifetime , nonce , err
274
293
}
275
294
if err = c .realm .GetFrom (res ); err != nil {
276
- return nil , err
295
+ return relayed , lifetime , nonce , err
277
296
}
278
297
c .realm = append ([]byte (nil ), c .realm ... )
279
298
c .integrity = stun .NewLongTermIntegrity (
@@ -283,48 +302,101 @@ func (c *Client) Allocate() (net.PacketConn, error) {
283
302
msg , err = stun .Build (
284
303
stun .TransactionID ,
285
304
stun .NewType (stun .MethodAllocate , stun .ClassRequest ),
286
- proto.RequestedTransport {Protocol : proto . ProtoUDP },
305
+ proto.RequestedTransport {Protocol : c . protocol },
287
306
& c .username ,
288
307
& c .realm ,
289
308
& nonce ,
290
309
& c .integrity ,
291
310
stun .Fingerprint ,
292
311
)
293
312
if err != nil {
294
- return nil , err
313
+ return relayed , lifetime , nonce , err
295
314
}
296
315
297
316
trRes , err = c .PerformTransaction (msg , c .turnServ , false )
298
317
if err != nil {
299
- return nil , err
318
+ return relayed , lifetime , nonce , err
300
319
}
301
320
res = trRes .Msg
302
321
303
322
if res .Type .Class == stun .ClassErrorResponse {
304
323
var code stun.ErrorCodeAttribute
305
324
if err = code .GetFrom (res ); err == nil {
306
- return nil , fmt .Errorf ("%s (error %s)" , res .Type , code ) //nolint:goerr113
325
+ return relayed , lifetime , nonce , fmt .Errorf ("%s (error %s)" , res .Type , code ) //nolint:goerr113
307
326
}
308
- return nil , fmt .Errorf ("%s" , res .Type ) //nolint:goerr113
327
+ return relayed , lifetime , nonce , fmt .Errorf ("%s" , res .Type ) //nolint:goerr113
309
328
}
310
329
311
330
// Getting relayed addresses from response.
312
- var relayed proto.RelayedAddress
313
331
if err := relayed .GetFrom (res ); err != nil {
332
+ return relayed , lifetime , nonce , err
333
+ }
334
+
335
+ // Getting lifetime from response
336
+ if err := lifetime .GetFrom (res ); err != nil {
337
+ return relayed , lifetime , nonce , err
338
+ }
339
+ return relayed , lifetime , nonce , nil
340
+ }
341
+
342
+ // Allocate sends a TURN allocation request to the given transport address
343
+ func (c * Client ) Allocate () (net.PacketConn , error ) {
344
+ if err := c .allocTryLock .Lock (); err != nil {
345
+ return nil , fmt .Errorf ("%w: %s" , errOneAllocateOnly , err .Error ())
346
+ }
347
+ defer c .allocTryLock .Unlock ()
348
+
349
+ relayedConn := c .getRelayedUDPConn ()
350
+ if relayedConn != nil {
351
+ return nil , fmt .Errorf ("%w: %s" , errAlreadyAllocated , relayedConn .LocalAddr ().String ())
352
+ }
353
+
354
+ relayed , lifetime , nonce , err := c .sendAllocateRequest ()
355
+ if err != nil {
314
356
return nil , err
315
357
}
358
+
316
359
relayedAddr := & net.UDPAddr {
317
360
IP : relayed .IP ,
318
361
Port : relayed .Port ,
319
362
}
320
363
321
- // Getting lifetime from response
322
- var lifetime proto.Lifetime
323
- if err := lifetime .GetFrom (res ); err != nil {
364
+ relayedConn = client .NewUDPConn (& client.ConnConfig {
365
+ Observer : c ,
366
+ RelayedAddr : relayedAddr ,
367
+ Integrity : c .integrity ,
368
+ Nonce : nonce ,
369
+ Lifetime : lifetime .Duration ,
370
+ Log : c .log ,
371
+ })
372
+ c .setRelayedUDPConn (relayedConn )
373
+
374
+ return relayedConn , nil
375
+ }
376
+
377
+ // Allocate TCP
378
+ func (c * Client ) AllocateTCP () (* client.TCPConn , error ) {
379
+ if err := c .allocTryLock .Lock (); err != nil {
380
+ return nil , fmt .Errorf ("%w: %s" , errOneAllocateOnly , err .Error ())
381
+ }
382
+ defer c .allocTryLock .Unlock ()
383
+
384
+ relayedConn := c .getRelayedTCPConn ()
385
+ if relayedConn != nil {
386
+ return nil , fmt .Errorf ("%w: %s" , errAlreadyAllocated , relayedConn .LocalAddr ().String ())
387
+ }
388
+
389
+ relayed , lifetime , nonce , err := c .sendAllocateRequest ()
390
+ if err != nil {
324
391
return nil , err
325
392
}
326
393
327
- relayedConn = client .NewUDPConn (& client.UDPConnConfig {
394
+ relayedAddr := & net.TCPAddr {
395
+ IP : relayed .IP ,
396
+ Port : relayed .Port ,
397
+ }
398
+
399
+ relayedConn = client .NewTCPConn (& client.ConnConfig {
328
400
Observer : c ,
329
401
RelayedAddr : relayedAddr ,
330
402
Integrity : c .integrity ,
@@ -333,15 +405,21 @@ func (c *Client) Allocate() (net.PacketConn, error) {
333
405
Log : c .log ,
334
406
})
335
407
336
- c .setRelayedUDPConn (relayedConn )
408
+ c .setRelayedTCPConn (relayedConn )
337
409
338
410
return relayedConn , nil
339
411
}
340
412
341
413
// CreatePermission Issues a CreatePermission request for the supplied addresses
342
414
// as described in https://datatracker.ietf.org/doc/html/rfc5766#section-9
343
415
func (c * Client ) CreatePermission (addrs ... net.Addr ) error {
344
- return c .relayedUDPConn ().CreatePermissions (addrs ... )
416
+ switch c .protocol {
417
+ case proto .ProtoUDP :
418
+ return c .getRelayedUDPConn ().CreatePermissions (addrs ... )
419
+ case proto .ProtoTCP :
420
+ return c .getRelayedTCPConn ().CreatePermissions (addrs ... )
421
+ }
422
+ return nil
345
423
}
346
424
347
425
// PerformTransaction performs STUN transaction
@@ -445,7 +523,8 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
445
523
}
446
524
447
525
if msg .Type .Class == stun .ClassIndication {
448
- if msg .Type .Method == stun .MethodData {
526
+ switch msg .Type .Method {
527
+ case stun .MethodData :
449
528
var peerAddr proto.PeerAddress
450
529
if err := peerAddr .GetFrom (msg ); err != nil {
451
530
return err
@@ -462,13 +541,37 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
462
541
463
542
c .log .Debugf ("data indication received from %s" , from .String ())
464
543
465
- relayedConn := c .relayedUDPConn ()
544
+ relayedConn := c .getRelayedUDPConn ()
466
545
if relayedConn == nil {
467
546
c .log .Debug ("no relayed conn allocated" )
468
547
return nil // silently discard
469
548
}
470
-
471
549
relayedConn .HandleInbound (data , from )
550
+ case stun .MethodConnectionAttempt :
551
+ var peerAddr proto.PeerAddress
552
+ if err := peerAddr .GetFrom (msg ); err != nil {
553
+ return err
554
+ }
555
+
556
+ from = & net.TCPAddr {
557
+ IP : peerAddr .IP ,
558
+ Port : peerAddr .Port ,
559
+ }
560
+
561
+ var cid proto.ConnectionID
562
+ if err := cid .GetFrom (msg ); err != nil {
563
+ return err
564
+ }
565
+
566
+ c .log .Debugf ("connection attempt from %s" , from .String ())
567
+
568
+ relayedConn := c .getRelayedTCPConn ()
569
+ if relayedConn == nil {
570
+ c .log .Debug ("no relayed conn allocated" )
571
+ return nil // silently discard
572
+ }
573
+
574
+ relayedConn .HandleConnectionAttempt (data , from , cid )
472
575
}
473
576
return nil
474
577
}
@@ -514,7 +617,7 @@ func (c *Client) handleChannelData(data []byte) error {
514
617
return err
515
618
}
516
619
517
- relayedConn := c .relayedUDPConn ()
620
+ relayedConn := c .getRelayedUDPConn ()
518
621
if relayedConn == nil {
519
622
c .log .Debug ("no relayed conn allocated" )
520
623
return nil // silently discard
@@ -573,9 +676,23 @@ func (c *Client) setRelayedUDPConn(conn *client.UDPConn) {
573
676
c .relayedConn = conn
574
677
}
575
678
576
- func (c * Client ) relayedUDPConn () * client.UDPConn {
679
+ func (c * Client ) getRelayedUDPConn () * client.UDPConn {
577
680
c .mutex .RLock ()
578
681
defer c .mutex .RUnlock ()
579
682
580
683
return c .relayedConn
581
684
}
685
+
686
+ func (c * Client ) setRelayedTCPConn (conn * client.TCPConn ) {
687
+ c .mutex .Lock ()
688
+ defer c .mutex .Unlock ()
689
+
690
+ c .relayedTCPConn = conn
691
+ }
692
+
693
+ func (c * Client ) getRelayedTCPConn () * client.TCPConn {
694
+ c .mutex .RLock ()
695
+ defer c .mutex .RUnlock ()
696
+
697
+ return c .relayedTCPConn
698
+ }
0 commit comments