@Override protected synchronized void loginNonAnonymously(String username, String password, String resource) throws XMPPException, SmackException, IOException { if (saslAuthentication.hasNonAnonymousAuthentication()) { // Authenticate using SASL if (password != null) { saslAuthentication.authenticate(username, password, resource); } else { saslAuthentication.authenticate(resource, config.getCallbackHandler()); } } else { throw new SmackException("No non-anonymous SASL authentication mechanism available"); } // If compression is enabled then request the server to use stream compression. XEP-170 // recommends to perform stream compression before resource binding. if (config.isCompressionEnabled()) { useCompression(); } if (isSmResumptionPossible()) { smResumedSyncPoint.sendAndWaitForResponse(new Resume(clientHandledStanzasCount, smSessionId)); if (smResumedSyncPoint.wasSuccessful()) { // We successfully resumed the stream, be done here afterSuccessfulLogin(true); return; } // SM resumption failed, what Smack does here is to report success of // lastFeaturesReceived in case of sm resumption was answered with 'failed' so that // normal resource binding can be tried. LOGGER.fine("Stream resumption failed, continuing with normal stream establishment process"); } bindResourceAndEstablishSession(resource); List<Stanza> previouslyUnackedStanzas = new LinkedList<Stanza>(); if (unacknowledgedStanzas != null) { // There was a previous connection with SM enabled but that was either not resumable or // failed to resume. Make sure that we (re-)send the unacknowledged stanzas. unacknowledgedStanzas.drainTo(previouslyUnackedStanzas); // Reset unacknowledged stanzas to 'null' to signal that we never send 'enable' in this // XMPP session (There maybe was an enabled in a previous XMPP session of this // connection instance though). This is used in writePackets to decide if stanzas should // be added to the unacknowledged stanzas queue, because they have to be added right // after the 'enable' stream element has been sent. dropSmState(); } if (isSmAvailable() && useSm) { // Remove what is maybe left from previously stream managed sessions serverHandledStanzasCount = 0; // XEP-198 3. Enabling Stream Management. If the server response to 'Enable' is 'Failed' // then this is a non recoverable error and we therefore throw an exception. smEnabledSyncPoint.sendAndWaitForResponseOrThrow(new Enable(useSmResumption, smClientMaxResumptionTime)); synchronized (requestAckPredicates) { if (requestAckPredicates.isEmpty()) { // Assure that we have at lest one predicate set up that so that we request acks // for the server and eventually flush some stanzas from the unacknowledged // stanza queue requestAckPredicates.add(Predicate.forMessagesOrAfter5Stanzas()); } } } // (Re-)send the stanzas *after* we tried to enable SM for (Stanza stanza : previouslyUnackedStanzas) { sendStanzaInternal(stanza); } afterSuccessfulLogin(false); }
@Override protected synchronized void loginInternal(String username, String password, Resourcepart resource) throws XMPPException, SmackException, IOException, InterruptedException { // Authenticate using SASL SSLSession sslSession = secureSocket != null ? secureSocket.getSession() : null; saslAuthentication.authenticate(username, password, config.getAuthzid(), sslSession); // If compression is enabled then request the server to use stream compression. XEP-170 // recommends to perform stream compression before resource binding. maybeEnableCompression(); if (isSmResumptionPossible()) { smResumedSyncPoint.sendAndWaitForResponse(new Resume(clientHandledStanzasCount, smSessionId)); if (smResumedSyncPoint.wasSuccessful()) { // We successfully resumed the stream, be done here afterSuccessfulLogin(true); return; } // SM resumption failed, what Smack does here is to report success of // lastFeaturesReceived in case of sm resumption was answered with 'failed' so that // normal resource binding can be tried. LOGGER.fine("Stream resumption failed, continuing with normal stream establishment process"); } List<Stanza> previouslyUnackedStanzas = new LinkedList<Stanza>(); if (unacknowledgedStanzas != null) { // There was a previous connection with SM enabled but that was either not resumable or // failed to resume. Make sure that we (re-)send the unacknowledged stanzas. unacknowledgedStanzas.drainTo(previouslyUnackedStanzas); // Reset unacknowledged stanzas to 'null' to signal that we never send 'enable' in this // XMPP session (There maybe was an enabled in a previous XMPP session of this // connection instance though). This is used in writePackets to decide if stanzas should // be added to the unacknowledged stanzas queue, because they have to be added right // after the 'enable' stream element has been sent. dropSmState(); } // Now bind the resource. It is important to do this *after* we dropped an eventually // existing Stream Management state. As otherwise <bind/> and <session/> may end up in // unacknowledgedStanzas and become duplicated on reconnect. See SMACK-706. bindResourceAndEstablishSession(resource); if (isSmAvailable() && useSm) { // Remove what is maybe left from previously stream managed sessions serverHandledStanzasCount = 0; // XEP-198 3. Enabling Stream Management. If the server response to 'Enable' is 'Failed' // then this is a non recoverable error and we therefore throw an exception. smEnabledSyncPoint.sendAndWaitForResponseOrThrow(new Enable(useSmResumption, smClientMaxResumptionTime)); synchronized (requestAckPredicates) { if (requestAckPredicates.isEmpty()) { // Assure that we have at lest one predicate set up that so that we request acks // for the server and eventually flush some stanzas from the unacknowledged // stanza queue requestAckPredicates.add(Predicate.forMessagesOrAfter5Stanzas()); } } } // (Re-)send the stanzas *after* we tried to enable SM for (Stanza stanza : previouslyUnackedStanzas) { sendStanzaInternal(stanza); } afterSuccessfulLogin(false); }