1
0
Fork 0
mirror of https://github.com/vanitasvitae/Smack.git synced 2024-11-25 21:42:07 +01:00

[core] Wrap current connection exception when re-throwing

Instead of directly throwing the current connection exception, wrap
it, so we do not lose the stack trace of the thread invoking
waitForConditionorThrowConnectionException().
This commit is contained in:
Florian Schmaus 2024-10-17 17:34:05 +02:00
parent 3c5fb5810e
commit 9e5ac5a39a
5 changed files with 24 additions and 39 deletions

View file

@ -281,8 +281,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
*/ */
protected Writer writer; protected Writer writer;
protected SmackException currentSmackException; private Exception currentConnectionException;
protected XMPPException currentXmppException;
protected boolean tlsHandled; protected boolean tlsHandled;
@ -511,8 +510,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
public abstract boolean isUsingCompression(); public abstract boolean isUsingCompression();
protected void initState() { protected void initState() {
currentSmackException = null; currentConnectionException = null;
currentXmppException = null;
saslFeatureReceived = lastFeaturesReceived = tlsHandled = false; saslFeatureReceived = lastFeaturesReceived = tlsHandled = false;
// TODO: We do not init closingStreamReceived here, as the integration tests use it to check if we waited for // TODO: We do not init closingStreamReceived here, as the integration tests use it to check if we waited for
// it. // it.
@ -686,28 +684,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
return streamId; return streamId;
} }
protected final void throwCurrentConnectionException() throws SmackException, XMPPException {
if (currentSmackException != null) {
throw currentSmackException;
} else if (currentXmppException != null) {
throw currentXmppException;
}
throw new AssertionError("No current connection exception set, although throwCurrentException() was called");
}
protected final boolean hasCurrentConnectionException() { protected final boolean hasCurrentConnectionException() {
return currentSmackException != null || currentXmppException != null; return currentConnectionException != null;
} }
protected final void setCurrentConnectionExceptionAndNotify(Exception exception) { protected final void setCurrentConnectionExceptionAndNotify(Exception exception) {
if (exception instanceof SmackException) { currentConnectionException = exception;
currentSmackException = (SmackException) exception;
} else if (exception instanceof XMPPException) {
currentXmppException = (XMPPException) exception;
} else {
currentSmackException = new SmackException.SmackWrappedException(exception);
}
notifyWaitingThreads(); notifyWaitingThreads();
} }
@ -741,10 +723,12 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
return true; return true;
} }
protected final void waitForConditionOrThrowConnectionException(Supplier<Boolean> condition, String waitFor) throws InterruptedException, SmackException, XMPPException { protected final void waitForConditionOrThrowConnectionException(Supplier<Boolean> condition, String waitFor)
throws InterruptedException, SmackException.SmackWrappedException, NoResponseException {
boolean success = waitFor(() -> condition.get().booleanValue() || hasCurrentConnectionException()); boolean success = waitFor(() -> condition.get().booleanValue() || hasCurrentConnectionException());
if (hasCurrentConnectionException()) { final Exception currentConnectionException = this.currentConnectionException;
throwCurrentConnectionException(); if (currentConnectionException != null) {
throw new SmackException.SmackWrappedException(currentConnectionException);
} }
// If there was no connection exception and we still did not successfully wait for the condition to hold, then // If there was no connection exception and we still did not successfully wait for the condition to hold, then
@ -1048,7 +1032,7 @@ public abstract class AbstractXMPPConnection implements XMPPConnection {
protected final boolean waitForClosingStreamTagFromServer() { protected final boolean waitForClosingStreamTagFromServer() {
try { try {
waitForConditionOrThrowConnectionException(() -> closingStreamReceived, "closing stream tag from the server"); waitForConditionOrThrowConnectionException(() -> closingStreamReceived, "closing stream tag from the server");
} catch (InterruptedException | SmackException | XMPPException e) { } catch (InterruptedException | SmackException.SmackWrappedException | NoResponseException e) {
LOGGER.log(Level.INFO, "Exception while waiting for closing stream element from the server " + this, e); LOGGER.log(Level.INFO, "Exception while waiting for closing stream element from the server " + this, e);
return false; return false;
} }

View file

@ -39,6 +39,7 @@ import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackException.OutgoingQueueFullException; import org.jivesoftware.smack.SmackException.OutgoingQueueFullException;
import org.jivesoftware.smack.SmackException.SmackWrappedException;
import org.jivesoftware.smack.SmackFuture; import org.jivesoftware.smack.SmackFuture;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
import org.jivesoftware.smack.XMPPException.FailedNonzaException; import org.jivesoftware.smack.XMPPException.FailedNonzaException;
@ -259,7 +260,7 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
@Override @Override
public void waitForConditionOrThrowConnectionException(Supplier<Boolean> condition, String waitFor) public void waitForConditionOrThrowConnectionException(Supplier<Boolean> condition, String waitFor)
throws InterruptedException, SmackException, XMPPException { throws InterruptedException, SmackWrappedException, NoResponseException {
ModularXmppClientToServerConnection.this.waitForConditionOrThrowConnectionException(condition, waitFor); ModularXmppClientToServerConnection.this.waitForConditionOrThrowConnectionException(condition, waitFor);
} }
@ -596,8 +597,7 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
case "error": case "error":
StreamError streamError = PacketParserUtils.parseStreamError(parser, null); StreamError streamError = PacketParserUtils.parseStreamError(parser, null);
StreamErrorException streamErrorException = new StreamErrorException(streamError); StreamErrorException streamErrorException = new StreamErrorException(streamError);
currentXmppException = streamErrorException; setCurrentConnectionExceptionAndNotify(streamErrorException);
notifyWaitingThreads();
throw streamErrorException; throw streamErrorException;
case "features": case "features":
parseFeatures(parser); parseFeatures(parser);
@ -1048,8 +1048,7 @@ public final class ModularXmppClientToServerConnection extends AbstractXMPPConne
XmppInputOutputFilter filter = it.next(); XmppInputOutputFilter filter = it.next();
try { try {
filter.waitUntilInputOutputClosed(); filter.waitUntilInputOutputClosed();
} catch (IOException | CertificateException | InterruptedException | SmackException } catch (IOException | CertificateException | InterruptedException | SmackException | XMPPException e) {
| XMPPException e) {
LOGGER.log(Level.WARNING, "waitUntilInputOutputClosed() threw", e); LOGGER.log(Level.WARNING, "waitUntilInputOutputClosed() threw", e);
} }
} }

View file

@ -26,6 +26,7 @@ import java.util.Queue;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException; import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.NotConnectedException; import org.jivesoftware.smack.SmackException.NotConnectedException;
import org.jivesoftware.smack.SmackException.SmackWrappedException;
import org.jivesoftware.smack.SmackReactor; import org.jivesoftware.smack.SmackReactor;
import org.jivesoftware.smack.SmackReactor.ChannelSelectedCallback; import org.jivesoftware.smack.SmackReactor.ChannelSelectedCallback;
import org.jivesoftware.smack.XMPPException; import org.jivesoftware.smack.XMPPException;
@ -127,7 +128,8 @@ public abstract class ModularXmppClientToServerConnectionInternal {
public abstract void asyncGo(Runnable runnable); public abstract void asyncGo(Runnable runnable);
public abstract void waitForConditionOrThrowConnectionException(Supplier<Boolean> condition, String waitFor) throws InterruptedException, SmackException, XMPPException; public abstract void waitForConditionOrThrowConnectionException(Supplier<Boolean> condition, String waitFor)
throws InterruptedException, SmackWrappedException, NoResponseException;
public abstract void notifyWaitingThreads(); public abstract void notifyWaitingThreads();

View file

@ -889,8 +889,7 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
if (startTlsFeature != null) { if (startTlsFeature != null) {
if (startTlsFeature.required() && config.getSecurityMode() == SecurityMode.disabled) { if (startTlsFeature.required() && config.getSecurityMode() == SecurityMode.disabled) {
SecurityRequiredByServerException smackException = new SecurityRequiredByServerException(); SecurityRequiredByServerException smackException = new SecurityRequiredByServerException();
currentSmackException = smackException; setCurrentConnectionExceptionAndNotify(smackException);
notifyWaitingThreads();
throw smackException; throw smackException;
} }
@ -1020,8 +1019,8 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
// situation. It is still possible to authenticate and // situation. It is still possible to authenticate and
// use the connection but using an uncompressed connection // use the connection but using an uncompressed connection
// TODO Parse failure stanza // TODO Parse failure stanza
currentSmackException = new SmackException.SmackMessageException("Could not establish compression"); SmackException.SmackMessageException exception = new SmackException.SmackMessageException("Could not establish compression");
notifyWaitingThreads(); setCurrentConnectionExceptionAndNotify(exception);
break; break;
default: default:
parseAndProcessNonza(parser); parseAndProcessNonza(parser);

View file

@ -46,9 +46,11 @@ import javax.net.ssl.SSLSession;
import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode; import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
import org.jivesoftware.smack.SmackException; import org.jivesoftware.smack.SmackException;
import org.jivesoftware.smack.SmackException.NoResponseException;
import org.jivesoftware.smack.SmackException.SecurityRequiredByClientException; import org.jivesoftware.smack.SmackException.SecurityRequiredByClientException;
import org.jivesoftware.smack.SmackException.SecurityRequiredByServerException; import org.jivesoftware.smack.SmackException.SecurityRequiredByServerException;
import org.jivesoftware.smack.SmackException.SmackCertificateException; import org.jivesoftware.smack.SmackException.SmackCertificateException;
import org.jivesoftware.smack.SmackException.SmackWrappedException;
import org.jivesoftware.smack.SmackFuture; import org.jivesoftware.smack.SmackFuture;
import org.jivesoftware.smack.SmackFuture.InternalSmackFuture; import org.jivesoftware.smack.SmackFuture.InternalSmackFuture;
import org.jivesoftware.smack.SmackReactor.SelectionKeyAttachment; import org.jivesoftware.smack.SmackReactor.SelectionKeyAttachment;
@ -1201,7 +1203,7 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM
return handshakeStatus == TlsHandshakeStatus.successful || handshakeStatus == TlsHandshakeStatus.failed; return handshakeStatus == TlsHandshakeStatus.successful || handshakeStatus == TlsHandshakeStatus.failed;
} }
private void waitForHandshakeFinished() throws InterruptedException, CertificateException, SSLException, SmackException, XMPPException { private void waitForHandshakeFinished() throws InterruptedException, CertificateException, SSLException, SmackWrappedException, NoResponseException {
connectionInternal.waitForConditionOrThrowConnectionException(() -> isHandshakeFinished(), "TLS handshake to finish"); connectionInternal.waitForConditionOrThrowConnectionException(() -> isHandshakeFinished(), "TLS handshake to finish");
if (handshakeStatus == TlsHandshakeStatus.failed) { if (handshakeStatus == TlsHandshakeStatus.failed) {
@ -1234,8 +1236,7 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM
} }
@Override @Override
public void waitUntilInputOutputClosed() throws IOException, CertificateException, InterruptedException, public void waitUntilInputOutputClosed() throws IOException, CertificateException, InterruptedException, SmackWrappedException, NoResponseException {
SmackException, XMPPException {
waitForHandshakeFinished(); waitForHandshakeFinished();
} }