Skip to content

Commit 4545194

Browse files
authored
feat: restrict ICE port ranges and control candidate gathering behavior (#202)
* feat: implement PortAllocatorConfig for ICE candidate management * test: add integration test for PortAllocatorConfig to verify ICE candidate behavior * docs: add PortAllocatorConfig guide
1 parent 7e47166 commit 4545194

File tree

14 files changed

+1069
-0
lines changed

14 files changed

+1069
-0
lines changed

docs/_sidebar.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@
2121
- [Custom Video Source](guide/custom_video_source.md)
2222
- Data
2323
- [Data Channels](guide/data_channels.md)
24+
- Networking and ICE
25+
- [Port Allocator Config](guide/port_allocator_config.md)
2426
- Monitoring and Debugging
2527
- [RTC Stats](guide/rtc_stats.md)
2628
- [Logging](guide/logging.md)

docs/guide/overview.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,10 @@ This section provides detailed guides for various features of the webrtc-java li
3131
- [RTC Stats](guide/rtc_stats.md) - Monitoring connection quality and performance
3232
- [Logging](guide/logging.md) - Configuring and using the logging system
3333

34+
## Networking and ICE
35+
36+
- [Port Allocator Config](guide/port_allocator_config.md) - Restrict ICE port ranges and control candidate gathering behavior
37+
3438
## Additional Resources
3539

3640
For a complete API reference, check the [JavaDoc](https://javadoc.io/doc/dev.onvoid.webrtc/webrtc-java/latest/index.html).
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
# Port Allocator Configuration (ICE) <!-- {docsify-ignore-all} -->
2+
3+
This guide explains how to configure the ICE port allocator using `dev.onvoid.webrtc.PortAllocatorConfig` and how to use it with `RTCConfiguration` when creating a peer connection.
4+
5+
The Port Allocator controls:
6+
- The local ephemeral port range used for gathering ICE candidates (HOST, SRFLX, RELAY).
7+
- Transport behavior via bit flags that mirror native WebRTC PortAllocator flags (e.g., disable TCP candidates, enable IPv6, etc.).
8+
9+
When you need to restrict the ports your application binds to (e.g., to satisfy firewall rules) or tweak which transport types are gathered, use `PortAllocatorConfig`.
10+
11+
## API Overview
12+
13+
`PortAllocatorConfig` exposes three fields:
14+
- `minPort` (int): Minimum UDP/TCP port to use for candidate gathering (inclusive). Set to 0 to leave unspecified.
15+
- `maxPort` (int): Maximum UDP/TCP port to use for candidate gathering (inclusive). Set to 0 to leave unspecified.
16+
- `flags` (int): Bitwise OR of allocator flags (default 0).
17+
18+
Notes:
19+
- If both `minPort` and `maxPort` are set to non‑zero values, `minPort` must be less than or equal to `maxPort`.
20+
- A value of 0 for either `minPort` or `maxPort` means "not specified" and the native defaults are used.
21+
22+
Convenience methods are provided to toggle specific behaviors and to combine flags:
23+
- `setFlag(int flag)`, `clearFlag(int flag)`, `isFlagEnabled(int flag)`
24+
- Boolean helpers like `setDisableTcp(boolean)`, `isTcpDisabled()`, etc.
25+
26+
## Supported Flags
27+
28+
The following flags mirror WebRTC's native PortAllocator flags. You can use them directly via `setFlag/clearFlag` or through the boolean helpers.
29+
30+
- `PORTALLOCATOR_DISABLE_UDP` — Disable local UDP socket allocation for host candidates.
31+
- `PORTALLOCATOR_DISABLE_STUN` — Disable STUN candidate gathering (server reflexive).
32+
- `PORTALLOCATOR_DISABLE_RELAY` — Disable TURN relay candidate gathering.
33+
- `PORTALLOCATOR_DISABLE_TCP` — Disable local TCP candidate gathering.
34+
- `PORTALLOCATOR_ENABLE_IPV6` — Enable IPv6 support.
35+
- `PORTALLOCATOR_ENABLE_SHARED_SOCKET` — Enable shared UDP socket mode (platform/stack‑dependent behavior).
36+
- `PORTALLOCATOR_ENABLE_STUN_RETRANSMIT_ATTRIBUTE` — Include STUN retransmit attribute on requests.
37+
- `PORTALLOCATOR_DISABLE_ADAPTER_ENUMERATION` — Do not enumerate network adapters.
38+
- `PORTALLOCATOR_DISABLE_DEFAULT_LOCAL_CANDIDATE` — Do not generate a default local candidate.
39+
- `PORTALLOCATOR_DISABLE_UDP_RELAY` — Disable UDP TURN relay.
40+
- `PORTALLOCATOR_DISABLE_COSTLY_NETWORKS` — Avoid cellular/expensive networks for candidate gathering.
41+
- `PORTALLOCATOR_ENABLE_IPV6_ON_WIFI` — Allow IPv6 over Wi‑Fi.
42+
- `PORTALLOCATOR_ENABLE_ANY_ADDRESS_PORTS` — Allow binding to any‑address (0.0.0.0/::) ports.
43+
- `PORTALLOCATOR_DISABLE_LINK_LOCAL_NETWORKS` — Avoid link‑local network interfaces.
44+
45+
## Basic Usage
46+
47+
You configure the port allocator on the `RTCConfiguration` before creating the `RTCPeerConnection`.
48+
49+
```java
50+
RTCConfiguration cfg = new RTCConfiguration();
51+
52+
// Constrain ephemeral port range for HOST candidates
53+
cfg.portAllocatorConfig.minPort = 48000;
54+
cfg.portAllocatorConfig.maxPort = 48100;
55+
56+
// Example: Disable TCP candidates, keep UDP enabled (default)
57+
cfg.portAllocatorConfig.setDisableTcp(true);
58+
59+
// Optional: Enable IPv6 support
60+
// cfg.portAllocatorConfig.setEnableIpv6(true);
61+
62+
RTCPeerConnection pc = factory.createPeerConnection(cfg, observer);
63+
```
64+
65+
## Using Flags Directly
66+
67+
You can combine flags using bitwise OR and set them at once:
68+
69+
```java
70+
int flags = PortAllocatorConfig.PORTALLOCATOR_DISABLE_TCP
71+
| PortAllocatorConfig.PORTALLOCATOR_DISABLE_RELAY
72+
| PortAllocatorConfig.PORTALLOCATOR_ENABLE_IPV6;
73+
74+
RTCConfiguration cfg = new RTCConfiguration();
75+
cfg.portAllocatorConfig.minPort = 50000;
76+
cfg.portAllocatorConfig.maxPort = 50100;
77+
cfg.portAllocatorConfig.flags = flags;
78+
79+
RTCPeerConnection pc = factory.createPeerConnection(cfg, observer);
80+
```
81+
82+
Or use the fluent helpers:
83+
84+
```java
85+
cfg.portAllocatorConfig
86+
.setDisableStun(true)
87+
.setDisableRelay(true)
88+
.setEnableSharedSocket(true);
89+
```
90+
91+
## Tips and Troubleshooting
92+
93+
- Port Range Validity: Ensure `minPort <= maxPort` when both are set. If either is 0, the native default behavior applies.
94+
- Firewalls/NATs: When running behind strict firewalls, restrict the host candidate port range to an allowed window and ensure your firewall allows outbound UDP for STUN/TURN as needed.
95+
- Disabling Candidates: Disabling STUN and RELAY will limit you to host candidates, which may prevent connectivity across NATs. Use with care.
96+
- TCP Candidates: Disabling TCP can speed up gathering and reduce unwanted candidates, but may reduce connectivity options in restrictive environments.
97+
- IPv6: Enabling IPv6 may improve connectivity on IPv6‑capable networks; consider also `setEnableIpv6OnWifi(true)` when applicable.
98+
99+
## Related API
100+
101+
- `RTCConfiguration` — holds `portAllocatorConfig` used by `PeerConnectionFactory#createPeerConnection`.
102+
- `RTCPeerConnection` — creating a peer connection triggers ICE gathering.
103+
- `RTCIceServer` — define STUN/TURN servers for non‑host candidates.
104+
105+
For the full API, see the JavaDoc for `PortAllocatorConfig` and `RTCConfiguration`.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright 2025 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#ifndef JNI_WEBRTC_API_PORT_ALLOCATOR_CONFIG_H_
18+
#define JNI_WEBRTC_API_PORT_ALLOCATOR_CONFIG_H_
19+
20+
#include "JavaClass.h"
21+
#include "JavaRef.h"
22+
23+
#include "api/peer_connection_interface.h"
24+
25+
#include <jni.h>
26+
27+
namespace jni
28+
{
29+
namespace PortAllocatorConfig
30+
{
31+
class JavaPortAllocatorConfigClass : public JavaClass
32+
{
33+
public:
34+
explicit JavaPortAllocatorConfigClass(JNIEnv * env);
35+
36+
jclass cls;
37+
jmethodID ctor;
38+
jfieldID minPort;
39+
jfieldID maxPort;
40+
jfieldID flags;
41+
};
42+
43+
JavaLocalRef<jobject> toJava(JNIEnv * env, const webrtc::PeerConnectionInterface::PortAllocatorConfig & cfg);
44+
}
45+
}
46+
47+
#endif

webrtc-jni/src/main/cpp/include/api/RTCConfiguration.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ namespace jni
4040
jfieldID bundlePolicy;
4141
jfieldID rtcpMuxPolicy;
4242
jfieldID certificates;
43+
jfieldID portAllocatorConfig;
4344
};
4445

4546
JavaLocalRef<jobject> toJava(JNIEnv * env, const webrtc::PeerConnectionInterface::RTCConfiguration & config);
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
/*
2+
* Copyright 2025 Alex Andres
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
#include "api/PortAllocatorConfig.h"
18+
#include "JavaClasses.h"
19+
#include "JavaObject.h"
20+
#include "JavaUtils.h"
21+
#include "JNI_WebRTC.h"
22+
23+
namespace jni
24+
{
25+
namespace PortAllocatorConfig
26+
{
27+
JavaLocalRef<jobject> toJava(JNIEnv * env, const webrtc::PeerConnectionInterface::PortAllocatorConfig & cfg)
28+
{
29+
const auto javaClass = JavaClasses::get<JavaPortAllocatorConfigClass>(env);
30+
31+
jobject jpac = env->NewObject(javaClass->cls, javaClass->ctor);
32+
33+
JavaObject obj(env, JavaLocalRef<jobject>(env, jpac));
34+
obj.setInt(javaClass->minPort, cfg.min_port);
35+
obj.setInt(javaClass->maxPort, cfg.max_port);
36+
obj.setInt(javaClass->flags, cfg.flags);
37+
38+
return JavaLocalRef<jobject>(env, jpac);
39+
}
40+
41+
JavaPortAllocatorConfigClass::JavaPortAllocatorConfigClass(JNIEnv * env)
42+
{
43+
cls = FindClass(env, PKG"PortAllocatorConfig");
44+
ctor = GetMethod(env, cls, "<init>", "()V");
45+
minPort = GetFieldID(env, cls, "minPort", "I");
46+
maxPort = GetFieldID(env, cls, "maxPort", "I");
47+
flags = GetFieldID(env, cls, "flags", "I");
48+
}
49+
}
50+
}

webrtc-jni/src/main/cpp/src/api/RTCConfiguration.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "api/RTCConfiguration.h"
1818
#include "api/RTCIceServer.h"
19+
#include "api/PortAllocatorConfig.h"
1920
#include "rtc/RTCCertificatePEM.h"
2021
#include "JavaArrayList.h"
2122
#include "JavaClasses.h"
@@ -56,6 +57,9 @@ namespace jni
5657
env->SetObjectField(config, javaClass->rtcpMuxPolicy, rtcpMuxPolicy.get());
5758
env->SetObjectField(config, javaClass->certificates, certificateList.listObject());
5859

60+
auto pac = jni::PortAllocatorConfig::toJava(env, nativeType.port_allocator_config);
61+
env->SetObjectField(config, javaClass->portAllocatorConfig, pac.get());
62+
5963
return JavaLocalRef<jobject>(env, config);
6064
}
6165

@@ -70,6 +74,7 @@ namespace jni
7074
JavaLocalRef<jobject> bp = obj.getObject(javaClass->bundlePolicy);
7175
JavaLocalRef<jobject> mp = obj.getObject(javaClass->rtcpMuxPolicy);
7276
JavaLocalRef<jobject> cr = obj.getObject(javaClass->certificates);
77+
JavaLocalRef<jobject> pac = obj.getObject(javaClass->portAllocatorConfig);
7378

7479
webrtc::PeerConnectionInterface::RTCConfiguration configuration;
7580

@@ -89,6 +94,15 @@ namespace jni
8994
}
9095
}
9196

97+
if (pac.get() != nullptr) {
98+
const auto pacJavaClass = JavaClasses::get<PortAllocatorConfig::JavaPortAllocatorConfigClass>(env);
99+
JavaObject pacObj(env, pac);
100+
101+
configuration.port_allocator_config.min_port = pacObj.getInt(pacJavaClass->minPort);
102+
configuration.port_allocator_config.max_port = pacObj.getInt(pacJavaClass->maxPort);
103+
configuration.port_allocator_config.flags = pacObj.getInt(pacJavaClass->flags);
104+
}
105+
92106
return configuration;
93107
}
94108

@@ -103,6 +117,7 @@ namespace jni
103117
bundlePolicy = GetFieldID(env, cls, "bundlePolicy", "L" PKG "RTCBundlePolicy;");
104118
rtcpMuxPolicy = GetFieldID(env, cls, "rtcpMuxPolicy", "L" PKG "RTCRtcpMuxPolicy;");
105119
certificates = GetFieldID(env, cls, "certificates", LIST_SIG);
120+
portAllocatorConfig = GetFieldID(env, cls, "portAllocatorConfig", "L" PKG "PortAllocatorConfig;");
106121
}
107122
}
108123
}

0 commit comments

Comments
 (0)