XEP-Remarks/XEP-0260: Jingle SOCKS5 Bytestreams Transport Method
If the nominated candidate is of the proxy type and either party cannot connect to the proxy (for example because of a restrictive firewall), the failing party shall send a transport-info message containing an <proxy-error/> element. The parties shall then consider the bytestream unsuccessful and SHOULD attempt to fall back to another transport as described in Fallback Methods.
This is a little bit weird. If remote send me proxy candidate and I can't connect to any remote candidate including this proxy, I would rather send <candidate-error>.
When to send candidate-used/error
If both parties send a candidate-error notification then the SOCKS5 negotiation has failed and the parties need to fall back to some other transport method, typically (but not necessarily) IBB; see the Fallback Methods section of this document for details.
A client should not send candidate-error if it hasn't sent yet all its local candidates. Otherwise if we already have candidate-error from remote then the transport will be considered failed. For example it's possible if upnp binding lasts too long while jingle session was auto-accepted and all candidates tried.
Basically this dependency of transport state on candidate-error is hardly compatible with trickle candidates. Instead we need another XEP with more clear and flexible s5b negotiation procedure. Or at least modify this one so each side can send an alert that its local candidates were exhausted. Then we can consider transport failed ony when remote reported us it doesn't have more candidates and candidate-error.
The spec is quite confusing either refering to XEP-0065's requester/target or Jingle's initiator/responder in its "2.2 Exchanging Candidates". Neither of these is valid in this case. As we know either party can add content in an already opened session and either party can propose a "proxy" candidate. With XEP-0065 it was different, only requester (session initiator) could have candidates. But with Jingle the algo has to be kept the same as with XEP-0065:
- One party sends a proxy candidate
- The other party connects and accepts it
- Then the first party connects to the proxy too and finally activates it
In other words the party which sent proxy eventually activates it, not obligtory the Jingle's initiator. Section "2.4 Completing the Negotiation" is more clear about in terms about activation, so probably one has to read it first.
Follow next rules regarding dstaddr computation:
- dstaddr for a local proxy candidate is computed like sha1(SID + Local JID + Remote JID)
- dstaddr for all other connections/bindings is computed like sha1(SID + Initiator JID + Responder JID)
Port bindings confusion
Let's assume one of your "Direct" candidates is 10.0.0.2:8000. Then you configured you router to forward your <external IP>:8000 to 10.0.0.2:8000. Looks pretty good until now. Next you send both cadidates to the remote side and if your ISP provides you with public IP the probability of successful connection is quite high and that's perfect. But there is one problem, you can't distinguish which candidate received the incoming connection. They always come to 10.0.0.2:8000 and there is no any requirement for source IP to be in the same network. Of course it's also useless to compare connection dst IP and candidate's host because in case of NAT the IP will be different anyway not talking about if the host is not an IP but a domain name. And as a consequence of lack of such a knowledge you can assign incoming connection socket to a wrong candidate. And then when remote side tells you candidate-used it may have no any socket or may have some wrong socket leading to connection failure.
If the XEP could provide a way to authenticates a specific candidate instead of the transport as a whole, that would make it possibe to listen on the same port (read do less port bindings). For example this could be done by computatio dstaddr per candidate like sha1(sid, cid, initiator jid, responder jid), but there is no such a way for now.
So as a rule of thumb:
- Never use the same local port for 2+ candidates
- If you still want to configure your router manually then do it, but use different local ports for all other candidates.
XEP-0166 allows to send multiple contents with the same creator and name. Lets suppose we do this to provide the same file (xep-0234) with different <security> elements. Now one of sides sends such a request with duplicated creator/name and the other side wants to change the transport before content-accept. What's going to be replaced in this case if we provide just name and creator in the request? So while it's not said explicitly you should do transport-replace either after session/content-accept or including all the other content elements (description/security/etc)
Another problem with early (before accept) transport replace is the fact we have to send the same offer twice. For example we have S5B and IBB. The lousy s5b implementation can only gather s5b proxy candidates so it may fail a little later (after proxy discovery when no proxies discovered). So after proxy discovery failure we may want to send transport-replace request to IBB which will contain everything needed for IBB negotiation (at least block size). Then we have to repeat transport offer with session/content-accept which will force the remote party to reinitialize IBB transport what looks like a bad practice, which may be even worse with other transports. To make things right it has to be allowed to send session/content-accept without transport element if it was accepted earlier.