Search in sources :

Example 1 with RequestPacket

use of eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket in project Conversations by siacs.

the class XmppConnection method processStream.

private void processStream() throws XmlPullParserException, IOException, NoSuchAlgorithmException {
    Tag nextTag = tagReader.readTag();
    while (nextTag != null && !nextTag.isEnd("stream")) {
        if (nextTag.isStart("error")) {
            processStreamError(nextTag);
        } else if (nextTag.isStart("features")) {
            processStreamFeatures(nextTag);
        } else if (nextTag.isStart("proceed")) {
            switchOverToTls(nextTag);
        } else if (nextTag.isStart("success")) {
            final String challenge = tagReader.readElement(nextTag).getContent();
            try {
                saslMechanism.getResponse(challenge);
            } catch (final SaslMechanism.AuthenticationException e) {
                disconnect(true);
                Log.e(Config.LOGTAG, String.valueOf(e));
            }
            Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": logged in");
            account.setKey(Account.PINNED_MECHANISM_KEY, String.valueOf(saslMechanism.getPriority()));
            tagReader.reset();
            sendStartStream();
            final Tag tag = tagReader.readTag();
            if (tag != null && tag.isStart("stream")) {
                processStream();
            } else {
                throw new IOException("server didn't restart stream after successful auth");
            }
            break;
        } else if (nextTag.isStart("failure")) {
            final Element failure = tagReader.readElement(nextTag);
            final String text = failure.findChildContent("text");
            if (failure.hasChild("account-disabled") && text != null && text.contains("renew") && Config.MAGIC_CREATE_DOMAIN != null && text.contains(Config.MAGIC_CREATE_DOMAIN)) {
                throw new PaymentRequiredException();
            } else {
                throw new UnauthorizedException();
            }
        } else if (nextTag.isStart("challenge")) {
            final String challenge = tagReader.readElement(nextTag).getContent();
            final Element response = new Element("response");
            response.setAttribute("xmlns", "urn:ietf:params:xml:ns:xmpp-sasl");
            try {
                response.setContent(saslMechanism.getResponse(challenge));
            } catch (final SaslMechanism.AuthenticationException e) {
                // TODO: Send auth abort tag.
                Log.e(Config.LOGTAG, e.toString());
            }
            tagWriter.writeElement(response);
        } else if (nextTag.isStart("enabled")) {
            final Element enabled = tagReader.readElement(nextTag);
            if ("true".equals(enabled.getAttribute("resume"))) {
                this.streamId = enabled.getAttribute("id");
                Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": stream management(" + smVersion + ") enabled (resumable)");
            } else {
                Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": stream management(" + smVersion + ") enabled");
            }
            this.stanzasReceived = 0;
            final RequestPacket r = new RequestPacket(smVersion);
            tagWriter.writeStanzaAsync(r);
        } else if (nextTag.isStart("resumed")) {
            lastPacketReceived = SystemClock.elapsedRealtime();
            final Element resumed = tagReader.readElement(nextTag);
            final String h = resumed.getAttribute("h");
            try {
                ArrayList<AbstractAcknowledgeableStanza> failedStanzas = new ArrayList<>();
                synchronized (this.mStanzaQueue) {
                    final int serverCount = Integer.parseInt(h);
                    if (serverCount != stanzasSent) {
                        Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": session resumed with lost packages");
                        stanzasSent = serverCount;
                    } else {
                        Log.d(Config.LOGTAG, account.getJid().toBareJid().toString() + ": session resumed");
                    }
                    acknowledgeStanzaUpTo(serverCount);
                    for (int i = 0; i < this.mStanzaQueue.size(); ++i) {
                        failedStanzas.add(mStanzaQueue.valueAt(i));
                    }
                    mStanzaQueue.clear();
                }
                Log.d(Config.LOGTAG, "resending " + failedStanzas.size() + " stanzas");
                for (AbstractAcknowledgeableStanza packet : failedStanzas) {
                    if (packet instanceof MessagePacket) {
                        MessagePacket message = (MessagePacket) packet;
                        mXmppConnectionService.markMessage(account, message.getTo().toBareJid(), message.getId(), Message.STATUS_UNSEND);
                    }
                    sendPacket(packet);
                }
            } catch (final NumberFormatException ignored) {
            }
            Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": online with resource " + account.getResource());
            changeStatus(Account.State.ONLINE);
        } else if (nextTag.isStart("r")) {
            tagReader.readElement(nextTag);
            if (Config.EXTENDED_SM_LOGGING) {
                Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": acknowledging stanza #" + this.stanzasReceived);
            }
            final AckPacket ack = new AckPacket(this.stanzasReceived, smVersion);
            tagWriter.writeStanzaAsync(ack);
        } else if (nextTag.isStart("a")) {
            final Element ack = tagReader.readElement(nextTag);
            lastPacketReceived = SystemClock.elapsedRealtime();
            try {
                synchronized (this.mStanzaQueue) {
                    final int serverSequence = Integer.parseInt(ack.getAttribute("h"));
                    acknowledgeStanzaUpTo(serverSequence);
                }
            } catch (NumberFormatException | NullPointerException e) {
                Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": server send ack without sequence number");
            }
        } else if (nextTag.isStart("failed")) {
            Element failed = tagReader.readElement(nextTag);
            try {
                final int serverCount = Integer.parseInt(failed.getAttribute("h"));
                Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": resumption failed but server acknowledged stanza #" + serverCount);
                synchronized (this.mStanzaQueue) {
                    acknowledgeStanzaUpTo(serverCount);
                }
            } catch (NumberFormatException | NullPointerException e) {
                Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": resumption failed");
            }
            resetStreamId();
            if (account.getStatus() != Account.State.ONLINE) {
                sendBindRequest();
            }
        } else if (nextTag.isStart("iq")) {
            processIq(nextTag);
        } else if (nextTag.isStart("message")) {
            processMessage(nextTag);
        } else if (nextTag.isStart("presence")) {
            processPresence(nextTag);
        }
        nextTag = tagReader.readTag();
    }
}
Also used : RequestPacket(eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket) Element(eu.siacs.conversations.xml.Element) ArrayList(java.util.ArrayList) AckPacket(eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket) IOException(java.io.IOException) MessagePacket(eu.siacs.conversations.xmpp.stanzas.MessagePacket) AbstractAcknowledgeableStanza(eu.siacs.conversations.xmpp.stanzas.AbstractAcknowledgeableStanza) Tag(eu.siacs.conversations.xml.Tag)

Example 2 with RequestPacket

use of eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket in project Conversations by siacs.

the class XmppConnection method sendPacket.

private synchronized void sendPacket(final AbstractStanza packet) {
    if (stanzasSent == Integer.MAX_VALUE) {
        resetStreamId();
        disconnect(true);
        return;
    }
    synchronized (this.mStanzaQueue) {
        tagWriter.writeStanzaAsync(packet);
        if (packet instanceof AbstractAcknowledgeableStanza) {
            AbstractAcknowledgeableStanza stanza = (AbstractAcknowledgeableStanza) packet;
            ++stanzasSent;
            this.mStanzaQueue.append(stanzasSent, stanza);
            if (stanza instanceof MessagePacket && stanza.getId() != null && getFeatures().sm()) {
                if (Config.EXTENDED_SM_LOGGING) {
                    Log.d(Config.LOGTAG, account.getJid().toBareJid() + ": requesting ack for message stanza #" + stanzasSent);
                }
                tagWriter.writeStanzaAsync(new RequestPacket(this.smVersion));
            }
        }
    }
}
Also used : MessagePacket(eu.siacs.conversations.xmpp.stanzas.MessagePacket) AbstractAcknowledgeableStanza(eu.siacs.conversations.xmpp.stanzas.AbstractAcknowledgeableStanza) RequestPacket(eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket)

Aggregations

AbstractAcknowledgeableStanza (eu.siacs.conversations.xmpp.stanzas.AbstractAcknowledgeableStanza)2 MessagePacket (eu.siacs.conversations.xmpp.stanzas.MessagePacket)2 RequestPacket (eu.siacs.conversations.xmpp.stanzas.streammgmt.RequestPacket)2 Element (eu.siacs.conversations.xml.Element)1 Tag (eu.siacs.conversations.xml.Tag)1 AckPacket (eu.siacs.conversations.xmpp.stanzas.streammgmt.AckPacket)1 IOException (java.io.IOException)1 ArrayList (java.util.ArrayList)1