导航菜单

页面标题

页面副标题

Housing v14.7.8 - XMPPTCPConnection.java 源代码

正在查看: Housing v14.7.8 应用的 XMPPTCPConnection.java JAVA 源代码文件

本页面展示 JAVA 反编译生成的源代码文件,支持语法高亮显示。 仅供安全研究与技术分析使用,严禁用于任何非法用途。请遵守相关法律法规。


package org.jivesoftware.smack.tcp;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.Writer;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.Socket;
import java.net.UnknownHostException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.net.SocketFactory;
import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
import org.jivesoftware.smack.ConnectionCreationListener;
import org.jivesoftware.smack.SmackConfiguration;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.StanzaListener;
import org.jivesoftware.smack.SynchronizationPoint;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.compress.packet.Compress;
import org.jivesoftware.smack.compression.XMPPInputOutputStream;
import org.jivesoftware.smack.filter.StanzaFilter;
import org.jivesoftware.smack.filter.StanzaIdFilter;
import org.jivesoftware.smack.packet.Bind;
import org.jivesoftware.smack.packet.Element;
import org.jivesoftware.smack.packet.PlainStreamElement;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StartTls;
import org.jivesoftware.smack.packet.StreamOpen;
import org.jivesoftware.smack.sm.SMUtils;
import org.jivesoftware.smack.sm.StreamManagementException;
import org.jivesoftware.smack.sm.packet.StreamManagement;
import org.jivesoftware.smack.sm.predicates.Predicate;
import org.jivesoftware.smack.util.ArrayBlockingQueueWithShutdown;
import org.jivesoftware.smack.util.Async;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.StringUtils;
import org.jivesoftware.smack.util.dns.HostAddress;
import org.jxmpp.util.XmppStringUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

public class XMPPTCPConnection extends AbstractXMPPConnection {
    private static final String PLAIN_FAST_MECHANIM_NAME = "PLAIN_FAST";
    private static final int QUEUE_SIZE = 500;
    private static final int SECURE_PORT = 5223;
    private static BundleAndDeferCallback defaultBundleAndDeferCallback;
    private BundleAndDeferCallback bundleAndDeferCallback;
    private long clientHandledStanzasCount;
    private final SynchronizationPoint<XMPPException> compressSyncPoint;
    private final XMPPTCPConnectionConfiguration config;
    private boolean disconnectedButResumeable;
    private final SynchronizationPoint<Exception> initalOpenStreamSend;
    private final SynchronizationPoint<XMPPException> maybeCompressFeaturesReceived;
    protected PacketReader packetReader;
    protected PacketWriter packetWriter;
    private final Set<StanzaFilter> requestAckPredicates;
    private String resource;
    private long serverHandledStanzasCount;
    private int smClientMaxResumptionTime;
    private final SynchronizationPoint<XMPPException> smEnabledSyncPoint;
    private final SynchronizationPoint<XMPPException> smResumedSyncPoint;
    private int smServerMaxResumptimTime;
    private String smSessionId;
    private boolean smWasEnabledAtLeastOnce;
    private Socket socket;
    private volatile boolean socketClosed;
    private final Collection<StanzaListener> stanzaAcknowledgedListeners;
    private final Map<String, StanzaListener> stanzaIdAcknowledgedListeners;
    private BlockingQueue<Stanza> unacknowledgedStanzas;
    private boolean useSm;
    private boolean useSmResumption;
    private boolean usingTLS;
    private static final Logger LOGGER = Logger.getLogger(XMPPTCPConnection.class.getName());
    private static boolean useSmDefault = false;
    private static boolean useSmResumptionDefault = true;

    public class PacketReader {
        static final boolean $assertionsDisabled = false;
        private volatile boolean done;
        XmlPullParser parser;

        public PacketReader() {
        }

        public void parsePackets() {
            throw new UnsupportedOperationException("Method not decompiled: org.jivesoftware.smack.tcp.XMPPTCPConnection.PacketReader.parsePackets():void");
        }

        public void init() {
            this.done = false;
            Async.go(new Runnable() {
                @Override
                public void run() {
                    PacketReader.this.parsePackets();
                }
            }, "Smack Packet Reader (" + XMPPTCPConnection.this.getConnectionCounter() + ")");
        }

        public void shutdown() {
            this.done = true;
        }
    }

    public class PacketWriter {
        public static final int QUEUE_SIZE = 500;
        private volatile boolean instantShutdown;
        private boolean shouldBundleAndDefer;
        protected SynchronizationPoint<SmackException.NoResponseException> shutdownDone;
        private final ArrayBlockingQueueWithShutdown<Element> queue = new ArrayBlockingQueueWithShutdown<>(500, true);
        protected volatile Long shutdownTimestamp = null;

        public PacketWriter() {
            this.shutdownDone = new SynchronizationPoint<>(XMPPTCPConnection.this);
        }

        public boolean done() {
            return this.shutdownTimestamp != null;
        }

        private void drainWriterQueueToUnacknowledgedStanzas() {
            ArrayList arrayList = new ArrayList(this.queue.size());
            this.queue.drainTo(arrayList);
            Iterator it = arrayList.iterator();
            while (it.hasNext()) {
                Element element = (Element) it.next();
                if (element instanceof Stanza) {
                    XMPPTCPConnection.this.unacknowledgedStanzas.add((Stanza) element);
                }
            }
        }

        private Element nextStreamElement() {
            if (this.queue.isEmpty()) {
                this.shouldBundleAndDefer = true;
            }
            try {
                return this.queue.take();
            } catch (InterruptedException e) {
                if (this.queue.isShutdown()) {
                    return null;
                }
                XMPPTCPConnection.LOGGER.log(Level.WARNING, "Packet writer thread was interrupted. Don't do that. Use disconnect() instead.", (Throwable) e);
                return null;
            }
        }

        public void writePackets() {
            Stanza stanza;
            try {
                try {
                    XMPPTCPConnection.this.openStream();
                    XMPPTCPConnection.this.initalOpenStreamSend.reportSuccess();
                    while (!done()) {
                        Element nextStreamElement = nextStreamElement();
                        if (nextStreamElement != null) {
                            BundleAndDeferCallback bundleAndDeferCallback = XMPPTCPConnection.this.bundleAndDeferCallback;
                            if (bundleAndDeferCallback != null && XMPPTCPConnection.this.isAuthenticated() && this.shouldBundleAndDefer) {
                                this.shouldBundleAndDefer = false;
                                AtomicBoolean atomicBoolean = new AtomicBoolean();
                                int bundleAndDeferMillis = bundleAndDeferCallback.getBundleAndDeferMillis(new BundleAndDefer(atomicBoolean));
                                if (bundleAndDeferMillis > 0) {
                                    long j = bundleAndDeferMillis;
                                    long currentTimeMillis = System.currentTimeMillis();
                                    synchronized (atomicBoolean) {
                                        for (long j2 = j; !atomicBoolean.get() && j2 > 0; j2 = j - (System.currentTimeMillis() - currentTimeMillis)) {
                                            try {
                                                atomicBoolean.wait(j2);
                                            } finally {
                                            }
                                        }
                                    }
                                }
                            }
                            if (nextStreamElement instanceof Stanza) {
                                stanza = (Stanza) nextStreamElement;
                            } else {
                                if (nextStreamElement instanceof StreamManagement.Enable) {
                                    XMPPTCPConnection.this.unacknowledgedStanzas = new ArrayBlockingQueue(500);
                                }
                                stanza = null;
                            }
                            if (XMPPTCPConnection.this.unacknowledgedStanzas != null && stanza != null) {
                                if (XMPPTCPConnection.this.unacknowledgedStanzas.size() == 400.0d) {
                                    ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.write(StreamManagement.AckRequest.INSTANCE.toXML().toString());
                                    ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.flush();
                                }
                                try {
                                    XMPPTCPConnection.this.unacknowledgedStanzas.put(stanza);
                                } catch (InterruptedException e) {
                                    throw new IllegalStateException(e);
                                }
                            }
                            ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.write(nextStreamElement.toXML().toString());
                            if (this.queue.isEmpty()) {
                                ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.flush();
                            }
                            if (stanza != null) {
                                XMPPTCPConnection.this.firePacketSendingListeners(stanza);
                            }
                        }
                    }
                    if (!this.instantShutdown) {
                        while (!this.queue.isEmpty()) {
                            try {
                                ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.write(this.queue.remove().toXML().toString());
                            } catch (Exception e2) {
                                XMPPTCPConnection.LOGGER.log(Level.WARNING, "Exception flushing queue during shutdown, ignore and continue", (Throwable) e2);
                            }
                        }
                        ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.flush();
                        try {
                            ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.write("</stream:stream>");
                            ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.flush();
                        } catch (Exception e3) {
                            XMPPTCPConnection.LOGGER.log(Level.WARNING, "Exception writing closing stream element", (Throwable) e3);
                        }
                        this.queue.clear();
                    } else if (this.instantShutdown && XMPPTCPConnection.this.isSmEnabled()) {
                        drainWriterQueueToUnacknowledgedStanzas();
                    }
                    try {
                        ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.close();
                    } catch (Exception unused) {
                    }
                } catch (Exception e4) {
                    if (done() || XMPPTCPConnection.this.isSocketClosed()) {
                        XMPPTCPConnection.LOGGER.log(Level.FINE, "Ignoring Exception in writePackets()", (Throwable) e4);
                    } else {
                        XMPPTCPConnection.this.notifyConnectionError(e4);
                    }
                }
                XMPPTCPConnection.LOGGER.fine("Reporting shutdownDone success in writer thread");
                this.shutdownDone.reportSuccess();
            } catch (Throwable th) {
                XMPPTCPConnection.LOGGER.fine("Reporting shutdownDone success in writer thread");
                this.shutdownDone.reportSuccess();
                throw th;
            }
        }

        public void init() {
            this.shutdownDone.init();
            this.shutdownTimestamp = null;
            if (XMPPTCPConnection.this.unacknowledgedStanzas != null) {
                drainWriterQueueToUnacknowledgedStanzas();
            }
            this.queue.start();
            Async.go(new Runnable() {
                @Override
                public void run() {
                    PacketWriter.this.writePackets();
                }
            }, "Smack Packet Writer (" + XMPPTCPConnection.this.getConnectionCounter() + ")");
        }

        public void sendStreamElement(Element element) throws SmackException.NotConnectedException {
            throwNotConnectedExceptionIfDoneAndResumptionNotPossible();
            boolean z = false;
            while (!z) {
                try {
                    this.queue.put(element);
                    z = true;
                } catch (InterruptedException e) {
                    throwNotConnectedExceptionIfDoneAndResumptionNotPossible();
                    XMPPTCPConnection.LOGGER.log(Level.WARNING, "Sending thread was interrupted", (Throwable) e);
                }
            }
        }

        public void shutdown(boolean z) {
            this.instantShutdown = z;
            this.shutdownTimestamp = Long.valueOf(System.currentTimeMillis());
            this.queue.shutdown();
            try {
                this.shutdownDone.checkIfSuccessOrWait();
            } catch (SmackException.NoResponseException e) {
                XMPPTCPConnection.LOGGER.log(Level.WARNING, "shutdownDone was not marked as successful by the writer thread", (Throwable) e);
            }
        }

        public void throwNotConnectedExceptionIfDoneAndResumptionNotPossible() throws SmackException.NotConnectedException {
            if (done() && !XMPPTCPConnection.this.isSmResumptionPossible()) {
                throw new SmackException.NotConnectedException();
            }
        }
    }

    public XMPPTCPConnection(CharSequence charSequence, String str) {
        this(XmppStringUtils.parseLocalpart(charSequence.toString()), str, XmppStringUtils.parseDomain(charSequence.toString()));
    }

    private void connectUsingConfiguration() throws IOException, SmackException.ConnectionException {
        Iterator it;
        List<HostAddress> populateHostAddresses = populateHostAddresses();
        SocketFactory socketFactory = this.config.getSocketFactory();
        if (socketFactory == null) {
            socketFactory = SocketFactory.getDefault();
        }
        for (HostAddress hostAddress : this.hostAddresses) {
            String fqdn = hostAddress.getFQDN();
            int port = hostAddress.getPort();
            this.socket = socketFactory.createSocket();
            try {
                it = Arrays.asList(InetAddress.getAllByName(fqdn)).iterator();
            } catch (Exception e) {
                hostAddress.setException(e);
                populateHostAddresses.add(hostAddress);
            }
            if (!it.hasNext()) {
                LOGGER.warning("InetAddress.getAllByName() returned empty result array.");
                throw new UnknownHostException(fqdn);
            }
            while (it.hasNext()) {
                this.socket = socketFactory.createSocket();
                InetAddress inetAddress = (InetAddress) it.next();
                String str = inetAddress + " at port " + port;
                Logger logger = LOGGER;
                logger.finer("Trying to establish TCP connection to " + str);
                try {
                    this.socket.connect(new InetSocketAddress(inetAddress, port), this.config.getConnectTimeout());
                    logger.finer("Established TCP connection to " + str);
                    this.host = fqdn;
                    this.port = port;
                    return;
                } catch (Exception e2) {
                    if (!it.hasNext()) {
                        throw e2;
                    }
                }
            }
        }
        throw SmackException.ConnectionException.from(populateHostAddresses);
    }

    public void dropSmState() {
        this.smSessionId = null;
        this.unacknowledgedStanzas = null;
    }

    private void initConnection() throws IOException {
        boolean z = this.packetReader == null || this.packetWriter == null;
        this.compressionHandler = null;
        initReaderAndWriter();
        if (z) {
            this.packetWriter = new PacketWriter();
            this.packetReader = new PacketReader();
            if (this.config.isDebuggerEnabled()) {
                addAsyncStanzaListener(this.debugger.getReaderListener(), null);
                if (this.debugger.getWriterListener() != null) {
                    addPacketSendingListener(this.debugger.getWriterListener(), null);
                }
            }
        }
        this.packetWriter.init();
        this.packetReader.init();
        if (z) {
            Iterator<ConnectionCreationListener> it = AbstractXMPPConnection.getConnectionCreationListeners().iterator();
            while (it.hasNext()) {
                it.next().connectionCreated(this);
            }
        }
    }

    private void initCurrentUser(String str, String str2, String str3) {
        this.user = XmppStringUtils.completeJidFrom(str, str2, str3);
    }

    public void initReaderAndWriter() throws IOException {
        InputStream inputStream = this.socket.getInputStream();
        OutputStream outputStream = this.socket.getOutputStream();
        XMPPInputOutputStream xMPPInputOutputStream = this.compressionHandler;
        if (xMPPInputOutputStream != null) {
            inputStream = xMPPInputOutputStream.getInputStream(inputStream);
            outputStream = this.compressionHandler.getOutputStream(outputStream);
        }
        this.writer = new OutputStreamWriter(outputStream, "UTF-8");
        this.reader = new BufferedReader(new InputStreamReader(inputStream, "UTF-8"));
        initDebugger();
    }

    private XMPPInputOutputStream maybeGetCompressionHandler() {
        Compress.Feature feature = (Compress.Feature) getFeature(Compress.Feature.ELEMENT, "http://jabber.org/protocol/compress");
        if (feature == null) {
            return null;
        }
        for (XMPPInputOutputStream xMPPInputOutputStream : SmackConfiguration.getCompresionHandlers()) {
            if (feature.getMethods().contains(xMPPInputOutputStream.getCompressionMethod())) {
                return xMPPInputOutputStream;
            }
        }
        return null;
    }

    public synchronized void notifyConnectionError(Exception exc) {
        try {
            PacketReader packetReader = this.packetReader;
            if (packetReader != null) {
                if (packetReader.done) {
                }
                instantShutdown();
                callConnectionClosedOnErrorListener(exc);
            }
            PacketWriter packetWriter = this.packetWriter;
            if (packetWriter != null) {
                if (packetWriter.done()) {
                }
                instantShutdown();
                callConnectionClosedOnErrorListener(exc);
            }
        } finally {
        }
    }

    public void proceedTLSReceived() throws java.security.NoSuchAlgorithmException, java.security.cert.CertificateException, java.io.IOException, java.security.KeyStoreException, java.security.NoSuchProviderException, java.security.UnrecoverableKeyException, java.security.KeyManagementException, org.jivesoftware.smack.SmackException {
        throw new UnsupportedOperationException("Method not decompiled: org.jivesoftware.smack.tcp.XMPPTCPConnection.proceedTLSReceived():void");
    }

    public void processHandledCount(long j) throws StreamManagementException.StreamManagementCounterError {
        long calculateDelta = SMUtils.calculateDelta(j, this.serverHandledStanzasCount);
        final ArrayList arrayList = new ArrayList(calculateDelta <= 2147483647L ? (int) calculateDelta : Integer.MAX_VALUE);
        for (long j2 = 0; j2 < calculateDelta; j2++) {
            Stanza poll = this.unacknowledgedStanzas.poll();
            if (poll == null) {
                throw new StreamManagementException.StreamManagementCounterError(j, this.serverHandledStanzasCount, calculateDelta, arrayList);
            }
            arrayList.add(poll);
        }
        if (this.stanzaAcknowledgedListeners.isEmpty()) {
            Iterator it = arrayList.iterator();
            while (it.hasNext()) {
                String stanzaId = ((Stanza) it.next()).getStanzaId();
                if (stanzaId == null || !this.stanzaIdAcknowledgedListeners.containsKey(stanzaId)) {
                }
            }
            this.serverHandledStanzasCount = j;
        }
        asyncGo(new Runnable() {
            @Override
            public void run() {
                StanzaListener stanzaListener;
                for (Stanza stanza : arrayList) {
                    Iterator it2 = XMPPTCPConnection.this.stanzaAcknowledgedListeners.iterator();
                    while (it2.hasNext()) {
                        try {
                            ((StanzaListener) it2.next()).processPacket(stanza);
                        } catch (SmackException.NotConnectedException e) {
                            XMPPTCPConnection.LOGGER.log(Level.FINER, "Received not connected exception", (Throwable) e);
                        }
                    }
                    String stanzaId2 = stanza.getStanzaId();
                    if (!StringUtils.isNullOrEmpty(stanzaId2) && (stanzaListener = (StanzaListener) XMPPTCPConnection.this.stanzaIdAcknowledgedListeners.remove(stanzaId2)) != null) {
                        try {
                            stanzaListener.processPacket(stanza);
                        } catch (SmackException.NotConnectedException e2) {
                            XMPPTCPConnection.LOGGER.log(Level.FINER, "Received not connected exception", (Throwable) e2);
                        }
                    }
                }
            }
        });
        this.serverHandledStanzasCount = j;
    }

    public void requestSmAcknowledgementInternal() throws SmackException.NotConnectedException {
        this.packetWriter.sendStreamElement(StreamManagement.AckRequest.INSTANCE);
    }

    public void sendSmAcknowledgementInternal() throws SmackException.NotConnectedException {
        this.packetWriter.sendStreamElement(new StreamManagement.AckAnswer(this.clientHandledStanzasCount));
    }

    public static void setDefaultBundleAndDeferCallback(BundleAndDeferCallback bundleAndDeferCallback) {
        defaultBundleAndDeferCallback = bundleAndDeferCallback;
    }

    public static void setUseStreamManagementDefault(boolean z) {
        useSmDefault = z;
    }

    @Deprecated
    public static void setUseStreamManagementResumptiodDefault(boolean z) {
        setUseStreamManagementResumptionDefault(z);
    }

    public static void setUseStreamManagementResumptionDefault(boolean z) {
        if (z) {
            setUseStreamManagementDefault(z);
        }
        useSmResumptionDefault = z;
    }

    private void useCompression() throws SmackException.NotConnectedException, SmackException.NoResponseException, XMPPException {
        this.maybeCompressFeaturesReceived.checkIfSuccessOrWait();
        XMPPInputOutputStream maybeGetCompressionHandler = maybeGetCompressionHandler();
        this.compressionHandler = maybeGetCompressionHandler;
        if (maybeGetCompressionHandler != null) {
            this.compressSyncPoint.sendAndWaitForResponseOrThrow(new Compress(maybeGetCompressionHandler.getCompressionMethod()));
        } else {
            LOGGER.warning("Could not enable compression because no matching handler/method pair was found");
        }
    }

    public boolean addRequestAckPredicate(StanzaFilter stanzaFilter) {
        boolean add;
        synchronized (this.requestAckPredicates) {
            add = this.requestAckPredicates.add(stanzaFilter);
        }
        return add;
    }

    public void addStanzaAcknowledgedListener(StanzaListener stanzaListener) {
        this.stanzaAcknowledgedListeners.add(stanzaListener);
    }

    public StanzaListener addStanzaIdAcknowledgedListener(final String str, StanzaListener stanzaListener) throws StreamManagementException.StreamManagementNotEnabledException {
        if (!this.smWasEnabledAtLeastOnce) {
            throw new StreamManagementException.StreamManagementNotEnabledException();
        }
        schedule(new Runnable() {
            @Override
            public void run() {
                XMPPTCPConnection.this.stanzaIdAcknowledgedListeners.remove(str);
            }
        }, Math.min(getMaxSmResumptionTime(), 43200), TimeUnit.SECONDS);
        return this.stanzaIdAcknowledgedListeners.put(str, stanzaListener);
    }

    @Override
    public void afterFeaturesReceived() throws SmackException.SecurityRequiredException, SmackException.NotConnectedException {
        StartTls startTls = (StartTls) getFeature(StartTls.ELEMENT, StartTls.NAMESPACE);
        if (startTls == null || 5223 == getPort()) {
            if (5223 == getPort()) {
                this.saslFeatureReceived.reportSuccess();
                return;
            }
        } else if (startTls.required() && this.config.getSecurityMode() == ConnectionConfiguration.SecurityMode.disabled) {
            notifyConnectionError(new SmackException.SecurityRequiredByServerException());
            return;
        } else if (this.config.getSecurityMode() != ConnectionConfiguration.SecurityMode.disabled) {
            send(new StartTls());
        }
        if (!isSecureConnection() && startTls == null && getConfiguration().getSecurityMode() == ConnectionConfiguration.SecurityMode.required) {
            throw new SmackException.SecurityRequiredByClientException();
        }
        if (getSASLAuthentication().authenticationSuccessful()) {
            this.maybeCompressFeaturesReceived.reportSuccess();
        }
    }

    @Override
    public void afterSuccessfulLogin(boolean z) throws SmackException.NotConnectedException {
        this.disconnectedButResumeable = false;
        super.afterSuccessfulLogin(z);
    }

    @Override
    public void bindResourceAndEstablishSession(String str) throws XMPPException.XMPPErrorException, IOException, SmackException {
        if (5223 != getPort()) {
            super.bindResourceAndEstablishSession(str);
        } else {
            Bind newSet = Bind.newSet(str);
            this.user = ((Bind) createPacketCollectorAndSend(new StanzaIdFilter(newSet), newSet).nextResultOrThrow()).getJid();
        }
    }

    @Override
    public void connectInternal() throws SmackException, IOException, XMPPException {
        connectUsingConfiguration();
        this.socketClosed = false;
        if (5223 == getPort()) {
            try {
                proceedTLSReceived();
            } catch (Exception e) {
                this.saslFeatureReceived.reportFailure(new SmackException(e));
            }
        }
        initConnection();
        this.saslFeatureReceived.checkIfSuccessOrWaitOrThrow();
        this.connected = true;
        callConnectionConnectedListener();
        if (this.wasAuthenticated) {
            login();
            notifyReconnection();
        }
    }

    public int getMaxSmResumptionTime() {
        int i = this.smClientMaxResumptionTime;
        if (i <= 0) {
            i = Integer.MAX_VALUE;
        }
        int i2 = this.smServerMaxResumptimTime;
        return Math.min(i, i2 > 0 ? i2 : Integer.MAX_VALUE);
    }

    public String getResource() {
        return this.resource;
    }

    public synchronized void instantShutdown() {
        shutdown(true);
    }

    public boolean isDisconnectedButSmResumptionPossible() {
        return this.disconnectedButResumeable && isSmResumptionPossible();
    }

    @Override
    public boolean isSecureConnection() {
        return this.usingTLS;
    }

    public boolean isSmAvailable() {
        return hasFeature(StreamManagement.StreamManagementFeature.ELEMENT, StreamManagement.NAMESPACE);
    }

    public boolean isSmEnabled() {
        return this.smEnabledSyncPoint.wasSuccessful();
    }

    public boolean isSmResumptionPossible() {
        if (this.smSessionId == null) {
            return false;
        }
        Long l = this.packetWriter.shutdownTimestamp;
        if (l == null) {
            return true;
        }
        return System.currentTimeMillis() <= l.longValue() + (((long) getMaxSmResumptionTime()) * 1000);
    }

    public boolean isSocketClosed() {
        return this.socketClosed;
    }

    @Override
    public boolean isUsingCompression() {
        return this.compressionHandler != null && this.compressSyncPoint.wasSuccessful();
    }

    @Override
    public synchronized void loginAnonymously() throws XMPPException, SmackException, IOException {
        try {
            this.saslFeatureReceived.checkIfSuccessOrWaitOrThrow();
            if (!this.saslAuthentication.hasAnonymousAuthentication()) {
                throw new SmackException("No anonymous SASL authentication mechanism available");
            }
            this.saslAuthentication.authenticateAnonymously();
            if (this.config.isCompressionEnabled()) {
                useCompression();
            }
            bindResourceAndEstablishSession(null);
            afterSuccessfulLogin(false);
        } catch (Throwable th) {
            throw th;
        }
    }

    @Override
    public synchronized void loginNonAnonymously(String str, String str2, String str3) throws XMPPException, SmackException, IOException {
        try {
            if (!this.saslAuthentication.hasNonAnonymousAuthentication()) {
                throw new SmackException("No non-anonymous SASL authentication mechanism available");
            }
            this.resource = str3;
            if (str2 != null) {
                this.saslAuthentication.authenticate(str, str2, str3);
            } else {
                this.saslAuthentication.authenticate(str3, this.config.getCallbackHandler());
            }
            if (this.config.isCompressionEnabled()) {
                useCompression();
            }
            if (isSmResumptionPossible()) {
                this.smResumedSyncPoint.sendAndWaitForResponse(new StreamManagement.Resume(this.clientHandledStanzasCount, this.smSessionId));
                if (this.smResumedSyncPoint.wasSuccessful()) {
                    afterSuccessfulLogin(true);
                    return;
                }
                LOGGER.fine("Stream resumption failed, continuing with normal stream establishment process");
            }
            LinkedList linkedList = new LinkedList();
            BlockingQueue<Stanza> blockingQueue = this.unacknowledgedStanzas;
            if (blockingQueue != null) {
                blockingQueue.drainTo(linkedList);
                dropSmState();
            }
            if (PLAIN_FAST_MECHANIM_NAME.equals(this.saslAuthentication.getCurrentMechanism().getName())) {
                initCurrentUser(str, getServiceName(), str3);
            } else {
                bindResourceAndEstablishSession(str3);
            }
            if (isSmAvailable() && this.useSm) {
                this.serverHandledStanzasCount = 0L;
                this.smEnabledSyncPoint.sendAndWaitForResponseOrThrow(new StreamManagement.Enable(this.useSmResumption, this.smClientMaxResumptionTime));
                synchronized (this.requestAckPredicates) {
                    try {
                        if (this.requestAckPredicates.isEmpty()) {
                            this.requestAckPredicates.add(Predicate.forMessagesOrAfter5Stanzas());
                        }
                    } finally {
                    }
                }
            }
            Iterator it = linkedList.iterator();
            while (it.hasNext()) {
                sendStanzaInternal((Stanza) it.next());
            }
            afterSuccessfulLogin(false);
        } catch (Throwable th) {
            throw th;
        }
    }

    public void openStream() throws SmackException {
        String serviceName = getServiceName();
        CharSequence username = this.config.getUsername();
        send(new StreamOpen(serviceName, username != null ? XmppStringUtils.completeJidFrom(username, serviceName) : null, getStreamId()));
        try {
            this.packetReader.parser = PacketParserUtils.newXmppParser(this.reader);
        } catch (XmlPullParserException e) {
            throw new SmackException(e);
        }
    }

    public void removeAllRequestAckPredicates() {
        synchronized (this.requestAckPredicates) {
            this.requestAckPredicates.clear();
        }
    }

    public void removeAllStanzaAcknowledgedListeners() {
        this.stanzaAcknowledgedListeners.clear();
    }

    public void removeAllStanzaIdAcknowledgedListeners() {
        this.stanzaIdAcknowledgedListeners.clear();
    }

    public boolean removeRequestAckPredicate(StanzaFilter stanzaFilter) {
        boolean remove;
        synchronized (this.requestAckPredicates) {
            remove = this.requestAckPredicates.remove(stanzaFilter);
        }
        return remove;
    }

    public boolean removeStanzaAcknowledgedListener(StanzaListener stanzaListener) {
        return this.stanzaAcknowledgedListeners.remove(stanzaListener);
    }

    public StanzaListener removeStanzaIdAcknowledgedListener(String str) {
        return this.stanzaIdAcknowledgedListeners.remove(str);
    }

    public void requestSmAcknowledgement() throws StreamManagementException.StreamManagementNotEnabledException, SmackException.NotConnectedException {
        if (!isSmEnabled()) {
            throw new StreamManagementException.StreamManagementNotEnabledException();
        }
        requestSmAcknowledgementInternal();
    }

    @Override
    public void send(PlainStreamElement plainStreamElement) throws SmackException.NotConnectedException {
        this.packetWriter.sendStreamElement(plainStreamElement);
    }

    public void sendSmAcknowledgement() throws StreamManagementException.StreamManagementNotEnabledException, SmackException.NotConnectedException {
        if (!isSmEnabled()) {
            throw new StreamManagementException.StreamManagementNotEnabledException();
        }
        sendSmAcknowledgementInternal();
    }

    @Override
    public void sendStanzaInternal(Stanza stanza) throws SmackException.NotConnectedException {
        this.packetWriter.sendStreamElement(stanza);
        if (isSmEnabled()) {
            Iterator<StanzaFilter> it = this.requestAckPredicates.iterator();
            while (it.hasNext()) {
                if (it.next().accept(stanza)) {
                    requestSmAcknowledgementInternal();
                    return;
                }
            }
        }
    }

    public void setBundleandDeferCallback(BundleAndDeferCallback bundleAndDeferCallback) {
        this.bundleAndDeferCallback = bundleAndDeferCallback;
    }

    public void setPreferredResumptionTime(int i) {
        this.smClientMaxResumptionTime = i;
    }

    public void setUseStreamManagement(boolean z) {
        this.useSm = z;
    }

    public void setUseStreamManagementResumption(boolean z) {
        if (z) {
            setUseStreamManagement(z);
        }
        this.useSmResumption = z;
    }

    public void setWriter(Writer writer) {
        this.writer = writer;
    }

    @Override
    public void shutdown() {
        if (isSmEnabled()) {
            try {
                sendSmAcknowledgementInternal();
            } catch (SmackException.NotConnectedException e) {
                LOGGER.log(Level.FINE, "Can not send final SM ack as connection is not connected", (Throwable) e);
            }
        }
        shutdown(false);
    }

    public boolean streamWasResumed() {
        return this.smResumedSyncPoint.wasSuccessful();
    }

    @Override
    public void throwAlreadyConnectedExceptionIfAppropriate() throws SmackException.AlreadyConnectedException {
        if (isConnected() && !this.disconnectedButResumeable) {
            throw new SmackException.AlreadyConnectedException();
        }
    }

    @Override
    public void throwAlreadyLoggedInExceptionIfAppropriate() throws SmackException.AlreadyLoggedInException {
        if (isAuthenticated() && !this.disconnectedButResumeable) {
            throw new SmackException.AlreadyLoggedInException();
        }
    }

    @Override
    public void throwNotConnectedExceptionIfAppropriate() throws SmackException.NotConnectedException {
        PacketWriter packetWriter = this.packetWriter;
        if (packetWriter == null) {
            throw new SmackException.NotConnectedException();
        }
        packetWriter.throwNotConnectedExceptionIfDoneAndResumptionNotPossible();
    }

    public XMPPTCPConnection(CharSequence charSequence, String str, String str2) {
        this(XMPPTCPConnectionConfiguration.builder().setUsernameAndPassword(charSequence, str).setServiceName(str2).build());
    }

    private void shutdown(boolean z) {
        if (this.disconnectedButResumeable) {
            return;
        }
        PacketReader packetReader = this.packetReader;
        if (packetReader != null) {
            packetReader.shutdown();
        }
        PacketWriter packetWriter = this.packetWriter;
        if (packetWriter != null) {
            packetWriter.shutdown(z);
        }
        this.socketClosed = true;
        try {
            this.socket.close();
        } catch (Exception e) {
            LOGGER.log(Level.WARNING, "shutdown", (Throwable) e);
        }
        setWasAuthenticated();
        if (isSmResumptionPossible() && z) {
            this.disconnectedButResumeable = true;
        } else {
            this.disconnectedButResumeable = false;
            this.smSessionId = null;
        }
        this.authenticated = false;
        this.connected = false;
        this.usingTLS = false;
        this.reader = null;
        this.writer = null;
        this.maybeCompressFeaturesReceived.init();
        this.compressSyncPoint.init();
        this.smResumedSyncPoint.init();
        this.smEnabledSyncPoint.init();
        this.initalOpenStreamSend.init();
    }

    public XMPPTCPConnection(XMPPTCPConnectionConfiguration xMPPTCPConnectionConfiguration) {
        super(xMPPTCPConnectionConfiguration);
        this.disconnectedButResumeable = false;
        this.socketClosed = false;
        this.usingTLS = false;
        this.initalOpenStreamSend = new SynchronizationPoint<>(this);
        this.maybeCompressFeaturesReceived = new SynchronizationPoint<>(this);
        this.compressSyncPoint = new SynchronizationPoint<>(this);
        this.bundleAndDeferCallback = defaultBundleAndDeferCallback;
        this.smResumedSyncPoint = new SynchronizationPoint<>(this);
        this.smEnabledSyncPoint = new SynchronizationPoint<>(this);
        this.smClientMaxResumptionTime = -1;
        this.smServerMaxResumptimTime = -1;
        this.useSm = useSmDefault;
        this.useSmResumption = useSmResumptionDefault;
        this.serverHandledStanzasCount = 0L;
        this.clientHandledStanzasCount = 0L;
        this.smWasEnabledAtLeastOnce = false;
        this.stanzaAcknowledgedListeners = new ConcurrentLinkedQueue();
        this.stanzaIdAcknowledgedListeners = new ConcurrentHashMap();
        this.requestAckPredicates = new LinkedHashSet();
        this.config = xMPPTCPConnectionConfiguration;
        addConnectionListener(new AbstractConnectionListener() {
            @Override
            public void connectionClosedOnError(Exception exc) {
                if (exc instanceof XMPPException.StreamErrorException) {
                    XMPPTCPConnection.this.dropSmState();
                }
            }
        });
    }
}