bosh speed tests

Now with the newly announced node-xmpp-bosh (NXB) my first tests left me with the impression that this thing is pretty speedy to what I am used to. So I decided to do some quick benchmarks on different implementations of BOSH. I did these tests on my desktop (some intel core 2 duo with 2,4 GHz and 4GB of RAM).

Login-Times (in ms):

Native NXB
Ejabberd 2.1.6 593 (process_delay: 100ms)
417 (process_delay 10ms)
204
Tigase 4.3.1 145 222
Prosody 0.7.0 111 170

So what we can see here is that NXB might be a feasible improvement over ejabberd’s native BOSH interface while tigase and prosody do fine in both cases.
Would be nice of course to also test with some decent load and see how the configurations behave with different loads put on them. But that’s out of scope of my quick tests for now, sorry.

Update: Ejabberd honors a ‘process_delay’ parameter which makes the BOSH CM wait for this amount of 100ms for incoming packets from the server in order to reduce the overall number of roundtrips between client and BOSH CM. This results in an overall improved client experience. Although it might be a bit slower at login times.
By default this value is set to 100ms so I did my tests again with ‘process_delay’ set to 10ms. A value of 1ms or 0ms made ejabberd fail to work properly unfortunately so I can’t provide any further numbers. But as the overall number of request roundtrips for a login is 4, the maximum number of time saved for the login would be 40ms in best case when only dealing with the ‘process_delay’ parameter.

JSJaC v1.3.4 bugfix release

Unfortunately the last version of JSJaC (v1.3.3) released just some days ago contained some serious bugs regarding handling of xmlns attributes and namespaces correctly. It was introduced by a fix for IE9 which caused other browsers to fail. So if you’re using JSJaC v1.3.3 and your app deals with accessing elements identified by namespaces you’re strongly encouraged to update in order to avoid heavy brain damage.

JSJaC 1.3.3: Grab it while it’s hot!

Thought it’s about time to release all the little fixes and patches I’ve collected over the years for JSJaC and here it is: JSJaC 1.3.3! Along with innumerable bug fixes it contains fixes for IE 9 and two new functions which allow to implement your own data store when suspending or resuming a BOSH session. Have a look at the docs if you’re curious.

jwchat.org now with like button

Better late than never: jwchat.org new features a facebook like button plus a flattr button. So if you like the service here’s your chance to let us know! :D

ezmlm on debian with dotdeb broken

Today I discovered my ezmlm-idx hasn’t been working anymore. Unfortunately this hasn’t been noticed for quite some time. I’m using the precompiled qmail stack from dotdeb.org. What I found in my logs was

ezmlm-send:_fatal:_temporary_qmail-queue_error:_unable_to_exec_qq_(#4.3.0)/ezmlm-gate:_fatal:_temporary_error_from_child/
Now that got me real headaches as there aren’t many useful results on google for this topic. The more I was surprised when I found out what caused the problem (thanks to ‘strace -f’): ezmlm was expecting qmail-queue to be found at /var/lib/qmail/bin. While it’s actually at /usr/sbin/qmail-queue. Adding a symlink to it fixed the issue for me.

gateways blocked

Short note: due to abuse I had to block access to all gateways (transports) of jwchat.org for external usage. I’m sorry about this but currently there’s no other way to maintain regular services as is.

Nagios Plugin to monitor BOSH services

Enjoy!


#!/usr/bin/perl -w
#
# check_bosh plugin for nagios
#
# usage:
# check_bosh -U url -H host
#
# Check if bosh service running at specified address
#
# initial version: 3 May 2000 by Truongchinh Nguyen and Karl DeBisschop
#
# current status: $Revision: 1196 $
#
# Copyright Notice: GPL
# $Id: check_bosh.pl 1196 2009-06-17 15:20:46Z s.strigler $
#

use strict;
use lib "/usr/lib/nagios/plugins";
use utils qw($TIMEOUT %ERRORS &print_revision &support);
use vars qw($PROGNAME);
my ($verbose,$host,$response,$state);
my ($opt_V,$opt_H,$opt_h,$opt_U);
$opt_V = $opt_h, $opt_h = $opt_U = '';
$state = 'UNKNOWN';

$PROGNAME = "check_bosh";
sub print_help ();
sub print_usage ();

$ENV{'BASH_ENV'}='';
$ENV{'ENV'}='';
$ENV{'PATH'}='';
$ENV{'LC_ALL'}='C';

use Getopt::Long;
Getopt::Long::Configure('bundling');
GetOptions(
"V" => \$opt_V, "version" => \$opt_V,
"h" => \$opt_h, "help" => \$opt_h,
"U=s" => \$opt_U, "url=s" => \$opt_U,
"H=s" => \$opt_H, "host=s" => \$opt_H,
"v+" => \$verbose, "verbose+" => \$verbose
);

# -h means display verbose help screen
if ($opt_h) { print_help(); exit $ERRORS{'OK'}; }

# -V means display version number
if ($opt_V) {
print_revision($PROGNAME,'$Revision: 1196 $ ');
exit $ERRORS{'OK'};
}

# -U means URL
unless ($opt_U) { print_usage(); exit $ERRORS{'UNKNOWN'}; }

# -H means host name
unless ($opt_H) { print_usage(); exit $ERRORS{'UNKNOWN'}; }

if (! utils::is_hostname($opt_H)){
print "$opt_H is not a valid host name\n";
print_usage();
exit $ERRORS{"UNKNOWN"};
}

# Just in case of problems, let's not hang Nagios
$SIG{'ALRM'} = sub {
print ("ERROR: No response from RPC server (alarm)\n");
exit $ERRORS{"UNKNOWN"};
};
alarm($TIMEOUT);

$state = &check_bosh($opt_U, $opt_H);

if ($state eq 'OK') {
print "$state: BOSH service at $opt_U up and running\n";
}elsif ($state eq 'WARNING') {
print "$state: BOSH service not working correctly. Bad hostname given?\n";
}else{
print "$state: BOSH service at $opt_U is not running\n";
}
exit $ERRORS{$state};

sub check_bosh() {
my $url = shift;
my $host = shift;

use LWP::UserAgent;
my $ua = LWP::UserAgent->new;

my $req = HTTP::Request->new(POST => $url);
$req->content_type('text/xml; charset=utf-8');
my $payload = "";
print "SEND: ", $payload, "\n" if($verbose);

$req->content($payload);

my $res = $ua->request($req);

if ($res->is_success) {
print "RECV: ", $res->content, "\n" if ($verbose);

if ($res->content =~ /type='terminate'/) {
return 'WARNING';
} elsif ($res->content =~ /sid='([^']+)'/) {
$req = HTTP::Request->new(POST => $url);
$req->content_type('text/xml; charset=utf-8');

$payload = "";
print "SEND: ", $payload, "\n" if($verbose);
$req->content($payload);

$res = $ua->request($req);

if ($res->is_success) {
print "RECV: ", $res->content, "\n" if ($verbose);
}
else {
print $res->status_line, "\n" if ($verbose);
return 'CRITICAL';
}
}
}
else {
print $res->status_line, "\n" if ($verbose);
return 'CRITICAL';
}

return 'OK';
}

sub print_help() {
print_revision($PROGNAME,'$Revision: 1196 $ ');
print "Copyright (c) 2009 Stefan Strigler\n";
print "adopted from check_rpc by Karl DeBisschop/Truongchinh Nguyen/Subhendu Ghosh\n";
print "\n";
print "Check if bosh service is up and running\n";
print "\n";
print_usage();
print "\n";
print " URL of bosh service\n";
print " XMPP host name\n";
print " [-v] Verbose \n";
print " [-v -v] Verbose - will print supported programs and numbers \n";
print "\n";
support();
}

sub print_usage () {
print "Usage: \n";
print " $PROGNAME -U url -H host [-v]\n";
print " $PROGNAME [-h | --help]\n";
print " $PROGNAME [-V | --version]\n";
}

Firefox 3.0.6 not able to read Cookie (breaks MUCkl/JWChat with HTTP Polling)

Firefox as of version 3.0.6 seems to not allow reading cookies from HTTP headers when doing AJAX requests. As a consequence JSJaC’s HTTP Polling backend can’t work correctly anymore and breaks usage of MUCkl and JWChat with this version of Firefox. If your site is affected please consider switching to HTTP Binding (aka BOSH) which should fix this issue.
HTTP Binding has been designed specifically to address issues with constrained clients not capable of reading HTTP header cookies.

JSJaC inherit

When integrating a web chat (like JWChat) into your existing community most likely you don’t want to have your users sign in a second time just for the chat. A possible solution to this problem domain is to let your web server handle BOSH session instantiation and xmpp authentication. Once successfull you can pass the credentials (i.e. the runtime data) of this BOSH session to JSJaC. There’s an undocumented method call ‘inherit’ which handles this.
Here’s a fine tutorial on how to do this: Chat Hacking, Part II

dojo vs. isArray

Some days ago a spent many hours to fix a somewhat broken toJson output from dojo. I’ve been copying around an array between different frames and ended up having an object instead of an array as it should be. Seems Ajaxian has a solution to this array bug now. So please dojo could you please fix your dojo.isArray?