Android Smack4.1.1 XMPP FileTransfer Issue with Iphone

377 views Asked by At

We have implemented FileTransfer feature with the new android 4.1.1 . Every thing works fine except while transferring file to an iphone client.Transfer fails when negotiating.

We get the following logs when transfer is successful with a windows smack client.

D/SMACK(25089): SENT (0): <iq to='[email protected]/QXmpp' id='tmfCy-335' type='set'><si xmlns='http://jabber.org/protocol/si' id='jsi_1094412687185521586' mime-type='image/jpeg' profile='http://jabber.org/protocol/si/profile/file-transfer'><file xmlns="http://jabber.org/protocol/si/profile/file-transfer" name="5_224724.jpg" size="630784" ><desc>normal</desc></file><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>

D/SMACK(25089): RECV (0): <iq from='[email protected]/QXmpp' to='[email protected]/Tablet' id='tmfCy-335' type='result'><si xmlns='http://jabber.org/protocol/si' profile='http://jabber.org/protocol/si/profile/file-transfer'><feature xmlns='http://jabber.org/protocol/feature-neg'><x xmlns='jabber:x:data' type='submit'><field type='list-single' var='stream-method'><value>http://jabber.org/protocol/bytestreams</value></field></x></feature></si></iq>

D/SMACK(25089): SENT (0): <iq to='192.168.100.239' id='tmfCy-341' type='get'><query xmlns='http://jabber.org/protocol/disco#items'></query></iq>

D/SMACK(25089): SENT (0): <iq to='[email protected]/QXmpp' id='tmfCy-353' type='set'><query xmlns='http://jabber.org/protocol/bytestreams' sid='jsi_1094412687185521586' mode='tcp'><streamhost jid='[email protected]/Tablet' host='192.168.100.133' port='7777'/><streamhost jid='[email protected]/Tablet' host='fe80::5cf8:a1ff:fe8b:b73b%p2p0' port='7777'/><streamhost jid='[email protected]/Tablet' host='fe80::5ef8:a1ff:fe8b:b73b%wlan0' port='7777'/><streamhost jid='proxy.192.168.100.239' host='192.168.100.239' port='7777'/></query></iq>

D/SMACK(25089): RECV (0): <iq from='[email protected]/QXmpp' to='[email protected]/Tablet' id='tmfCy-353' type='result'><query xmlns='http://jabber.org/protocol/bytestreams' sid='jsi_1094412687185521586'><streamhost-used jid='[email protected]/Tablet'/></query></iq>

D/SMACK(25089): RECV (0): <iq from='192.168.100.239' to='[email protected]/Tablet' id='4072246770' type='get'><ping xmlns='urn:xmpp:ping'/></iq>

D/SMACK(25089): SENT (0): <iq to='192.168.100.239' id='4072246770' type='result'></iq>

We get the following logs when transfer is unsuccessful with an iphone smack client:

D/SMACK(25089): SENT (0): <iq to='[email protected]/iPad' id='tmfCy-441' type='set'><si xmlns='http://jabber.org/protocol/si' id='jsi_1968597579584741254' mime-type='image/jpeg' profile='http://jabber.org/protocol/si/profile/file-transfer'><file xmlns="http://jabber.org/protocol/si/profile/file-transfer" name="5_224724.jpg" size="630784" ><desc>normal</desc></file><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>

D/SMACK(25089): RECV (0): <iq from='[email protected]/iPad' to='[email protected]/Tablet' type='result' id='tmfCy-441'><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></field></x></feature></si></iq>


D/SMACK(25089): SENT (0): <iq to='[email protected]/iPad' id='tmfCy-443' type='get'><query xmlns='http://jabber.org/protocol/disco#info'></query></iq>

D/SMACK(25089): RECV (0): <iq from='[email protected]/iPad' to='[email protected]/Tablet' type='error' id='tmfCy-443'><query xmlns='http://jabber.org/protocol/disco#info'/><error type='cancel' code='501'><feature-not-implemented xmlns='urn:ietf:params:xml:ns:xmpp-stanzas'/></error></iq>

By Comparing the logs i feel its a matter of setting an incorrect proxy for the xmpp login connection.

Code for XMPP login :

ProxyInfo proxy = new ProxyInfo(null, loc_IP, 7777, null,null);

I would really like to use it this way ,

ProxyInfo proxy = new ProxyInfo(ProxyType.SOCKS5, loc_IP, 7777, null,null);

, but then the login process fails.

= XMPPTCPConnectionConfiguration.builder()
    .setProxyInfo(proxy)
    .setServiceName(loc_IP)
    .setHost(loc_IP)
    .setPort(XMPP_PORT)
    .setCompressionEnabled(false)
    .setDebuggerEnabled(true)
    .setCustomSSLContext(sslContext)
    .setSecurityMode(SecurityMode.ifpossible)
    .setHostnameVerifier(verifier)
    .setUsernameAndPassword(username, pwd)
    .setResource(resourcestring)
    .build();

File transfer enabling service code :

    ServiceDiscoveryManager sdm=ServiceDiscoveryManager.getInstanceFor(main.login.connection);

    if (sdm == null) {
     sdm = ServiceDiscoveryManager.getInstanceFor(main.login.connection);
     sdm.addFeature("http://jabber.org/protocol/disco#info");
     sdm.addFeature("jabber:iq:privacy");
     sdm.removeFeature("http://jabber.org/protocol/ibb");
    }
  
    SmackConfiguration.DEBUG  = true;
  
    //   FileTransfer Service
        ProviderManager.addIQProvider("query",
    "http://jabber.org/protocol/bytestreams",new     BytestreamsProvider());

    ProviderManager.addIQProvider("query",
    "http://jabber.org/protocol/disco#items",new  DiscoverItemsProvider());

    ProviderManager.addIQProvider("query",
    "http://jabber.org/protocol/disco#info",new  DiscoverInfoProvider());

    ProviderManager.addIQProvider("si","http://jabber.org/protocol/si",new StreamInitiationProvider());

 
    fileTransferNegotiator =     FileTransferNegotiator.getInstanceFor(main.login.connection);
    fileTransferNegotiator.IBB_ONLY = false;

    fileTransferManager = FileTransferManager.getInstanceFor(main.login.connection);
    fileTransferManager.addFileTransferListener(fileTransferListener);

    fileTransferListener =new FileTransferListener() {

    @Override
     public void fileTransferRequest(FileTransferRequest request) {

      IncomingFileTransfer inComingFileTransfer = request.accept();
     //followed by status handling code in a thread
    }
   };

1

There are 1 answers

0
AChau On BEST ANSWER

The following settings helped me achieve one to one file transfer:

We needed to create a Socks5 based File transfer listener , the problem happened when file transfer was taking place between iphone and android.

1)Since file transfer was taking place via WIFI , Android was including all types of ip : ipV4 + ipv6(if available in a device),so we needed strip the default proxy settings of any ipv6 type address or blank 0.0.0.0 type address. 2)We were not implementing proxy correctly, needed to implement socks5 proxy settings.

Finally these are the settings on the connection configuration that worked.

//XMPP Connection Setup
connConfig = XMPPTCPConnectionConfiguration
  .builder()
  .setServiceName(loc_IP)
  .setHost(loc_IP)
  .setPort(XMPP_PORT)
  .setCompressionEnabled(false)
  .setDebuggerEnabled(true)
  .setCustomSSLContext(sslContext)
  .setSecurityMode(SecurityMode.disabled)
  .setHostnameVerifier(verifier)
  .setUsernameAndPassword(nick_Name, password)
  .setResource(resourcestring)
  .build();

SmackConfiguration.setDefaultPacketReplyTimeout(50000);
Socks5Proxy.setLocalSocks5ProxyEnabled(false);
Socks5Proxy.setLocalSocks5ProxyPort(7777);

removeAbnormalIP();

SASLPlainMechanism saslPlainMechanism = new SASLPlainMechanism();
SASLAuthentication.registerSASLMechanism(saslPlainMechanism);


CXmppFileTransferManager xmppFileManager = main.getXMPPTransferManager();
xmppFileManager.serviceEnabledForXmppFileTransfer();

////////////////////////////////////////////////////////////////////////

private void removeAbnormalIP() {

WifiManager wifiManager = (WifiManager) main.currentContext.getSystemService(Context.WIFI_SERVICE);
WifiInfo wifiInfo = wifiManager.getConnectionInfo();

Socks5Proxy mProxy = Socks5Proxy.getSocks5Proxy();
List<String> addresses = new ArrayList<String>();

if (wifiInfo != null) {
 int ipAddress = wifiInfo.getIpAddress();
 String strIPAddess = ((ipAddress >> 0) & 0xFF) + "."
   + ((ipAddress >> 8) & 0xFF) + "."
   + ((ipAddress >> 16) & 0xFF) + "."
   + ((ipAddress >> 24) & 0xFF);

 // ignore "0.0.0.0"
 if (!strIPAddess.equals("0.0.0.0"))
  addresses.add(strIPAddess);

}
// set an ip in case there is a Wifi Connection
// otherwise addresses will be empty and local S5B proxy will not be
// used
mProxy.replaceLocalAddresses(addresses);
}

/////////////////////////////////////////////////////////////////////
XmppFileTransferManager Class:

ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(main.login.connection);

if (sdm == null) {
  sdm = ServiceDiscoveryManager.getInstanceFor(main.login.connection);
  sdm.addFeature("http://jabber.org/protocol/disco#info");
  sdm.addFeature("jabber:iq:privacy");
  sdm.addFeature("jabber.org/protocol/si"); 
  sdm.removeFeature("http://jabber.org/protocol/ibb");

}
      
SmackConfiguration.DEBUG  = true;
      
      
     //   FileTransfer
ProviderManager.addIQProvider("query","http://jabber.org/protocol/bytestreams",new BytestreamsProvider());

ProviderManager.addIQProvider("query",
    "http://jabber.org/protocol/disco#items",new DiscoverItemsProvider());

ProviderManager.addIQProvider("si","http://jabber.org/protocol/si",new StreamInitiationProvider());
      
ProviderManager.addIQProvider("x","jabber:x:roster", new RosterPacketProvider());
      
fileTransferNegotiator=FileTransferNegotiator.getInstanceFor(main.login.connection);
fileTransferNegotiator.IBB_ONLY = false;