From 488d01796a5e64e9b62aecf58699daf1c3858f7c Mon Sep 17 00:00:00 2001 From: Florian Schmaus Date: Thu, 17 Sep 2020 21:07:35 +0200 Subject: [PATCH] [tcp] Fix TlsState by aborting the channel selected callback Instead of breaking in case the SSLEngine signals NEED_WRAP, which leads to an endless loop while holding the channelSelectedCallbackLock, we have to return, so that the asynchronously invoked callback can aquire it, and do its work. --- .../smack/tcp/XmppTcpTransportModule.java | 20 +++++++++++++++---- 1 file changed, 16 insertions(+), 4 deletions(-) diff --git a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java index 946eb4a1a..965ddb192 100644 --- a/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java +++ b/smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XmppTcpTransportModule.java @@ -1066,18 +1066,25 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM SSLEngineResult.HandshakeStatus handshakeStatus = handleHandshakeStatus(result); switch (handshakeStatus) { case NEED_TASK: - // A delegated task is asynchronously running. Signal that there is pending input data and - // cycle again through the smack reactor. + // A delegated task is asynchronously running. Take care of the remaining accumulatedData. addAsPendingInputData(accumulatedData); - break; + // Return here, as the async task created by handleHandshakeStatus will continue calling the + // cannelSelectedCallback. + return null; case NEED_UNWRAP: continue; case NEED_WRAP: // NEED_WRAP means that the SSLEngine needs to send data, probably without consuming data. // We exploit here the fact that the channelSelectedCallback is single threaded and that the // input processing is after the output processing. + addAsPendingInputData(accumulatedData); + // Note that it is ok that we the provided argument for pending input filter data to channel + // selected callback is false, as setPendingInputFilterData() will have set the internal state + // boolean accordingly. connectionInternal.asyncGo(() -> callChannelSelectedCallback(false, true)); - break; + // Do not break here, but instead return and let the asynchronously invoked + // callChannelSelectedCallback() do its work. + return null; default: break; } @@ -1109,8 +1116,13 @@ public class XmppTcpTransportModule extends ModularXmppClientToServerConnectionM } private void addAsPendingInputData(ByteBuffer byteBuffer) { + // TODO: Why doeesn't simply + // pendingInputData = byteBuffer; + // work? pendingInputData = ByteBuffer.allocate(byteBuffer.remaining()); pendingInputData.put(byteBuffer).flip(); + + pendingInputFilterData = pendingInputData.hasRemaining(); } private SSLEngineResult.HandshakeStatus handleHandshakeStatus(SSLEngineResult sslEngineResult) {