cmeng

Smack 4.1.3 cannot properly handle Sock5ByteStreamSession with multiple <streamhost/>

Discussion created by cmeng on Sep 6, 2015
Latest reply on Sep 14, 2015 by 张俊瑞

Attached below is a log of the file transfer between Pidgin client and an xmpp client uses smack 4.1.3

When pidgin reply <query xmlns='http://jabber.org/protocol/bytestreams' sid='purple6d1e6f8'> with multiple <streamhost/>,

file transfer process aborted with exceptions when the first <streamhost/> connection cannot be established.

 

Following changes to the file resolve the problem:

org.jivesoftware.smackx.bytestreams.socks5.Socks5BytestreamRequest.java#accept()

 

========== Socks5BytestreamSession accept() modifications =================

public Socks5BytestreamSession accept()

  throws InterruptedException, XMPPErrorException, SmackException

  {

        Collection<StreamHost> streamHosts = this.bytestreamRequest.getStreamHosts();

 

        // throw exceptions if request contains no stream hosts

        if (streamHosts.size() == 0) {

            cancelRequest();

        }

 

        StreamHost selectedHost = null;

        Socket socket = null;

 

        String digest = Socks5Utils.createDigest(this.bytestreamRequest.getSessionID(), this.bytestreamRequest.getFrom(), this.manager.getConnection().getUser());

 

        /*

         * determine timeout for each connection attempt; each SOCKS5 proxy has the same amount of time so that the first does not consume

         * the whole timeout

         */

        int timeout = Math.max(getTotalConnectTimeout() / streamHosts.size(), getMinimumConnectTimeout());

 

        for (StreamHost streamHost : streamHosts) {

            String address = streamHost.getAddress() + ":" + streamHost.getPort();

 

 

            // check to see if this address has been blacklisted

            int failures = getConnectionFailures(address);

            if ((CONNECTION_FAILURE_THRESHOLD <= 0) || (failures < CONNECTION_FAILURE_THRESHOLD)) {

 

                // try establish socket connection

                try {

                    // build SOCKS5 client

                    final Socks5Client socks5Client = new Socks5Client(streamHost, digest);

 

                    // connect to SOCKS5 Proxy with a timeout

                    socket = socks5Client.getSocket(timeout);

                    // set selected host only if socket connection is OK; Otherwise loop exit with exception

                    if (socket != null) {

                        selectedHost = streamHost;

                        break;

                    }

                    else {

                        incrementConnectionFailures(address);

                    }

                }

                catch (TimeoutException e) {

                    incrementConnectionFailures(address);

                }

                catch (IOException e) {

                    incrementConnectionFailures(address);

                }

                catch (XMPPException e) {

                    incrementConnectionFailures(address);

                }

            }

        }

 

        // throw exception if connecting to all SOCKS5 proxies failed

        if (selectedHost == null || socket == null) {

            cancelRequest();

        }

        // send used-host confirmation

        Bytestream response = createUsedHostResponse(selectedHost);

        this.manager.getConnection().sendStanza(response);

 

        return new Socks5BytestreamSession(socket, selectedHost.getJID().equals(this.bytestreamRequest.getFrom()));

    }

 

=================== File Transfer Log =======================

09-05 22:46:02.836: D/SMACK(32726): RECV (0): <iq from='swan@xyz.com/pidgin' to='leopard@xyz.com/office' type='set' id='purple6d1e6f7'>

<si xmlns='http://jabber.org/protocol/si' id='purple6d1e6f8' profile='http://jabber.org/protocol/si/profile/file-transfer'>

<file xmlns='http://jabber.org/protocol/si/profile/file-transfer' name='abc_blocks.png' size='15002'/>

<feature xmlns='http://jabber.org/protocol/feature-neg'>

<x xmlns='jabber:x:data' type='form'>

<field var='stream-method' type='list-single'>

<option><value>http://jabber.org/protocol/bytestreams</value></option>

<option><value>http://jabber.org/protocol/ibb</value></option>

</field></x></feature></si></iq>

<r xmlns='urn:xmpp:sm:3'/>

 

09-05 22:46:02.876: D/SMACK(32726): SENT (0): <a xmlns='urn:xmpp:sm:3' h='33'/>

09-05 22:46:23.926: D/ViewRootImpl(32726): ViewPostImeInputStage ACTION_DOWN

09-05 22:46:24.066: D/SMACK(32726): SENT (0): <iq to='swan@xyz.com/pidgin' id='purple6d1e6f7' type='result'>

<si xmlns='http://jabber.org/protocol/si'>

<feature xmlns="http://jabber.org/protocol/feature-neg">

<x xmlns='jabber:x:data' type='submit'>

<field var='stream-method'><value>http://jabber.org/protocol/bytestreams</value>

<value>http://jabber.org/protocol/ibb</value></field></x></feature></si></iq>

 

 

09-05 22:46:24.116: D/SMACK(32726): RECV (0): <iq from='swan@xyz.com/pidgin' to='leopard@xyz.com/office' type='set' id='purple6d1e6f9'>

<query xmlns='http://jabber.org/protocol/bytestreams' sid='purple6d1e6f8'>

<streamhost jid='swan@xyz.com/pidgin' host='192.168.56.1' port='64656'/>

<streamhost jid='swan@xyz.com/pidgin' host='192.168.1.11' port='64656'/>

<streamhost jid='swan@xyz.com/pidgin' host='0.0.0.0' port='64656'/>

<streamhost jid='proxy.xyz.com' host='118.200.189.122' port='7777'/>

</query></iq><r xmlns='urn:xmpp:sm:3'/>

09-05 22:46:24.116: D/SMACK(32726): SENT (0): <a xmlns='urn:xmpp:sm:3' h='34'/>

Outcomes