Skip to content

Conversation

ha-ves
Copy link
Contributor

@ha-ves ha-ves commented Mar 15, 2025

This enables TCP relay communication.

The justification was that the network--even the TURN server network, only allows TCP.

Though, as it currently stands, the RFC is quite new and the browsers don't seem to be implementing it anytime soon, this mode will not support connection with browser-based WebRTC peers.

may close #1294

remaining drafts:

  • SecureContext (replacing DTLS handshake?)

New public APIs:

  • X_ICEForceTCP on RTCConfiguration of bool
  • X_ICERelayProtocol on RTCIceServer of RTCIceProtocol

Dev notes:

  • IceServer class additional _secondaryRelayUri for TURN-TCP

refs:

- internal fields and properties for turn-tcp state-machine
- streamline DateTime epoch specifier

IceServer.cs:
- internal static properties for turn-tcp state-machine
- refactor icerelay property because it's internal-only

** RtpIceChannel.cs **:
- refactor descriptions
- reduce class constructor overloading by rearranging new useTcp parameter
- extract creating new IceTcpReceiver with relay specifier
- new logging lines are set as trace-level
- fix processchecklist overrun (didn't return after disabling timer)
- adds timer skipper on turn-tcp candidate
- some TODO suggestions comments
- adds turn-tcp state-machine & make the connectivity check block more readable
- fixes turn-tcp connection attempt indication and stun binding matching with checklist
- extract IP equals function from inside the method
- remove TLS placeholder
- put TCP reconnection placeholder
- *** send TCP by Socket synchronously ***
- detached OnPacketReceived to enable internal turn-tcp relay specifier
- remove redundant conditional local candidate relay && iceserver null

RTPChannel.cs:
- reduce class constructor overloading by rearranging new useTcp parameter
- adds closereason to receivers closings

RTCPeerConnection.cs:
- rearrange new useTcp in create RTP channel
@ha-ves ha-ves force-pushed the tcp-and-turn-tcp branch from 4431faf to adcdadf Compare April 25, 2025 02:25
@ha-ves
Copy link
Contributor Author

ha-ves commented Apr 25, 2025

Hi @sipsorcery ,

I did a whole PR rebase and merged with v8.0.12 bdbb80f.

After reading for quite a while, I'm stuck on the DTLS handshake part. What I found is that the networking part of the library is quite low-level. Once it hits the DTLS handshake as a server, it disconnects the TCP Socket.

I'm guessing it has something to do with context switching and threading and the such, it will need more than enough time to figure out what to do, so what I'd like to know is:

  • What did you have in mind on this matter?
  • Do you mind if I try to add a separate codebase for TCP implementation?

That said, both still require a lot of time with the legend Stephen's blog on C# .NET async stuff and sockets.
So I might close the PR or just leave it as is until that time comes around. There is so much potential with this library.

Thanks,

@sipsorcery
Copy link
Member

@ha-ves it takes a bit of mental gymnastics to work out how TCP TURN is meant to work for WebRTC. I think this statement from the Transports for WebRTC best explains it:

If TCP connections are used, RTP framing according to [RFC4571] MUST be used for all packets. This includes the RTP packets, DTLS packets used to carry data channels, and STUN connectivity check packets.

So it seems that once the TCP TURN connection is established all packets need to be sent in an RTP packet. This includes the DTLS packets, STUN checks and SCTP (data channel packets).

In theory it shouldn't be too difficult to manage the RTP framing given all the packet formats are already supported in this library. I suspect the hardest bit will be managing the TCP connections, particularly edge cases around dropping, re-connecting etc. I always found the TCP/TLS connection management problematic with the SIP transport purely because there is so much more state required to manage timeouts etc. etc. See the SIPTCPChannel class header for lots of gory details.

In theory to implement the TCP TURN mechanism what's required is a new implementation of the RTPChannel class that uses a TCP socket instead of the current UDP socket. The RTP framing mechanism could then be completely handled in the RTPTCPChannel. I'd classify it as a medium sized task where the SCTP protocol implementation was a big task (took me 6-7 weeks of full time effort).

Apart from that, if it is the case that as you say the support is not yet there in the browsers hard to see it being worth the effort...

@ha-ves
Copy link
Contributor Author

ha-ves commented Apr 25, 2025

@sipsorcery I see, I think I understand it now.

It does seem like there's not quite a way to just replace the network layer if in the end it'll need to be deriving the RTPChannel class.

Thanks, it's really helpful to know what you'd expect.

I'll port the current PR and see where it goes from there.

As for the browser peer, they don't support it, though RTP middlebox apps usually do support it, and as some people mentioned, their case wants TCP-only connection with the middlebox.

And I think especially in industrial areas they only use TCP because they need the connection state.
In such cases they usually don't traverse the uncontrollable network called The Internet so it'll make the PR start in a more ideal conditions.

@Forever-OnLine
Copy link

@ha-ves Hello, in my project, I want to use TCP for communication between TURN and WebRTC. I noticed that ICE specifies TCP by setting "transport=tcp". I would like to ask what the mechanism of this is?
And if I want to use TCP for communication, what steps should I take?
thank you!

@ha-ves
Copy link
Contributor Author

ha-ves commented Aug 24, 2025

@Forever-OnLine

I noticed that ICE specifies TCP by setting "transport=tcp".

That parameter only controls the connection with the relay server, not the resulting ICE candidate.
I believe TCP with a relay server is already implemented in this library.

I would like to ask what the mechanism of this is?
And if I want to use TCP for communication, what steps should I take?

This PR enables that, but is still stuck on the DTLS part and no direct TCP-TCP yet.

ChatGPT:

How to use TCP with this library

  • Ensure your TURN server supports TCP relaying (RFC 6062). With coturn, do not set no-tcp or no-tcp-relay; expose TCP port (e.g., 3478) and, if needed, TLS (5349).
  • Configure ICE servers to use TCP when talking to TURN and allow TCP relayed candidates.
var pc = new RTCPeerConnection(new()
{
    iceServers =
    [
        new()
        {
            urls = "turn:turn.example.com:3478?transport=tcp",
            username = "user",
            credential = "pass",
            credentialType = RTCIceCredentialType.password,
            X_ICERelayProtocol = RTCIceProtocol.tcp
        },
    ],
    iceTransportPolicy = RTCIceTransportPolicy.relay,
    //X_ICEForceTCP = true
});

Notes

  • RFC 6062 (TURN-TCP) is different from RFC 6544 (ICE-TCP host/srflx over TCP). This change is about TURN relayed TCP, not advertising host TCP candidates.
  • Browser JS usually doesn’t expose ICE-TCP candidates; many stacks use TURN over TCP to reach the server but still relay UDP for media. TURN-TCP is most useful for native/interop scenarios.
  • In TCP mode the agent handles TURN permissions first, then Connect/ConnectionBind, and only then proceeds with the connectivity checks over the established relay.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

WebRTC TURN over TCP needs adjust
3 participants