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