CarrotChat v2.8.80.240429版本的 MD5 值为:fdf98761f01e715a89df24b85b0d206e

以下内容为反编译后的 Socks5BytestreamManager.java 源代码,内容仅作参考


package org.jivesoftware.smackx.bytestreams.socks5;

import java.io.IOException;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Random;
import java.util.Set;
import java.util.WeakHashMap;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeoutException;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.Manager;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.XMPPConnection;
import org.jivesoftware.smack.XMPPConnectionRegistry;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.packet.IQ;
import org.jivesoftware.smack.packet.XMPPError;
import org.jivesoftware.smackx.bytestreams.BytestreamListener;
import org.jivesoftware.smackx.bytestreams.BytestreamManager;
import org.jivesoftware.smackx.bytestreams.socks5.packet.Bytestream;
import org.jivesoftware.smackx.disco.ServiceDiscoveryManager;
import org.jivesoftware.smackx.disco.packet.DiscoverItems;
import org.jxmpp.jid.Jid;

public final class Socks5BytestreamManager extends Manager implements BytestreamManager {
    private static final String SESSION_ID_PREFIX = "js5_";
    private static final Map<XMPPConnection, Socks5BytestreamManager> managers;
    private static final Random randomGenerator;
    private final List<BytestreamListener> allRequestListeners;
    private final List<String> ignoredBytestreamRequests;
    private final InitiationListener initiationListener;
    private Jid lastWorkingProxy;
    private final Set<Jid> proxyBlacklist;
    private int proxyConnectionTimeout;
    private boolean proxyPrioritizationEnabled;
    private int targetResponseTimeout;
    private final Map<Jid, BytestreamListener> userListeners;

    static {
        XMPPConnectionRegistry.addConnectionCreationListener(new ConnectionCreationListener() {
            @Override
            public void connectionCreated(XMPPConnection xMPPConnection) {
                Socks5BytestreamManager.getBytestreamManager(xMPPConnection);
            }
        });
        randomGenerator = new Random();
        managers = new WeakHashMap();
    }

    private Socks5BytestreamManager(XMPPConnection xMPPConnection) {
        super(xMPPConnection);
        this.userListeners = new ConcurrentHashMap();
        this.allRequestListeners = Collections.synchronizedList(new LinkedList());
        this.targetResponseTimeout = 10000;
        this.proxyConnectionTimeout = 10000;
        this.proxyBlacklist = Collections.synchronizedSet(new HashSet());
        this.proxyPrioritizationEnabled = true;
        this.ignoredBytestreamRequests = Collections.synchronizedList(new LinkedList());
        this.initiationListener = new InitiationListener(this);
        activate();
    }

    private void activate() {
        connection().registerIQRequestHandler(this.initiationListener);
        enableService();
    }

    private static Bytestream createBytestreamInitiation(String str, Jid jid, List<Bytestream.StreamHost> list) {
        Bytestream bytestream = new Bytestream(str);
        Iterator<Bytestream.StreamHost> it = list.iterator();
        while (it.hasNext()) {
            bytestream.addStreamHost(it.next());
        }
        bytestream.setType(IQ.Type.set);
        bytestream.setTo(jid);
        return bytestream;
    }

    private static Bytestream createStreamHostRequest(Jid jid) {
        Bytestream bytestream = new Bytestream();
        bytestream.setType(IQ.Type.get);
        bytestream.setTo(jid);
        return bytestream;
    }

    private List<Jid> determineProxies() throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
        XMPPConnection connection = connection();
        ServiceDiscoveryManager instanceFor = ServiceDiscoveryManager.getInstanceFor(connection);
        ArrayList arrayList = new ArrayList();
        for (DiscoverItems.Item item : instanceFor.discoverItems(connection.getXMPPServiceDomain()).getItems()) {
            if (!this.proxyBlacklist.contains(item.getEntityID())) {
                try {
                    if (instanceFor.discoverInfo(item.getEntityID()).hasIdentity("proxy", "bytestreams")) {
                        arrayList.add(item.getEntityID());
                    } else {
                        this.proxyBlacklist.add(item.getEntityID());
                    }
                } catch (SmackException.NoResponseException | XMPPException.XMPPErrorException unused) {
                    this.proxyBlacklist.add(item.getEntityID());
                }
            }
        }
        return arrayList;
    }

    private List<Bytestream.StreamHost> determineStreamHostInfos(List<Jid> list) {
        XMPPConnection connection = connection();
        ArrayList arrayList = new ArrayList();
        List<Bytestream.StreamHost> localStreamHost = getLocalStreamHost();
        if (localStreamHost != null) {
            arrayList.addAll(localStreamHost);
        }
        for (Jid jid : list) {
            try {
                arrayList.addAll(((Bytestream) connection.createStanzaCollectorAndSend(createStreamHostRequest(jid)).nextResultOrThrow()).getStreamHosts());
            } catch (Exception unused) {
                this.proxyBlacklist.add(jid);
            }
        }
        return arrayList;
    }

    private void enableService() {
        ServiceDiscoveryManager.getInstanceFor(connection()).addFeature(Bytestream.NAMESPACE);
    }

    public static synchronized Socks5BytestreamManager getBytestreamManager(XMPPConnection xMPPConnection) {
        synchronized (Socks5BytestreamManager.class) {
            if (xMPPConnection == null) {
                return null;
            }
            Map<XMPPConnection, Socks5BytestreamManager> map = managers;
            Socks5BytestreamManager socks5BytestreamManager = map.get(xMPPConnection);
            if (socks5BytestreamManager == null) {
                socks5BytestreamManager = new Socks5BytestreamManager(xMPPConnection);
                map.put(xMPPConnection, socks5BytestreamManager);
            }
            return socks5BytestreamManager;
        }
    }

    private List<Bytestream.StreamHost> getLocalStreamHost() {
        XMPPConnection connection = connection();
        Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
        if (!socks5Proxy.isRunning()) {
            return null;
        }
        List<String> localAddresses = socks5Proxy.getLocalAddresses();
        if (localAddresses.isEmpty()) {
            return null;
        }
        int port = socks5Proxy.getPort();
        ArrayList arrayList = new ArrayList();
        for (String str : localAddresses) {
            String[] strArr = {"127.0.0.1", "0:0:0:0:0:0:0:1", "::1"};
            int i10 = 0;
            while (true) {
                if (i10 < 3) {
                    if (str.startsWith(strArr[i10])) {
                        break;
                    }
                    i10++;
                } else {
                    arrayList.add(new Bytestream.StreamHost(connection.getUser(), str, port));
                    break;
                }
            }
        }
        return arrayList;
    }

    private static String getNextSessionID() {
        return SESSION_ID_PREFIX + Math.abs(randomGenerator.nextLong());
    }

    private boolean supportsSocks5(Jid jid) throws SmackException.NoResponseException, XMPPException.XMPPErrorException, SmackException.NotConnectedException, InterruptedException {
        return ServiceDiscoveryManager.getInstanceFor(connection()).supportsFeature(jid, Bytestream.NAMESPACE);
    }

    @Override
    public void addIncomingBytestreamListener(BytestreamListener bytestreamListener) {
        this.allRequestListeners.add(bytestreamListener);
    }

    public synchronized void disableService() {
        XMPPConnection connection = connection();
        connection.unregisterIQRequestHandler(this.initiationListener);
        this.initiationListener.shutdown();
        this.allRequestListeners.clear();
        this.userListeners.clear();
        this.lastWorkingProxy = null;
        this.proxyBlacklist.clear();
        this.ignoredBytestreamRequests.clear();
        Map<XMPPConnection, Socks5BytestreamManager> map = managers;
        map.remove(connection);
        if (map.size() == 0) {
            Socks5Proxy.getSocks5Proxy().stop();
        }
        ServiceDiscoveryManager instanceFor = ServiceDiscoveryManager.getInstanceFor(connection);
        if (instanceFor != null) {
            instanceFor.removeFeature(Bytestream.NAMESPACE);
        }
    }

    public List<BytestreamListener> getAllRequestListeners() {
        return this.allRequestListeners;
    }

    public XMPPConnection getConnection() {
        return connection();
    }

    public List<String> getIgnoredBytestreamRequests() {
        return this.ignoredBytestreamRequests;
    }

    public int getProxyConnectionTimeout() {
        if (this.proxyConnectionTimeout <= 0) {
            this.proxyConnectionTimeout = 10000;
        }
        return this.proxyConnectionTimeout;
    }

    public int getTargetResponseTimeout() {
        if (this.targetResponseTimeout <= 0) {
            this.targetResponseTimeout = 10000;
        }
        return this.targetResponseTimeout;
    }

    public BytestreamListener getUserListener(Jid jid) {
        return this.userListeners.get(jid);
    }

    public void ignoreBytestreamRequestOnce(String str) {
        this.ignoredBytestreamRequests.add(str);
    }

    public boolean isProxyPrioritizationEnabled() {
        return this.proxyPrioritizationEnabled;
    }

    @Override
    public void removeIncomingBytestreamListener(BytestreamListener bytestreamListener) {
        this.allRequestListeners.remove(bytestreamListener);
    }

    public void replyRejectPacket(IQ iq) throws SmackException.NotConnectedException, InterruptedException {
        connection().sendStanza(IQ.createErrorResponse(iq, XMPPError.getBuilder(XMPPError.Condition.not_acceptable)));
    }

    public void setProxyConnectionTimeout(int i10) {
        this.proxyConnectionTimeout = i10;
    }

    public void setProxyPrioritizationEnabled(boolean z10) {
        this.proxyPrioritizationEnabled = z10;
    }

    public void setTargetResponseTimeout(int i10) {
        this.targetResponseTimeout = i10;
    }

    @Override
    public void addIncomingBytestreamListener(BytestreamListener bytestreamListener, Jid jid) {
        this.userListeners.put(jid, bytestreamListener);
    }

    @Override
    public void removeIncomingBytestreamListener(String str) {
        this.userListeners.remove(str);
    }

    @Override
    public Socks5BytestreamSession establishSession(Jid jid) throws XMPPException, IOException, InterruptedException, SmackException {
        return establishSession(jid, getNextSessionID());
    }

    @Override
    public Socks5BytestreamSession establishSession(Jid jid, String str) throws IOException, InterruptedException, SmackException, XMPPException {
        XMPPConnection connection = connection();
        if (supportsSocks5(jid)) {
            ArrayList arrayList = new ArrayList();
            Bytestream.StreamHost streamHost = null;
            try {
                arrayList.addAll(determineProxies());
                e = null;
            } catch (XMPPException.XMPPErrorException e10) {
                e = e10;
            }
            List<Bytestream.StreamHost> determineStreamHostInfos = determineStreamHostInfos(arrayList);
            if (determineStreamHostInfos.isEmpty()) {
                if (e != null) {
                    throw e;
                }
                throw new SmackException("no SOCKS5 proxies available");
            }
            String createDigest = Socks5Utils.createDigest(str, connection.getUser(), jid);
            if (this.proxyPrioritizationEnabled && this.lastWorkingProxy != null) {
                Iterator<Bytestream.StreamHost> it = determineStreamHostInfos.iterator();
                while (true) {
                    if (!it.hasNext()) {
                        break;
                    }
                    Bytestream.StreamHost next = it.next();
                    if (next.getJID().equals((CharSequence) this.lastWorkingProxy)) {
                        streamHost = next;
                        break;
                    }
                }
                if (streamHost != null) {
                    determineStreamHostInfos.remove(streamHost);
                    determineStreamHostInfos.add(0, streamHost);
                }
            }
            Socks5Proxy socks5Proxy = Socks5Proxy.getSocks5Proxy();
            try {
                try {
                    socks5Proxy.addTransfer(createDigest);
                    Bytestream createBytestreamInitiation = createBytestreamInitiation(str, jid, determineStreamHostInfos);
                    Bytestream.StreamHost streamHost2 = createBytestreamInitiation.getStreamHost(((Bytestream) connection.createStanzaCollectorAndSend(createBytestreamInitiation).nextResultOrThrow(getTargetResponseTimeout())).getUsedHost().getJID());
                    if (streamHost2 != null) {
                        Socket socket = new Socks5ClientForInitiator(streamHost2, createDigest, connection, str, jid).getSocket(getProxyConnectionTimeout());
                        this.lastWorkingProxy = streamHost2.getJID();
                        return new Socks5BytestreamSession(socket, streamHost2.getJID().equals((CharSequence) connection.getUser()));
                    }
                    throw new SmackException("Remote user responded with unknown host");
                } catch (TimeoutException unused) {
                    throw new IOException("Timeout while connecting to SOCKS5 proxy");
                }
            } finally {
                socks5Proxy.removeTransfer(createDigest);
            }
        }
        throw new SmackException.FeatureNotSupportedException("SOCKS5 Bytestream", jid);
    }
}