@@ -41,6 +41,7 @@ type ClientConfig struct {
4141 Password string
4242 Realm string
4343 Software string
44+ Protocol string
4445 RTO time.Duration
4546 Conn net.PacketConn // Listening socket (net.PacketConn)
4647 LoggerFactory logging.LoggerFactory
@@ -49,25 +50,27 @@ type ClientConfig struct {
4950
5051// Client is a STUN server client
5152type 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
7174}
7275
7376// 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) {
9396 log .Warn ("Virtual network is enabled" )
9497 }
9598
99+ protocol := proto .ProtoUDP
100+ if config .Protocol == "tcp" {
101+ protocol = proto .ProtoTCP
102+ }
103+
96104 var stunServ , turnServ net.Addr
97105 var stunServStr , turnServStr string
98106 if len (config .STUNServerAddr ) > 0 {
99107 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 ()
103121 }
104- stunServStr = stunServ .String ()
105122 log .Debugf ("stunServ: %s" , stunServStr )
106123 }
107124 if len (config .TURNServerAddr ) > 0 {
108125 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 ()
112139 }
113- turnServStr = turnServ .String ()
114140 log .Debugf ("turnServ: %s" , turnServStr )
115141 }
116142
@@ -133,6 +159,7 @@ func NewClient(config *ClientConfig) (*Client, error) {
133159 trMap : client .NewTransactionMap (),
134160 rto : rto ,
135161 log : log ,
162+ protocol : protocol ,
136163 }
137164
138165 return c , nil
@@ -238,42 +265,34 @@ func (c *Client) SendBindingRequest() (net.Addr, error) {
238265 return c .SendBindingRequestTo (c .stunServ )
239266}
240267
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
252272
253273 msg , err := stun .Build (
254274 stun .TransactionID ,
255275 stun .NewType (stun .MethodAllocate , stun .ClassRequest ),
256- proto.RequestedTransport {Protocol : proto . ProtoUDP },
276+ proto.RequestedTransport {Protocol : c . protocol },
257277 stun .Fingerprint ,
258278 )
259279 if err != nil {
260- return nil , err
280+ return relayed , lifetime , nonce , err
261281 }
262282
263283 trRes , err := c .PerformTransaction (msg , c .turnServ , false )
264284 if err != nil {
265- return nil , err
285+ return relayed , lifetime , nonce , err
266286 }
267287
268288 res := trRes .Msg
269289
270290 // Anonymous allocate failed, trying to authenticate.
271- var nonce stun.Nonce
272291 if err = nonce .GetFrom (res ); err != nil {
273- return nil , err
292+ return relayed , lifetime , nonce , err
274293 }
275294 if err = c .realm .GetFrom (res ); err != nil {
276- return nil , err
295+ return relayed , lifetime , nonce , err
277296 }
278297 c .realm = append ([]byte (nil ), c .realm ... )
279298 c .integrity = stun .NewLongTermIntegrity (
@@ -283,48 +302,101 @@ func (c *Client) Allocate() (net.PacketConn, error) {
283302 msg , err = stun .Build (
284303 stun .TransactionID ,
285304 stun .NewType (stun .MethodAllocate , stun .ClassRequest ),
286- proto.RequestedTransport {Protocol : proto . ProtoUDP },
305+ proto.RequestedTransport {Protocol : c . protocol },
287306 & c .username ,
288307 & c .realm ,
289308 & nonce ,
290309 & c .integrity ,
291310 stun .Fingerprint ,
292311 )
293312 if err != nil {
294- return nil , err
313+ return relayed , lifetime , nonce , err
295314 }
296315
297316 trRes , err = c .PerformTransaction (msg , c .turnServ , false )
298317 if err != nil {
299- return nil , err
318+ return relayed , lifetime , nonce , err
300319 }
301320 res = trRes .Msg
302321
303322 if res .Type .Class == stun .ClassErrorResponse {
304323 var code stun.ErrorCodeAttribute
305324 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
307326 }
308- return nil , fmt .Errorf ("%s" , res .Type ) //nolint:goerr113
327+ return relayed , lifetime , nonce , fmt .Errorf ("%s" , res .Type ) //nolint:goerr113
309328 }
310329
311330 // Getting relayed addresses from response.
312- var relayed proto.RelayedAddress
313331 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 {
314356 return nil , err
315357 }
358+
316359 relayedAddr := & net.UDPAddr {
317360 IP : relayed .IP ,
318361 Port : relayed .Port ,
319362 }
320363
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 {
324391 return nil , err
325392 }
326393
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 {
328400 Observer : c ,
329401 RelayedAddr : relayedAddr ,
330402 Integrity : c .integrity ,
@@ -333,15 +405,21 @@ func (c *Client) Allocate() (net.PacketConn, error) {
333405 Log : c .log ,
334406 })
335407
336- c .setRelayedUDPConn (relayedConn )
408+ c .setRelayedTCPConn (relayedConn )
337409
338410 return relayedConn , nil
339411}
340412
341413// CreatePermission Issues a CreatePermission request for the supplied addresses
342414// as described in https://datatracker.ietf.org/doc/html/rfc5766#section-9
343415func (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
345423}
346424
347425// PerformTransaction performs STUN transaction
@@ -445,7 +523,8 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
445523 }
446524
447525 if msg .Type .Class == stun .ClassIndication {
448- if msg .Type .Method == stun .MethodData {
526+ switch msg .Type .Method {
527+ case stun .MethodData :
449528 var peerAddr proto.PeerAddress
450529 if err := peerAddr .GetFrom (msg ); err != nil {
451530 return err
@@ -462,13 +541,37 @@ func (c *Client) handleSTUNMessage(data []byte, from net.Addr) error {
462541
463542 c .log .Debugf ("data indication received from %s" , from .String ())
464543
465- relayedConn := c .relayedUDPConn ()
544+ relayedConn := c .getRelayedUDPConn ()
466545 if relayedConn == nil {
467546 c .log .Debug ("no relayed conn allocated" )
468547 return nil // silently discard
469548 }
470-
471549 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 )
472575 }
473576 return nil
474577 }
@@ -514,7 +617,7 @@ func (c *Client) handleChannelData(data []byte) error {
514617 return err
515618 }
516619
517- relayedConn := c .relayedUDPConn ()
620+ relayedConn := c .getRelayedUDPConn ()
518621 if relayedConn == nil {
519622 c .log .Debug ("no relayed conn allocated" )
520623 return nil // silently discard
@@ -573,9 +676,23 @@ func (c *Client) setRelayedUDPConn(conn *client.UDPConn) {
573676 c .relayedConn = conn
574677}
575678
576- func (c * Client ) relayedUDPConn () * client.UDPConn {
679+ func (c * Client ) getRelayedUDPConn () * client.UDPConn {
577680 c .mutex .RLock ()
578681 defer c .mutex .RUnlock ()
579682
580683 return c .relayedConn
581684}
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