1
votes

I have a little JavaScript XMPP client, written with Strophe, that connects to a server hosted on hosted.im. I think hosted.im uses ejabberd on their backend.

I establish the connection using

Strophe.Connection(myBoshService), and am able to send chat messages back and forth. However, after a certain time, it seems, there is an automatic disconnect if there is no activity.

Now, my question is, what would be a good way to keep the session active, so that it does not disconnect. Disconnect time seems to be very short, about 60 seconds or so.

Should I send some kind of activity back and forth to keep it open? Or, which seems simpler to me, should I somehow change the timout of the session. If so, where can I change this? Is this a server-setting, irregardless of the Strophe.Connection object, or can I set the timeout when initializing Strophe.Connection?

Thanks for any and all help.

Best regards,

Chris

Edit: Here is the code I use for connecting:

I manage the connection through a global variable Hello (yes, name is awkward, I took it from an example):

var Hello = {
connection: null,
start_time: null,
partner: {
    jid: null,
    name: null
},
log: function (msg) {
    $('#log').append("<p>" + msg + "</p>");
},

send_ping: function (to) {
    var ping = $iq({
        to: to,
        type: "get",
        id: "ping1"}).c("ping", {xmlns: "urn:xmpp:ping"});

    Hello.log("Sending ping to " + to + ".");
    console.log("Sending ping to " + to + ".");

    Hello.start_time = (new Date()).getTime();
    Hello.connection.send(ping);
},

handle_pong: function (iq) {
    var elapsed = (new Date()).getTime() - Hello.start_time;
    Hello.log("Received pong from server in " + elapsed + "ms.");
    console.log('Received pong from server in " + elapsed + "ms.');
    $('#login').hide();
    $('#chat').show();
    //window.location = "chat.html";
    //Hello.connection.disconnect();

    return true;
}, 

//"<active xmlns="http://jabber.org/protocol/chatstates"/><body xmlns="http://jabber.org/protocol/httpbind">tuiuyi</body>"

displayIncomingText: function (text) {

    var body = $(text).find("xml > body");
    if (body.length === 0)
    {
        body = $(text).find('body');
        if (body.length > 0) 
        {
            body = body.text();
            $('#chattext').append("<p>"+ body + "</p>");
        }
        else
        {
            body = null;
        }
    }
    return true;
},

readRoster: function (iq) {
    $(iq).find('item').each(function () {
        var jid = $(this).attr('jid');
        var name = $(this).attr('name') || jid;
        Hello.partner.name = name;
        Hello.partner.jid = jid;
    });
    return true;
}

};

The main relevant objects here are Hello.connect and Hello.partner, which stores the jid of the only person on the accounts roster, as this is a one to one chat.

Then, in $(document).ready, I bind two buttons to connect and send messages respectively:

$(document).ready(function () {
$('#chat').hide();
$('#chatSend').bind('click', function () {
    Hello.connection.send(
        $msg(
            {to : Hello.partner.jid, type : 'chat'}
            ).c('body').t($('#chattextinput').val())
            );
            $('#chattext').append("<p align='right'>" + $('#chattextinput').val() + "</p>");
    });


$('#SignIn').bind('click', function () {
$(document).trigger('connect', { 
                                jid: $('#eMail').val(), password: $('#password_f').val()
                                }
                    );
                    });

});

Clicking the sign-in button triggers the event "connect":

$(document).bind('connect', function (ev, data) {
console.log('connect fired');
var conn = new Strophe.Connection("http://bosh.metajack.im:5280/xmpp-httpbind");
conn.connect(data.jid, data.password, function (status) {
    console.log('callback being done');
    if (status === Strophe.Status.CONNECTED) {
        alert('connected!');
        $(document).trigger('connected');
        alert('Connected successfully');
    } else if (status === Strophe.Status.DISCONNECTED) {
        $(document).trigger('disconnected');
    }
    else
    {
        Hello.log("error");
        console.log('error');
    }
});

Hello.connection = conn;
});

This creates the Strophe.Connection and stores it in Hello.connection. Also, it sets the callback function of the connection object. This code is taken straight from an example in a Strophe.js book. Anyway, the callback checks the status of the connection, and if status === Strophe.Status.DISCONNECTED, triggers "disconnected", which only does this:

$(document).bind('disconnected', function () {
Hello.log("Connection terminated.");
console.log('Connection terminated.');
// remove dead connection object
Hello.connection = null;
});

Anyway, what is happening is that, for some reason, in the callback set with conn.connect, after a short time, the status evaluates to Strophe.Status.DISCONNECTED, and I am not sure why, unless somewhere, either in the server or in the connection object, there is a timeout specified which seems to be ca. 60 seconds.

As to a log of the stanzas going back and forth, I guess I would need to quickly write a handler to see all incoming stanzas, or is it possible to see a log of all stanzas between the client and server in ejabberd?

1
It seems strange that Strophe is unable to remain connected for more than 60 seconds.. When your disconnect occurs, is it graceful? What type of stanza do you get from the server? There are some server-side settings relating to BOSH idle timeout but these shouldn't be triggered unless Strophe's connection has been paused, otherwise it should remain connected.fpsColton
Could you provide code showing your call to Strophe Connection's connect() and also a log of the stanza's which are sent during your disconnect.fpsColton
one easy way to capture the incoming and outgoing stanza's is by using a network debugging tool such as fiddler, alternatively you can use the browsers built in network debugger, but fiddler can also display the stanza as a parsed XML document which makes it much easier to see what's going on. You can also add a custom handler to Strophe's XMLInput and XMLOutput to view the stanzas.fpsColton
One more thing, have you tried passing in the optional wait and hold variables to the connect() function? I'm not sure if it will make any difference but perhaps try conn.connect(data.jid, data.password, function(..){...}, 60, 1);fpsColton
Strophe should be sending a new stanza every 60 seconds. If it does not, that could be why you're getting disconnected. In your console, you should see a body getting sent and should look like: <body rid='11111111' xmlns='jabber.org/protocol/httpbind' sid='xxxxxxxxxxxxxx'/>Mark S

1 Answers

2
votes

For the sake of other people who come upon this and have a similar problem, the solution in this case was that the servers at hosted.im send a ping request every 60 seconds to check if the client is still online.

This ping request looks like this:

<iq from="testserver.p1.im" to="[email protected]/23064809721410433741569348" id="164323654" type="get"> <ping xmlns="urn:xmpp:ping"></ping> </iq>

What is needed, of course, is to form a response, which will look something like this:

<iq from="[email protected]" to="testserver.p1.im" id="164323654" type="result" xmlns="jabber:client"><ping xmlns="urn:xmpp:ping"/></iq>

Note the "to"-attribute. I omitted it at the beginning as I was under the assumption a message sent with no to-attribute is automatically assumed to be a client->server message. Not in this case however. Not sure if this is the case in general, or whether it is an oddity of servers at hosted.im.

Thanks to everyone for their comments and suggestions!

Best regards,

Chris