@@ -5,12 +5,14 @@ import (
5
5
"net"
6
6
"sync"
7
7
"sync/atomic"
8
+ "syscall"
8
9
"time"
9
10
10
11
"github.com/pion/logging"
11
12
"github.com/pion/stun"
12
13
"github.com/pion/turn/v2/internal/ipnet"
13
14
"github.com/pion/turn/v2/internal/proto"
15
+ "golang.org/x/sys/unix"
14
16
)
15
17
16
18
type allocationResponse struct {
@@ -21,18 +23,23 @@ type allocationResponse struct {
21
23
// Allocation is tied to a FiveTuple and relays traffic
22
24
// use CreateAllocation and GetAllocation to operate
23
25
type Allocation struct {
24
- RelayAddr net.Addr
25
- Protocol Protocol
26
- TurnSocket net.PacketConn
27
- RelaySocket net.PacketConn
28
- fiveTuple * FiveTuple
29
- permissionsLock sync.RWMutex
30
- permissions map [string ]* Permission
31
- channelBindingsLock sync.RWMutex
32
- channelBindings []* ChannelBind
33
- lifetimeTimer * time.Timer
34
- closed chan interface {}
35
- log logging.LeveledLogger
26
+ RelayAddr net.Addr
27
+ Protocol Protocol
28
+ RequestedTransportProtocol proto.Protocol
29
+ TurnSocket net.PacketConn
30
+ RelaySocket net.PacketConn
31
+ RelayListener net.Listener
32
+ fiveTuple * FiveTuple
33
+ permissionsLock sync.RWMutex
34
+ permissions map [string ]* Permission
35
+ channelBindingsLock sync.RWMutex
36
+ channelBindings []* ChannelBind
37
+ lifetimeTimer * time.Timer
38
+ closed chan interface {}
39
+ log logging.LeveledLogger
40
+ connsLock sync.RWMutex
41
+ addrToConn map [string ]net.Conn
42
+ cidToConn map [proto.ConnectionID ]net.Conn
36
43
37
44
// some clients (Firefox or others using resiprocate's nICE lib) may retry allocation
38
45
// with same 5 tuple when received 413, for compatible with these clients,
@@ -52,13 +59,16 @@ func addr2IPFingerprint(addr net.Addr) string {
52
59
}
53
60
54
61
// NewAllocation creates a new instance of NewAllocation.
55
- func NewAllocation (turnSocket net.PacketConn , fiveTuple * FiveTuple , log logging.LeveledLogger ) * Allocation {
62
+ func NewAllocation (turnSocket net.PacketConn , fiveTuple * FiveTuple , log logging.LeveledLogger , requestedTransportProtocol proto. Protocol ) * Allocation {
56
63
return & Allocation {
57
- TurnSocket : turnSocket ,
58
- fiveTuple : fiveTuple ,
59
- permissions : make (map [string ]* Permission , 64 ),
60
- closed : make (chan interface {}),
61
- log : log ,
64
+ TurnSocket : turnSocket ,
65
+ RequestedTransportProtocol : requestedTransportProtocol ,
66
+ fiveTuple : fiveTuple ,
67
+ permissions : make (map [string ]* Permission , 64 ),
68
+ addrToConn : make (map [string ]net.Conn ),
69
+ cidToConn : make (map [proto.ConnectionID ]net.Conn ),
70
+ closed : make (chan interface {}),
71
+ log : log ,
62
72
}
63
73
}
64
74
@@ -215,7 +225,11 @@ func (a *Allocation) Close() error {
215
225
}
216
226
a .channelBindingsLock .RUnlock ()
217
227
218
- return a .RelaySocket .Close ()
228
+ if a .RequestedTransportProtocol == proto .ProtoTCP {
229
+ return a .RelayListener .Close ()
230
+ } else {
231
+ return a .RelaySocket .Close ()
232
+ }
219
233
}
220
234
221
235
// https://tools.ietf.org/html/rfc5766#section-10.3
@@ -291,3 +305,133 @@ func (a *Allocation) packetHandler(m *Manager) {
291
305
}
292
306
}
293
307
}
308
+
309
+ func (a * Allocation ) GetConnectionByAddr (peerAddr string ) net.Conn {
310
+ a .connsLock .RLock ()
311
+ defer a .connsLock .RUnlock ()
312
+ return a .addrToConn [peerAddr ]
313
+ }
314
+
315
+ func (a * Allocation ) GetConnectionByID (cid proto.ConnectionID ) net.Conn {
316
+ a .connsLock .RLock ()
317
+ defer a .connsLock .RUnlock ()
318
+ return a .cidToConn [cid ]
319
+ }
320
+
321
+ func (a * Allocation ) newConnection (cid proto.ConnectionID , dst string ) error {
322
+ a .connsLock .Lock ()
323
+ a .addrToConn [dst ] = nil
324
+ a .cidToConn [cid ] = nil
325
+ a .connsLock .Unlock ()
326
+
327
+ dialer := & net.Dialer {
328
+ LocalAddr : a .RelayAddr ,
329
+ Control : func (network , address string , c syscall.RawConn ) error {
330
+ var err error
331
+ c .Control (func (fd uintptr ) {
332
+ err = syscall .SetsockoptInt (int (fd ), syscall .SOL_SOCKET , unix .SO_REUSEADDR | unix .SO_REUSEPORT , 1 )
333
+ })
334
+ return err
335
+ },
336
+ }
337
+
338
+ conn , err := dialer .Dial ("tcp" , dst )
339
+ if err != nil {
340
+ return err
341
+ }
342
+
343
+ a .connsLock .Lock ()
344
+ a .addrToConn [dst ] = conn
345
+ a .cidToConn [cid ] = conn
346
+ a .connsLock .Unlock ()
347
+
348
+ return nil
349
+ }
350
+
351
+ func (a * Allocation ) removeConnection (cid proto.ConnectionID , dst string ) {
352
+ a .connsLock .Lock ()
353
+ c := a .cidToConn [cid ]
354
+ delete (a .addrToConn , dst )
355
+ delete (a .cidToConn , cid )
356
+ a .connsLock .Unlock ()
357
+ c .Close ()
358
+ }
359
+
360
+ func (a * Allocation ) connectionHandler (m * Manager ) {
361
+ for {
362
+ // When a server receives an incoming TCP connection on a relayed
363
+ // transport address, it processes the request as follows.
364
+ // The server MUST accept the connection. If it is not successful,
365
+ // nothing is sent to the client over the control connection.
366
+ conn , err := a .RelayListener .Accept ()
367
+ if err != nil {
368
+ m .DeleteAllocation (a .fiveTuple )
369
+ return
370
+ }
371
+
372
+ a .log .Debugf ("relay listener %s received connection from %s" ,
373
+ a .RelayListener .Addr ().String (),
374
+ conn .RemoteAddr ().String ())
375
+
376
+ // If the connection is successfully accepted, it is now called a peer
377
+ // data connection. The server MUST buffer any data received from the
378
+ // peer. The server adjusts its advertised TCP receive window to
379
+ // reflect the amount of empty buffer space.
380
+
381
+ // If no permission for this peer has been installed for this
382
+ // allocation, the server MUST close the connection with the peer
383
+ // immediately after it has been accepted.
384
+
385
+ if p := a .GetPermission (conn .RemoteAddr ()); p == nil {
386
+ a .log .Infof ("No Permission or Channel exists for %v on allocation %v" , conn .RemoteAddr (), a .RelayAddr .String ())
387
+ conn .Close ()
388
+ continue
389
+ }
390
+
391
+ // Otherwise, the server sends a ConnectionAttempt indication to the
392
+ // client over the control connection. The indication MUST include an
393
+ // XOR-PEER-ADDRESS attribute containing the peer's transport address,
394
+ // as well as a CONNECTION-ID attribute uniquely identifying the peer
395
+ // data connection.
396
+ cid := m .newCID (a )
397
+
398
+ a .connsLock .Lock ()
399
+ a .addrToConn [conn .RemoteAddr ().String ()] = conn
400
+ a .cidToConn [cid ] = conn
401
+ a .connsLock .Unlock ()
402
+
403
+ msg , err := stun .Build (
404
+ stun .TransactionID ,
405
+ stun .NewType (stun .MethodConnectionAttempt , stun .ClassIndication ),
406
+ )
407
+ if err != nil {
408
+ a .log .Errorf ("Failed to build MethodConnectionAttempt message %v" , err )
409
+ continue
410
+ }
411
+
412
+ addr , ok := conn .RemoteAddr ().(* net.TCPAddr )
413
+ if ! ok {
414
+ a .log .Errorf ("Failed to parse remote tcp address" )
415
+ continue
416
+ }
417
+
418
+ peerAddr := proto.PeerAddress {}
419
+ peerAddr .IP = addr .IP
420
+ peerAddr .Port = addr .Port
421
+
422
+ if err = peerAddr .AddTo (msg ); err != nil {
423
+ a .log .Errorf ("Failed to build MethodConnectionAttempt message %v" , err )
424
+ return
425
+ }
426
+
427
+ attrCid := proto .ConnectionID (cid )
428
+ attrCid .AddTo (msg )
429
+ a .TurnSocket .WriteTo (msg .Raw , a .fiveTuple .SrcAddr )
430
+
431
+ // If no ConnectionBind request associated with this peer data
432
+ // connection is received after 30 seconds, the peer data connection
433
+ // MUST be closed.
434
+
435
+ go m .removeAfter30 (cid , conn .RemoteAddr ())
436
+ }
437
+ }
0 commit comments