[tcp] Do not send SM ack after we send a </stream:stream>

Do net put an ack to the queue if it has already been shutdown. Some
servers, like ejabberd, like to request an ack even after we have send
a stream close (and hance the queue was shutdown). If we would not
check here, then the ack would dangle around in the queue, and be send
on the next re-connection attempt even before the stream open.

See the following trace of the MUC bookmarks integration test. The
fact that it is a MUC test does not matter, but this test does
disconnect the connection and reconnect it. Not how the server,
ejabberd in this case, requests an SM ack by sending an <r/> even
though we already send the </stream:stream>:

22:22:05 SENT (4):
<iq id='MD4UC-61' type='set'>
  <query xmlns='jabber:iq:private'>
    <storage xmlns='storage:bookmarks'>
      <conference name='Smack Inttest: 7in7j' autojoin='true' jid='y9jcn5@conference.salem.geekplace.eu'>
        <nick>
          Nick-P2VXD7
        </nick>
      </conference>
    </storage>
  </query>
</iq>
22:22:05 RECV (4):
<r xmlns='urn:xmpp:sm:3'/>
22:22:05 SENT (4):
<a xmlns='urn:xmpp:sm:3' h='29'/>
22:22:05 RECV (4):
<message to='sinttest-7in7j-4@salem.geekplace.eu' from='sinttest-7in7j-4@salem.geekplace.eu' type='headline'>
  <event xmlns='http://jabber.org/protocol/pubsub#event'>
    <items node='storage:bookmarks'>
      <item id='current'>
        <storage xmlns='storage:bookmarks'>
          <conference name='Smack Inttest: 7in7j' autojoin='true' jid='y9jcn5@conference.salem.geekplace.eu'>
            <nick>
              Nick-P2VXD7
            </nick>
          </conference>
        </storage>
      </item>
    </items>
  </event>
  <addresses xmlns='http://jabber.org/protocol/address'>
    <address jid='sinttest-7in7j-4@salem.geekplace.eu/1415073683806426185213090' type='replyto'/>
  </addresses>
</message>
22:22:05 RECV (4):
<iq xml:lang='en-US' to='sinttest-7in7j-4@salem.geekplace.eu/1415073683806426185213090' from='sinttest-7in7j-4@salem.geekplace.eu' type='result' id='MD4UC-61'/>
22:22:05 SENT (4):
<presence id='6MS6J-20' type='unavailable'/>
<a xmlns='urn:xmpp:sm:3' h='31'/>
<!-- We have closed the stream -->
</stream:stream>
<!-- But the server still requests an SM ack -->
22:22:05 RECV (4):
<r xmlns='urn:xmpp:sm:3'/>
22:22:05 RECV (4):
</stream:stream>
22:22:05 XMPPConnection closed (XMPPTCPConnection[sinttest-7in7j-4@salem.geekplace.eu/1415073683806426185213090] (4))
22:22:05 SENT (4):
<a xmlns='urn:xmpp:sm:3' h='31'/>
22:22:05 SENT (4):
<stream:stream xmlns='jabber:client' to='salem.geekplace.eu' xmlns:stream='http://etherx.jabber.org/streams' version='1.0' from='sinttest-7in7j-4@salem.geekplace.eu' xml:lang='en-US'>
22:22:05 RECV (4): ?xml version='1.0'?>
<stream:stream id='3379123514446782311' ver
22:22:05 RECV (4): sion='1.0' xml:lang='en' xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client'>
<stream:error>
  <invalid-xml xmlns='urn:ietf:params:xml:ns:xmpp-streams'/>
</stream:error>
</stream:stream>
22:22:05 XMPPConnection closed due to an exception (XMPPTCPConnection[sinttest-7in7j-4@salem.geekplace.eu/1415073683806426185213090] (4))
org.jivesoftware.smack.XMPPException$StreamErrorException: invalid-xml You can read more about the meaning of this stream error at http://xmpp.org/rfcs/rfc6120.html#streams-error-conditions
<stream:error><invalid-xml xmlns='urn:ietf:params:xml:ns:xmpp-streams'/></stream:error>
	at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.parsePackets(XMPPTCPConnection.java:981)
	at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader.access$700(XMPPTCPConnection.java:913)
	at org.jivesoftware.smack.tcp.XMPPTCPConnection$PacketReader$1.run(XMPPTCPConnection.java:936)
	at java.base/java.lang.Thread.run(Thread.java:834)
4.4
Florian Schmaus 2 years ago
parent 488d01796a
commit 525ee09ea1
  1. 24
      smack-core/src/main/java/org/jivesoftware/smack/util/ArrayBlockingQueueWithShutdown.java
  2. 7
      smack-tcp/src/main/java/org/jivesoftware/smack/tcp/XMPPTCPConnection.java

@ -293,6 +293,30 @@ public class ArrayBlockingQueueWithShutdown<E> extends AbstractQueue<E> implemen
}
}
/**
* Put if the queue has not been shutdown yet.
*
* @param e the element to put into the queue.
* @return <code>true</code> if the element has been put into the queue, <code>false</code> if the queue was shutdown.
* @throws InterruptedException if the calling thread was interrupted.
* @since 4.4
*/
public boolean putIfNotShutdown(E e) throws InterruptedException {
checkNotNull(e);
lock.lockInterruptibly();
try {
if (isShutdown) {
return false;
}
putInternal(e, true);
return true;
} finally {
lock.unlock();
}
}
public void putAll(Collection<? extends E> elements) throws InterruptedException {
checkNotNull(elements);
lock.lockInterruptibly();

@ -1592,7 +1592,12 @@ public class XMPPTCPConnection extends AbstractXMPPConnection {
}
private void sendSmAcknowledgementInternal() throws NotConnectedException, InterruptedException {
packetWriter.sendStreamElement(new AckAnswer(clientHandledStanzasCount));
AckAnswer ackAnswer = new AckAnswer(clientHandledStanzasCount);
// Do net put an ack to the queue if it has already been shutdown. Some servers, like ejabberd, like to request
// an ack even after we have send a stream close (and hance the queue was shutdown). If we would not check here,
// then the ack would dangle around in the queue, and be send on the next re-connection attempt even before the
// stream open.
packetWriter.queue.putIfNotShutdown(ackAnswer);
}
/**

Loading…
Cancel
Save