Skip to content

TCP ICE first iteration#89

Open
sgfn wants to merge 9 commits intomasterfrom
tcp-ice
Open

TCP ICE first iteration#89
sgfn wants to merge 9 commits intomasterfrom
tcp-ice

Conversation

@sgfn
Copy link
Member

@sgfn sgfn commented Nov 20, 2025

The current implementation successfully gathers host and server-reflexive TCP candidates, and connects to the other side. Relay candidates are not supported.

Note that not all STUN servers support TCP (e.g. stun.l.google.com:19302 does not).

Potential issues and bottlenecks are outlined in the comments.

ref: elixir-webrtc/ex_webrtc#238

Relevant RFCs:

@codecov
Copy link

codecov bot commented Feb 12, 2026

Codecov Report

❌ Patch coverage is 90.74890% with 21 lines in your changes missing coverage. Please review.
✅ Project coverage is 87.13%. Comparing base (34824b2) to head (76490f0).

Files with missing lines Patch % Lines
lib/ex_ice/priv/transport/tcp_client.ex 85.71% 11 Missing ⚠️
lib/ex_ice/candidate.ex 82.14% 5 Missing ⚠️
lib/ex_ice/priv/app.ex 50.00% 1 Missing ⚠️
lib/ex_ice/priv/candidate.ex 96.87% 1 Missing ⚠️
lib/ex_ice/priv/ice_agent.ex 97.61% 1 Missing ⚠️
lib/ex_ice/priv/mdns/resolver.ex 75.00% 1 Missing ⚠️
lib/ex_ice/priv/transport/tcp.ex 92.30% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master      #89      +/-   ##
==========================================
+ Coverage   86.06%   87.13%   +1.06%     
==========================================
  Files          25       27       +2     
  Lines        1902     2075     +173     
==========================================
+ Hits         1637     1808     +171     
- Misses        265      267       +2     
Files with missing lines Coverage Δ
lib/ex_ice/ice_agent.ex 70.51% <100.00%> (+4.29%) ⬆️
lib/ex_ice/priv/candidate/host.ex 100.00% <100.00%> (ø)
lib/ex_ice/priv/candidate/prflx.ex 75.00% <100.00%> (+17.85%) ⬆️
lib/ex_ice/priv/candidate/relay.ex 83.67% <100.00%> (+0.34%) ⬆️
lib/ex_ice/priv/candidate/srflx.ex 75.00% <100.00%> (+3.57%) ⬆️
lib/ex_ice/priv/candidate_base.ex 94.11% <100.00%> (+1.26%) ⬆️
lib/ex_ice/priv/checklist.ex 100.00% <ø> (ø)
lib/ex_ice/priv/gatherer.ex 96.00% <100.00%> (+0.22%) ⬆️
lib/ex_ice/priv/transport/udp.ex 100.00% <100.00%> (ø)
test/support/transport/mock.ex 80.64% <100.00%> (+0.64%) ⬆️
... and 7 more

Continue to review full report in Codecov by Sentry.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update 34824b2...76490f0. Read the comment docs.

🚀 New features to boost your workflow:
  • ❄️ Test Analytics: Detect flaky tests, report on failures, and find test suite problems.

@sgfn sgfn changed the title [WIP] TCP ICE TCP ICE first iteration Feb 12, 2026
@sgfn sgfn marked this pull request as ready for review February 12, 2026 16:58
@sgfn sgfn requested a review from Karolk99 February 12, 2026 16:58
Copy link
Contributor

@Karolk99 Karolk99 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall, great job!

  1. When I read this, I became curious about pion implementation. Did you look at how they manage tcp candidates?
  2. We should release the ICE and the WebRTC packages before merging this PR.
  3. We should add some more tests for this feature, if possible. From what I saw in this PR, the only new tests are for candidates' priority and candidates gathering.

Comment on lines 39 to 41
# HACK: using listen sockets here is ugly, but was easier to fit into the existing ICE Agent implementation.
# This should be changed, especially because we're going to want to close the listen sockets
# after the connection is successfully established.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You can add to this comment that listen_socket is used to access connected_socket.


@impl true
def handle_call({:close, listen_socket}, _from, state) do
# TODO: revisit the closing logic
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you add more specific comment.

<<length::unsigned-big-16, data::binary-size(length), rest::binary>> ->
# HACK: this is dirty and means that, with framing, we're miscalculating
# the bytes_sent and bytes_received counters
send(state.ice_agent, {:udp, state.listen_socket, src_ip, src_port, data})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could call {:tcp, ,,,,} then in ICEAgent call Priv.ICEAgent.handle_tcp and only in Priv.ICEAgent add call to handle_udp with comment that this is the same because framing is handled in tcp_client.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure how I feel about this change because ideally (in the future) we'd want the ICE Agent to be the controlling process of the TCP connection, and handle the 3-element {:tcp, socket, packet} messages, not the 5-element {:tcp, listen_socket, ip, port, reconstructed_payload} ones we'd be creating in the Client.

That being said, I won't contest it if you strongly believe this way is better/more descriptive

def send(listen_socket, dest, packet, tp_opts \\ []) do
with {:ok, local} <- sockname(listen_socket),
[{pid, _}] <- Registry.lookup(ExICE.Priv.Registry, local) do
GenServer.call(pid, {:send, listen_socket, dest, packet, tp_opts})
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can use Client.send

@sgfn
Copy link
Member Author

sgfn commented Feb 19, 2026

Ad 1. No, but I can take a look
Ad 2. Agreed
Ad 3. Added transport option to P2P integration tests (and fixed one bug in the process)

@sgfn sgfn requested a review from Karolk99 February 19, 2026 13:23
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.

2 participants

Comments