Detailed changes
@@ -1,17 +1,8 @@
package eu.siacs.conversations.xmpp.jingle;
-import android.util.Log;
-import com.google.common.base.Strings;
-import com.google.common.collect.ImmutableSet;
-import com.google.common.primitives.Ints;
-import eu.siacs.conversations.Config;
-import eu.siacs.conversations.utils.IP;
-import eu.siacs.conversations.xml.Element;
-import eu.siacs.conversations.xml.Namespace;
+import im.conversations.android.xmpp.model.disco.external.Services;
import im.conversations.android.xmpp.model.stanza.Iq;
-import java.util.Arrays;
import java.util.Collections;
-import java.util.List;
import java.util.Set;
import org.webrtc.PeerConnection;
@@ -21,74 +12,10 @@ public final class IceServers {
if (response.getType() != Iq.Type.RESULT) {
return Collections.emptySet();
}
- final var builder = new ImmutableSet.Builder<PeerConnection.IceServer>();
- final Element services =
- response.findChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY);
- final List<Element> children =
- services == null ? Collections.emptyList() : services.getChildren();
- for (final Element child : children) {
- if ("service".equals(child.getName())) {
- final String type = child.getAttribute("type");
- final String host = child.getAttribute("host");
- final String sport = child.getAttribute("port");
- final Integer port = sport == null ? null : Ints.tryParse(sport);
- final String transport = child.getAttribute("transport");
- final String username = child.getAttribute("username");
- final String password = child.getAttribute("password");
- if (Strings.isNullOrEmpty(host) || port == null) {
- continue;
- }
- if (port < 0 || port > 65535) {
- continue;
- }
-
- if (Arrays.asList("stun", "stuns", "turn", "turns").contains(type)
- && Arrays.asList("udp", "tcp").contains(transport)) {
- if (Arrays.asList("stuns", "turns").contains(type) && "udp".equals(transport)) {
- Log.w(
- Config.LOGTAG,
- "skipping invalid combination of udp/tls in external services");
- continue;
- }
-
- // STUN URLs do not support a query section since M110
- final String uri;
- if (Arrays.asList("stun", "stuns").contains(type)) {
- uri = String.format("%s:%s:%s", type, IP.wrapIPv6(host), port);
- } else {
- uri =
- String.format(
- "%s:%s:%s?transport=%s",
- type, IP.wrapIPv6(host), port, transport);
- }
-
- final PeerConnection.IceServer.Builder iceServerBuilder =
- PeerConnection.IceServer.builder(uri);
- iceServerBuilder.setTlsCertPolicy(
- PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK);
- if (username != null && password != null) {
- iceServerBuilder.setUsername(username);
- iceServerBuilder.setPassword(password);
- } else if (Arrays.asList("turn", "turns").contains(type)) {
- // The WebRTC spec requires throwing an
- // InvalidAccessError when username (from libwebrtc
- // source coder)
- // https://chromium.googlesource.com/external/webrtc/+/master/pc/ice_server_parsing.cc
- Log.w(
- Config.LOGTAG,
- "skipping "
- + type
- + "/"
- + transport
- + " without username and password");
- continue;
- }
- final PeerConnection.IceServer iceServer = iceServerBuilder.createIceServer();
- Log.w(Config.LOGTAG, "discovered ICE Server: " + iceServer);
- builder.add(iceServer);
- }
- }
+ final var services = response.getExtension(Services.class);
+ if (services == null) {
+ return Collections.emptySet();
}
- return builder.build();
+ return services.getIceServers();
}
}
@@ -44,6 +44,7 @@ import eu.siacs.conversations.xmpp.jingle.stanzas.Proceed;
import eu.siacs.conversations.xmpp.jingle.stanzas.Propose;
import eu.siacs.conversations.xmpp.jingle.stanzas.Reason;
import eu.siacs.conversations.xmpp.jingle.stanzas.RtpDescription;
+import im.conversations.android.xmpp.model.disco.external.Services;
import im.conversations.android.xmpp.model.jingle.Jingle;
import im.conversations.android.xmpp.model.stanza.Iq;
import java.util.Arrays;
@@ -2824,7 +2825,7 @@ public class JingleRtpConnection extends AbstractJingleConnection
if (id.account.getXmppConnection().getFeatures().externalServiceDiscovery()) {
final Iq request = new Iq(Iq.Type.GET);
request.setTo(id.account.getDomain());
- request.addChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY);
+ request.addExtension(new Services());
xmppConnectionService.sendIqPacket(
id.account,
request,
@@ -14,12 +14,12 @@ import com.google.common.util.concurrent.MoreExecutors;
import com.google.common.util.concurrent.SettableFuture;
import eu.siacs.conversations.Config;
import eu.siacs.conversations.entities.Account;
-import eu.siacs.conversations.xml.Namespace;
import eu.siacs.conversations.xmpp.XmppConnection;
import eu.siacs.conversations.xmpp.jingle.IceServers;
import eu.siacs.conversations.xmpp.jingle.WebRTCWrapper;
import eu.siacs.conversations.xmpp.jingle.stanzas.IceUdpTransportInfo;
import eu.siacs.conversations.xmpp.jingle.stanzas.WebRTCDataChannelTransportInfo;
+import im.conversations.android.xmpp.model.disco.external.Services;
import im.conversations.android.xmpp.model.stanza.Iq;
import java.io.IOException;
import java.io.InputStream;
@@ -233,7 +233,7 @@ public class WebRTCDataChannelTransport implements Transport {
SettableFuture.create();
final Iq request = new Iq(Iq.Type.GET);
request.setTo(this.account.getDomain());
- request.addChild("services", Namespace.EXTERNAL_SERVICE_DISCOVERY);
+ request.addExtension(new Services());
xmppConnection.sendIqPacket(
request,
(response) -> {
@@ -1,7 +1,17 @@
package im.conversations.android.xmpp.model.disco.external;
+import android.util.Log;
+import com.google.common.base.Strings;
+import com.google.common.collect.ImmutableSet;
+import com.google.common.primitives.Ints;
+import eu.siacs.conversations.Config;
+import eu.siacs.conversations.utils.IP;
import im.conversations.android.annotation.XmlElement;
import im.conversations.android.xmpp.model.Extension;
+import java.util.Arrays;
+import java.util.Collection;
+import java.util.Set;
+import org.webrtc.PeerConnection;
@XmlElement
public class Services extends Extension {
@@ -9,4 +19,74 @@ public class Services extends Extension {
public Services() {
super(Services.class);
}
+
+ public Collection<Service> getServices() {
+ return this.getExtensions(Service.class);
+ }
+
+ public Set<PeerConnection.IceServer> getIceServers() {
+ final var builder = new ImmutableSet.Builder<PeerConnection.IceServer>();
+ for (final var service : this.getServices()) {
+ final String type = service.getAttribute("type");
+ final String host = service.getAttribute("host");
+ final String sport = service.getAttribute("port");
+ final Integer port = sport == null ? null : Ints.tryParse(sport);
+ final String transport = service.getAttribute("transport");
+ final String username = service.getAttribute("username");
+ final String password = service.getAttribute("password");
+ if (Strings.isNullOrEmpty(host) || port == null) {
+ continue;
+ }
+ if (port < 0 || port > 65535) {
+ continue;
+ }
+
+ if (Arrays.asList("stun", "stuns", "turn", "turns").contains(type)
+ && Arrays.asList("udp", "tcp").contains(transport)) {
+ if (Arrays.asList("stuns", "turns").contains(type) && "udp".equals(transport)) {
+ Log.w(
+ Config.LOGTAG,
+ "skipping invalid combination of udp/tls in external services");
+ continue;
+ }
+
+ // STUN URLs do not support a query section since M110
+ final String uri;
+ if (Arrays.asList("stun", "stuns").contains(type)) {
+ uri = String.format("%s:%s:%s", type, IP.wrapIPv6(host), port);
+ } else {
+ uri =
+ String.format(
+ "%s:%s:%s?transport=%s",
+ type, IP.wrapIPv6(host), port, transport);
+ }
+
+ final PeerConnection.IceServer.Builder iceServerBuilder =
+ PeerConnection.IceServer.builder(uri);
+ iceServerBuilder.setTlsCertPolicy(
+ PeerConnection.TlsCertPolicy.TLS_CERT_POLICY_INSECURE_NO_CHECK);
+ if (username != null && password != null) {
+ iceServerBuilder.setUsername(username);
+ iceServerBuilder.setPassword(password);
+ } else if (Arrays.asList("turn", "turns").contains(type)) {
+ // The WebRTC spec requires throwing an
+ // InvalidAccessError when username (from libwebrtc
+ // source coder)
+ // https://chromium.googlesource.com/external/webrtc/+/master/pc/ice_server_parsing.cc
+ Log.w(
+ Config.LOGTAG,
+ "skipping "
+ + type
+ + "/"
+ + transport
+ + " without username and password");
+ continue;
+ }
+ final PeerConnection.IceServer iceServer = iceServerBuilder.createIceServer();
+ Log.w(Config.LOGTAG, "discovered ICE Server: " + iceServer);
+ builder.add(iceServer);
+ }
+ }
+ return builder.build();
+ }
}