1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License. 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * http://www.apache.org/licenses/LICENSE-2.0 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS, 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License. 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smackx.bytestreams.socks5; 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.io.IOException; 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.lang.ref.WeakReference; 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.net.Socket; 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.ArrayList; 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Collections; 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Iterator; 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.LinkedList; 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.List; 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Map; 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Random; 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.WeakHashMap; 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.ConcurrentHashMap; 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.TimeoutException; 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.AbstractConnectionListener; 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.Connection; 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.ConnectionCreationListener; 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.XMPPException; 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.IQ; 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Packet; 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.XMPPError; 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.SyncPacketSend; 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.ServiceDiscoveryManager; 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.bytestreams.BytestreamListener; 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.bytestreams.BytestreamManager; 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream; 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHost; 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream.StreamHostUsed; 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.filetransfer.FileTransferManager; 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverInfo; 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverItems; 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverInfo.Identity; 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smackx.packet.DiscoverItems.Item; 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * The Socks5BytestreamManager class handles establishing SOCKS5 Bytestreams as specified in the <a 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * href="http://xmpp.org/extensions/xep-0065.html">XEP-0065</a>. 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A SOCKS5 Bytestream is negotiated partly over the XMPP XML stream and partly over a separate 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * socket. The actual transfer though takes place over a separately created socket. 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A SOCKS5 Bytestream generally has three parties, the initiator, the target, and the stream host. 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * The stream host is a specialized SOCKS5 proxy setup on a server, or, the initiator can act as the 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * stream host. 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * To establish a SOCKS5 Bytestream invoke the {@link #establishSession(String)} method. This will 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * negotiate a SOCKS5 Bytestream with the given target JID and return a socket. 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * If a session ID for the SOCKS5 Bytestream was already negotiated (e.g. while negotiating a file 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * transfer) invoke {@link #establishSession(String, String)}. 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * To handle incoming SOCKS5 Bytestream requests add an {@link Socks5BytestreamListener} to the 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * manager. There are two ways to add this listener. If you want to be informed about incoming 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SOCKS5 Bytestreams from a specific user add the listener by invoking 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link #addIncomingBytestreamListener(BytestreamListener, String)}. If the listener should 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * respond to all SOCKS5 Bytestream requests invoke 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link #addIncomingBytestreamListener(BytestreamListener)}. 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Note that the registered {@link Socks5BytestreamListener} will NOT be notified on incoming Socks5 75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bytestream requests sent in the context of <a 76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See 77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link FileTransferManager}) 78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * If no {@link Socks5BytestreamListener}s are registered, all incoming SOCKS5 Bytestream requests 80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * will be rejected by returning a <not-acceptable/> error to the initiator. 81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Henning Staib 83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic final class Socks5BytestreamManager implements BytestreamManager { 85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * create a new Socks5BytestreamManager and register a shutdown listener on every established 88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * connection 89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen static { 91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Connection.addConnectionCreationListener(new ConnectionCreationListener() { 92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void connectionCreated(final Connection connection) { 94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen final Socks5BytestreamManager manager; 95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen manager = Socks5BytestreamManager.getBytestreamManager(connection); 96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // register shutdown listener 98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen connection.addConnectionListener(new AbstractConnectionListener() { 99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void connectionClosed() { 101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen manager.disableService(); 102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void connectionClosedOnError(Exception e) { 105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen manager.disableService(); 106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void reconnectionSuccessful() { 109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen managers.put(connection, manager); 110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen }); 113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen }); 116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * The XMPP namespace of the SOCKS5 Bytestream 120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public static final String NAMESPACE = "http://jabber.org/protocol/bytestreams"; 122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* prefix used to generate session IDs */ 124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static final String SESSION_ID_PREFIX = "js5_"; 125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* random generator to create session IDs */ 127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final static Random randomGenerator = new Random(); 128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* stores one Socks5BytestreamManager for each XMPP connection */ 130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final static Map<Connection, Socks5BytestreamManager> managers = new WeakHashMap<Connection, Socks5BytestreamManager>(); 131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* XMPP connection */ 133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final Connection connection; 134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * assigns a user to a listener that is informed if a bytestream request for this user is 137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * received 138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final Map<String, BytestreamListener> userListeners = new ConcurrentHashMap<String, BytestreamListener>(); 140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * list of listeners that respond to all bytestream requests if there are not user specific 143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * listeners for that request 144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final List<BytestreamListener> allRequestListeners = Collections.synchronizedList(new LinkedList<BytestreamListener>()); 146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* listener that handles all incoming bytestream requests */ 148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final InitiationListener initiationListener; 149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* timeout to wait for the response to the SOCKS5 Bytestream initialization request */ 151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private int targetResponseTimeout = 10000; 152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* timeout for connecting to the SOCKS5 proxy selected by the target */ 154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private int proxyConnectionTimeout = 10000; 155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* blacklist of errornous SOCKS5 proxies */ 157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private final List<String> proxyBlacklist = Collections.synchronizedList(new LinkedList<String>()); 158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* remember the last proxy that worked to prioritize it */ 160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private String lastWorkingProxy = null; 161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* flag to enable/disable prioritization of last working proxy */ 163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private boolean proxyPrioritizationEnabled = true; 164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * list containing session IDs of SOCKS5 Bytestream initialization packets that should be 167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * ignored by the InitiationListener 168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private List<String> ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList<String>()); 170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the Socks5BytestreamManager to handle SOCKS5 Bytestreams for a given 173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link Connection}. 174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * If no manager exists a new is created and initialized. 176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param connection the XMPP connection or <code>null</code> if given connection is 178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <code>null</code> 179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the Socks5BytestreamManager for the given XMPP connection 180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public static synchronized Socks5BytestreamManager getBytestreamManager(Connection connection) { 182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (connection == null) { 183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Socks5BytestreamManager manager = managers.get(connection); 186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (manager == null) { 187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen manager = new Socks5BytestreamManager(connection); 188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen managers.put(connection, manager); 189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen manager.activate(); 190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return manager; 192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Private constructor. 196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param connection the XMPP connection 198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Socks5BytestreamManager(Connection connection) { 200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.connection = connection; 201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.initiationListener = new InitiationListener(this); 202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request unless 206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * there is a user specific BytestreamListener registered. 207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * If no listeners are registered all SOCKS5 Bytestream request are rejected with a 209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <not-acceptable/> error. 210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5 212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bytestream requests sent in the context of <a 213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See 214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link FileTransferManager}) 215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param listener the listener to register 217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void addIncomingBytestreamListener(BytestreamListener listener) { 219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.allRequestListeners.add(listener); 220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Removes the given listener from the list of listeners for all incoming SOCKS5 Bytestream 224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * requests. 225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param listener the listener to remove 227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 228d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void removeIncomingBytestreamListener(BytestreamListener listener) { 229d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.allRequestListeners.remove(listener); 230d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 231d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 232d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 233d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Adds BytestreamListener that is called for every incoming SOCKS5 Bytestream request from the 234d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * given user. 235d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 236d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Use this method if you are awaiting an incoming SOCKS5 Bytestream request from a specific 237d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * user. 238d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 239d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * If no listeners are registered all SOCKS5 Bytestream request are rejected with a 240d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <not-acceptable/> error. 241d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 242d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Note that the registered {@link BytestreamListener} will NOT be notified on incoming Socks5 243d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bytestream requests sent in the context of <a 244d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * href="http://xmpp.org/extensions/xep-0096.html">XEP-0096</a> file transfer. (See 245d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link FileTransferManager}) 246d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 247d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param listener the listener to register 248d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param initiatorJID the JID of the user that wants to establish a SOCKS5 Bytestream 249d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 250d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void addIncomingBytestreamListener(BytestreamListener listener, String initiatorJID) { 251d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.userListeners.put(initiatorJID, listener); 252d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 253d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 254d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 255d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Removes the listener for the given user. 256d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 257d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param initiatorJID the JID of the user the listener should be removed 258d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 259d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void removeIncomingBytestreamListener(String initiatorJID) { 260d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.userListeners.remove(initiatorJID); 261d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 262d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 263d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 264d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Use this method to ignore the next incoming SOCKS5 Bytestream request containing the given 265d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * session ID. No listeners will be notified for this request and and no error will be returned 266d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * to the initiator. 267d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 268d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * This method should be used if you are awaiting a SOCKS5 Bytestream request as a reply to 269d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * another packet (e.g. file transfer). 270d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 271d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param sessionID to be ignored 272d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 273d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void ignoreBytestreamRequestOnce(String sessionID) { 274d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.ignoredBytestreamRequests.add(sessionID); 275d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 276d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 277d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 278d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Disables the SOCKS5 Bytestream manager by removing the SOCKS5 Bytestream feature from the 279d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * service discovery, disabling the listener for SOCKS5 Bytestream initiation requests and 280d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * resetting its internal state. 281d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 282d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * To re-enable the SOCKS5 Bytestream feature invoke {@link #getBytestreamManager(Connection)}. 283d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Using the file transfer API will automatically re-enable the SOCKS5 Bytestream feature. 284d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 285d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public synchronized void disableService() { 286d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 287d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // remove initiation packet listener 288d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.connection.removePacketListener(this.initiationListener); 289d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 290d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // shutdown threads 291d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.initiationListener.shutdown(); 292d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 293d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // clear listeners 294d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.allRequestListeners.clear(); 295d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.userListeners.clear(); 296d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 297d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // reset internal state 298d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.lastWorkingProxy = null; 299d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxyBlacklist.clear(); 300d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.ignoredBytestreamRequests.clear(); 301d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 302d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // remove manager from static managers map 303d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen managers.remove(this.connection); 304d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 305d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // shutdown local SOCKS5 proxy if there are no more managers for other connections 306d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (managers.size() == 0) { 307d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Socks5Proxy.getSocks5Proxy().stop(); 308d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 309d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 310d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // remove feature from service discovery 311d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection); 312d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 313d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // check if service discovery is not already disposed by connection shutdown 314d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (serviceDiscoveryManager != null) { 315d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen serviceDiscoveryManager.removeFeature(NAMESPACE); 316d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 317d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 318d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 319d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 320d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 321d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the timeout to wait for the response to the SOCKS5 Bytestream initialization request. 322d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Default is 10000ms. 323d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 324d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the timeout to wait for the response to the SOCKS5 Bytestream initialization request 325d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 326d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public int getTargetResponseTimeout() { 327d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (this.targetResponseTimeout <= 0) { 328d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.targetResponseTimeout = 10000; 329d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 330d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return targetResponseTimeout; 331d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 332d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 333d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 334d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sets the timeout to wait for the response to the SOCKS5 Bytestream initialization request. 335d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Default is 10000ms. 336d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 337d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param targetResponseTimeout the timeout to set 338d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 339d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void setTargetResponseTimeout(int targetResponseTimeout) { 340d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.targetResponseTimeout = targetResponseTimeout; 341d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 342d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 343d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 344d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the timeout for connecting to the SOCKS5 proxy selected by the target. Default is 345d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 10000ms. 346d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 347d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the timeout for connecting to the SOCKS5 proxy selected by the target 348d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 349d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public int getProxyConnectionTimeout() { 350d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (this.proxyConnectionTimeout <= 0) { 351d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxyConnectionTimeout = 10000; 352d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 353d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return proxyConnectionTimeout; 354d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 355d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 356d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 357d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Sets the timeout for connecting to the SOCKS5 proxy selected by the target. Default is 358d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 10000ms. 359d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 360d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param proxyConnectionTimeout the timeout to set 361d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 362d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void setProxyConnectionTimeout(int proxyConnectionTimeout) { 363d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxyConnectionTimeout = proxyConnectionTimeout; 364d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 365d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 366d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 367d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns if the prioritization of the last working SOCKS5 proxy on successive SOCKS5 368d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Bytestream connections is enabled. Default is <code>true</code>. 369d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 370d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return <code>true</code> if prioritization is enabled, <code>false</code> otherwise 371d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 372d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public boolean isProxyPrioritizationEnabled() { 373d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return proxyPrioritizationEnabled; 374d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 375d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 376d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 377d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Enable/disable the prioritization of the last working SOCKS5 proxy on successive SOCKS5 378d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Bytestream connections. 379d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 380d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param proxyPrioritizationEnabled enable/disable the prioritization of the last working 381d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SOCKS5 proxy 382d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 383d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void setProxyPrioritizationEnabled(boolean proxyPrioritizationEnabled) { 384d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxyPrioritizationEnabled = proxyPrioritizationEnabled; 385d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 386d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 387d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 388d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Establishes a SOCKS5 Bytestream with the given user and returns the Socket to send/receive 389d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * data to/from the user. 390d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 391d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Use this method to establish SOCKS5 Bytestreams to users accepting all incoming Socks5 392d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bytestream requests since this method doesn't provide a way to tell the user something about 393d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the data to be sent. 394d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <p> 395d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * To establish a SOCKS5 Bytestream after negotiation the kind of data to be sent (e.g. file 396d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * transfer) use {@link #establishSession(String, String)}. 397d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 398d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param targetJID the JID of the user a SOCKS5 Bytestream should be established 399d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the Socket to send/receive data to/from the user 400d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5 401d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies 402d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException if the bytestream could not be established 403d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws InterruptedException if the current thread was interrupted while waiting 404d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 405d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Socks5BytestreamSession establishSession(String targetJID) throws XMPPException, 406d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen IOException, InterruptedException { 407d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String sessionID = getNextSessionID(); 408d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return establishSession(targetJID, sessionID); 409d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 410d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 411d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 412d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Establishes a SOCKS5 Bytestream with the given user using the given session ID and returns 413d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the Socket to send/receive data to/from the user. 414d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 415d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param targetJID the JID of the user a SOCKS5 Bytestream should be established 416d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param sessionID the session ID for the SOCKS5 Bytestream request 417d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the Socket to send/receive data to/from the user 418d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws XMPPException if the user doesn't support or accept SOCKS5 Bytestreams, if no Socks5 419d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Proxy could be found, if the user couldn't connect to any of the SOCKS5 Proxies 420d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws IOException if the bytestream could not be established 421d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws InterruptedException if the current thread was interrupted while waiting 422d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 423d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public Socks5BytestreamSession establishSession(String targetJID, String sessionID) 424d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throws XMPPException, IOException, InterruptedException { 425d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 426d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen XMPPException discoveryException = null; 427d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // check if target supports SOCKS5 Bytestream 428d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!supportsSocks5(targetJID)) { 429d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new XMPPException(targetJID + " doesn't support SOCKS5 Bytestream"); 430d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 431d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 432d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<String> proxies = new ArrayList<String>(); 433d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // determine SOCKS5 proxies from XMPP-server 434d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 435d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen proxies.addAll(determineProxies()); 436d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } catch (XMPPException e) { 437d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // don't abort here, just remember the exception thrown by determineProxies() 438d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // determineStreamHostInfos() will at least add the local Socks5 proxy (if enabled) 439d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen discoveryException = e; 440d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 441d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 442d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // determine address and port of each proxy 443d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<StreamHost> streamHosts = determineStreamHostInfos(proxies); 444d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 445d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (streamHosts.isEmpty()) { 446d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw discoveryException != null ? discoveryException : new XMPPException("no SOCKS5 proxies available"); 447d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 448d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 449d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // compute digest 450d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String digest = Socks5Utils.createDigest(sessionID, this.connection.getUser(), targetJID); 451d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 452d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // prioritize last working SOCKS5 proxy if exists 453d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) { 454d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen StreamHost selectedStreamHost = null; 455d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (StreamHost streamHost : streamHosts) { 456d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (streamHost.getJID().equals(this.lastWorkingProxy)) { 457d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen selectedStreamHost = streamHost; 458d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen break; 459d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 460d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 461d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (selectedStreamHost != null) { 462d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen streamHosts.remove(selectedStreamHost); 463d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen streamHosts.add(0, selectedStreamHost); 464d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 465d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 466d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 467d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 468d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy(); 469d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 470d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 471d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // add transfer digest to local proxy to make transfer valid 472d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen socks5Proxy.addTransfer(digest); 473d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 474d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // create initiation packet 475d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Bytestream initiation = createBytestreamInitiation(sessionID, targetJID, streamHosts); 476d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 477d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // send initiation packet 478d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Packet response = SyncPacketSend.getReply(this.connection, initiation, 479d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen getTargetResponseTimeout()); 480d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 481d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // extract used stream host from response 482d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen StreamHostUsed streamHostUsed = ((Bytestream) response).getUsedHost(); 483d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen StreamHost usedStreamHost = initiation.getStreamHost(streamHostUsed.getJID()); 484d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 485d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (usedStreamHost == null) { 486d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new XMPPException("Remote user responded with unknown host"); 487d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 488d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 489d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // build SOCKS5 client 490d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Socks5Client socks5Client = new Socks5ClientForInitiator(usedStreamHost, digest, 491d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.connection, sessionID, targetJID); 492d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 493d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // establish connection to proxy 494d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Socket socket = socks5Client.getSocket(getProxyConnectionTimeout()); 495d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 496d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // remember last working SOCKS5 proxy to prioritize it for next request 497d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.lastWorkingProxy = usedStreamHost.getJID(); 498d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 499d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // negotiation successful, return the output stream 500d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return new Socks5BytestreamSession(socket, usedStreamHost.getJID().equals( 501d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.connection.getUser())); 502d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 503d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 504d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch (TimeoutException e) { 505d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new IOException("Timeout while connecting to SOCKS5 proxy"); 506d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 507d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen finally { 508d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 509d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // remove transfer digest if output stream is returned or an exception 510d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // occurred 511d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen socks5Proxy.removeTransfer(digest); 512d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 513d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 514d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 515d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 516d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 517d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns <code>true</code> if the given target JID supports feature SOCKS5 Bytestream. 518d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 519d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param targetJID the target JID 520d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return <code>true</code> if the given target JID supports feature SOCKS5 Bytestream 521d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * otherwise <code>false</code> 522d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws XMPPException if there was an error querying target for supported features 523d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 524d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private boolean supportsSocks5(String targetJID) throws XMPPException { 525d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection); 526d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen DiscoverInfo discoverInfo = serviceDiscoveryManager.discoverInfo(targetJID); 527d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return discoverInfo.containsFeature(NAMESPACE); 528d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 529d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 530d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 531d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a list of JIDs of SOCKS5 proxies by querying the XMPP server. The SOCKS5 proxies are 532d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * in the same order as returned by the XMPP server. 533d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 534d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return list of JIDs of SOCKS5 proxies 535d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @throws XMPPException if there was an error querying the XMPP server for SOCKS5 proxies 536d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 537d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private List<String> determineProxies() throws XMPPException { 538d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ServiceDiscoveryManager serviceDiscoveryManager = ServiceDiscoveryManager.getInstanceFor(this.connection); 539d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 540d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<String> proxies = new ArrayList<String>(); 541d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 542d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // get all items form XMPP server 543d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen DiscoverItems discoverItems = serviceDiscoveryManager.discoverItems(this.connection.getServiceName()); 544d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Iterator<Item> itemIterator = discoverItems.getItems(); 545d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 546d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // query all items if they are SOCKS5 proxies 547d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen while (itemIterator.hasNext()) { 548d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Item item = itemIterator.next(); 549d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 550d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // skip blacklisted servers 551d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (this.proxyBlacklist.contains(item.getEntityID())) { 552d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen continue; 553d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 554d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 555d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 556d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen DiscoverInfo proxyInfo; 557d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen proxyInfo = serviceDiscoveryManager.discoverInfo(item.getEntityID()); 558d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Iterator<Identity> identities = proxyInfo.getIdentities(); 559d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 560d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // item must have category "proxy" and type "bytestream" 561d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen while (identities.hasNext()) { 562d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Identity identity = identities.next(); 563d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 564d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if ("proxy".equalsIgnoreCase(identity.getCategory()) 565d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen && "bytestreams".equalsIgnoreCase(identity.getType())) { 566d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen proxies.add(item.getEntityID()); 567d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen break; 568d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 569d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 570d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /* 571d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * server is not a SOCKS5 proxy, blacklist server to skip next time a Socks5 572d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * bytestream should be established 573d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 574d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxyBlacklist.add(item.getEntityID()); 575d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 576d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 577d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 578d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch (XMPPException e) { 579d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // blacklist errornous server 580d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxyBlacklist.add(item.getEntityID()); 581d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 582d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 583d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 584d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return proxies; 585d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 586d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 587d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 588d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a list of stream hosts containing the IP address an the port for the given list of 589d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SOCKS5 proxy JIDs. The order of the returned list is the same as the given list of JIDs 590d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * excluding all SOCKS5 proxies who's network settings could not be determined. If a local 591d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * SOCKS5 proxy is running it will be the first item in the list returned. 592d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 593d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param proxies a list of SOCKS5 proxy JIDs 594d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return a list of stream hosts containing the IP address an the port 595d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 596d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private List<StreamHost> determineStreamHostInfos(List<String> proxies) { 597d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<StreamHost> streamHosts = new ArrayList<StreamHost>(); 598d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 599d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // add local proxy on first position if exists 600d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<StreamHost> localProxies = getLocalStreamHost(); 601d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (localProxies != null) { 602d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen streamHosts.addAll(localProxies); 603d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 604d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 605d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // query SOCKS5 proxies for network settings 606d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (String proxy : proxies) { 607d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Bytestream streamHostRequest = createStreamHostRequest(proxy); 608d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen try { 609d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Bytestream response = (Bytestream) SyncPacketSend.getReply(this.connection, 610d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen streamHostRequest); 611d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen streamHosts.addAll(response.getStreamHosts()); 612d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 613d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen catch (XMPPException e) { 614d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // blacklist errornous proxies 615d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.proxyBlacklist.add(proxy); 616d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 617d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 618d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 619d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return streamHosts; 620d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 621d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 622d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 623d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a IQ packet to query a SOCKS5 proxy its network settings. 624d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 625d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param proxy the proxy to query 626d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return IQ packet to query a SOCKS5 proxy its network settings 627d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 628d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Bytestream createStreamHostRequest(String proxy) { 629d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Bytestream request = new Bytestream(); 630d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen request.setType(IQ.Type.GET); 631d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen request.setTo(proxy); 632d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return request; 633d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 634d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 635d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 636d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the stream host information of the local SOCKS5 proxy containing the IP address and 637d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the port or null if local SOCKS5 proxy is not running. 638d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 639d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the stream host information of the local SOCKS5 proxy or null if local SOCKS5 proxy 640d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * is not running 641d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 642d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private List<StreamHost> getLocalStreamHost() { 643d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 644d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // get local proxy singleton 645d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Socks5Proxy socks5Server = Socks5Proxy.getSocks5Proxy(); 646d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 647d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (socks5Server.isRunning()) { 648d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<String> addresses = socks5Server.getLocalAddresses(); 649d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen int port = socks5Server.getPort(); 650d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 651d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (addresses.size() >= 1) { 652d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<StreamHost> streamHosts = new ArrayList<StreamHost>(); 653d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (String address : addresses) { 654d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen StreamHost streamHost = new StreamHost(this.connection.getUser(), address); 655d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen streamHost.setPort(port); 656d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen streamHosts.add(streamHost); 657d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 658d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return streamHosts; 659d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 660d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 661d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 662d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 663d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // server is not running or local address could not be determined 664d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return null; 665d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 666d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 667d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 668d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a SOCKS5 Bytestream initialization request packet with the given session ID 669d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * containing the given stream hosts for the given target JID. 670d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 671d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param sessionID the session ID for the SOCKS5 Bytestream 672d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param targetJID the target JID of SOCKS5 Bytestream request 673d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param streamHosts a list of SOCKS5 proxies the target should connect to 674d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return a SOCKS5 Bytestream initialization request packet 675d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 676d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Bytestream createBytestreamInitiation(String sessionID, String targetJID, 677d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen List<StreamHost> streamHosts) { 678d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen Bytestream initiation = new Bytestream(sessionID); 679d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 680d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // add all stream hosts 681d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen for (StreamHost streamHost : streamHosts) { 682d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen initiation.addStreamHost(streamHost); 683d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 684d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 685d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen initiation.setType(IQ.Type.SET); 686d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen initiation.setTo(targetJID); 687d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 688d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return initiation; 689d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 690d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 691d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 692d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Responses to the given packet's sender with a XMPP error that a SOCKS5 Bytestream is not 693d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * accepted. 694d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 695d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param packet Packet that should be answered with a not-acceptable error 696d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 697d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen protected void replyRejectPacket(IQ packet) { 698d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen XMPPError xmppError = new XMPPError(XMPPError.Condition.no_acceptable); 699d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen IQ errorIQ = IQ.createErrorResponse(packet, xmppError); 700d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.connection.sendPacket(errorIQ); 701d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 702d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 703d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 704d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Activates the Socks5BytestreamManager by registering the SOCKS5 Bytestream initialization 705d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * listener and enabling the SOCKS5 Bytestream feature. 706d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 707d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private void activate() { 708d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // register bytestream initiation packet listener 709d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.connection.addPacketListener(this.initiationListener, 710d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.initiationListener.getFilter()); 711d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 712d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // enable SOCKS5 feature 713d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen enableService(); 714d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 715d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 716d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 717d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Adds the SOCKS5 Bytestream feature to the service discovery. 718d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 719d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private void enableService() { 720d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen ServiceDiscoveryManager manager = ServiceDiscoveryManager.getInstanceFor(this.connection); 721d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!manager.includesFeature(NAMESPACE)) { 722d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen manager.addFeature(NAMESPACE); 723d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 724d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 725d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 726d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 727d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a new unique session ID. 728d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 729d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return a new unique session ID 730d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 731d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private String getNextSessionID() { 732d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen StringBuilder buffer = new StringBuilder(); 733d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buffer.append(SESSION_ID_PREFIX); 734d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen buffer.append(Math.abs(randomGenerator.nextLong())); 735d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return buffer.toString(); 736d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 737d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 738d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 739d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the XMPP connection. 740d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 741d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the XMPP connection 742d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 743d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen protected Connection getConnection() { 744d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return this.connection; 745d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 746d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 747d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 748d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the {@link BytestreamListener} that should be informed if a SOCKS5 Bytestream request 749d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * from the given initiator JID is received. 750d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 751d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param initiator the initiator's JID 752d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return the listener 753d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 754d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen protected BytestreamListener getUserListener(String initiator) { 755d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return this.userListeners.get(initiator); 756d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 757d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 758d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 759d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a list of {@link BytestreamListener} that are informed if there are no listeners for 760d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * a specific initiator. 761d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 762d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return list of listeners 763d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 764d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen protected List<BytestreamListener> getAllRequestListeners() { 765d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return this.allRequestListeners; 766d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 767d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 768d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 769d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns the list of session IDs that should be ignored by the InitialtionListener 770d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 771d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return list of session IDs 772d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 773d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen protected List<String> getIgnoredBytestreamRequests() { 774d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return ignoredBytestreamRequests; 775d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 776d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 777d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen} 778