Smack 4.4.6: XEP-0047 Sending of 'close' element implementation

Please refer to:
XEP-0047: In-Band Bytestreams 2.0.1 (2021-01-12)

Per the XEP-0047: 2. Protocol

  1. How to set up and tear down an IBB session using and elements sent within IQ stanzas.

and in 2.3 Closing the Bytestream
it mentions that: To close the bytestream, either party sends an IQ-set containing a <close/> element.

During aTalk system testing for both legacy and jingle file transfer via In-Band ByteStreams protocol;
it was found that the <close/> element are sent by both the file sender and recipient. This leads to the file sender returns an <item-not-found/> stanza error by the CloseListener(); as the sessionId had already been removed in InBandBytestreamSession#closeByLocal() i.e. InBandBytestreamManager.getByteStreamManager(this.connection).getSessions().remove(byteStreamRequest.getSessionID());

When testing with Conversations xmpp client in JingleFileTransfer protocol, the <close/> element is only sent by the sender, but not the file recipient.

I believe that in smack IBB implementation, since the sender has already closed the IBB Bytestream, the file recipient should not again send the <close/>; also as per recommended by XEP-0047
To close the bytestream, either party sends an IQ-set containing a <close/> element.

2023-01-13 09:47:04.028 17220-17430/org.atalk.android D/SMACK: SENT (0): 
    <iq to='swan@atalk.sytes.net/atalk' id='5WJSN-46' type='set'>
      <data xmlns='http://jabber.org/protocol/ibb' seq='1' sid='jsi_-1891711564'>       h+QACelegax498XeLrGHwlEqeRc3TFba2jw0zPKWCkknPzN7dB717/8ABn9nKy06CDWfHSJeXrYdNoTlCSlF2aO/HxQ1XGG0PRWPr5Uo/lIK1fDnxs8Q+HNUOp6ToOgw3RhaAs0dwwKEgkYM3qoryuikoRWqR1VMdiqseSpUk12bbR1PxH8b6r4/8Q/2/rNtZQXfkrCRZxsilVzjIZmOefWuWooqjjCiiigAooooAKKKKAP/2Q==
      </data>
    </iq>
2023-01-13 09:47:08.532 17220-17431/org.atalk.android D/SMACK: RECV (0): 
    <iq xml:lang='en-US' to='swordfish@atalk.sytes.net/atalk' from='swan@atalk.sytes.net/atalk' type='result' id='5WJSN-46'/>
2023-01-13 09:47:08.550 17220-17430/org.atalk.android D/SMACK: SENT (0): 
    <iq to='swan@atalk.sytes.net/atalk' id='5WJSN-48' type='set'>
      <close xmlns='http://jabber.org/protocol/ibb' sid='jsi_-1891711564'/>
    </iq>
2023-01-13 09:47:11.546 17220-17431/org.atalk.android D/SMACK: RECV (0): 
    <iq xml:lang='en-US' to='swordfish@atalk.sytes.net/atalk' from='swan@atalk.sytes.net/atalk' type='result' id='5WJSN-48'/>
2023-01-13 09:47:12.532 17220-17431/org.atalk.android D/SMACK: RECV (0): 
    <iq xml:lang='en-US' to='swordfish@atalk.sytes.net/atalk' from='swan@atalk.sytes.net/atalk' type='set' id='1C4Z7-128'>
      <close xmlns='http://jabber.org/protocol/ibb' sid='jsi_-1891711564'/>
    </iq>
2023-01-13 09:47:12.555 17220-17430/org.atalk.android D/SMACK: SENT (0): 
    <iq to='swan@atalk.sytes.net/atalk' id='1C4Z7-128' type='error'>
      <error type='cancel'>
        <item-not-found xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/>
      </error>
    </iq>

What you wrote seems sensible (haven’t look at the specification nor the implementation, though). The next step would be to submit a change proposal that can be discussed.

That said, I believe that closing (and this something like this) will always be racy. You never know if the other party may already put a close on the wire that just has not yet arrived when you want to close the session.

Has raised a pull request on the matter

The proposed fix has been implemented in aTalk. It is tested working for the legacy InBandByteStream file transferring.

However when tested with Jingle File Transfer, there appear a race condition occurred in both the Jingle Initiator and Responder. With the network delay, the sending and receiving of <close/> elements are too close to each other for either parties to act according. In both cases, neither of them trigger an error.

I do not have a good proposal for fixing this problem.

========== Jingle Initiator ============
2023-01-21 11:02:22.272 4531-5622/org.atalk.android D/SMACK: SENT (0): 
    <iq to='swan@atalk.sytes.net/atalk' id='4J6EX-39' type='set'>
      <data xmlns='http://jabber.org/protocol/ibb' seq='1' sid='3Y8Y2CQT9V'>
        h+QACelegax498XeLrGHwlEqeRc3TFba2jw0zPKWCkknPzNCDWfHSJeXrYdN3
        .....
        rNtZQXfkrCRZxsilVzjIZmOefWuWooqjjCiiigAooooAKKKKAP/2Q==
      </data>
    </iq>
2023-01-21 11:02:27.273 4531-5623/org.atalk.android D/SMACK: RECV (0): 
    <iq xml:lang='en-US' to='swordfish@atalk.sytes.net/atalk' from='swan@atalk.sytes.net/atalk' type='result' id='4J6EX-39'/>
2023-01-21 11:02:27.285 4531-5916/org.atalk.android E/(InBandBytestreamSession.java:235)#closeByLocal: java.lang.Exception: Send <close/> element!!!
        at org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession.closeByLocal(InBandBytestreamSession.java:235)
        at org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession$IBBOutputStream.close(InBandBytestreamSession.java:785)
        at org.jivesoftware.smackx.jingle_filetransfer.component.JingleOutgoingFileOffer.onBytestreamReady(JingleOutgoingFileOffer.java:92)
        at org.jivesoftware.smackx.jingle.component.JingleContentImpl.lambda$onTransportReady$5$JingleContentImpl(JingleContentImpl.java:460)
        at org.jivesoftware.smackx.jingle.component.-$$Lambda$JingleContentImpl$oRapt0Mgef4poLutihGMYyk7E6g.run(Unknown Source:4)
        at java.lang.Thread.run(Thread.java:920)
2023-01-21 11:02:27.289 4531-5623/org.atalk.android D/SMACK: RECV (0): 
    <iq xml:lang='en-US' to='swordfish@atalk.sytes.net/atalk' from='swan@atalk.sytes.net/atalk' type='set' id='2R12X-36'>
      <close xmlns='http://jabber.org/protocol/ibb' sid='3Y8Y2CQT9V'/>
    </iq>
2023-01-21 11:02:27.290 4531-5622/org.atalk.android D/SMACK: SENT (0): 
    <iq to='swan@atalk.sytes.net/atalk' id='4J6EX-41' type='set'>
      <close xmlns='http://jabber.org/protocol/ibb' sid='3Y8Y2CQT9V'/>
    </iq>
========== Jingle Responder ============

2023-01-21 11:02:27.027 9316-9477/org.atalk.android D/SMACK: RECV (0): 
    <iq xml:lang='en' to='swan@atalk.sytes.net/atalk' from='swordfish@atalk.sytes.net/atalk' type='set' id='4J6EX-39'>
      <data xmlns='http://jabber.org/protocol/ibb' seq='1' sid='3Y8Y2CQT9V'>
       h+QACelegax498XeLrGHba2jw0zPKWCkknPzN7dB717/8ABn9nKy06CDWfHSJeXrYdN
       ....
       8Q/2/rNtZQXfkrCRZxsilVzjIZmOefWuWooqjjCiiigAooooAKKKKAP/2Q==
      </data>
    </iq>
2023-01-21 11:02:27.031 9316-9476/org.atalk.android D/SMACK: SENT (0): 
    <iq to='swordfish@atalk.sytes.net/atalk' id='4J6EX-39' type='result'>
    </iq>
2023-01-21 11:02:27.033 9316-9566/org.atalk.android I/aTalk: [167] org.jivesoftware.smackx.jingle_filetransfer.component.JingleIncomingFileOffer.onBytestreamReady() Reading/Writing finished.
2023-01-21 11:02:27.034 9316-9566/org.atalk.android E/(InBandBytestreamSession.java:235)#closeByLocal: java.lang.Exception: Send <close element!!!
        at org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession.closeByLocal(InBandBytestreamSession.java:235)
        at org.jivesoftware.smackx.bytestreams.ibb.InBandBytestreamSession$IBBInputStream.close(InBandBytestreamSession.java:444)
        at java.io.FilterInputStream.close(FilterInputStream.java:180)
        at org.jivesoftware.smackx.jingle_filetransfer.component.JingleIncomingFileOffer.onBytestreamReady(JingleIncomingFileOffer.java:116)
        at org.jivesoftware.smackx.jingle.component.JingleContentImpl.lambda$onTransportReady$5$JingleContentImpl(JingleContentImpl.java:460)
        at org.jivesoftware.smackx.jingle.component.-$$Lambda$JingleContentImpl$oRapt0Mgef4poLutihGMYyk7E6g.run(Unknown Source:4)
        at java.lang.Thread.run(Thread.java:1012)
2023-01-21 11:02:27.037 9316-9476/org.atalk.android D/SMACK: SENT (0): 
    <iq to='swordfish@atalk.sytes.net/atalk' id='2R12X-36' type='set'>
      <close xmlns='http://jabber.org/protocol/ibb' sid='3Y8Y2CQT9V'/>
    </iq>
2023-01-21 11:02:29.989 9316-9477/org.atalk.android D/SMACK: RECV (0): 
    <iq xml:lang='en' to='swan@atalk.sytes.net/atalk' from='swordfish@atalk.sytes.net/atalk' type='set' id='4J6EX-41'>
      <close xmlns='http://jabber.org/protocol/ibb' sid='3Y8Y2CQT9V'/>
    </iq>