Smack/smack-core/src/main/java/org/jivesoftware/smack/c2s/internal/ModularXmppClientToServerCo...

144 lines
6.0 KiB
Java
Raw Normal View History

/**
*
* Copyright 2020-2021 Florian Schmaus
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jivesoftware.smack.c2s.internal;
import java.io.IOException;
import java.nio.channels.ClosedChannelException;
import java.nio.channels.SelectableChannel;
import java.nio.channels.SelectionKey;
import java.util.ListIterator;
import java.util.Queue;
import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackReactor;
import org.jivesoftware.smack.SmackReactor.ChannelSelectedCallback;
import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.FailedNonzaException;
import org.jivesoftware.smack.XmppInputOutputFilter;
import org.jivesoftware.smack.c2s.ModularXmppClientToServerConnection;
import org.jivesoftware.smack.c2s.XmppClientToServerTransport;
import org.jivesoftware.smack.debugger.SmackDebugger;
import org.jivesoftware.smack.fsm.ConnectionStateEvent;
import org.jivesoftware.smack.internal.SmackTlsContext;
import org.jivesoftware.smack.packet.Nonza;
import org.jivesoftware.smack.packet.TopLevelStreamElement;
import org.jivesoftware.smack.packet.XmlEnvironment;
import org.jivesoftware.smack.util.Consumer;
import org.jivesoftware.smack.util.PacketParserUtils;
import org.jivesoftware.smack.util.Supplier;
import org.jivesoftware.smack.xml.XmlPullParser;
import org.jivesoftware.smack.xml.XmlPullParserException;
public abstract class ModularXmppClientToServerConnectionInternal {
private final SmackReactor reactor;
public final ModularXmppClientToServerConnection connection;
public final SmackDebugger smackDebugger;
public final Queue<TopLevelStreamElement> outgoingElementsQueue;
public ModularXmppClientToServerConnectionInternal(ModularXmppClientToServerConnection connection, SmackReactor reactor,
SmackDebugger smackDebugger, Queue<TopLevelStreamElement> outgoingElementsQueue) {
this.connection = connection;
this.reactor = reactor;
this.smackDebugger = smackDebugger;
this.outgoingElementsQueue = outgoingElementsQueue;
}
public SelectionKey registerWithSelector(SelectableChannel channel, int ops, ChannelSelectedCallback callback)
throws ClosedChannelException {
return reactor.registerWithSelector(channel, ops, callback);
}
public void setInterestOps(SelectionKey selectionKey, int interestOps) {
reactor.setInterestOps(selectionKey, interestOps);
}
public final void withSmackDebugger(Consumer<SmackDebugger> smackDebuggerConsumer) {
if (smackDebugger == null) {
return;
}
smackDebuggerConsumer.accept(smackDebugger);
}
public abstract XmlEnvironment getOutgoingStreamXmlEnvironment();
// TODO: The incomingElement parameter was previously of type TopLevelStreamElement, but I believe it has to be
// of type string. But would this also work for BOSH or WebSocket?
public abstract void parseAndProcessElement(String wrappedCompleteIncomingElement);
public abstract void notifyConnectionError(Exception e);
public final String onStreamOpen(String streamOpen) {
XmlPullParser streamOpenParser;
try {
streamOpenParser = PacketParserUtils.getParserFor(streamOpen);
} catch (XmlPullParserException | IOException e) {
// Should never happen.
throw new AssertionError(e);
}
String streamClose = onStreamOpen(streamOpenParser);
return streamClose;
}
2020-05-14 14:35:37 +02:00
public abstract String onStreamOpen(XmlPullParser parser);
public abstract void onStreamClosed();
public abstract void fireFirstLevelElementSendListeners(TopLevelStreamElement element);
public abstract void invokeConnectionStateMachineListener(ConnectionStateEvent connectionStateEvent);
public abstract void addXmppInputOutputFilter(XmppInputOutputFilter xmppInputOutputFilter);
public abstract ListIterator<XmppInputOutputFilter> getXmppInputOutputFilterBeginIterator();
public abstract ListIterator<XmppInputOutputFilter> getXmppInputOutputFilterEndIterator();
2020-05-14 14:35:37 +02:00
public abstract void waitForFeaturesReceived(String waitFor) throws InterruptedException, SmackException, XMPPException;
public abstract void newStreamOpenWaitForFeaturesSequence(String waitFor) throws InterruptedException,
NoResponseException, NotConnectedException, SmackException, XMPPException;
public abstract SmackTlsContext getSmackTlsContext();
public abstract <SN extends Nonza, FN extends Nonza> SN sendAndWaitForResponse(Nonza nonza,
Class<SN> successNonzaClass, Class<FN> failedNonzaClass)
throws NoResponseException, NotConnectedException, FailedNonzaException, InterruptedException;
public abstract void asyncGo(Runnable runnable);
public abstract void waitForConditionOrThrowConnectionException(Supplier<Boolean> condition, String waitFor) throws InterruptedException, SmackException, XMPPException;
public abstract void notifyWaitingThreads();
public abstract void setCompressionEnabled(boolean compressionEnabled);
Set 'connected' to 'true' as early as possible We previously only set 'connected' after connectInternal() returned. This could lead to notifyConnectionError() ignoring stream error exceptions, e.g. when establishing TLS which happens also in connectInternal(), because 'connected' was still 'false'. 2020-08-06 13:08:06.265 19830-20423/org.atalk.android D/SMACK: SENT (0): <stream:stream xmlns='jabber:client' to='atalk.sytes.net' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' xml:lang='en'> 2020-08-06 13:08:06.333 19830-20424/org.atalk.android D/SMACK: RECV (0): ?xml version='1.0'?> <stream:stream id='16420577292739412012' version='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' from='atalk.sytes.net' xmlns='jabber:client'> <stream:error> <policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'/> <text xml:lang='en' xmlns='urn:ietf:params:xml:ns:xmpp-streams'> Too many (20) failed authentications from this IP address (::ffff:42.60.7.13). The address will be unblocked at 05:15:34 06.08.2020 UTC </text> </stream:error> </stream:stream> 2020-08-06 13:08:06.346 19830-20424/org.atalk.android I/aTalk: [241896] org.jivesoftware.smack.AbstractXMPPConnection.notifyConnectionError() Connection was already disconnected when attempting to handle org.jivesoftware.smack.XMPPException$StreamErrorException: policy-violation You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions <stream:error><policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xml:lang='en'>Too many (20) failed authentications from this IP address (::ffff:42.60.7.13). The address will be unblocked at 05:15:34 06.08.2020 UTC</text></stream:error> org.jivesoftware.smack.XMPPException$StreamErrorException: policy-violation You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions <stream:error><policy-violation xmlns='urn:ietf:params:xml:ns:xmpp-streams'/><text xml:lang='en'>Too many (20) failed authentications from this IP address (::ffff:42.60.7.13). The address will be unblocked at 05:15:34 06.08.2020 UTC</text></stream:error> at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:966) at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$700(XMPPTCPConnection.java:898) at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:921) at java.lang.Thread.run(Thread.java:919) Which eventually leads to a NoResponseException org.jivesoftware.smack.SmackException$NoResponseException: No response received within reply timeout. Timeout was 30000ms (~30s). While waiting for establishing TLS [XMPPTCPConnection[not-authenticated] (4)] We now set 'connected' to 'true' as soon as the transport (e.g. TCP, BOSH, …) is connected. While this is in other ways also sensible, it also allows notifyConnectionError() to handle exceptions in the early connection stage. Thanks to Eng Chong Meng for reporting this.
2020-08-06 10:28:07 +02:00
/**
* Set the active transport (TCP, BOSH, WebSocket, ) to be used for the XMPP connection. Also marks the connection
* as connected.
*
* @param xmppTransport the active transport.
*/
public abstract void setTransport(XmppClientToServerTransport xmppTransport);
}