After finishing the SOCKS5 bytestreams transport for Jingle (S5B, XEP-0065, XEP-0260), I was asked whether I had already done interoperability testing with other clients for the fallback to in-band bytestreams.
flow: […] which other transports do you support? How far has interoperability testing between different implementations be done?
hrxi: only socks5 and ibb, conversations and gajim both work fine
flow: […] did you also test the socks5 to ibb fallback?
hrxi: no, that doesn’t work yet
flow: uh, maybe you find the time to implement that in the remaining two weeks, or are there other plans?
I guess I should’ve seen it coming at this point. Here’s how the fallback should work, according to the Jingle SOCKS5 XEP (XEP-0260#Fallback), excluding acks and simplified (dropping a lot of elements that need to be present):
1. <jingle action="session-initiate"> <transport xmlns="j-s5b" /> </jingle> ==> 2. <jingle action="session-accept"> <transport xmlns="j-s5b" /> </jingle> <== 3. <jingle action="transport-info"> <transport xmlns="j-s5b"> <candidate-error /> </transport> </jingle> <=> 4. <jingle action="transport-replace"> <transport xmlns="j-ibb" /> </jingle> ==> 5. <jingle action="transport-accept"> <transport xmlns="j-ibb" /> </jingle> <== 6. <open xmlns="ibb" /> ==>
First, the normal Jingle session initiation happens, the client offering a file
session-initiate including SOCKS5 proxy information and waits. Then,
when the receiving user accepts the file, or if the receiving client
automatically accepts the file based on some conditions, it sends a
session-accept including its SOCKS5 proxy information.
In point 3, we start to deviate from the normal “happy path”; in order to test
the fallback, I made Dino send no local candidates and skipped checking all of
the remote candidates, leading to both clients sending a
candidate-error, meaning that none of the candidates offered by the peer
Now (4), according to the XEP, the initiator (left side) should send a
transport-replace to change the transport method to in-band bytestreams.
In 5, the responder accepts this change.
After getting this response, the initiator is supposed to open the in-band bytestream (XEP-0261#Protocol flow) to complete the negotiation.
It took a few tries until I had Dino-Dino fallback working. The other clients were also fun:
Dino → Conversations The best case. Fails in step 2, but only because of
some minor problems, the block size negotiation doesn’t take into account what
Dino sent. Dino asks for a block size of 4096 bytes, Conversation is only
allowed to lower this value but sets the consensus to 8192 bytes. I ignored
this and the fact that Conversations did not send a
sid and got a working
Conversations → Dino
Fails in step 4, for some reason Conversations
doesn't send a `transport-replace` after the SOCKS5 transport failed.
EDIT Seems to be my mistake, couldn’t reproduce it when trying to test it
with the Conversations developer.
Dino → Gajim Fails in a funny way, in step 5. Gajim responds to
transport-replace with a
session-accept is only valid in
session-initiate, so I don’t know how that happens. Some
Conversations user already reported that issue.
Gajim → Dino Gets stuck in step 6, Gajim doesn’t open the in-band bytestream even though it is the initiator. Gajim#9784.
Of course I’m not sure that I diagnosed all of these issues correctly, these might be mistakes on my part and in my code, too. Let’s see how these issue threads develop.
EDIT And of course there was at least one mistake by me, Conversations → Dino seems to work.