Asmack File Sending Error 503 Type = cancel with o

2019-08-30 23:13发布

问题:

Login Code. Login done successfully.

        String host=AppContext.HOST;//myHost
        String [] params={"a1","aa"}
        int port=AppContext.PORT;//My Port 2777
        String service=AppContext.SERVICE;  //service = smack
        ConnectionConfiguration connConfig = new ConnectionConfiguration(
                host, port, service);
        connConfig.setDebuggerEnabled(true);
            Connection.DEBUG_ENABLED = true;
     connConfig.setSASLAuthenticationEnabled(true);
    XMPPConnection connection = new XMPPConnection(connConfig);
        Log.e("XMPP LoginActivity Username ",params[0]+" pass "+params[1]);
        try {
            connection.connect();
            connectionFlg=true;
            Log.i("XMPP LoginActivity",
                    "Connected to " + connection.getHost());
        } catch (XMPPException ex) {
            Log.e("XMPP LoginActivity", "Failed to connect to "
                    + connection.getHost());
            Log.e("XMPP LoginActivity", ex.toString());
            appContext.setConnection(null);
        }
        try {
            if(connectionFlg)
            {
            connection.login(params[0], params[1]);
            Log.i("XMPP LoginActivity",
                    "Logged in as " + connection.getUser());

            Presence presence = new Presence(Presence.Type.available);
            presence.setStatus("I’m available");
            connection.sendPacket(presence);
            loginFlg=true;
            appContext.setConnection(connection);
            }else
            {
                Log.e("XMPP LoginActivity", "Failed to connect to "
                        + connection.getHost());
            }

        } catch (XMPPException ex) {
            loginFlg=false;                     ;
            Log.e("XMPP LoginActivity", "Failed to log in as "
                    + params[0]);
            Log.e("XMPP LoginActivity", ex.toString());
            appContext.setConnection(null);
        }

My file sending code is bellow

public void sendFile(String sentTo) {
    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());

    FileTransferManager manager = new FileTransferManager(connection);
    OutgoingFileTransfer transfer = manager.createOutgoingFileTransfer(sentTo);
    File file = new File(Environment.getExternalStorageDirectory()
            .getPath() + "/user.json");
    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");
    }

}

while sending i am getting this below two xml response. please take a look.

1)

12:55:16 PM SENT (1092826504): <iq id="SU8c1-17" to="a2@aaa" from="a1@aaa/Smack" type="set"><si xmlns="http://jabber.org/protocol/si" id="jsi_2427513438410796738" profile="http://jabber.org/protocol/si/profile/file-transfer"><file xmlns="http://jabber.org/protocol/si/profile/file-transfer" name="user.json" size="379" ><desc>test_file</desc></file><feature xmlns="http://jabber.org/protocol/feature-neg"><x xmlns="jabber:x:data" type="form"><field var="stream-method" type="list-multi"><option><value>http://jabber.org/protocol/bytestreams</value></option><option><value>http://jabber.org/protocol/ibb</value></option></field></x></feature></si></iq>

2)

12:55:16 PM RCV  (1092826504): <iq type="error" id="SU8c1-17" from="a2@aaa" to="a1@aaa/Smack"><si xmlns="http://jabber.org/protocol/si" id="jsi_2427513438410796738" profile="http://jabber.org/protocol/si/profile/file-transfer"><file xmlns="http://jabber.org/protocol/si/profile/file-transfer" name="user.json" size="379"><desc>test_file</desc></file><feature xmlns="http://jabber.org/protocol/feature-neg"><x xmlns="jabber:x:data" type="form"><field var="stream-method" type="list-multi"><option><value>http://jabber.org/protocol/bytestreams</value></option><option><value>http://jabber.org/protocol/ibb</value></option></field></x></feature></si><error code="503" type="cancel"><service-unavailable xmlns="urn:ietf:params:xml:ns:xmpp-stanzas"/></error></iq>

Please Friends help. i have tried many code snippet. since three days i am working on that only :(

回答1:

I had same problem, I investigated the stanza and solved it this way.

Many people use "/Smack" or "/Resource" as resource part in jid, but it can be configured also the another way.

Resource path is changing with every presence changed of user. Lets say we want to send image to this user: "user1@mydomain"

You must add "/Resource" part to this jid and it become this: user1@mydomain/Resource

But /Resource path is changing with presence so you must follow every presence change to update resource path. Best way is to get user presence is in roster listener and in presencheChanged() method you get last user resource part like this:

Roster roster=getRoster();
roster.addRosterListener(new RosterListener() {
                @Override
                public void entriesAdded(Collection<Jid> addresses) {
                    Log.d("entriesAdded", "ug");
                    context.sendBroadcast(new Intent("ENTRIES_ADDED"));
                }

                @Override
                public void entriesUpdated(Collection<Jid> addresses) {
                    Log.d("entriesUpdated", "ug");
                }

                @Override
                public void entriesDeleted(Collection<Jid> addresses) {
                    Log.d("entriesDeleted", "ug");
                }

                @Override
                public void presenceChanged(Presence presence) {
                    Log.d("presenceChanged", "ug");
                    //Resource from presence
                    String resource = presence.getFrom().getResourceOrEmpty().toString();
                    //Update resource part for user in DB or preferences
                    //...
                }
            });
}

Resource string will be some generated string like "6u1613j3kv" and jid will become:

user1@mydomain/6u1613j3kv

That means that you must create your outgoing transfer like this:

EntityFullJid jid = JidCreate.entityFullFrom("user1@mydomain/6u1613j3kv"); 
OutgoingFileTransfer transfer = manager.createOutgoingFileTransfer(jid)
transfer.sendFile(new File("DirectoryPath"), "Description");

And that is how i have solved my problem with file transfer on smack and Openfire.

In your case form in sendFile(String sentTo) function sentTo must be formed like my jid with resource path that is changing with every rpesence change.

Also to mention you must add following properties in your Openfire server:

xmpp.proxy.enabled - true
xmpp.proxy.externalip - MY_IP_ADDRESS
xmpp.proxy.port - 7777

Just to mention, I am using Openfire 4.0.2 and Smack 4.2.2.

Also this can be configured the easy way, just set the resource on

XMPPTCPConnectionConfiguration.Builder .

like

XMPPTCPConnectionConfiguration.Builder configurationBuilder = 
XMPPTCPConnectionConfiguration.builder(); 

configurationBuilder.setResource("yourResourceName");