导航菜单

页面标题

页面副标题

bbinstant v6.24.0 - XMPPTCPConnection.java 源代码

正在查看: bbinstant v6.24.0 应用的 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.util.ArrayList;
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 javax.net.ssl.SSLSocket;
import org.jivesoftware.smack.AbstractConnectionListener;
import org.jivesoftware.smack.AbstractXMPPConnection;
import org.jivesoftware.smack.ConnectionConfiguration;
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.packet.Element;
import org.jivesoftware.smack.packet.Nonza;
import org.jivesoftware.smack.packet.Stanza;
import org.jivesoftware.smack.packet.StartTls;
import org.jivesoftware.smack.packet.StreamOpen;
import org.jivesoftware.smack.proxy.ProxyInfo;
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.XmlStringBuilder;
import org.jivesoftware.smack.util.dns.HostAddress;
import org.jxmpp.jid.b;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.jid.parts.d;
import org.jxmpp.util.XmppStringUtils;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;

public class XMPPTCPConnection extends AbstractXMPPConnection {
    static final boolean $assertionsDisabled = false;
    private static final int QUEUE_SIZE = 500;
    private static BundleAndDeferCallback defaultBundleAndDeferCallback;
    private BundleAndDeferCallback bundleAndDeferCallback;
    private long clientHandledStanzasCount;
    private final SynchronizationPoint<Exception> closingStreamReceived;
    private final SynchronizationPoint<SmackException> 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 SSLSocket secureSocket;
    private long serverHandledStanzasCount;
    private int smClientMaxResumptionTime;
    private final SynchronizationPoint<SmackException> smEnabledSyncPoint;
    private final SynchronizationPoint<XMPPException.FailedNonzaException> smResumedSyncPoint;
    private int smServerMaxResumptimTime;
    private String smSessionId;
    private boolean smWasEnabledAtLeastOnce;
    private Socket socket;
    private final Collection<StanzaListener> stanzaAcknowledgedListeners;
    private final Map<String, StanzaListener> stanzaIdAcknowledgedListeners;
    private BlockingQueue<Stanza> unacknowledgedStanzas;
    private boolean useSm;
    private boolean useSmResumption;
    private static final Logger LOGGER = Logger.getLogger(XMPPTCPConnection.class.getName());
    private static boolean useSmDefault = true;
    private static boolean useSmResumptionDefault = true;

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

        protected PacketReader() {
        }

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

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

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

    protected 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;

        protected PacketWriter() {
            this.shutdownDone = new SynchronizationPoint<>(XMPPTCPConnection.this, "shutdown completed");
        }

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

        private void drainWriterQueueToUnacknowledgedStanzas() {
            ArrayList<Element> arrayList = new ArrayList(this.queue.size());
            this.queue.drainTo(arrayList);
            for (Element element : arrayList) {
                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()) {
                    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;
            Exception exc = null;
            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);
                                }
                            }
                            CharSequence xml = nextStreamElement.toXML();
                            if (xml instanceof XmlStringBuilder) {
                                ((XmlStringBuilder) xml).write(((AbstractXMPPConnection) XMPPTCPConnection.this).writer);
                            } else {
                                ((AbstractXMPPConnection) XMPPTCPConnection.this).writer.write(xml.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();
                    }
                } catch (Exception e4) {
                    if (done() || this.queue.isShutdown()) {
                        XMPPTCPConnection.LOGGER.log(Level.FINE, "Ignoring Exception in writePackets()", (Throwable) e4);
                    } else {
                        exc = e4;
                    }
                }
                XMPPTCPConnection.LOGGER.fine("Reporting shutdownDone success in writer thread");
                this.shutdownDone.reportSuccess();
                if (exc != null) {
                    XMPPTCPConnection.this.notifyConnectionError(exc);
                }
            } catch (Throwable th) {
                XMPPTCPConnection.LOGGER.fine("Reporting shutdownDone success in writer thread");
                this.shutdownDone.reportSuccess();
                throw th;
            }
        }

        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() + ")");
        }

        protected void sendStreamElement(Element element) throws SmackException.NotConnectedException, InterruptedException {
            throwNotConnectedExceptionIfDoneAndResumptionNotPossible();
            try {
                this.queue.put(element);
            } catch (InterruptedException e) {
                throwNotConnectedExceptionIfDoneAndResumptionNotPossible();
                throw e;
            }
        }

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

        protected void throwNotConnectedExceptionIfDoneAndResumptionNotPossible() throws SmackException.NotConnectedException {
            boolean isSmResumptionPossible;
            boolean done = done();
            if (!done || (isSmResumptionPossible = XMPPTCPConnection.this.isSmResumptionPossible())) {
                return;
            }
            throw new SmackException.NotConnectedException(XMPPTCPConnection.this, "done=" + done + " smResumptionPossible=" + isSmResumptionPossible);
        }
    }

    public XMPPTCPConnection(XMPPTCPConnectionConfiguration xMPPTCPConnectionConfiguration) {
        super(xMPPTCPConnectionConfiguration);
        this.disconnectedButResumeable = false;
        this.initalOpenStreamSend = new SynchronizationPoint<>(this, "initial open stream element send to server");
        this.maybeCompressFeaturesReceived = new SynchronizationPoint<>(this, "stream compression feature");
        this.compressSyncPoint = new SynchronizationPoint<>(this, "stream compression");
        this.closingStreamReceived = new SynchronizationPoint<>(this, "stream closing element received");
        this.bundleAndDeferCallback = defaultBundleAndDeferCallback;
        this.smResumedSyncPoint = new SynchronizationPoint<>(this, "stream resumed element");
        this.smEnabledSyncPoint = new SynchronizationPoint<>(this, "stream enabled element");
        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();
                }
            }
        });
    }

    private void connectUsingConfiguration() throws SmackException.ConnectionException, IOException {
        Iterator<HostAddress> it;
        List<HostAddress> populateHostAddresses = populateHostAddresses();
        SocketFactory socketFactory = this.config.getSocketFactory();
        ProxyInfo proxyInfo = this.config.getProxyInfo();
        int connectTimeout = this.config.getConnectTimeout();
        if (socketFactory == null) {
            socketFactory = SocketFactory.getDefault();
        }
        SocketFactory socketFactory2 = socketFactory;
        Iterator<HostAddress> it2 = this.hostAddresses.iterator();
        while (it2.hasNext()) {
            HostAddress next = it2.next();
            String fqdn = next.getFQDN();
            int port = next.getPort();
            if (proxyInfo == null) {
                Iterator<InetAddress> it3 = next.getInetAddresses().iterator();
                while (true) {
                    if (!it3.hasNext()) {
                        it = it2;
                        break;
                    }
                    this.socket = socketFactory2.createSocket();
                    InetAddress next2 = it3.next();
                    String str = next2 + " at port " + port;
                    Logger logger = LOGGER;
                    StringBuilder sb = new StringBuilder();
                    it = it2;
                    sb.append("Trying to establish TCP connection to ");
                    sb.append(str);
                    logger.finer(sb.toString());
                    try {
                        this.socket.connect(new InetSocketAddress(next2, port), connectTimeout);
                        logger.finer("Established TCP connection to " + str);
                        this.host = fqdn;
                        this.port = port;
                        return;
                    } catch (Exception e) {
                        next.setException(next2, e);
                        if (!it3.hasNext()) {
                            break;
                        } else {
                            it2 = it;
                        }
                    }
                }
                populateHostAddresses.add(next);
            } else {
                it = it2;
                this.socket = socketFactory2.createSocket();
                StringUtils.requireNotNullOrEmpty(fqdn, "Host of HostAddress " + next + " must not be null when using a Proxy");
                String str2 = fqdn + " at port " + port;
                Logger logger2 = LOGGER;
                logger2.finer("Trying to establish TCP connection via Proxy to " + str2);
                try {
                    proxyInfo.getProxySocketConnection().connect(this.socket, fqdn, port, connectTimeout);
                    logger2.finer("Established TCP connection to " + str2);
                    this.host = fqdn;
                    this.port = port;
                    return;
                } catch (IOException e2) {
                    next.setException(e2);
                }
            }
            it2 = it;
        }
        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();
    }

    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 void maybeEnableCompression() throws SmackException.NotConnectedException, SmackException.NoResponseException, SmackException, InterruptedException {
        if (this.config.isCompressionEnabled()) {
            this.maybeCompressFeaturesReceived.checkIfSuccessOrWait();
            Compress.Feature feature = (Compress.Feature) getFeature(Compress.Feature.ELEMENT, "http://jabber.org/protocol/compress");
            if (feature == null) {
                return;
            }
            XMPPInputOutputStream maybeGetCompressionHandler = maybeGetCompressionHandler(feature);
            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");
            }
        }
    }

    private static XMPPInputOutputStream maybeGetCompressionHandler(Compress.Feature feature) {
        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()).processStanza(stanza);
                        } catch (InterruptedException | SmackException.NotConnectedException e) {
                            XMPPTCPConnection.LOGGER.log(Level.FINER, "Received exception", e);
                        }
                    }
                    String stanzaId2 = stanza.getStanzaId();
                    if (!StringUtils.isNullOrEmpty(stanzaId2) && (stanzaListener = (StanzaListener) XMPPTCPConnection.this.stanzaIdAcknowledgedListeners.remove(stanzaId2)) != null) {
                        try {
                            stanzaListener.processStanza(stanza);
                        } catch (InterruptedException | SmackException.NotConnectedException e2) {
                            XMPPTCPConnection.LOGGER.log(Level.FINER, "Received exception", e2);
                        }
                    }
                }
            }
        });
        this.serverHandledStanzasCount = j;
    }

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

    public void sendSmAcknowledgementInternal() throws SmackException.NotConnectedException, InterruptedException {
        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;
    }

    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
    protected void afterFeaturesReceived() throws SmackException.NotConnectedException, InterruptedException {
        StartTls startTls = (StartTls) getFeature(StartTls.ELEMENT, StartTls.NAMESPACE);
        if (startTls == null) {
            this.tlsHandled.reportSuccess();
        } else if (startTls.required() && this.config.getSecurityMode() == ConnectionConfiguration.SecurityMode.disabled) {
            SmackException.SecurityRequiredByServerException securityRequiredByServerException = new SmackException.SecurityRequiredByServerException();
            this.tlsHandled.reportFailure(securityRequiredByServerException);
            notifyConnectionError(securityRequiredByServerException);
            return;
        } else if (this.config.getSecurityMode() != ConnectionConfiguration.SecurityMode.disabled) {
            sendNonza(new StartTls());
        } else {
            this.tlsHandled.reportSuccess();
        }
        if (getSASLAuthentication().authenticationSuccessful()) {
            this.maybeCompressFeaturesReceived.reportSuccess();
        }
    }

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

    @Override
    protected void connectInternal() throws SmackException, IOException, XMPPException, InterruptedException {
        this.closingStreamReceived.init();
        connectUsingConfiguration();
        initConnection();
    }

    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 synchronized void instantShutdown() {
        shutdown(true);
    }

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

    @Override
    public boolean isSecureConnection() {
        return this.secureSocket != null;
    }

    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 l2 = this.packetWriter.shutdownTimestamp;
        if (l2 == null) {
            return true;
        }
        return System.currentTimeMillis() <= l2.longValue() + (((long) getMaxSmResumptionTime()) * 1000);
    }

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

    @Override
    protected synchronized void loginInternal(String str, String str2, d dVar) throws XMPPException, SmackException, IOException, InterruptedException {
        try {
            SSLSocket sSLSocket = this.secureSocket;
            this.saslAuthentication.authenticate(str, str2, this.config.getAuthzid(), sSLSocket != null ? sSLSocket.getSession() : null);
            maybeEnableCompression();
            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();
            }
            bindResourceAndEstablishSession(dVar);
            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;
        }
    }

    void openStream() throws SmackException, InterruptedException {
        b xMPPServiceDomain = getXMPPServiceDomain();
        CharSequence username = this.config.getUsername();
        sendNonza(new StreamOpen(xMPPServiceDomain, username != null ? XmppStringUtils.completeJidFrom(username, xMPPServiceDomain) : 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, InterruptedException {
        if (!isSmEnabled()) {
            throw new StreamManagementException.StreamManagementNotEnabledException();
        }
        requestSmAcknowledgementInternal();
    }

    @Override
    public void sendNonza(Nonza nonza) throws SmackException.NotConnectedException, InterruptedException {
        this.packetWriter.sendStreamElement(nonza);
    }

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

    @Override
    protected void sendStanzaInternal(Stanza stanza) throws SmackException.NotConnectedException, InterruptedException {
        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;
    }

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

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

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

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

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

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

    private void shutdown(boolean z) {
        if (this.disconnectedButResumeable) {
            return;
        }
        if (this.packetWriter != null) {
            LOGGER.finer("PacketWriter shutdown()");
            this.packetWriter.shutdown(z);
        }
        LOGGER.finer("PacketWriter has been shut down");
        if (!z) {
            try {
                this.closingStreamReceived.checkIfSuccessOrWait();
            } catch (InterruptedException | SmackException.NoResponseException e) {
                LOGGER.log(Level.INFO, "Exception while waiting for closing stream element from the server " + this, e);
            }
        }
        if (this.packetReader != null) {
            LOGGER.finer("PacketReader shutdown()");
            this.packetReader.shutdown();
        }
        LOGGER.finer("PacketReader has been shut down");
        try {
            this.socket.close();
        } catch (Exception e2) {
            LOGGER.log(Level.WARNING, "shutdown", (Throwable) e2);
        }
        setWasAuthenticated();
        if (isSmResumptionPossible() && z) {
            this.disconnectedButResumeable = true;
        } else {
            this.disconnectedButResumeable = false;
            this.smSessionId = null;
        }
        this.authenticated = false;
        this.connected = false;
        this.secureSocket = null;
        this.reader = null;
        this.writer = null;
        this.maybeCompressFeaturesReceived.init();
        this.compressSyncPoint.init();
        this.smResumedSyncPoint.init();
        this.smEnabledSyncPoint.init();
        this.initalOpenStreamSend.init();
    }

    public XMPPTCPConnection(CharSequence charSequence, String str) throws org.jxmpp.stringprep.b {
        this(XmppStringUtils.parseLocalpart(charSequence.toString()), str, XmppStringUtils.parseDomain(charSequence.toString()));
    }

    public XMPPTCPConnection(CharSequence charSequence, String str, String str2) throws org.jxmpp.stringprep.b {
        this(XMPPTCPConnectionConfiguration.builder().setUsernameAndPassword(charSequence, str).setXmppDomain(JidCreate.domainBareFrom(str2)).build());
    }
}