Copyright © 2003 by FhG FOKUS
Sip Express Router (SER) is a very fast and scalable Session Initiation Protocol (SIP) server.
This manual presents how to configure and use a very complex SER module: "jabber". The module implements a gateway between SIMPLE (SIP for Instant Messaging and Presence Leveraging Extensions) and XMPP ( eXtensible Messaging and Presence Protocol - also known as Jabber protocol) protocols.
The module needs a local Jabber server for co-working with it. Each SIP user who wants to send or to receive messages to/from Jabber network must have an associated Jabber ID on local Jabber server. This association between SIP users and local Jabber users is stored in a MySQL database.
Each SIP message for a Jabber user is translated into a Jabber message and sent to local Jabber server, using the associated Jabber ID as origin of the message. Each Jabber messages intended for associated Jabber ID is translated to a SIP message and sent to the SIP user.
The Jabber module integrates XODE XML parser to parse the XMPP messages. That introduces a module dependency to "expat" library.
"Expat' is a common XML library and is the fastest available for Linux/Unix, the second over all, after msxml library. It is integrated in most of well known Linux distributions. '"
Presence support together with Presence Agent module (see doc/xxjab.cfg for a sample cfg file).
SIP/SIMPLE to Jabber conference support.
Possibility to manage most important types of Jabber messages (message/presence/iq).
Aliases -- Possibility to set host aliases for IM (Jabber, ICQ, MSN, AIM, Yahoo) destinations (see parameter's description).
Ability to send SIP MESSAGE requests to different IM networks (Jabber, ICQ, MSN, AIM, Yahoo) using the Jabber server.
Send incoming messages from Jabber networ to a SIP destination.
Gateways detection -- Ability to detect whether an IM gateway is available or not.
SQL URL of database -- username, password, host, port and database (ex: sql://username:password@hostname.com/database).
Default value is "sql://root@127.0.0.1/sip_jab".
IP or hostname of Jabber server -- it must be the same as the value from <host> tag of Jabber server config file.
Default value is "127.0.0.1".
Format: jabber.sipserver.com=<delim>. If the destination is for Jabber network the URI should be like: "username<delim>jabber_server@jdomain" or " nickname<delim>roomname<delim>conference_server@jdomain "
<delim> must be a un-reserved character. By default this character is "*". The destination will be transformed to "username@jabber_server" or "roomname@conference_server/nickname" before the message is sent to Jabber server.
Default value is NULL.
Aliases for IM networks.
Format: "N;alias1=<delim1>;...;aliasN=<delimN>;" Destinations like '*@aliasX' could have other format than the ones for Jabber network. All <delim> from user part of the destination address will be changed to <delimX> if the destination address contains <aliasX>.
(Ex: jdomain is 'jabber.x.com=*' and msn_alias is 'msn.x.com=%'. The destination address forM MSN Network, on SIP side, is like "username*hotmail.com@msn.x.com". The destination address will be transformed to "username%hotmail.com@msn.x.com". "msn.x.com" must be the same as the JID associated with MSN transport in Jabber configuration file (usually is "jabberd.xml"))
Default value is NULL.
Outbound proxy address.
Format: "ip_address:port" or "hostname:port".
All SIP messages genereated by gateway will be sent to that address. If is missing, the message will be delivered to the hostname of the destination address
Default value is NULL.
The address in whose behalf the INFO and ERROR messages are sent.
Default value is "jabber_gateway@127.0.0.1".
Number of workers - extra processes that open connections to the Jabber server and do the translation SIMPLE-XMPP.
Default value is 2.
Maximum jobs per worker - how many Jabber connections can handle a worker.
Default value is 10.
Cache time (seconds) of a Jabber connection - how long a Jabber connection is kept alive if no traffic is through it.
Default value is 600.
Time interval (seconds) to keep trying sending a SIP message to Jabber server.
Default value is 90 seconds.
Converts SIP MESSAGE requests to Jabber messages and sends them to Jabber server.
Converts SIP MESSAGE message to a Jabber message and sends it to Jabber server.
Join a Jabber conference--the nickname, room name and conference server address should be included in To header as: "nickname%roomname%conference_server@jdomain". If the nickname is missing, then the SIP username is used.
Leave a Jabber conference -- the nickname, room name and conference server address should be included in To header as: "nickname%roomname%conference_server@jdomain".
Useful scripts, to create Jabber Gateway database or to manage the Jabber accounts with a web browser, are located in "doc" subdirectory of the module.
The module uses a MySQL database for keeping the association between SIP users an Jabber users. The script that creates the database is presented below.
Example 1-20. SQL Script
... # # DATABASE definition # DROP DATABASE IF EXISTS sip_jab; CREATE DATABASE sip_jab; USE sip_jab; # jabber users CREATE TABLE jusers( juid INT NOT NULL AUTO_INCREMENT, jab_id VARCHAR(128) NOT NULL, jab_passwd VARCHAR(50), sip_id VARCHAR(128) NOT NULL, type INT NOT NULL DEFAULT 0, PRIMARY KEY(juid), KEY(jab_id), KEY(sip_id) ); # icq users CREATE TABLE icq( juid INT NOT NULL, icq_id INT NOT NULL, icq_passwd VARCHAR(50), icq_nick VARCHAR(50), type INT NOT NULL DEFAULT 0, PRIMARY KEY(juid), # --- REFERENCES jusers(juid) ON UPDATE CASCADE ON DELETE CASCADE, KEY(icq_id) ); # msn users CREATE TABLE msn( juid INT NOT NULL, msn_id VARCHAR(128) NOT NULL, msn_passwd VARCHAR(50), msn_nick VARCHAR(50), type INT NOT NULL DEFAULT 0, PRIMARY KEY(juid), # --- REFERENCES jusers(juid) ON UPDATE CASCADE ON DELETE CASCADE, KEY(msn_id) ); # aim users CREATE TABLE aim( juid INT NOT NULL, aim_id VARCHAR(128) NOT NULL, aim_passwd VARCHAR(50), aim_nick VARCHAR(50), type INT NOT NULL DEFAULT 0, PRIMARY KEY(juid), # --- REFERENCES jusers(juid) ON UPDATE CASCADE ON DELETE CASCADE, KEY(aim_id) ); # yahoo users CREATE TABLE yahoo( juid INT NOT NULL, yahoo_id VARCHAR(128) NOT NULL, yahoo_passwd VARCHAR(50), yahoo_nick VARCHAR(50), type INT NOT NULL DEFAULT 0, PRIMARY KEY(juid), # --- REFERENCES jusers(juid) ON UPDATE CASCADE ON DELETE CASCADE, KEY(yahoo_id) ); ... |
In the table "jusers" you must have entries like in next example for each pair SIP user - Jabber user. The jab_id field must not contain the server hostname.
Table 1-1. Sample jusers table
| juid | jab_id | password | sip_id | type |
|---|---|---|---|---|
| 1 | jabber_username | xxxxxxx | sip:sip_username@sipserver.com | 0 |
In the table "aim" the juid must be the same with the value from table "jusers" of the row containing the sip_id of the SIP user that wants to use SIP-to-AIM gateway. The aim_id field must not contain the server hostname.
Table 1-2. Sample aim table
| juid | aim_id | aim_passwd | aim_nick | type |
|---|---|---|---|---|
| 1 | aim_username | xxxxxxx | aim_nickname | 0 |
In the table "icq" the juid must be the same with the value from table "jusers" of the row containing the sip_id of the SIP user that wants to use SIP-to-ICQ gateway. The icq_id is the number of an ICQ account.
In the table "msn" the juid must be the same with the value from table "jusers" of the row containing the sip_id of the SIP user that wants to use SIP-to-MSN gateway. The msn_id must contain the server hostname and the character @ must be replaced by %. The server hostname must be "hotmail.com" or "msn.com".
Table 1-4. Sample msn table
| juid | msn_id | msn_passwd | msn_nick | type |
|---|---|---|---|---|
| 1 | msn_username%hotmail.com | xxxxxxx | msn_nickname | 0 |
In the table "yahoo" the juid must be the same with the value from table "jusers" of the row containing the sip_id of the SIP user that wants to use SIP-to-Yahoo gateway. The yahoo_id field must not contain the server hostname (e.g. yahoo.com).
It is not recommended to allow external users to use the local Jabber server. It should be a private server that accepts client connections only from SER module. The Jabber server setup is not a subject of this document. Check http://www.jabber.org for that. Next are presented the relevant parts of Jabber server configuration file.
Example 1-21. Jabber Server configuration file
...
<!-- jabber.xml file from jabserv.x.com -->
<jabber>
<service id="sessions">
<host>jabserv.x.com</host>
<jsm xmlns="jabber:config:jsm">
........................................
<browse>
<conference type="public" jid="conference.x.com"
name="Public Chatrooms"/>
<service jid="icq.x.com" name="ICQ Transport">
<ns>jabber:iq:register</ns>
<ns>jabber:iq:gateway</ns>
</service>
<service type="msn" jid="msn.x.com" name="MSN Transport">
<ns>jabber:iq:gateway</ns>
<ns>jabber:iq:register</ns>
</service>
<service type="aim" jid="aim.x.com" name="AIM Transport">
<ns>jabber:iq:gateway</ns>
<ns>jabber:iq:register</ns>
</service>
<service type="yahoo" jid="yahoo.x.com" name="Yahoo Transport">
<ns>jabber:iq:gateway</ns>
<ns>jabber:iq:register</ns>
</service>
</browse>
</jsm>
..............................................
<service id='conference.x.com'>
<conference xmlns="jabber:config:conference">
<public/>
<vCard>
<FN>Public Chatrooms</FN>
<DESC>This service is for public chatrooms.</DESC>
<URL>http://www.x.vom/</URL>
</vCard>
<history>20</history>
<notice>
<join> has joined</join>
<leave> has left</leave>
<rename> is now known as </rename>
</notice>
</conference>
<load>
<conference>./conference-0.4/conference.so</conference>
</load>
</service>
<service id='aim.x.com'>
<load>
<aim_transport>./aim-transport-0.9.0/src/aimtrans.so</aim_transport>
</load>
<aimtrans xmlns='jabber:config:aimtrans'>
<vCard>
<FN>AIM Transport</FN>
<DESC>This is the AIM Transport</DESC>
<URL>http://www.x.com/</URL>
</vCard>
</aimtrans>
</service>
<service id="icq.x.com">
<icqtrans xmlns="jabber:config:icqtrans">
<instructions>Please enter your ICQ number (in the "username" field),
nickname, and password.</instructions>
<search>Search for ICQ users</search>
<vCard>
<FN>ICQ Transport</FN>
<DESC>This is the ICQ Transport</DESC>
<URL>http://www.x.com/</URL>
</vCard>
<prime>37</prime>
<ports>
<min>2000</min>
<max>3000</max>
</ports>
</icqtrans>
<load>
<icqtrans>./icq-transport/icqtrans.so</icqtrans>
</load>
</service>
<service id="msn.x.com">
<msntrans xmlns="jabber:config:msntrans">
<instructions>Enter your MSN Messenger account and password.
Example: user@hotmail.com.</instructions>
<servers><ip>messenger.hotmail.com</ip></servers>
<vCard>
<FN>MSN Transport</FN>
<DESC>This is the MSN Transport</DESC>
<URL>http://www.x.com/</URL>
</vCard>
</msntrans>
<load>
<msntrans>./msn-transport/src/msntrans.so</msntrans>
</load>
</service>
<service id="yahoo.x.com">
<load>
<yahoo_transport>./yahoo-transport/yahoo-transport.so</yahoo_transport>
</load>
<config xmlns="jabber:config:yahoo">
<vCard>
<FN>Yahoo! Transport</FN>
<NAME>Yahoo Transport</NAME>
</vCard>
<server>scs.yahoo.com</server>
<port>5050</port>
<charmap>CP1252</charmap>
</config>
</service>
................................................
</jabber>
...
|
The JID of Jabber transports must start with the name of the instant messaging network. For AIM, JID must start with "aim.", for ICQ with "icq" (that because of icqv7-t), for MSN with "msn." and for Yahoo with "yahoo.". The gateway needs these to find out what transport is working and which not.
The SER administrator has to set up the Jabber transport (module) for each IM network wanted to be reacheable from SIP side.
Next picture displays a sample usage of jabber module.
Example 1-22. SER config script - sample jabber usage
...
#
# configuration for Jabber module testing
# (sample config file using the module with presence support)
#
# $ID: daniel $
#
debug=9 # debug level (cmd line: -dddddddddd)
#fork=yes # (cmd. line: -D)
fork=no
log_stderror=yes # (cmd line: -E)
#log_stderror=no # (cmd line: -E)
children=2
check_via=no # (cmd. line: -v)
dns=off # (cmd. line: -r)
rev_dns=off # (cmd. line: -R)
port=5060
#listen=10.0.0.179
listen=193.175.135.68
fifo="/tmp/ser_fifo"
# for more info: sip_router -h
# ------------------ module loading ----------------------------------
#modules
loadmodule "../sip_router/modules/print/print.so"
loadmodule "../sip_router/modules/textops/textops.so"
loadmodule "../sip_router/modules/tm/tm.so"
loadmodule "../sip_router/modules/maxfwd/maxfwd.so"
loadmodule "../sip_router/modules/sl/sl.so"
loadmodule "../sip_router/modules/mysql/mysql.so"
loadmodule "../sip_router/modules/jabber/jabber.so"
loadmodule "../sip_router/modules/registrar/registrar.so"
loadmodule "../sip_router/modules/usrloc/usrloc.so"
loadmodule "../sip_router/modules/pa/pa.so"
# ----------------- setting module-specific parameters ---------------
# -- registrar params --
modparam("registrar", "default_expires", 120)
modparam("registrar", "use_domain", 1)
# -- usrloc params --
modparam("usrloc", "use_domain", 1)
modparam("usrloc", "db_mode", 0)
# -- jabber params --
modparam("jabber","db_url","sql://user:password@127.0.0.1/sip_jab")
modparam("jabber","jaddress","jabber.server.com")
modparam("jabber","jport",5222)
modparam("jabber","workers",2)
modparam("jabber","max_jobs",10)
modparam("jabber","cache_time",200)
modparam("jabber","delay_time",60)
modparam("jabber","jdomain","jabber.server.com=*")
modparam("jabber","aliases","4;aim.jabber.server.com;icq.jabber.server.com;msn.jabber.server.com=%;yahoo.jabber.server.com;")
route{
#if ( !mf_process_maxfwd_header("10") )
#{
# sl_send_reply("483","To Many Hops");
# drop();
#};
if (uri=~"[@:]sip\.server\.com([;:].*)*")
{
# for testing purposes, simply okay all REGISTERs
if (method=="REGISTER")
{
if (t_newtran())
{
save("location");
log("REGISTER received -> reply okay\n");
};
if(search("egistration"))
{
log("XJAB: Going ONline in Jabber network!!!\n");
if(jab_go_online())
{
sl_send_reply("200", "Accepted");
}
else
{
sl_send_reply("404","Not found");
};
}
else
{
log("XJAB: Going OFFline in Jabber network!!!\n");
if(jab_go_offline())
{
sl_send_reply("200", "Accepted");
}
else
{
sl_send_reply("404","Not found");
};
};
break;
};
if (method=="SUBSCRIBE")
{
if (t_newtran())
{
subscribe("registrar");
};
break;
};
if(!lookup("location"))
{
sl_send_reply("404","Not found");
break;
};
};
if ((search("To:.*@icq\.jabber\.server\.com"))
|| (search("To:.*@jabber\.server\.com"))
|| (search("To:.*@msn\.jabber\.server\.com"))
|| (search("To:.*@yahoo\.jabber\.server\.com")))
{
if (! t_newtran())
{
sl_reply_error();
break;
};
if (method=="MESSAGE")
{
log("MESSAGE received -> manage it with XJAB\n");
if(search("\n:on"))
{
if (jab_go_online())
{
sl_send_reply("200","Accepted");
}else{
sl_send_reply("404","Not found");
};
break;
};
if(search("\n:off"))
{
if (jab_go_offline())
{
sl_send_reply("200","Accepted");
}else{
sl_send_reply("404","Not found");
};
break;
};
if(search("\n:join"))
{
if (jab_join_jconf())
{
sl_send_reply("200","Accepted");
}else{
sl_send_reply("404","Not Found");
};
break;
};
if(search("\n:exit"))
{
if (jab_exit_jconf())
{
sl_send_reply("200","Accepted");
}else{
sl_send_reply("404","Not Found");
};
break;
};
if (jab_send_message())
{
sl_send_reply("200","Accepted");
}else{
sl_send_reply("503","Service Unavailable");
};
break;
};
if (method=="SUBSCRIBE") {
subscribe("jabber");
break;
};
log("NON_Message request received for JABBER gateway->dropt!\n");
sl_send_reply("202","Accepted");
break;
};
if (!t_relay())
{
sl_reply_error();
};
#forward(uri:host,uri:port);
}
...
|
It is recommended to have DNS entries for "aliases", "jaddress" and "jdomain", thus any SIP or Jabber client can resolve them. Otherwise, the SIP client must use the gateway as outbound proxy.
The "aliases' must have the same values as the JIDs defined in Jabber server config file. "jaddress" must have the same value with the hostname specified by the tag <host> in Jabber config file. The administrator of SER/Jabber gateway must inform the users what are the aliases for Jabber, AIM, ICQ, MSN, Yahoo networks... '"
Next step is to configure SER to recognize messages for Jabber gateway. The idea is to look into messages for the destination address and if it contains the Jabber server alias or other Instant Messaging network alias, that means the message should be passed to Jabber gateway. After that must be defined the meaning that message for Jabber gateway. It might be a special message what triggers the gateway to take an action or is a simple message which should be delivered intto Jabber network.
Above are presented some examples how to set the routing rules for Jabber module. The module exports methods for logging on/off an user to the local Jabber server, convert a SIP message to a Jabber message and send it to local Jabber server, join/exit a Jabber conference (see Exported Methods chapter).
What a SER admin has to do when he wants to set up the routing rules is to define the events to call the methods.
In the above example, the routing rules are based on special messages. If the body of a SIP message is ":online" and the destination is one of the defined "aliases" or "jdomain", the message is dropped and SER will sign in to local Jabber server the associated Jabber user of the SIP user who has sent the message. The ":offline" message rises the sign out from Jabber network. The ":join" and ":exit" are used for handling Jabber conference events: joining and leaving a room. Any other message is translated and delivered to local Jabber server.
Next config file piece presents a sample of using the REGISTER message to sing in/out the associated Jabber user to local Jabber server.
Example 1-23. Sign in/out at registration time
...
if (uri=~"[@:]sip\.x\.com([;:].*)*")
{
if (method=="REGISTER")
{
if(search("egistration"))
{
log("XJAB: Going Online in Jabber network!!!\n");
if(jab_go_online())
{
sl_send_reply("200", "Accepted");
}
else
{
sl_send_reply("404","Not found");
};
}
else
{
log("XJAB: Going Offline in Jabber network!!!\n");
if(jab_go_offline())
{
sl_send_reply("200", "Accepted");
}
else
{
sl_send_reply("404","Not found");
};
};
break;
};
}; ...
|
Next it is a sample script sequence for using SUBSCRIBE messages to join or leave a Jabber conference.
Example 1-24. Join/leave the conference rooms using SUBSCRIBE requests
...
if (method=="SUBSCRIBE"){
if(search("To:.*\*.+\*.+@jabber\.x\.de"))
{
if(search("\nExpires:[ \t]*0+[ \t\r]*\n"))
{
log("XJAB:UNSUBSCRIBE request for a JABBER conference!\n");
if (jab_exit_jconf())
{
sl_send_reply("200","Accepted");
}else{
sl_send_reply("404","Not Found");
};
}
else
{
log("XJAB:SUBSCRIBE request for a JABBER conference!\n");
if (jab_join_jconf())
{
sl_send_reply("200","Accepted");
}else{
sl_send_reply("404","Not Found");
};
};
break;
};
sl_send_reply("200","OK");
break;
};
...
|
To enable the presence support, the PA module must be loaded and when the SUBSCRIBE requests for a Jabber conference are received, the handle_subscription() method of the PA module must be called with parameter "jabber". After that PA and Jabber modules will take care about.
Example 1-25. Join/leave the conference rooms using SUBSCRIBE requests
...
loadmodule "../sip_router/modules/pa/pa.so"
...
route {
...
if ((search("To:.*@icq\.x\.com"))
|| (search("To:.*@jabber\.x\.de"))
|| (search("To:.*@aim\.x\.com"))
|| (search("To:.*@msn\.x\.com"))
|| (search("To:.*@yahoo\.x\.com")))
{
if (method=="SUBSCRIBE") {
handle_subscription("jabber");
break;
};
};
...
}
...
|
Each IM network has its own format for user's ID and, in some cases, many servers. Excepting the body of the message, usually only the destination address can be specified by SIP end-user. Most of the application clients do not allow to set other headers or parameters and because of that all information about destination network and user are encoded in this field. How a SIP address has the email address format, and the last part should be a DNS resolvable hostname, the user part of it is where can be dynamically encoded the necessary information. The destination address is fixed per chat session and it is less annoying than including this information in the body of each message.
In our case, when the message is for Jabber gateway, the destination address must follow some patterns:
for Jabber network: "username<delim>jabber_server@jabber_alias". (ex: alpha*jabber.org@jabber.x.com)
for Jabber conference: " nickname<delim>room<delim>conference_server@jabber_alias " (ex: alpha*chatting*conference.jabber.org@jabber.x.com).
for AIM network: "aim_username@aim_alias" (ex: alpha@aim.x.com).
for ICQ network: "icq_number@icq_alias" (ex: 1234567@icq.x.com).
for MSN network: "msn_username<delim>msn_server@msn_alias". msn_server can be either "msn.com" or "hotmail.com" (ex: alpha*hotmail.com@msn.x.com).
for YAHOO network: "yahoo_username@yahoo_alias" (ex: alpha@yahoo.x.com).
NOTE: 'jabber_alias' is the first part of 'jdomain' (the part before =).
There are many implementations of SIP clients that supports Instant Messaging. Here are named a few of them:
MSN Messenger 4.5-4.7 (Windows 9x/2000/NT/XP) - here is a simple manual how to configure and use MSN Messenger with SIP.
KPhone (Linux)
JSip (Java based)
The user must have an account on Jabber gateway to use it. For each other IM network where he wants to send messages, he must set up an account. The gateway is not able to create a new account in foreign networks, excepting local Jabber server. The administrator of the SER can provide information about how to create the Jabber gateway account and how to set up the other IM accounts.
When you want to send a message to someone in other IM network, you must set the destination of the message according with the pattern corresponding to that IM network (see last part of 'Admin's guide' - chapter " How looks the destination address'). '"
Ex: sending a message to user@jabber.org which is in Jabber network, the destination must be: "user<delim>jabber.org@jabber_alias'. In the case presented by this document, the <delim> is "*" and jabber_alias is "jabber.x.com", so the destination address is "user*jabber.org@jabber.x.com". '"
For someone who is in Yahoo network the destination must be: "user@yahoo_alias" (for our case: "user@yahoo.x.com").
NOTE: The alias of each IM network can be found out from SER admin.
NOTE: You cannot send messages from your SIP client to your associated Jabber account - is something like sending messages to yourself.
The module does not provide any sort of API to use in other SER modules.
Take a look at http://iptel.org/ser.
First at all check if your question was already answered on one of our mailing lists:
E-mails regarding any stable version should be sent to <serusers@iptel.org> and e-mail regarding development versions or CVS snapshots should be send to <serdev@iptel.org>.
If you want to keep the mail private, send it to <serhelp@iptel.org>.
Please follow the guidelines provided at: http://iptel.org/ser/bugs