Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support active TCP candidates (RFC6544) #565

Merged
merged 2 commits into from
May 15, 2023
Merged

Support active TCP candidates (RFC6544) #565

merged 2 commits into from
May 15, 2023

Conversation

ashellunts
Copy link
Contributor

@ashellunts ashellunts commented May 9, 2023

This PR implements support for active TCP candidates as specified in RFC6544

Open issue: local active TCP candidate can be connected only with 1 remote.

@ashellunts ashellunts changed the title Active tcp Active TCP mode May 9, 2023
@ashellunts ashellunts requested review from stv0g and Sean-Der May 9, 2023 19:20
@codecov
Copy link

codecov bot commented May 9, 2023

Codecov Report

Patch coverage: 66.99% and project coverage change: +0.59 🎉

Comparison is base (898746c) 77.84% compared to head (5b2e30d) 78.44%.

❗ Current head 5b2e30d differs from pull request most recent head 72773df. Consider uploading reports for the commit 72773df to get more accurate results

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #565      +/-   ##
==========================================
+ Coverage   77.84%   78.44%   +0.59%     
==========================================
  Files          41       41              
  Lines        4215     4272      +57     
==========================================
+ Hits         3281     3351      +70     
+ Misses        726      714      -12     
+ Partials      208      207       -1     
Flag Coverage Δ
go 78.44% <66.99%> (+0.59%) ⬆️
wasm 22.80% <9.70%> (+0.04%) ⬆️

Flags with carried forward coverage won't be shown. Click here to find out more.

Impacted Files Coverage Δ
agent_config.go 83.14% <40.00%> (+1.00%) ⬆️
candidate_base.go 86.47% <62.50%> (+0.15%) ⬆️
gather.go 66.54% <63.15%> (-0.25%) ⬇️
agent.go 82.16% <70.73%> (+0.12%) ⬆️
candidatetype.go 79.48% <80.00%> (+0.69%) ⬆️
candidate_peer_reflexive.go 81.81% <100.00%> (+0.56%) ⬆️

... and 3 files with indirect coverage changes

☔ View full report in Codecov by Sentry.
📢 Do you have feedback about the report comment? Let us know in this issue.

@ashellunts ashellunts marked this pull request as ready for review May 10, 2023 06:42
@ashellunts ashellunts force-pushed the active-tcp branch 2 times, most recently from 5e6c8d0 to 9afe3ad Compare May 10, 2023 07:00
agent.go Outdated Show resolved Hide resolved
agent_config.go Outdated Show resolved Hide resolved
agent_active_tcp_test.go Outdated Show resolved Hide resolved
agent_active_tcp_test.go Outdated Show resolved Hide resolved
gather.go Show resolved Hide resolved
gather.go Outdated Show resolved Hide resolved
@stv0g
Copy link
Member

stv0g commented May 10, 2023

Hi @ashellunts, its really cool to see some progress here :) 🥳

@stv0g stv0g mentioned this pull request May 10, 2023
@ashellunts
Copy link
Contributor Author

Another thing I am thinking. Would it be a good idea to test in different network conditions using vnet? @stv0g

@stv0g
Copy link
Member

stv0g commented May 10, 2023

@ashellunts Unfortuantely, transport/vnet has no TCP support yet: pion/transport#27

I also dont expect this to land soon. Hence, we should proceed without vnet tests for now..

@Sean-Der
Copy link
Member

Amazing work @ashellunts so happy to see this land. Huge thank you @stv0g for being a great reviewer :)

Passive requires using a Mux. I think that makes sense. TCP is only preferable in restrictive environments. Those environments usually only allow a few TCP ports.

I think we can put this behind Type+NetworkTypes in Config! If Host+TCP is enabled we should have Active TCP.

My only call out is we should prefer Host+Srflx UDP over TCP. TCP I think is preferable to Relay IMO

I would love to see this land ASAP! If it has bugs/TODOs we can always fix those :)

@stv0g
Copy link
Member

stv0g commented May 10, 2023

Hi @Sean-Der,

thanks for your feedback!

TCP is only preferable in restrictive environments. Those environments usually only allow a few TCP ports.

I assumed that we will see the passive side usually deployed at a Pion agent running at some public server.
In that case the active agents would be running in a restricted network.

My only call out is we should prefer Host+Srflx UDP over TCP. TCP I think is preferable to Relay IMO

Good point. Actually RFC6544 Section 4.2 specifies this behaviour:

The transport protocol itself is a criteria for choosing one candidate over another.
If a particular media stream can run over UDP or TCP, the UDP candidates might be preferred over the TCP candidates.
This allows ICE to use the lower latency UDP connectivity if it exists but fallback to TCP if UDP doesn't work.

(The RFC continues to elaborate here...)

I would love to see this land ASAP! If it has bugs/TODOs we can always fix those :)

I agree :) We just need to get the API right :-S

@stv0g stv0g changed the title Active TCP mode Support active TCP candidates (RFC6544) May 10, 2023
@ashellunts
Copy link
Contributor Author

ashellunts commented May 10, 2023

I think we can put this behind Type+NetworkTypes in Config! If Host+TCP is enabled we should have Active TCP.

Currently passive candidates are collected when Host+TCP is used. Do you suggest to enable active ones always together with passive ones, when Host+TCP is enabled?

Does it make sense to have option to choose from following cases:

  • only passive ones (as it is right now); this one allows to disable active candidates so no changes in behavior for library clients;
  • only active ones; for client-side applications;
  • both active and passive; not sure use case here. @stv0g you had some ideas regarding this. Is it server to server communication?

@Sean-Der
Copy link
Member

Currently passive candidates are collected when Host+TCP is used. Do you suggest to enable active ones always together with passive ones, when Host+TCP is enabled?

I think we should do this.

Enable Active by default. If AgentConfig has ICECandidateTypeHost and NetworkTypeTCP (the default values) we should connect to remote Passives.

This will have zero effect on most users today. If the remote only publishes UDP candidates no TCP connections will be made. If the remote publishes a TCP candidate we will attempt a connection.


Leave Passive disabled (same behavior we have now). Don't modify any passive UDP code and leave UDP Mux etc.. as it is.

Passive candidates require special configuration. You usually want them on :80 or :443 and you want all your ICE Agents sharing that. If we just listen on random TCP ports I don't think we are giving users the best experience possible.

I also believe that listening on a new random TCP Port would be confusing to users.

@stv0g
Copy link
Member

stv0g commented May 11, 2023

Enable Active by default.

👍

Leave Passive disabled (same behavior we have now).

👍

@stv0g
Copy link
Member

stv0g commented May 11, 2023

Both active and passive; not sure use case here. @stv0g you had some ideas regarding this. Is it server to server communication?

I think also local LAN connectivity can profit from TCP candidates if requested.
Using TCP candidates can have also its advantages based on the use case (e.g. file transfers instead of video streaming).

And while pion/ice is mainly used for pion/webrtc, WebRTC is not the only use case (I have others :D)

@ashellunts
Copy link
Contributor Author

ashellunts commented May 11, 2023

OK, let me try to summarize:

  • ActiveTCP flag is removed, so no API changes needed.
  • If ICECandidateTypeHost and NetworkTypeTCP is set, active TCP candidate is generated.
  • If (ICECandidateTypeHost and NetworkTypeTCP is set) AND TCPMux is set, both active and passive candidates are generated.

I have checked: UDP host+srflx has less priority than TCP host+prflx (active/passive pair).
Priority calculation should be updated...

@Sean-Der
Copy link
Member

@ashellunts summary sounds great to me! If you have a PR that does that would approve.

@stv0g totally agree. If we prioritize WebRTC it makes everything worse :(

We should write a ‘best configuration guide’. So developers know the best way to build their systems for connectivity success. If they are doing cross subnet TCP they probably want on a known part. Things like that could help a lot .

@ashellunts ashellunts force-pushed the active-tcp branch 3 times, most recently from 459f146 to e4e2848 Compare May 12, 2023 12:13
@ashellunts ashellunts requested a review from stv0g May 12, 2023 12:56
Copy link
Member

@stv0g stv0g left a comment

Choose a reason for hiding this comment

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

Hey, good work :)

I think we are not yet following the RFC in terms of type and local preferences.

agent.go Outdated Show resolved Hide resolved
agent_config.go Show resolved Hide resolved
candidate_base.go Show resolved Hide resolved
candidatetype.go Outdated
@@ -38,7 +38,21 @@ func (c CandidateType) String() string {
// The RECOMMENDED values are 126 for host candidates, 100
// for server reflexive candidates, 110 for peer reflexive candidates,
// and 0 for relayed candidates.
func (c CandidateType) Preference() uint16 {
func (c CandidateType) Preference(networkType NetworkType) uint16 {
Copy link
Member

Choose a reason for hiding this comment

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

I dont think this exactly reflects the recommendation of RFC6544 Section 4.2:

When both UDP and TCP candidates are offered for the same media stream, and one transport protocol should be preferred over the other, the type preferences for the preferred transport protocol candidates SHOULD be increased and/or the type preferences for the other transport protocol candidates SHOULD be decreased.

So I think we should have a user-configurable offset which is added/substracted from the type-dependent preference.

How much the values should be increased or decreased depends on whether it is more important to choose a certain transport protocol or a certain candidate type. If the candidate type is more important (e.g., even if UDP is preferred, TCP host candidates are preferred over UDP server reflexive candidates) changing type preference values by one for the other transport protocol candidates is enough. On the other hand, if the transport protocol is more important (e.g., any UDP candidate is preferred over any TCP candidate), all the preferred transport protocol candidates SHOULD have type preference higher than the other transport protocol candidates. However, it is RECOMMENDED that the relayed candidates are still preferred lower than the other candidate types. For RTP-based media streams, it is RECOMMENDED that UDP candidates are preferred over TCP candidates.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

That would mean we need to change existing default type priority for UDP.
Because currently host UDP type priority is 126, max value. So we can't increase it anymore.
If we want to use offsets, we need to make lower.

That may affect existing applications. Personally I would not want to affect existing library clients if they don't use TCP at all.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

See also 92be181

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Though we may use offset to reduce TCP priorities and not change UDP ones. That would conform to the standard.

gather.go Outdated
@@ -225,7 +199,7 @@ func (a *Agent) gatherCandidatesLocal(ctx context.Context, networkTypes []Networ
Address: address,
Port: connAndPort.port,
Component: ComponentRTP,
TCPType: tcpType,
TCPType: connAndPort.tcpType,
Copy link
Member

Choose a reason for hiding this comment

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

Can we rename this simply to cfg? And the corresponding conns to cfgs?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I prefer more verbose naming. What about connectionConfiguration?

agent.go Outdated Show resolved Hide resolved
@ashellunts
Copy link
Contributor Author

I have added tests that check if both TCP/UDP are enabled, UDP is selected pair but the test fails sometime. Not sure why... any ideas? @stv0g

Looks like if TCP is selected at first, later it is not changed to UDP (I have added sleep and selected candidate does not change), though UDP pair priority is higher.

@ashellunts ashellunts force-pushed the active-tcp branch 2 times, most recently from dbdde52 to 268fff8 Compare May 13, 2023 17:05
@ashellunts
Copy link
Contributor Author

Looks like it is expected behavior.

If I add timeout for host candidate, UDP is always selected.

@ashellunts ashellunts requested a review from stv0g May 13, 2023 21:25
Copy link
Member

@Sean-Der Sean-Der left a comment

Choose a reason for hiding this comment

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

Fantastic work! I am all for merging this @ashellunts

We should then cut a release and reach out to the user that was looking to use Active TCP. Tell me if there is anything I can do to help :)

@ashellunts
Copy link
Contributor Author

Added user option to configure relative offset of TCP candidate type priority. By default it is set to 27 so that UDP+srlfx > TCP+host.

@Sean-Der
Copy link
Member

@ashellunts mind just squashing into one commit? Just to make debugging easier!

really excited to see this long standing issue resolved:)

By default TCP candidate type priority is UDP one minus 27 (except
relay), so that UDP+srlfx priority > TCP+host priority. That priority
offset can be configured using AgentConfig.

Ipv6 TCP candidates are also supported.

Open issue: local active TCP candidate can be connected only with 1
remote passive candidate.
@ashellunts
Copy link
Contributor Author

Sure, I like to make smaller commits during review phases, so that reviewer can see difference pushed.
Currently there is 1 open issue: local active TCP candidate can be connected only with 1 remote passive candidate.

really excited to see this long standing issue resolved:)

Yes, I am also glad to finish the feature, especially when there are people waiting for it.

Off topic: what percentage in codecov/patch report means?

agent_config.go Show resolved Hide resolved
@stv0g stv0g merged commit 1d502ca into master May 15, 2023
@stv0g stv0g deleted the active-tcp branch May 15, 2023 20:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

3 participants