StreamHostManager.java

 1package eu.siacs.conversations.xmpp.manager;
 2
 3import android.content.Context;
 4import com.google.common.util.concurrent.Futures;
 5import com.google.common.util.concurrent.ListenableFuture;
 6import com.google.common.util.concurrent.MoreExecutors;
 7import eu.siacs.conversations.Config;
 8import eu.siacs.conversations.services.XmppConnectionService;
 9import eu.siacs.conversations.xml.Namespace;
10import eu.siacs.conversations.xmpp.Jid;
11import eu.siacs.conversations.xmpp.XmppConnection;
12import eu.siacs.conversations.xmpp.jingle.transports.SocksByteStreamsTransport;
13import im.conversations.android.xmpp.model.socks5.Query;
14import im.conversations.android.xmpp.model.stanza.Iq;
15import java.util.UUID;
16
17public class StreamHostManager extends AbstractManager {
18
19    public StreamHostManager(final XmppConnectionService context, final XmppConnection connection) {
20        super(context, connection);
21    }
22
23    public ListenableFuture<SocksByteStreamsTransport.Candidate> getProxyCandidate(
24            final boolean asInitiator) {
25        if (Config.DISABLE_PROXY_LOOKUP) {
26            return Futures.immediateFailedFuture(
27                    new IllegalStateException("Proxy look up is disabled"));
28        }
29        final var streamer =
30                getManager(DiscoManager.class).findDiscoItemByFeature(Namespace.BYTE_STREAMS);
31        if (streamer == null) {
32            return Futures.immediateFailedFuture(
33                    new IllegalStateException("No proxy/streamer found"));
34        }
35        return getProxyCandidate(asInitiator, streamer.getKey());
36    }
37
38    private ListenableFuture<SocksByteStreamsTransport.Candidate> getProxyCandidate(
39            final boolean asInitiator, final Jid streamer) {
40        final var iq = new Iq(Iq.Type.GET, new Query());
41        iq.setTo(streamer);
42        return Futures.transform(
43                connection.sendIqPacket(iq),
44                response -> {
45                    final var query = response.getExtension(Query.class);
46                    if (query == null) {
47                        throw new IllegalStateException("No stream host query found in response");
48                    }
49                    final var streamHost = query.getStreamHost();
50                    if (streamHost == null) {
51                        throw new IllegalStateException("no stream host found in query");
52                    }
53                    final var jid = streamHost.getJid();
54                    final var host = streamHost.getHost();
55                    final var port = streamHost.getPort();
56                    if (jid == null || host == null || port == null) {
57                        throw new IllegalStateException("StreamHost had incomplete information");
58                    }
59                    return new SocksByteStreamsTransport.Candidate(
60                            UUID.randomUUID().toString(),
61                            host,
62                            streamer,
63                            port,
64                            655360 + (asInitiator ? 0 : 15),
65                            SocksByteStreamsTransport.CandidateType.PROXY);
66                },
67                MoreExecutors.directExecutor());
68    }
69}