Home » Android » Android Core » Android: File transfer with asmack and Openfire

About Harsh Raval

Android: File transfer with asmack and Openfire

I have seen many peoples struggling from file transfer in asmackAndroid build environment and patches for smack. I tried same library with Openfire server after some debugging got success in it. So I will like to share my problem and solution for it. I found that the problem is in Byte Stream host, it tries to connect to wrong host for initiating file transfer using byte streams. If you have not configured the file transfer proxy properly then it will choose 127.0.0.1 or localhost or any internally configured host/ip as a bytestream host, which in android is not considered as proper ip for communicating. But wait then why it is working properly with desktop client with same server. The reason is desktop clients can easily identify this ips and can use it to open socket for file transfer.

The variable names used in following discussions are:

NameMeaning
myHostThe hostname of machine on which Openfire is running.
user1@myHostFile transfer initiator user
user2@myHostRecipient of file

How to know which host is chosen for byte streams: (Following XMLs are shown as they are sent and received to the file transfer initiator.)

  • First query other client for information about supported features:

Sent:

<iq id='x1ixz-13' to='user2@myHost/Smack' type='get'>
   <query xmlns='http://jabber.org/protocol/disco#info'></query>
</iq>

Received:

<iq id='x1ixz-13' to='user1@myHost/Smack' type='result' from='user2@myHost/Smack'>
   <query xmlns='http://jabber.org/protocol/disco#info'>
      <!—some other items -->
      <feature var='http://jabber.org/protocol/bytestreams'/>
      <!—some other items -->
   </query>
</iq>

Here you can know that whether bytestream file transfer is supported on the client other side or not. If you see a xml like above in response then it’s supported on the other side and you can go further.

  • Query server for disco items:

Sent:

<iq id='x1ixz-14' to='myHost' type='get'>
   <query xmlns='http://jabber.org/protocol/disco#items'></query>
</iq>

Received:

<iq type='result' id='x1ixz-14' from='myHost' to='user1@ myHost /Smack'>
   <query xmlns='http://jabber.org/protocol/disco#items'>
      <!—some other items -->
      <item jid='proxy. myHost ' name='Socks 5 Bytestreams Proxy'/>
      <!—some other items -->
   </query>
</iq>

Here you will receive various items for different items supported by server like , file transfer proxy, search service, conference service… The item we should look for is ` Socks 5 Bytestreams Proxy `.

  • Request for more information on proxy

Sent:

<iq id='x1ixz-19' to='proxy. myHost ' type='get'>
   <query xmlns='http://jabber.org/protocol/bytestreams'/>
</iq>

Received:

<iq type='result' id='x1ixz-19' from='proxy. myHost '  to='user1@ myHost /Smack'>
   <query xmlns='http://jabber.org/protocol/bytestreams'>
      <streamhost jid='proxy. myHost ' host=' myHost ' port='7777'/>
   </query>
</iq>

Here the host in the <streamhost> is the key for the file transfer. You have to make sure that this host is accessible from your android phone. It should not be like localhost, 127.0.0.1 or any company’s internal configured server which is not accessible outside of the company. It must be a publicly accessible ip address or host.

To configure proper proxy add/change these 3 properties in Openfire:

  1. xmpp.proxy.enabled – true
  2. xmpp.proxy.port – 7777
  3. xmpp.proxy.externalip – [publicly accessible host or ip]

The code for file transfer:

FileTransferManager manager = new FileTransferManager(connection);
OutgoingFileTransfer transfer = manager.createOutgoingFileTransfer('usre2@myHost/Smack');
File file = new File(filenameWithPath);
try {
   transfer.sendFile(file, 'test_file');
} catch (XMPPException e) {
   e.printStackTrace();
}
while(!transfer.isDone()) {
   if(transfer.getStatus().equals(Status.error)) {
      System.out.println('ERROR!!! ' + transfer.getError());
   } else if (transfer.getStatus().equals(Status.cancelled)
                    || transfer.getStatus().equals(Status.refused)) {
      System.out.println('Cancelled!!! ' + transfer.getError());
   }
   try {
      Thread.sleep(1000L);
   } catch (InterruptedException e) {
      e.printStackTrace();
   }
}
if(transfer.getStatus().equals(Status.refused) || transfer.getStatus().equals(Status.error)
 || transfer.getStatus().equals(Status.cancelled)){
   System.out.println('refused cancelled error ' + transfer.getError());
} else {
   System.out.println('Success');
}

And the code for file receive:

FileTransferManager manager = new FileTransferManager(connection);
manager.addFileTransferListener(new FileTransferListener() {
   public void fileTransferRequest(final FileTransferRequest request) {
      new Thread(){
         @Override
         public void run() {
            IncomingFileTransfer transfer = request.accept();
            File mf = Environment.getExternalStorageDirectory();
            File file = new File(mf.getAbsoluteFile()+'/DCIM/Camera/' + transfer.getFileName());
            try{
                transfer.recieveFile(file);
                while(!transfer.isDone()) {
                   try{
                      Thread.sleep(1000L);
                   }catch (Exception e) {
                      Log.e('', e.getMessage());
                   }
                   if(transfer.getStatus().equals(Status.error)) {
                      Log.e('ERROR!!! ', transfer.getError() + '');
                   }
                   if(transfer.getException() != null) {
                      transfer.getException().printStackTrace();
                   }
                }
             }catch (Exception e) {
                Log.e('', e.getMessage());
            }
         };
       }.start();
    }
 });

Also configure ProviderManager to properly decode/parse bytestreams and other required xmls:

ProviderManager.getInstance().addIQProvider('query','http://jabber.org/protocol/bytestreams', new BytestreamsProvider());
ProviderManager.getInstance().addIQProvider('query','http://jabber.org/protocol/disco#items', new DiscoverItemsProvider());
ProviderManager.getInstance().addIQProvider('query','http://jabber.org/protocol/disco#info', new DiscoverInfoProvider());

The asmack library I used was asmack-jse-buddycloud.jar.

Reference: File transfer in android with asmack and Openfire from our JCG partner Harsh Raval at the harryjoy blog.

Do you want to know how to develop your skillset to become a Java Rockstar?

Subscribe to our newsletter to start Rocking right now!

To get you started we give you our best selling eBooks for FREE!

1. JPA Mini Book

2. JVM Troubleshooting Guide

3. JUnit Tutorial for Unit Testing

4. Java Annotations Tutorial

5. Java Interview Questions

6. Spring Interview Questions

7. Android UI Design

and many more ....

 

4 comments

  1. Hi i am not able to file transfer. in my code i am get file transfer notification and i am able to get Transfer File name but not able to download file. always show file transfer progress 0.0 in thared. please help me. can u give me full source code for this.
    Thank you.

  2. Hi I am not able to transfer file. the problem is of 503 service unavailable

  3. i am also getting 503 error

  4. Hi i am not able to file transfer. in my code i am get file transfer notification and i am able to get Transfer File name but not able to download file. always show file transfer progress 0.0 in thared. please help me. can u give me full source code for this.

    Can you please help really need when I am using PSI client and Device and check sending and receiving file its working properly but when I am using 2 devices and check same thing I am not able to send or receive file I just got name of file and loop thread with progress 0.0.
    Thank you.

Leave a Reply

Your email address will not be published. Required fields are marked *

*


Want to take your Java Skills to the next level?
Grab our programming books for FREE!
  • Save time by leveraging our field-tested solutions to common problems.
  • The books cover a wide range of topics, from JPA and JUnit, to JMeter and Android.
  • Each book comes as a standalone guide (with source code provided), so that you use it as reference.
Last Step ...

Where should we send the free eBooks?

Good Work!
To download the books, please verify your email address by following the instructions found on the email we just sent you.