I use a Git
post-receive
hook
that sends commit notifications to a Jabber server using the
Net::XMPP
Perl module.
For the first year or so of its operation, the hook would connect to the
Jabber server (first jabberd 1.4, later
Ejabberd) that I ran on oryx.com,
and send the commit message as git@oryx.com, and all was well. Recently,
we reorganised our servers. The git repository stayed in the same place,
but we wanted it to connect to the Jabber server on aox.toroid.org and
send notifications as git@aox.org.
I run Ejabberd on toroid.org too, and it was the work of a moment to add
aox.org to its list of hostnames and create an account for git@aox.org.
But when I tried to make my hook connect to the new server, I discovered
that Net::XMPP
does not allow me to specify the name of the
server independently of the hostname in the Jabber ID:
my $client = new Net::Jabber::Client ();
$client->Connect(
hostname => 'aox.toroid.org',
) or die "Can't connect: $!\n";
my @r = $client->AuthSend(
username => 'git',
password => '...',
resource => 'aox.git'
);
die "Cannot authenticate (@r)\n" if $r[0] ne "ok";
This code would connect to aox.toroid.org and try to authenticate as
git@aox.toroid.org. Changing hostname to "aox.org" didn't work (even
though we had SRV records pointing to the right server). Changing the
username to "git@aox.org" didn't work either. I spent some time looking
through the code and a tcpdump of the session to understand the problem.
It turns out that an XMPP session begins with a
<stream>
element like this:
<stream:stream version='1.0'
xmlns:stream='http://etherx.jabber.org/streams'
xmlns='jabber:client'
to='aox.toroid.org'
from='git.aox.org'
xml:lang='en'>
What is needed is to connect to aox.toroid.org and send
to='aox.org'
in the stream, because Ejabberd rejects
connections to a hostname not listed in its configuration.
Net::XMPP
and XML::Stream
(the underlying
module) use the hostname passed to Connect()
to decide
where to connect and what to send in the <stream>
.
Furthermore, XML::Stream
did support SRV lookups, but it
would replace the hostname with the result of the lookup and
use that name to compose the stream; and Net::XMPP
had no
way to enable the SRV lookups anyway.
I whipped up a patch to solve these problems. It adds "servername" and
"srv" parameters to the Connect()
method, which are passed
down to XML::Stream
. If the servername is specified, it is
used to decide where to connect (and if not, the old behaviour remains
unchanged). The srv parameter enables SRV lookups, and the results are
used to set (only) the servername; but the hostname is used to compose
the stream in every case. Thus the two are separated enough for my hook
to work again.
I sent my patch to the module maintainers, but did not receive a reply.
The patch is archived here.
It applies to Net::XMPP
1.02 and XML::Stream
1.23, but may need minor tweaking to apply cleanly to other versions.